Как стать автором
Обновить

Актуален ли еще Solid?

Время на прочтение5 мин
Количество просмотров14K
Автор оригинала: Robert C. Martin (Uncle Bob)

Недавно я получил письмо:

В течение многих лет проверка понимания принципов SOLID было стандартной частью нашей процедуры приема на работу. Предполагалось, что кандидаты хорошо знакомы с этими принципами. Однако в последнее время один из наших менеджеров, который больше не занимается программированием, усомнился в том, что это разумно. Его аргументы заключались в том, что принцип открытости-закрытости (open–closed principle) больше не очень важен, потому что большая часть кода, который мы пишем, не содержится в больших монолитах, а внесение изменений в небольшие микросервисы безопасно и легко. Принцип подстановки Лисков (Liskov substitution principle) давно устарел, потому что мы не уделяем столько внимания наследованию, как 20 лет назад. Я думаю, нам следует рассмотреть позицию Дэна Норта по SOLID: «Просто напишите простой код».

В ответ я написал следующее письмо:

Принципы SOLID остаются актуальными и сегодня, как и в 90-е годы (и даже до этого). Это потому, что программное обеспечение не сильно изменилось за все эти годы. Оно не сильно изменилось даже с 1945 года, когда Тьюринг написал первые строчки кода для электронного компьютера. Программное обеспечение по-прежнему представляет собой операторы if, циклы while и операторы присваивания - последовательность, выбор и итерацию.

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

SRP - Принцип единой ответственности (The Single Responsibility Principle)

Соберите воедино то, что меняется по одним и тем же причинам. Разделяйте вещи, которые меняются по разным причинам.

Трудно представить, что этот принцип не применим в программном обеспечении. Мы не смешиваем бизнес-правила с кодом графического интерфейса. Мы не смешиваем SQL-запросы с протоколами связи. Мы храним код, который изменяется по разным причинам, отдельно, чтобы изменения одной части не нарушали работу других частей. Мы следим за тем, чтобы модули, которые изменяются по разным причинам, не имели запутывающих их зависимостей.

Микросервисы не решают эту проблему. Вы можете создать запутанный микросервис или запутанный набор микросервисов, если вы смешиваете код, который изменяется по разным причинам.

Слайды Дэна Норта полностью упускают суть этого вопроса и убеждают меня, что он вообще не понимал принципа. (или то, что он иронизировал, что, зная Дэна, гораздо более вероятно) Его ответ на SRP - «Напишите простой код». Я согласен. SRP - это один из способов упростить код.

OCP - Принцип открытости-закрытости (The Open-Closed Principle)

Модуль должен быть открыт для расширения, но закрыт для модификации.

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

Или… Хотим ли мы отделить абстрактные концепции от подробных понятий. Хотим ли мы изолировать бизнес-правила от мелких неприятных деталей графического интерфейса пользователя, протоколов связи микросервисов и произвольного поведения базы данных? Конечно!

Опять же, на слайде Дэна это совершенно неверно. При изменении требований неверна только часть существующего кода. Большая часть существующего кода все еще верна. И мы хотим быть уверены, что нам не нужно менять правильный код только для того, чтобы неправильный код снова заработал. Дэн ответил: «Напишите простой код». Опять же, я согласен. И, по иронии судьбы, он прав. Простой код бывает одновременно открытым и закрытым.

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

Программа, использующая интерфейс, не должна быть сбита с толку реализацией этого интерфейса.

Люди (в том числе и я) совершили ошибку, сказав, что речь идет о наследовании. Нет. Речь идет о подтипе. Все реализации интерфейсов являются подтипами интерфейса. Все типы уток - это подтипы подразумеваемого интерфейса. И каждый пользователь базового интерфейса, заявленный или подразумеваемый, должен согласовать значение этого интерфейса. Если реализация вводит в заблуждение пользователя базового типа, тогда операторы if / switch будут распространяться по коду.

Этот принцип заключается в сохранении четкости абстракций и их точного определения. Невозможно поверить, что это устаревшее понятие.

Слайды Дэна полностью соответствуют этой теме. Он просто упустил суть принципа. Простой код - это код, который поддерживает четкие отношения подтипов.

ISP - Принцип разделения интерфейса (The Interface Segregation Principle)

Делайте интерфейсы небольшими, чтобы пользователи не зависели от ненужных вещей.

Мы по-прежнему работаем с компилируемыми языками. Мы по-прежнему зависим от дат модификации, чтобы определить, какие модули следует перекомпилировать и повторно развернуть. Пока это верно, нам придется столкнуться с проблемой, заключающейся в том, что, когда модуль A зависит от модуля B во время компиляции, но не во время выполнения, изменения в модуле B вызовут перекомпиляцию и повторное развертывание модуля A.

Эта проблема особенно остро стоит в языках со статической типизацией, таких как Java, C #, C ++, GO, Swift и т. Д. Языки с динамической типизацией затрагиваются гораздо меньше; но все же не застрахованы. Существование Maven и Leiningen является тому доказательством.

Слайд Дэна по этой теме явно некорректен. Клиенты действительно зависят от методов, которые они не вызывают, если их нужно перекомпилировать и повторно развернуть при изменении одного из этих методов. Если вы можете разделить класс с двумя интерфейсами на два отдельных класса, это хорошая идея (SRP). Но такое разделение часто невозможно и даже нежелательно.

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

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

Трудно представить архитектуру, в которой этот принцип в значительной степени не использовался бы. Мы не хотим, чтобы наши бизнес-правила высокого уровня зависели от деталей низкого уровня. Надеюсь, это совершенно очевидно. Мы не хотим, чтобы вычисления, приносящие нам деньги, были загрязнены SQL, низкоуровневыми проверками или проблемами форматирования. Мы хотим изолировать абстракции высокого уровня от деталей низкого уровня. Это разделение достигается за счет тщательного управления зависимостями в системе, так что все зависимости исходного кода, особенно те, которые пересекают архитектурные границы, указывают на абстракции высокого уровня, а не на детали низкого уровня.

В каждом случае слайды Дэна заканчиваются словами: «Просто напишите простой код. Это хороший совет. Однако если годы и научили нас чему-то, так это тому, что простота требует дисциплины, основанной на принципах. Это те принципы, которые определяют простоту. Именно эти дисциплины вынуждают программистов создавать код, ориентированный на простоту.

Лучший способ устроить большой беспорядок - сказать всем: «Просто будьте простыми» и не давайте им никаких дальнейших указаний.

Теги:
Хабы:
Всего голосов 19: ↑15 и ↓4+11
Комментарии45

Публикации

Истории

Ближайшие события

Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург