Clean Architecture

Как многие разработчики, я прекрасно понимаю, насколько важно создавать приложения, которые будет легко поддерживать, расширять и развивать в долгосрочной перспективе. Именно поэтому принципы Clean Architecture (Чистая архитектура) стали неотъемлемой частью моей работы. В этой статье я расскажу о том, почему следование принципам Clean Architecture так важно и какие преимущества эти принципы могут дать.
Почему важно следовать принципам Clean Architecture
Первое, что необходимо понимать — приложения, созданные с помощью принципов чистой архитектуры, обладают высокой устойчивостью к изменениям. Они быстро адаптируются к новым требованиям и возможностям, сохраняя при этом высокое качество кода и производительность. Кроме того, система становится гораздо проще для понимания и сопровождения, что делает ее более доступной для других разработчиков.
Принципы чистой архитектуры также помогают избежать проблем с зависимостями и разделить приложение на логические блоки. Это повышает удобство добавления новых функций и изменения уже существующих. В результате, время разработки сокращается, а приложение становится более гибким и масштабируемым.
Какие преимущества могут дать принципы Clean Architecture :
- Улучшение качества кода;
- Быстрая адаптация к изменениям и новым функциям;
- Удобство сопровождения и расширения приложений;
- Минимизация проблем с зависимостями;
- Повышение гибкости и масштабируемости приложений;
- Сокращение времени разработки и улучшение производительности.
Все эти пункты дают принципам чистой архитектуры важное преимущество в сравнении с другими методиками разработки. Поэтому, как профессиональный разработчик, я настоятельно рекомендую следовать этим принципам для создания лучших приложений.
Принципы Clean Architecture
Clean Architecture состоит из нескольких принципов, которые помогают разработчикам создавать качественное и устойчивое программное обеспечение. Рассмотрим основные принципы Clean Architecture:
Разделение на уровни
Ключевой принцип Clean Architecture — разделение приложения на уровни, каждый из которых выполняет свои задачи и управляет своей ответственностью. Обычно такое разделение выглядит следующим образом:
- Уровень представления
- Уровень приложения
- Уровень домена
- Уровень инфраструктуры
Уровень представления отвечает за взаимодействие с пользователем и обработку запросов. Уровень приложения выполняет бизнес-логику и координирует работу между уровнями представления и домена. Уровень домена содержит бизнес-логику и компоненты, отвечающие за работу с данными. Уровень инфраструктуры занимается поддержкой структур приложения и связью с внешними системами (например, базами данных, API и т.д.).

