- OOP (Object Oriented Programming)
- SOLID
- DRY - Don’t repeat yourself
- KISS (Keep it simple, stupid!)
- Avoid Creating a YAGNI (You aren’t going to need it)
- LOD (Law of Demeter)
- DDD
За этой аббревиатурой скрываются 5 базовых принципов ООП, предложенные Робертом Мартином в его статье «Принципы проектирования и шаблоны проектирования». Следование их духу сделает код легко тестируемым, расширяемым, читаемым и поддерживаемым.
Вот шпаргалка по этим принципам:
- (S) Single Responsibility Principle (принцип единственности ответственности)
- (O) Open/Closed Principle (принцип открытости/закрытости)
- (L) Liskov Substitution Principle (принцип подстановки Барбары Лисков)
- (I) Interface Segregation Principle (принцип разделения интерфейса)
- (D) Dependency Inversion Principle (принцип инверсии зависимостей)
По словам Роберта С. Мартина, симптомы гниющего дизайна или плохого кода:
- Жесткость (трудно менять код, так как простое изменение затрагивает много мест);
- Неподвижность (сложно разделить код на модули, которые можно использовать в других программах);
- Вязкость (разрабатывать и/или тестировать код довольно тяжело);
- Ненужная Сложность (в коде есть неиспользуемый функционал);
- Ненужная Повторяемость (Copy/Paste);
- Плохая Читабельность (трудно понять что код делает, трудно его поддерживать);
- Хрупкость (легко поломать функционал даже небольшими изменениями);
Но это улучшение, теперь мы можем сказать что то вроде "мне не нравится это потому, что слишком сложно модифицировать", или "мне не нравится это потому, что я не могу сказать, что этот код пытается сделать", но что насчет того, чтобы вести обсуждение позитивно?
Разве это не было бы здорово, если бы существовал способ описать свойства хорошего дизайна, а не только плохого и иметь возможность рассуждать объективными терминами? Для этого нам на помощь спешат принципы проектирования архитектуры и написания программного кода.
Сейчас мы рассмотрим эти принципы на схематичных примерах. Обратите внимание на то, что главная цель примеров заключается в том, чтобы помочь читателю понять принципы SOLID, узнать, как их применять и как следовать им, проектируя приложения. Автор материала не стремился к тому, чтобы выйти на работающий код, который можно было бы использовать в реальных проектах.
В golang в качестве отдельных частей у нас есть - пакаджи, структуры, методы и интерфейсы. Давайте расссмотрим SOLID в этих терминах.
- Single Responsibility Principle (принцип единственности ответственности)
- Open/Closed Principle (принцип открытости/закрытости)
- Liskov Substitution Principle (принцип подстановки Барбары Лисков)
- Interface Segregation Principle (принцип разделения интерфейса)
- Dependency Inversion Principle (принцип инверсии зависимостей)
Не повторяй сам себя
Следование принципу программирования «DRY» позволяет добиться высокой сопровождаемости проекта, простоты внесения изменений и качественного тестирования.
Если код не дублируется, то для изменения логики достаточно внесения исправлений всего в одном месте и проще тестировать одну (пусть и более сложную) функцию, а не набор из десятков однотипных. Следование принципу DRY всегда приводит к декомпозиции сложных алгоритмов на простые функции. А декомпозиция сложных операций на более простые (и повторно используемые) значительно упрощает понимание программного кода. Повторное использование функций, вынесенных из сложных алгоритмов, позволяет сократить время разработки и тестирования новой функциональности.
Следование принципу DRY приводит к модульной архитектуре приложения и к чёткому разделению ответственности за бизнес-логику между программными классами. А это — залог сопровождаемой архитектуры. Хотя чаще не DRY приводит к модульности, а уже модульность, в свою очередь, обеспечивает принципиальную возможность соблюдения этого принципа в больших проектах.
В рамках одного программного класса (или модуля) следовать DRY и не повторяться обычно достаточно просто. Также не требует титанических усилий делать это в рамках небольших проектов, где все разработчики «владеют» всем кодом системы. А вот в больших проектах ситуация с DRY несколько сложнее — повторы чаще всего появляются из-за отсутствия у разработчиков целостной картины или несогласованности действий в рамках команды. Следовать принципу «don’t repeat yourself» в рамках больших проектов не так просто, как это может показаться на первый взгляд. От разработчиков требуется тщательное планирование архитектуры, а от архитектора или тимлида требуется наличие видения системы в целом и чёткая постановка задач разработчикам.
В пректировании DRY тоже имеет место — доступ к конкретному функционалу должен быть доступен в одном месте, унифицирован и сгруппирован по какому-либо принципу, а не «разбросан» по системе в произвольных вариациях. Этот подход пересекается с принципом единственной ответственности из пяти принципов SOLID, сформулированных Робертом Мартином.
Принцип программирования KISS — делайте вещи проще
Большая часть программных систем необосновано перегружена практически ненужными функциями, что ухудшает удобство их использование конечными пользователями, а также усложняет их поддержку и развитие разработчиками. Следование принципу «KISS» позволяет разрабатывать решения, которые просты в использовании и в сопровождении.
KISS — это принцип проектирования и программирования, при котором простота системы декларируется в качестве основной цели или ценности. Есть два варианта расшифровки аббревиатуры: «keep it simple, stupid» и более корректный «keep it short and simple».
В проектировании следование принципу KISS выражается в том, что:
-
не имеет смысла реализовывать дополнительные функции, которые не будут использоваться вовсе или их использование крайне маловероятно, как правило, большинству пользователей достаточно базового функционала, а усложнение только вредит удобству приложения;
-
не стоит перегружать интерфейс теми опциями, которые не будут нужны большинству пользователей, гораздо проще предусмотреть для них отдельный «расширенный» интерфейс (или вовсе отказаться от данного функционала);
-
бессмысленно делать реализацию сложной бизнес-логики, которая учитывает абсолютно все возможные варианты поведения системы, пользователя и окружающей среды, — во-первых, это просто невозможно, а во-вторых, такая фанатичность заставляет собирать «звездолёт», что чаще всего иррационально с коммерческой точки зрения.
В программировании следование принципу KISS можно описать так:
- не имеет смысла беспредельно увеличивать уровень абстракции, надо уметь вовремя остановиться;
- бессмысленно закладывать в проект избыточные функции «про запас», которые может быть когда-нибудь кому-либо понадобятся (тут скорее правильнее подход согласно принципу YAGNI, который рассмотрим чуть ниже);
- не стоит подключать огромную библиотеку, если вам от неё нужна лишь пара функций;
- декомпозиция чего-то сложного на простые составляющие — это архитектурно верный подход (тут KISS перекликается с DRY);
- абсолютная математическая точность или предельная детализация нужны не всегда — большинство систем создаются не для запуска космических шаттлов, данные можно и нужно обрабатывать с той точностью, которая достаточна для качественного решения задачи, а детализацию выдавать в нужном пользователю объёме, а не в максимально возможном объёме.
Также KISS имеет много общего c принципом разделения интерфейса из пяти принципов SOLID, сформулированных Робертом Мартином.
Лучший код — это ненаписанный код.
Если упрощенно, то следование данному принципу заключается в том, что возможности, которые не описаны в требованиях к системе, просто не должны реализовываться. Это позволяет вести разработку, руководствуясь экономическими критериями — Заказчик не должен оплачивать ненужные ему функции, а разработчики не должны тратить своё оплачиваемое время на реализацию того, что не требуется.
Основная проблема, которую решает принцип YAGNI — это устранение тяги программистов к излишней абстракции, к экспериментам «из интереса» и к реализации функционала, который сейчас не нужен, но, по мнению разработчика, может либо вскоре понадобиться, либо просто будет полезен, хотя в реальности такого очень часто не происходит.
«Бесплатных» функций в программных продуктах просто не бывает. Если рассматривать материальную сторону, то любые ненужные, но фактически реализованные «фичи» оплачиваются либо Заказчиком (в бюджет закладываются расходы на те функции, которые не нужны), либо Исполнителем из прибыли по проекту. И тот, и другой варианты с точки зрения бизнеса неверны. Если же говорить о нематериальных затратах, то любые «бонусные» возможности усложняют сопровождение, увеличивают вероятность ошибок и усложняют взаимодействие с продуктом, — между объёмом кодовой базы и описанными характеристиками есть прямая зависимость. Больше написанного кода — труднее сопровождать и выше вероятность появления «багов».
Принципы YAGNI и KISS очень похожи, если KISS нацелен на упрощение и полезен в плане работы с теми требованиями, которые имеют место быть, то YAGNI более категоричен и применяется для ограждения проектов по разработке ПО от «размывания» их рамок.
Подход к реализации проектов строго по ТЗ верен с нескольких ракурсов. Заказчик не должен платить за то, что ему не надо, а продукт должен быть максимально сопровождаем и его качество не должно страдать от интеграции ненужных функций.