вторник, 21 октября 2014 г.

четверг, 9 октября 2014 г.

Шпаргалка по SOLID принципам

S – The Single Responsibility Principle

Название: Принцип единственной ответственности.

Определение: У класса/модуля должна быть лишь одна причина для изменения.

Смысл принципа: Борьба со сложностью, важность которой резко возрастает при развитии логики приложения.

Краткое описание: Любой сложный класс должен быть разбит на несколько простых составляющих, отвечающих за определенный аспект поведения, что упрощает как понимание, так и будущее развитие.

Типовые примеры нарушения: 1) смешивание логики и инфраструктуры: бизнес-логика смешана с представлением, слоем персистентности, находится внутри WCF или windows-сервисов и т.п. 2) класс/модуль решает задачи разных уровней абстракции: вычисляет CRC и отправляет уведомления по электронной почте; разбирает json-объект и анализирует его содержимое и т.п.

Anti-SRP – Принцип размытой ответственности. Чрезмерная любовь к SRP ведет к обилию мелких классов/методов и размазыванию логики между ними.

четверг, 2 октября 2014 г.

О принципах проектирования

Цикл статей о SOLID принципах

--------------------------------------------------

Для чего выдумывать все эти паттерны проектирования, принципы и методики? Разве не было бы проще обойтись без всего этого, а просто научить разработчиков хорошему дизайну? Или почему бы не формализовать этот процесс и ввести четкие количественные метрики, которые бы говорили, что одно решение однозначно лучше другого?

«Правильный дизайн» - это святой Грааль молодых разработчиков и молодых менеджеров. И те, и другие мечтают найти ответ на главный вопрос жизни, вселенной и всего такого разработки ПО – как добиться качественного дизайна, в сжатые сроки и с минимумом усилий.

Со временем и молодой разработчик, и молодой менеджер придут к пониманию того, что это невозможно. Невозможно найти идеальный абстрактный дизайн, поскольку слова «идеальный» и «абстрактный» противоречат друг другу. Дизайн – это постоянный поиск компромисса между противоречивыми требованиями: производительностью и читабельностью, простотой и расширяемостью, тестируемостью и цельностью решения.

четверг, 25 сентября 2014 г.

The Dependency Inversion Principle

Цикл статей о SOLID принципах

--------------------------------------------------

clip_image001

Принцип инверсии зависимости (Dependency Inversion Principle – DIP):

  • Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те и другие должны зависеть от абстракций.
  • Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Роберт Мартин «Принципы, паттерны и методики гибкой разработки» ([Martin2006]).

Принцип инверсии зависимостей – один из самых известных сегодня принципов проектирования, который лежит в основе популярных техник внедрения зависимостей (Dependency Injection). Однако, если посмотреть лишь на его название и описание, то будет довольно сложно понять, что же он означает. Поэтому, если спросить простых обывателей о том, что означает этот принцип, то они начнут что-то говорить о пользе интерфейсов и абстракций, и, вообще, будут путаться в показаниях.

четверг, 18 сентября 2014 г.

LSP Часть 2. О сложностях наследования

Цикл статей о SOLID принципах

--------------------------------------------------

Бытует мнение, что генерация исключений InvalidOperationException или NotSupportedException методами наследника означает нарушение этим классом принципа замещения Лисков. И хотя в некоторых случаях это действительно так, судить так однозначно нельзя.

Является ли нарушением LSP, что ImmutableList<T> и ReadOnlyCollection<T> реализует IList<T>, поскольку попытка добавления элемента в такую коллекцию приводит к генерации NotSupportedException? Может показаться, что нарушают, однако в «контракте» интерфейса IList<T> четко сказано, что метод Add будет добавлять элемент, только в случае выполнения «предусловия» – коллекция должна быть изменяемой! Аналогично дела обстоят с потоками ввода вывода, методы Read/Write которых могут генерировать исключения, если свойствами CanRead/CanWrite возвращают false. Во всех этих случаях мы можем говорить о неудачном дизайне, но не можем говорить о нарушении принципа подстановки Лисков!

вторник, 9 сентября 2014 г.

Liskov Substitution Principle

Цикл статей о SOLID принципах

--------------------------------------------------

Принцип подстановки Лисков (Liskov Substitution Principle, LSP):

Должна быть возможность вместо базового типа подставить любой его подтип.
Роберт К. Мартин "Принципы, паттерны и практики гибкой разработки", 2006

...если для каждого объекта o1 типа S существует объект o2 типа T такой, что для всех программ P, определенных в терминах T, поведение P не изменяется при замене o2 на o1, то S является подтипом (subtype) для T.
Барбара Лисков "Абстракция данных и иерархия", 1988

Наследование и полиморфизм является ключевым инструментом ОО разработчика при борьбе со сложностью, для получения простого и расширяемого решения. Наследование используется в большинстве паттернов проектирования и лежит в основе таких принципов, как Open-Closed Principle и Dependency Inversion Principle.

вторник, 2 сентября 2014 г.

Open/Closed Principle. ФП vs. ООП

Цикл статей о SOLID принципах

--------------------------------------------------

Как мы выяснили в прошлый раз, принцип открыт/закрыт подразумевает две вещи: необходимость фиксации интерфейса с возможностью изменения реализации, а также расширяемость за счет использования наследования и полиморфизма.

Давайте рассмотрим вопрос расширяемости в рамках семейства типов более подробно.

Большинство примеров, показывающих пользу «открытости» модулей обычно сводятся к демонстрации мощи полиморфизма над старым структурным подходом: «Смотрите, как здорово, когда мы избавляемся от конструкции switch в функции Draw и переносим всю логику в класс Shape и его наследники! Теперь наше решение является расширяемым и соответствует принципу Открыт/Закрыт, поскольку мы легко можем к квадрату и треугольнику добавить еще ромб с кругом!».

Да, действительно, добавить новый класс в существующую иерархию довольно легко, но что если мы хотим добавить в существующую иерархию новую операцию, например, метод GetArea в иерархию Shapes?