Skip to content

Конспект книги «Чистая архитектура»

Notifications You must be signed in to change notification settings

e-repo/clean-architecture

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 

Repository files navigation

Чистая архитектура

Тезисы о важности архитектуры в программном продукте:

  • Хорошая архитектура позволяет минифицировать затраты на поддержку и улучшение программы в будущем.
  • Если не продумать архитектуру на старте проекта, а заниматься только продуктовыми задачами, то вскоре стоимость этих задач сильно возрастёт. Возможно, что в один момент придётся перестать работать над функционалом и сесть за дорогостоящее переделывание архитектуры.
  • Не стоит откладывать «на потом» архитектурные моменты. Вряд ли это время наступит, а плохие решения могут надолго закрепиться в проекте.
  • С плохой архитектурой увеличение количества разработчиков не поможет масштабированию.

Ценности программы

У программного обеспечения есть две ценности: структура и поведение.

Поведение — это то, как программа работает, какие требование бизнеса выполняет. Именно ради поведения бизнес нанимает разработчиков и платит им деньги.

Но кроме этого, у софта есть и другая ценность — структура. Структура — это возможность вносить изменения в программу.

Если программа работает правильно, но в неё нельзя вносить правки, она быстро придёт в негодность. Однако же, если программа работает неправильно, но в неё можно без проблем вносить правки, то исправить ошибку не составит большого труда.

Выбор между этими двумя ценностями — это всегда борьба. Борьба, в которой разработчику необходимо научиться доказывать пользу от рефакторинга и улучшения архитектуры.

Что важнее — правильная работа системы или простота ее изменения? Если задать этот вопрос руководителю предприятия, он наверняка ответит, что важнее правильная работа. Разработчики часто соглашаются с этим мнением. Но оно ошибочно.

Тесты

Тесты — не панацея. Наличие тестов не гарантирует, что программа работает правильно.

Все, что дает тестирование после приложения достаточных усилий, — это уверенность, что программа действует достаточно правильно.

Парадигмы программирования

Парадигмы программирования не добавляют нам новых возможностей, а что‑то запрещают, говорят о том, чего не стоит делать. Эти запреты позволяют строить более надёжные программы, которые легко адаптировать к новым требованиям.

Структурное программирование

Накладывает ограничение на прямую передачу управления. СП ознаменовалось отказом от безусловных переходов (go to) в пользу условных операторов и циклов.

Методология структурного программирования появилась как следствие усложнения программного обеспечения — неструктурированная разработка порождала программы, которые было сложно поддерживать.

ООП

ООП вовсе не про инкапсуляцию (ее можно организовать через заголовочные файлы в C, или через замыкания в JavaScript), не про наследование и не про полиморфизм (обеспечить полиморфное поведение можно имея в распоряжении только функции), а про инверсию зависимостей. ООП накладывает ограничение на косвенную передачу управления.

Функциональное программирование

Главный принцип функционального программирования — запрет за изменение значений. Программу, данные в которой не меняются, легче понимать. Функциональное программирование накладывает ограничение на присваивание. Кроме этого ФП предлагает event sourcing — подход, когда хранится не состояния, а транзакции (переходы между состояниями).

SOLID

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

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

Single Responsibility Principle

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

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

Соблюдать принцип единственной ответственности помогает TDD, а также паттерны «Выделение класса» и «Фасад».

Open Closed Principle

Программные сущности должна быть открыты для расширения и закрыты для изменения.

«Открытость для расширения» означает, что поведение сущности может быть расширено путём создания новых типов сущностей.

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

Liskov Substitution Principle

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

Классический пример нарушения принципа LSP — наследование класса Square от класса Rectangle (определяющим методы setHeight и setWidth). Квадрат, расширяющий класс прямоугольника, не получится использовать как прямоугольник из-за того, что стороны квадрата равны и не могут задаваться отдельно.

Interface Segregation Principle

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

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

Dependency Inversion Principle

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

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

Разумеется, полностью соблюсти этот принцип для всех не получится — некоторые сущности будут знать о конкретной реализации. Лучше, чтобы о реализациях знало минимальное число модулей.

Компоненты

Компоненты — это единицы развёртывания. Они представляют наименьшие сущности, которые можно развертывать в составе системы.

Три принципа связанности компонентов:

Принцип эквивалентности повторного использования (Reuse/Release Equivalence Principle - REP)

"Единица повторного использования есть единица выпуска"

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

Принцип согласованного изменения (Common Closure Principle - CCP)

"В один компонент должны включаться классы, изменяющиеся по одним принципам и в одно время. В разные компоненты должны включаться классы, изменяющиеся в разное время и по разным причинам"

Это принцип единственной ответственности перефразированных для компонентов. Так же, как принцип SRP, гласящий, что класс не должен иметь несколько причин для изменения, принцип согласованного изменения (CCP) требует, чтобы компонент не имел нескольких причин для изменения

Принцип совместного повторного использования (Common Reuse Principle - CRP)

"Не вынуждайте пользователей компонента зависеть от того, чего им не требуется"

Принцип является обобщенной версией принципа разделения интерфейсов (ISP). Принцип ISP советует не создавать зависимости от классов, методы которых не используются. Принцип CRP советует не создавать зависимости от компонентов имеющих неиспользуемые классы.

Три принципа связности компонентов вступают в противоречия друг с другом. Принцип эквивалентности повторного использования (REP) и принцип согласованного изменения являются "включительными" - оба стремятся сделать компонент как можно крупнее. Принцип совместного повторного использования (CRP) - исключительный, стремящийся сделать компонент как можно мельче. Задача хорошего архитектора разрешить это противоречие

Сочетаемость компонентов

Принцип ацикличности зависимостей

Нельзя допускать зацикленности в графе зависимостей компонента. Если в зависимостях есть цикл, его можно разорвать с помощью принципа инверсии зависимостей.

Принцип устойчивых зависимостей

Зависимости должны быть направлены в сторону устойчивости. Некоторые компоненты должны быть более изменяемыми, но важно, чтобы менее стабильные компоненты всегда зависели от более стабильных.

Нестабильность = Число выходов / (Число входов + Число выходов)

Где:
Число входов - количество входящих зависимостей. Эта метрика определяет кол-во классов вне данного компонента, которые зависят от классов внутри компонента

Число выходов - кличество исходящих зависимостей. Эта метрика определяет кол-во классов внутри компонента, зависящих от классов за его пределами

Не все компоненты должны быть устойчивыми в системе, иначе систему невозможно будет изменить. Это нежелательная ситуация. В действительности структура компонентов должна проектироваться так, что-бы в ней имелись и устойчивые и не устойчивые компоненты.

Принцип стабильности абстракций

Устойчивость компонента пропорциональна его абстрактности.

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

Метрика абстрактности:
Абстрактность = Кол‑во абстрактных классов и интерфейсов в компоненте / Общее количество классов в компоненте

Границы

Прежде чем провести границы в архитектуре ПО, систему нужно разделить на компоненты. Границы должны отделять сущности, которые имеют значение для бизнес‑логики, от тех, которые не имеют. Например, бизнес‑логика не должна зависеть ни от схемы БД, ни от языка запросов.

Бизнес-правила

Бизнес-правила являются причиной существования программной системы. Они должны быть в неприкосновенности, незапятнанными низкоуровневыми аспектами, такими как пользовательский интерфейс или база данных. В идеале код, представляющий бизнес-правила должен быть сердцем системы, а другие задачи - просто подключаются к ним. Реализация бизнес-правил должна быть самым независимым кодом в системе, готовым к многократному использованию.

Чистая архитектура

Хорошая архитектура системы способствует созданию систем, обладающих следующими характеристиками:

  • Независимость от фреймворков
  • Простота тестирования
  • Независимость от пользовательского интерфейса
  • Независимость от базы данных
  • Независимость от любых внешних агентов

Зависимости в исходном коде должны быть направлены внутрь, в сторону высокоуровневых политик. Ничего во внутреннем круге не знает о внешних кругах. (см https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)

  • Сущности инкапсулируют критичные бизнес‑правила. Уровень бизнес-логики
  • Юзкейсы содержат специфические для приложения правила. Содержит бизнес-правила характерные для приложения, например отправку уведомлений на почту через почтовый сервис после каких-либо манипуляций с сущностью
  • Адаптеры интерфейсов конвертируют данные из формата, удобного для юзкейсов, в формат удобный для внешних слоёв.

Пересечение границ слоев системы обычно происходит с помощью простых структур (DTO, массивы, объекты, аргументы функций при вызове самой функции). Важно что-бы границы пересекали изолированные структуры данных

Признаки чистой архитектуры

  • Не зависит от фреймворков. Грамотная архитектура у проекта — та, при которой выбор фреймворка становится настолько неважным, что это решение можно откладывать до самого последнего момента.

  • Не зависит от пользовательского интерфейса, базы данных и каких-либо внешних агентов. Бизнес‑логике не важно, какую мы используем базу данных, будем ли мы доставлять данные через веб или иначе, она не зависит от устройства, на котором будет работать система и т.д.

  • Легко тестируется. Если тесты сильно связаны с компонентами, то небольшое изменение может уронить сотни тестов.

About

Конспект книги «Чистая архитектура»

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published