Зависимости внутри уровней в предыдущем сообщение подробно
Одна из важных частей этого принципа — зависимости внутри уровней. В каждом уровне приложения (например, Presentation, Domain или Data) важно тщательно контролировать зависимости между компонентами. Например, компоненты внутри слоя Domain не должны зависеть от компонентов в слое Data.
Один из способов достичь этого — использование инверсии зависимостей (Dependency Inversion Principle, DIP). Вместо того, чтобы компоненты в верхнем слое зависели от компонентов в нижнем слое, управление зависимостями и обмен данными происходит через общий интерфейс. Это позволяет упростить добавление, удаление или изменение компонентов с минимальными изменениями внутри каждого слоя.
Пример: в слое Domain, классы UseCase должны зависеть только от интерфейсов и классов, определенных в этом же слое. Они не должны зависеть напрямую от классов и интерфейсов слоя Data. Вместо этого классы слоя Data должны реализовывать интерфейсы, определенные в слое Domain, и затем передаваться в UseCase как аргументы конструктора. Такой подход помогает избежать прямых зависимостей между уровнями и обеспечивает более высокую гибкость и тестируемость кода.
Граничные интерфейсы
Граничные интерфейсы (Boundary Interfaces) — это интерфейсы, которые разделяют используемые элементы на две области: внутри приложения и вне его. Они служат для определения, какие элементы способны перейти за границу приложения и какие нет.
Граничные интерфейсы играют важную роль в Clean Architecture, так как они определяют, как пользовательский интерфейс должен общаться с приложением. Пользовательский интерфейс является внешней частью приложения, которая взаимодействует с пользователем и передает запросы в приложение. Граничные интерфейсы определяют, какие запросы пользовательский интерфейс может отправлять в приложение, и какие данные он может получать в ответ.
Примером граничного интерфейса является REST API веб-сервера, который позволяет клиентской стороне общаться с серверной стороной приложения. Если слой приложения использует граничные интерфейсы, то он был бы независим от клиентской стороны и мог бы быть более гибким при изменениях в клиентской стороне.
«Чистая зависимость»
Принцип «Чистой зависимости» (Pure Dependency Rule) гласит, что более высокоуровневые модули не должны зависеть от более низкоуровневых модулей. Оба модуля должны зависеть от абстракций. Абстракции не должны зависеть от деталей, а детали должны зависеть от абстракций.
Таким образом, при разработке уровней приложения, каждый уровень использует интерфейсы и абстракции, что позволяет изолировать изменения сверху. Это обеспечивает большую гибкость системы при изменениях.
Например, если нам нужно изменить базу данных, то мы можем заменить конкретную базу данных на новую, не меняя остальную структуру приложения. Это было бы невозможно, если бы мы использовали конкретную реализацию базы данных во всех частях приложения.
Use case — это принцип, который определяет входы и выходы пользовательских сценариев. В основе этого принципа лежит модель, где каждый пользовательский сценарий описывается согласно интересующим его элементам.
Шаг за шагом: как реализовать Clean Architecture в приложении
Ниже рассмотрены шаги, необходимые для реализации Clean Architecture в приложении.
1. Определение основных сущностей и границ приложения
Определение основных сущностей и границ приложения является первым и одним из важнейших шагов в реализации Clean Architecture. На этом этапе важно понять, какие компоненты приложения могут быть выделены как отдельные сущности, а также определить границы приложения, которые разделят его на отдельные модули.
К примеру, для учебного приложения для изучения иностранных языков основными сущностями могут быть ученик, преподаватель, задание и т.д. Границы приложения могут быть определены, например, в виде разных модулей: модуль для ученика, модуль для преподавателя, модуль для заданий и т.д.
Важно, чтобы на этом этапе были определены более общие и абстрактные концепции, которые затем могут быть конкретизированы и реализованы в соответствии с принципами Clean Architecture.
2. Создание модулей в соответствии с принципами Dependency Rule
Создание модулей в соответствии с принципами Dependency Rule — это важный шаг в реализации Clean Architecture. Принципы Dependency Rule помогают легко и эффективно управлять зависимостями между компонентами приложения и избежать проблем, связанных с круговыми зависимостями и множественными зависимостями.
В соответствии с принципами Dependency Rule, весь код приложения должен быть разбит на отдельные модули с четкими границами и зависимостями. Эти модули могут быть различными по своему функциональному предназначению, например, модулем для работы с базой данных, модулем для представления пользовательского интерфейса и т.д.

Каждый модуль имеет свои входные и выходные точки, которые позволяют ему получать информацию от других модулей и передавать ее дальше. При этом модули не могут напрямую зависеть от других модулей. Вместо этого, все зависимости должны быть определены через интерфейсы, что позволит легко заменить одну реализацию на другую, не внося изменений в другие модули.
3. Реализация Use Case с помощью интерфейса
Реализация Use Case с помощью интерфейса — это еще один важный шаг в реализации Clean Architecture. Этот шаг помогает разделить логику приложения на более простые и понятные компоненты, что значительно облегчает поддержку и дальнейшее развитие приложения.

