Показаны сообщения с ярлыком SOLID. Показать все сообщения
Показаны сообщения с ярлыком SOLID. Показать все сообщения

вторник, 23 августа 2016 г.

Принцип YAGNI

На ru.stackoverflow.com недавно был задан вопрос, который, ИМХО, стоит вашего внимания: Нарушает ли OCP и DIP (из SOLID) принцип YAGNI?. Ниже представлен немного более развернутая версия моего ответа.

Разные принципы проектирования направлены на решение противоречащих друг другу задач проектирования. Можно сказать, что разные принципы «тянут» дизайн в разные стороны и нужно найти правильный вектор, наиболее полезный в данном конкретном случае. SRP толкает в стороны простого решения, а OCP – в сторону изоляции компонентов, а DIP – направлен на построение правильных отношений между типами.

Следование одному принципу может привести к нарушению другого. Так, например, любое наследование *можно* рассматривать как нарушение SPR, поскольку теперь за одну ответственность (рисование фигур) отвечает целая группа классов. Принципы DIP и OCP, которые часто требуют наследования, могут привести к появлению дополнительных «швов», т.е. интерфейсов/базовых классов в системе, что, опять-таки, приведет к нарушению SRP и/или ISP.

четверг, 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?

вторник, 26 августа 2014 г.

Open/Closed Principle

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

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

Принцип открыт/закрыт (Open-Closed Principle, OCP): Программные сущности (классы, модули, функции и т.п.) должны быть открытыми для расширения, но закрытыми для модификации.
Роберт Мартин. Принципы, паттерны и практики гибкой разработки, 2010

Из всех «цельных» (SOLID) принципов, принцип Открыт/Закрыт является самым неоднозначным. Его неоднозначность кроется в противоречивости его определения (как что-то может быть одновременно «открытым» и «закрытым»?), а подкрепляется неоднозначными и разнообразными формулировками этого принципа в разных источниках. Не удивительно, что даже такие монстры, типа Эрика Липперта или Джона Скита относятся к этому принципу неоднозначно и признаются в его непонимании.

среда, 13 августа 2014 г.

Single Responsibility Principle

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

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

Принцип единственной обязанности (Single-Responsibility Principle, SRP): У класса должна быть только одна причина для изменения.
Роберт Мартин. Принципы, паттерны и практики гибкой разработки

Существует ряд патологических случаев нарушения принципа единственной обязанности, которые будут очевидны сегодня практически любому. Классы бизнес-логики, которые знают о пользовательском интерфейсе или о базе данных; класс windows-сервиса c кучей бизнес-логики; статические утилитные классы, изменяющие глобальное состояние и т.п.

При этом нарушение SRP бывают как на уровне классов/модулей, так и на уровне подсистем и приложений. Классическим примером из моей практики являются два вопиющих нарушения SRP на уровне приложений: использование Windows Forms приложения в качестве WCF сервиса, и необходимость взаимодействия виндового сервиса с пользователем через Message Box-ы.

вторник, 5 августа 2014 г.

Interface Segregation Principle

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

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

Вы никогда не ловили себя на мысли, что Принцип разделения интерфейса (ISP, Interface Segregation Principle) вам не вполне понятен или, что он является лишь разновидностью принципа единой ответственности (SRP, Single Responsibility Principle)? До недавнего времени у меня было подобное отношение, но оно несколько изменилось, после того, как я посмотрел на него с другой точки зрения.

Причина некоторого недопонимания принципа ISP, как мне кажется, кроется вот в чем. Во-первых, ISP отличается от других принципов SOLID тем, с какой стороны он применяется (об этом позднее), а во-вторых, у него далеко не самое лучшее определение.

Давайте начнем с определения. Вот формулировка принципа ISP из любимой мною книги Боба Мартина «Принципы, паттерны и методики гибкой разработки»:

"Этот принцип относится к недостаткам "жирных" интерфейсов. Говорят, что класс имеет жирный интерфейс, если функции этого интерфейса недостаточно сцепленные (not cohesive). Иными словами, интерфейс класса можно разбить на группу методов. Каждая группа предназначена для обслуживания разных клиентов. Одним клиентам нужна одна группа методов, другим – другая."