Интерфейс Use Case определяет, какие задачи должно выполнять приложение. Реализация Use Case обычно содержит в себе бизнес-логику приложения, а также обращения к внешним источникам данных и сервисам. Чтобы реализовать Use Case с помощью интерфейса, необходимо определить абстрактный интерфейс, описывающий выполнение задачи, а затем реализовать этот интерфейс в соответствующем месте приложения.
Важно отметить, что эти шаги — это только базовые методы, используемые для реализации Clean Architecture в приложении. Каждое приложение уникально, и вам может потребоваться некоторая адаптация методов для его реализации.
Примеры реализации Clean Architecture
Пример чистой архитектуры в проектах на Java:
Один из наиболее популярных проектов, который использует Clean Architecture, — это Android-приложение Tivi. Исходный код можно найти на GitHub. При проектировании Tivi-приложения был использован подход Clean Architecture, который позволил разделить код на отдельные слои, а также улучшить масштабируемость и производительность приложения. Разработчики Tivi используют MVP-архитектуру (Model-View-Presenter) для практической реализации Clean Architecture. Они используют главную активность, которая является View-компонентом, Presenter-компонент, который находится в промежуточном слое и содержит бизнес-логику приложения, и Model-компонент, который находится в самом нижнем слое и обрабатывает данные и сетевые запросы. Каждый из слоев в Tivi-приложении максимально независимы друг от друга, поэтому изменения в одном слое не приводят к непредсказуемым результатам в других компонентах.
Примеры применения Clean Architecture в проектах на Python и C#:
Одним из замечательных проектов на Python, который использует Clean Architecture, является проект Saleor, который является открытым исходным кодом электронной торговой платформы. Он полностью соответствует принципам и концепциям чистой архитектуры. Этот проект использует фреймворк Django в качестве полноценной модели для реализации Clean Architecture. В Saleor-проекте каждый из компонентов приложения разделен на отдельные слои, которые управляют отдельными аспектами логики приложения.
Пример применения Clean Architecture в проектах на C# — графический редактор Draw. Этот портативный редактор рисунков был разработан с использованием принципов Clean Architecture. Разработчики решили разделить систему на три отдельных слоя. В первом слое находятся интерфейс пользователя и слой представления данных. Следующий слой включает логику приложения и приложение с бизнес-логикой. В последнем слое расположены классы, связанные с хранением данных. Каждый из слоев в Draw полностью независим и может быть легко изменен без изменения других слоев.
Частые ошибки
Одной из частых ошибок при использовании Clean Architecture является неправильное определение границ приложения. Это может привести к тому, что различные уровни архитектуры могут переплетаться, что усложняет понимание и поддержку кода в будущем. Например, некоторые разработчики могут смешивать представление с бизнес-логикой, подрывая основные принципы Clean Architecture. Чтобы избежать этой ошибки, всегда необходимо определять границы между уровнями архитектуры и придерживаться их при проектировании и написании кода.
Еще одним распространенным моментом при работе с Clean Architecture является неправильная реализация Use Case. Use Case — это часть бизнес-логики приложения, которая определяет конкретный сценарий использования. Ошибка состоит в том, что разработчики часто пытаются комбинировать несколько Use Case вместе, порождая тем самым огромный склад кода, который трудно поддерживать и расширять. Чтобы избежать этой проблемы, необходимо разбивать Use Case на более мелкие задачи и реализовывать их по отдельности.
Кроме того, неправильное использование зависимостей может пагубно сказаться на функционировании приложения. Различные компоненты должны быть независимыми от друг друга, что обеспечивает гибкость и легкость тестирования. Однако, когда разработчики пытаются сохранить связи между компонентами, это может привести к тому, что изменение одной части кода повлияет на другую. Чтобы избежать этой проблемы, все компоненты должны быть разделены на отдельные модули, и зависимости должны быть определены явно.
Заключение
В сравнении с другими подходами, Clean Architecture предоставляет более явное и понятное разделение приложения на компоненты. Команда разработчиков может легко видеть, как каждая часть приложения взаимодействует друг с другом, что упрощает сопровождение и устранение ошибок.
Из моего личного опыта Clean Architecture является хорошим подходом для создания качественных приложений, которые будут доставлять удовольствие пользователям. Благодаря этому подходу разработка приложений может быть быстрой и простой, что является необходимым условием для достижения успеха на рынке.
Напоследок хочу порекомендовать вам бесплатный вебинар в рамках которого эксперты OTUS расскажут про подход Data Streams, о том как принцип инверсии зависимостей (dependency inversion principle, DIP) используется для получения паттерна Iterator. Покажут, как применяется принцип инверсии зависимостей для получения повторно используемых алгоритмов над коллекциями объектов. А также расскажут, почему стоит избавляться от циклов при работе с коллекциями.
- паттерны
- clean architecture
Чистая архитектура: руководство для начинающих
Чистая архитектура — это рекомендации по организации системной архитектуры. Они были предложены Робертом С. Мартином (известным также как Дядя Боб) и основаны на ряде прежних архитектурных построений, таких как гексагональная архитектура, луковая архитектура и т. д.
Это одно из основных правил для создания адаптируемого программного обеспечения (ПО), удобного в тестировании и поддержке.
Зачем нужна архитектура?
“Задача архитектуры ПО — минимизация человеческих ресурсов при разработке и последующем сопровождении системы”, — Роберт С. Мартин.
Правильно выбранная архитектура упрощает тестирование, поддержку, модификацию, разработку и развертывание, а также обеспечивает независимость.
Чистая архитектура
Вот иллюстрация чистой архитектуры, созданная Робертом Мартином.
Схематично стек архитектуры представлен четырьмя уровнями: синий, зеленый, красный и желтый.
Каждая окружность соответствует различным составляющим ПО. Внешний уровень ПО является самым низким. К центру уровень повышается. В целом, чем ближе слой к центру, тем он менее подвержен изменениям.
Правило зависимостей
Согласно этому правилу, зависимости исходного кода могут быть направлены только внутрь круговой схемы.
Это означает, что компоненты из внутренней окружности могут вообще ничего не знать о компонентах из внешней, то есть внутренняя окружность никак не зависит от внешней. Направление черных стрелок на схеме соответствует этому принципу.
Это важное, но не всегда понятное правило архитектуры. Чтобы лучше понять имеющиеся проблемы, сначала нарушим правило, а затем разберемся как нужно его соблюдать.
Круговая схема представляется не очень наглядной, поэтому отобразим все вертикально.
Цветовые обозначения на обоих схемах идентичные.
Помните, что стрелка должна читаться как “зависит от”, т.е. Frameworks and Drivers должны зависеть от Interface Adapters , те в свою очередь зависят от Application Business Rules , а они зависят от Enterprise Business Rules .
Ни один нижний слой не должен зависеть от верхнего.
Frameworks and Drivers
В этом слое размещены программные компоненты:
- User Interface (пользовательский интерфейс);
- Database (база данных);
- External Interfaces (внешние интерфейсы, например платформа API);
- Web (например, сетевой запрос);
- Devices (устройства, например принтеры и сканеры).
Interface Adapters
Слой интерфейсных адаптеров включает:
- Presenters (логика и состояния пользовательского интерфейса);
- Controllers (интерфейс с необходимыми приложению методами, которые реализованы через интернет (Web), устройства (Devices) или внешние интерфейсы (External Interfaces);
- Gateways (интерфейс, включающий все операции типа CRUD (create, read, update, delete), выполняемые приложением с базой данных).
Application Business Rules (Правила логики функционирования приложения)
Это правила, которые являются хоть и не основными, но необходимыми для логики функционирования конкретного приложения. В этот уровень входят Use Cases (сценарии использования), то есть он содержит все предоставляемые приложением функции.
Кроме того, этот уровень определяет контроллер/шлюз ( Controller / Gateway ), вызываемые для конкретного варианта использования. Иногда нужны контроллеры из разных модулей.
Именно здесь они и выбираются. Например, нужно применить скидку для пользователя, который в течение месяца совершил покупки на сумму x.
В этом случае нужно получить из purchase module (модуля покупки) сумму, потраченную пользователем в этом месяце, а затем по результату применить скидку в checkout module (модуле оформления заказа). Здесь applyDiscountUseCase вызывает контроллер модуля покупки для получения данных, а затем применяет скидку в модуле оформления заказа.
Application Business Rules (Правила логики функционирования проекта)
Это уровень содержит правила основной или предметного уровня логики функционирования. Кроме того, это наименее подверженный изменениям уровень.
На него не влияют изменения на любом внешнем (нижнем) уровне. Поскольку логика функционирования ( Business Rules ) меняться будет не часто, изменения на этом уровне происходят очень редко. Этот уровень включает Entities.
Entity (логический объект) может быть либо основной структурой данных, необходимой для правил логики функционирования, либо объектом с методами, содержащими логику функционирования.
Например, модуль Interest (вычисления процентов) в банковском приложении — это основная логика функционирования, которая должна находиться на этом уровне.
Разберемся на примере. Для этого создадим простое приложение с одним сетевым запросом. Оно выполняет перевод заданного пользователем предложения с помощью специального API . Посмотрим, как это можно сделать.
На каждом уровне выполняется определенная задача. Но все ли здесь логично? Проконтролируем направление зависимостей для этой архитектуры (структуры) в соответствии с правилом: “Зависимости в исходном коде должны иметь только внутренние направления”.
- UI → Presenter (✅ Верно)
- Presenter → Translate Usecase (✅ Верно)
- Translate Usecase → Translate Controller (❌ Не верно)
- Translate Controller → Web (❌ Не верно)
UI запрашивает данные от Presenter , который запрашивает данные от Use Case , а он должен запросить данные от Controller , который должен запросить от Web .
Можно ли ожидать, что Web передает какие-либо данные в Controller , а Use Case получит необходимые данные от Controller в нарушение правила зависимости? Ведь именно оно делает архитектуру работоспособной.
В соответствии с этим правилом некоторые стрелки здесь должны иметь другое направление. Возможно ли это? На помощь нам приходит способность полиморфизма функций.
Зависимость можно просто инвертировать, имея Interface (интерфейс) между этими двумя слоями. Это известный принцип инверсии зависимостей.
Реализуем этот принцип в случаях нарушений правила зависимости.
В результате получаем следующую схему.
Теперь проверим отсутствие нарушений в потоке зависимостей.
Теперь ни один внутренний уровень не зависит от внешних. Скорее, внешние зависят от внутренних.
Почему же так должно быть?
Представьте себя постояльцем отеля, которому в номер принесут совсем не то, что он заказывал. Здесь происходит то же самое. Приложению нужно, чтобы БД выдавала необходимые данные, а не любые.
Приложение заказывает необходимые данные, но при этом все равно, как БД или API обрабатывают их. Таким образом приложение не зависит ни от БД, ни от API. При необходимости можно легко вносить в БД или API изменения. Приложение даже не узнает об этом, поскольку будет получать все запрашиваемые данные.
Кроме того, правило односторонней зависимости предотвращает взаимоблокировку приложения, которая в двухуровневой архитектуре возникает, когда первый уровень зависит от второго, а второй уровень зависит от первого. В таком случае любое изменение в первом слое нарушает второй слой. А любое изменение во втором негативно отражается на первом. Предотвратить состояние взаимоблокировки позволяет чистая архитектура, описанная Робертом С. Мартином.
- Краткий обзор 10 популярных архитектурных шаблонов приложений
- Архитектура ПО: разница между архитектурой и проектированием
- Как научиться задавать вопросы, проектировать системы и выявлять ошибки?
Чистая архитектура на Go: плюсы и минусы
15-17 июля в Слёрм пройдёт практический интенсив «Чистая архитектура приложения на Go». Мы пообщались с его автором Николаем Колядко, Senior Go Backend в Robovoice. Он рассказал, что такое чистая архитектура и какие проблемы она помогает решить. А ещё разобрал основные плюсы и минусы такого подхода к разработке приложений.
Что такое чистая архитектура
Чистая архитектура — это способ организации кода, который способствует строгому разделению ответственности. Приложение разбивается на независимые функциональные компоненты, которые взаимодействуют друг с другом определённым способом, при этом между ними передаются только те ресурсы, которые необходимы для выполнения поставленной задачи. Это помогает минимизировать сложность каждого компонента, снижает вероятность ошибок и ускоряет их устранение при выявлении.
Как и любой архитектурный подход, чистая архитектура сама по себе не уберегает от написания плохого кода. Чтобы она упрощала жизнь, ты должен осознанно следовать её принципам.
Плюсы чистой архитектуры
На проекте с плохой архитектурой задачу, которую можно решить за час, ты делаешь две недели, а потом ещё чинишь полгода, потому что у тебя много лишних зависимостей. Чистая архитектура убирает лишние зависимости и собирает главную функциональность приложения в одном месте — в домене. Функциональность в домене независима, за счёт чего её проще тестировать. Плюс, обособленный домен помогает быстрее искать ошибки и неточности, упрощает написание тестов.
В чистой архитектуре сценарии приложения (use case) описаны отдельно. Именно они определяют, какие сторонние сервисы нам понадобятся. Благодаря этому мы получаем больше свободы в выборе инструментов и можем подстраивать внешний мир под свои нужды, а не наоборот.
Удобство тестирования, независимость от фреймворков, баз данных и UI — вот основные плюсы чистой архитектуры.
Какие проблемы решает чистая архитектура
- Проблема реализации. Первый симптом, что пора внедрять чистую архитектуру, — тебе нужно вносить изменения, а ты боишься, потому что не знаешь, к чему это приведёт. Я неоднократно становился свидетелем ситуации, когда люди с опаской добавляли новую функциональность в проект, а потом что-то реально ломалось. Чистая архитектура как раз позволяет избавиться от такого страха и сделать процесс внесения изменений более предсказуемым и управляемым.
- Проблема расширения. Предположим, тебе нужно сделать голосовой помощник, который бы распознавал ответы клиентов и продолжал диалог. Но идея звукового распознавания ничем не отличается от распознавания ответов клиентов в чате. А такой процесс у тебя уже настроен для Telegram. Хорошим архитектурным решением является создания ядра принятия решений, к которому будут подключаться другие сервисы, которые работают с конкретным каналом связи. Так, логика принятия решения будет находится в одном месте, поэтому её не нужно переписывать с нуля.
Минусы чистой архитектуры
На мой взгляд, основной минус чистой архитектуры в том, что тебе нужно писать больше кода. Допустим, ты хочешь настроить получение контактов из базы данных. Ты можешь написать метод, который обратится к библиотеке, сделать там небольшой select и задать ID-шник. Затем отправить данные на front, и это будет что-то около 200 строк.
В чистой архитектуре тебе сначала нужно сделать папку со слоем delivery, который будет принимать данные от front. Затем описать данные, которые должен прислать front, и вызвать слой use case. Use case проведёт валидацию, вызовет метод обращения к базе, и только после этого ты сможешь получить данные.
Ещё один минус — высокий порог входа. Продумать взаимодействие всех модулей системы довольно сложно, а для новичков это и вовсе непосильная задача.
Как удержать проект в рамках чистой архитектуры
С одной стороны, если ты начинаешь проект с чистой архитектуры, в нём сложно что-то сломать. С другой стороны, уже в процессе сопровождения проекта кто-то может поменять логику. Скажем, перенести валидацию полей, которая задаётся клиентом, на слой с базой данных. Единственный вариант контролировать и отслеживать это — код-ревью от более опытного коллеги.
На мой взгляд, важно разобраться в основах слоёв. Дальше ты уже поймёшь, как все раскидывать, и начнёшь делать это на автомате.
Для тех, кто хочет разобраться в слоях и понять, что такое чистая архитектура приложения на Go, мы запускаем новый практический интенсив «Чистая архитектура приложения на Go», который пройдет 15-17 июля.
За три дня вы изучите, что такое чистая архитектура на языке Golang, и под руководством спикера создадите сервис по работе с контактами и возможностью их группировки.
Будет полезно junior-разработчикам на Go и опытным разработчикам, которые переходят на Go с других языков.
Коротко о главном: Clean Architecture, Robert C. Martin
Можете ли вы, читая эту публикацию, дать четкий ответ на вопрос, что такое архитектура? Что такое архитектура в контексте программирования и проектирования? Какую роль она играет? Достаточно много неясностей есть в этом термине. И вроде бы все понятно, но как-то абстрактно, и без точности. Мартин считает, и я с ним солидарен, что приложение имеет две составляющих:
- Поведение (behavior) — функции и задачи, которые программа (компонент, сервис) выполняет.
- Архитектура — этот термин в большей мере о изменении приложения.
Но даже, если приложение очень хорошо выполняет задачу, которую она должна выполнять, это совсем не значит, что оно имеет хорошую архитектуру. Архитектура — это не о поведении приложения. Архитектура — это о легкости изменяемости, архитектура — это о легкости развертывания, архитектура — это о независимости разработки. Архитектура — это о скорости, с которой понимание приходит к новому человеку в команде
И вот как строить эту архитектуру, как избавится от головной боли при маленьком изменении требований от PM’а, или от стейкхолдера: об этом и поведает книга
Об авторах
Перед тем, как что-либо говорить об этой книге, я хочу сказать немного о себе.
На данный момент я Strong Junior Developer, специализирующийся на разработке сервисов посредством ASP .NET CORE’а.
Я уже год работаю на одной “галерке”, и вроде бы по чуть-чуть справляюсь
Книгу я эту уже прочел 2 раза, и к чтению рекомендую всем:
- разработчикам embeded систем;
- фронт-эндщикам;
- бэк-эндщикам;
- и даже девопсам.
Вообщем всем, кто хоть как то связан с разработкой ПЗ, имеется в виду непосредственной разработкой разных там Сейлов и ПМ’ов сюда не учитываем (хотя тоже было бы полезно знать, почему дев бывает тратит в 2 раза больше времени на задачу), советую прочесть эту книгу.
И сейчас я попробую аргументировать, почему я так считаю
Немного об авторе этой книги ( потому что для меня авторитет пишущего играет большую роль). Я думаю вы меня поймете, хоть это не всегда правильно, но если вам что-то говорит авторитетный человек в сфере — вы проявляете намного больше доверия к сказанному им. Например, я думаю вы больше поверите в диагноз, который вам ставит врач, нежели от какой-то человек из толпы (погугливший симптомы)
Роберт Мартин — он же Анкл Боб (дядюшка Боб) — работает в сфере программирования, причем разных систем (от вебсервисов до ембедит систем), с 1970 года. является техническим консультантом и архитектором, писал в разные технические журналы, сам по себе очень опытный программист, и человек который играл одну из ключевых ролей при создание всем известных SOLID принципов (можно сказать создатель). Так же, хочется добавить, что мне эту книгу посоветовал мой тимлид с 15+ опытом работы
О книге
Зависимости
Перед прочтением книги, я достаточно много статеек на том же Хабре читал, где фигурировало такое слово, как “зависимость”. Что это такое, кто от кого зависим, что конкретно значит “зависеть”, и как какой то класс может зависеть от кого-то?
И вот по мере прочтения книги я усвоил два момента:
Зависимость — это термин, значащий, что какой-то класс (компонент, сервис) знает о каком-то другом классе (компоненте, сервисе), и это знание на уровне кода определяется (сейчас джависты, шарписты, сишники меня поймут) определенным импортом неймспейса. Иными словами: есть у вас класс А с неймспейсом Default.Classes и класс B Another.Classes. Так вот, если в сорс коде класса А будет фигурировать using Another.Classes; — то это значит, что класс А зависит от класса B.
Чтобы понять по схеме, где зависимый класс, а где нет — смотрите на направление стрелки: в 1) стрелка будет указывать от класса А в направлении класса B. Это значит, что класс B более независимый, чем класс А. И изменения в классе А, никакого “ущерба” классу B не нанесут
SOLID
Одной из основной причины, которая была для меня к прочтению этой книги — это объяснение SОLID принципов из первоисточника, потому что дядя Роб разрабатывал эти принципы и можно сказать, благодаря ему мы слышим это название — SOLID.
Для тех, кто не в курсе — эти принципы говорят и советуют дизайнить свои приложения в соответствии с 5 правилами:
S — SRP (Single responsibility principle)
O — OCP (Open-closed principle)
L — LSP (Liskov substitution principle)
I — ISP (Interface segregation principle)
D — DIP (Dependency Inversion principle)
Все эти принципы могут быть применены на уровне классов и объектов, на уровне модулей и компонентов и на уровне лееров (сервисов).
Если вы считаете что Single responsibility principle — это про то, что класс, или же модуль должен делать только что-то одно — то вам обязательно нужно прочитать хоть бы главу про Солид. Ибо то определение, что дано выше — это следствие, но никак не определение самого принципа
О Dependency Inversion
Особое внимание хочу обратить на объяснение Dependency Inversion Principle (тот, что D из SOLID’a). По ходу прочтения книги, я понимал, это не просто принцип, это ещё механизм и инструмент, с помощью которого, вы можете менять направление ваших зависимостей, и делать, к примеру, бизнес логику (DOMAIN) независимой от деталей реализации Data access layer’а (DAL’a)

Хоть сам принцип на ряду с остальными в СОЛИД значит немного не то, что механизм, сам механизм используется на протяжении всей книги, и это один из основных методов инвертировать и менять направление ваших зависимостей, который кстати используется при DDD
О принятии архитектурных решений
Очень часто в книге будет упоминается принцип о принятии важных архитектурных решений: о том, какую БД использовать, какой фреймворк использовать, какую библиотеку подключать, что использовать как поисковой движок и т.д
Так вот, автор считает: вы должны КАК МОЖНО МЕНЬШЕ принимать такого рода решения. Ибо requirements могут изменяться, ограничения по perfomance’у тоже, сама поведенческая составляющая имеет тенденцию меняться. В процессе разработки каке-то решение может показаться менее эффективным нежели другое, менее удобным нежели другое. И сила твоей архитектуры будет определять, насколько быстро и безболезненно ты сможешь заменить одну технологию на другую (об этом кстати твердит OCP).
Например, внезапно, вы решите использовать вместо Postgresql MongoDb, или вообще файлики, или использовать mock’нутые данные, операции с которыми будут производится в памяти. И при некоторых условиях — это может заставить переписать почти всю логику.
Чтобы таких ситуаций не возникало, мы можем использовать некоторые механизмы, которые будут максимально далеко отодвигать время принятия решения. Один из этих механизмов — абстракция.
Отсылки на DDD
DDD — Domain Driven Design — подход к разработке сервисов с сложной бизнес логикой, критической к изменениям, который направленный на максимальной понимание руководящих должностей проекта (PMs, Sale managers etc), с рядовыми гребцами. То есть, что бы между все членами проекта был ubiquitous language, и каждый мог понять другого, и чтобы все мыслили в одном domain’е с одними и теме же бизнес правилами.
Если вы — приверженец DDD, или хотите быть таковым, или вы что-то в этом не понимаете, но хотите понимать — книга обязательна к прочтению, особенно вторая часть книги.
Здесь автор объясняет о существование Dependency Rule, и почему, следуя ему — вы будете строить правильную архитектуру приложения. Почему зависимости должны следовать в направлении к High Policy компонентам, почему домен (High Policy компонент) должен быть независим от инфраструктуры и как это упростит вам деплоймент и девелопинг
Абстрагирование
Дядя Роб, также рассказывает о том, как детали реализации могут навредить вашей системе, и не дать эволюционировать без боли в дальнейшем.
Помните!
БД — это деталь реализации
Клиенты (Web, Mobile, etc) — детали реализации
Фреймворки — это деталь реализации
От этого всего нужно максимально абстрагироваться и не зависеть, используя выше описанный Dependency Inversion с интерфейсами и абстракциями, Dependency Rule и прочие механизмы
Методы построения модулей
Этот раздел мне понравился особо сильно, как разработчику сервисов на ASP .NET CORE’е. Ибо здесь рассказываются о методологиях построения единой архитектуры сервиса из готовых компонентов.
Роберт описал 4 возможных схемы разделения слоев.
Он дал понять почему так часто используемый механизм 3-х слоевой архитектуры: UI (controllers), Services (Domain), DAL (Database) — достаточно плох по сравнению с другими. Я видел не очень много проектов, но в каждом, например микро-сервисе, на бэк-энде, используется именно трех-слоевая архитектура.
Так же, достаточно часто, используется архитектура один-компонент-один-сервис. В целом они обе неплохие, но она имеет достаточно много минусов, в сравнении к примеру, как строится архитектура при использовании DDD, особенно при критических к изменению, и сложных сервисов.
В общем, вот и подошел к концу этот обзор на книгу. Сама книга мне очень понравилась, не жалею о прочитанном, спасибо автору. Вам, дорогие читатели, спасибо за внимание, не судите строго — эта публикация, основанная на впечатлении от книги и моем личном энтузиазме
Добавить комментарий Отменить ответ
Для отправки комментария вам необходимо авторизоваться.