Привет!🤠 Так ты хочешь быть архитектором, не так ли? Не лги мне, я знаю. Даже если вы этого не сделаете, вы все равно хотите стать лучшим разработчиком. Иначе вы бы не тратили время на чтение этой статьи 😁

Это похвально. В конце концов, мы все хотим быть лучше, если не лучшими в том, что мы делаем. Вот я, чтобы помочь вам с этим.

Итак, как стать архитектором? Очевидно, изучив все архитектуры! 😂 Конечно, это не так. Вам не нужно знать все. Вам также не нужно иметь опыт работы со всеми из них. Однако зная хотя бы самые популярные из них, такие как N-Layered, DDD, Hexagon, Onion и Clean Architecture; понимание их истории, их использования и различий между ними определенно отличает вас от других разработчиков.

Я надеюсь, что было достаточно вводных слов, чтобы заинтересовать вас. Если вам все еще интересно, давайте начнем 😉

Где все началось?

В старые добрые времена архитектуры не было вообще. Какие это были благословенные дни. Назвать себя архитектором можно было только зная паттерны GoF 😌

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

Первое, что решили разработчики, — отделить UI от бизнес-логики. В зависимости от UI-фреймворка рождались разные MVC-подобные паттерны:

На какое-то время это помогло, но не так сильно. Если вы из сообщества C#, как и я, вы, вероятно, ошибочно думаете, что желтая рамка под названием Модель на этих диаграммах — это просто DTO. Это все из-за Microsoft. Они запутали нас своим фреймворком ASP MVC. Будь ты проклят, Майкрософт! Ты думаешь, что ты умнее меня только потому, что я глупее? 😤

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

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

Это был период, когда паттернов GoF было просто недостаточно. Поэтому должны были появиться новые идеи. Как мы справляемся со сложностью? Верно! Разделяй и властвуй. Мы уже делали это с MVC, так что давайте сделаем это еще раз.

2002 — N-слоистый

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

Парня, который стал пионером в архитектуре разработки программного обеспечения и оказал влияние на целые поколения разработчиков в предстоящее десятилетие, зовут Джезу…кхе Мартин Фаулер. Он был такой:

Так они и сделали.

Он опубликовал Шаблоны архитектуры корпоративных приложений, где описал N-уровневую архитектуру.

Идея здесь проста: сгруппировать весь связанный код вместе и вызвать эти слои.

Однако есть еще кое-что. Фаулер знает, насколько вредной может быть непоследовательность. Поэтому, чтобы мы не выстрелили себе в ногу, он попытался ввести нас в некоторые ограничения:

  • вы можете называть слои так, как хотите
  • у вас может быть столько слоев, сколько вам нужно
  • вы можете добавить слои между ними
  • вы можете иметь несколько компонентов в одном слое
  • просто убедитесь, что существует четкая иерархия между слоями таким образом, что они ссылаются друг на друга один за другим

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

Несмотря на то, что эти правила довольно гибкие, на практике трех слоев было более чем достаточно для большинства проектов.

  • Пользовательский интерфейс (UI) — отвечает за взаимодействие с пользователями.
  • Слой бизнес-логики (BLL) — представляет концепции бизнеса. Он управляет тем, что делает ваше приложение, и делает его таким уникальным по сравнению с другими.
  • Уровень доступа к данным (DAL) — сохраняет данные в памяти и сохраняет состояние вашего приложения.

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

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

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

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

Каждый уровень вызывает нижний через свой API, который обычно представляется в виде interface. Модификаторы доступа для каждого класса так же важны, как и эти слои:

Это может показаться вам очевидным прямо сейчас, но это только потому, что вы не пережили действительно тяжелые времена. Его всегда легко использовать, но трудно изобрести. 😁

2003 — Дизайн, управляемый доменом

В 2003 году молодой 46-летний разработчик из Бостона Эрик Эванс опубликовал собственную книгу Дизайн, ориентированный на предметную область: решение сложных задач в основе программного обеспечения один Мартин в мире действительно грустно.

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

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

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

Но самое важное, что сделал Эванс, это то, что он сказал: «К черту базу данных, бизнес-логика важнее». Он сказал это и ничего не сделал по этому поводу🤷‍♂️. Да, да, да, я знаю… DDD и так далее. Однако с архитектурной точки зрения он не сильно изменился.

В его архитектуре определены следующие слои:

  • Уровень представления — отвечает за взаимодействие с пользователями.
  • Уровень приложений — координирует задачи и делегирует работу объектам предметной области.
  • Уровень предметной области — представляет концепции бизнеса. Он управляет тем, что делает ваше приложение, и делает его таким уникальным по сравнению с другими.
  • Уровень инфраструктуры — сохраняет данные в памяти и сохраняет состояние вашего приложения.

Вы видите, он сделал некоторые переименования.

Пользовательский интерфейс подразумевает, что у вас есть пользователи, что не всегда так. Иногда это GUI (графический интерфейс пользователя) для пользователей, иногда это CLI (интерфейс командной строки) для разработчиков, а часто это API (интерфейс прикладного программирования) для программ. Слой Presentation — это просто более общее и подходящее название.

Бизнес-логика сбивала с толку некоторых разработчиков, особенно тех, кто вообще не занимается бизнесом, поэтому было введено новое название — Домен.

База данных — не единственный внешний инструмент, который мы используем, поэтому все отправители электронной почты, шины событий, SQL и другие cr💩p были перемещены в инфраструктуру.

Это в основном все. Некоторые переименования здесь. Плюс один новый слой. Много сил было отдано домену. Но это та же архитектура с теми же зависимостями. Если бы он только знал о принципе инверсии зависимостей 😉.

2005 — Hexagon (Порты и адаптеры)

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

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

Первым парнем, который увидел здесь потенциал, был Алистер Кокберн. Парень был под кайфом, нарисовал шестиугольник, пытался вызвать Сатану и так далее. Мне не нужно вам рассказывать, вы сами лучше знаете, как это происходит на рок-тусовках 😒. Здесь ничего особенного, в один день куришь травку, в другой, проснувшись утром с сильным похмельем, обнаруживаешь, что случайно обнаружил новую архитектуру.

Алистерту надоели прямоугольники, поэтому он нарисовал шестиугольник, придумал для всего два названия, постарался сделать это священным. Но не пугайся, мой парень-разработчик. На самом деле эта архитектура не намного сложнее, чем N-слойная:

Было много вращения и движения, так что давайте посмотрим, что там произошло на самом деле.

Кокберносуществил мечту Эванса. Теперь Домен является центральным компонентом системы не только на словах, но и на деле. Он не ссылается на какой-либо другой проект.

Чтобы подчеркнуть, что это действительно сердце, Business Logic был переименован в Core.

Модули инфраструктуры были разделены пополам — абстракция (интерфейсы) и реализация. Абстракции стали частью бизнес-логики и были переименованы в порты. Реализация осталась на уровне инфраструктуры. Теперь они называются адаптеры. На практике UI оказался тем же фреймворком, что и БД, поэтому его постигла та же участь.

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

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

Каждый компонент может быть развернут отдельно. Если вы измените доступ к данным, необходимо перестроить только доступ к данным. Если вы измените пользовательский интерфейс, изменится только пользовательский интерфейс.

Поскольку модули можно развертывать отдельно, это означает, что их можно разрабатывать отдельно.

Только все плюсы.

Забудем упомянуть, адаптеры, которые вызывают нашу систему, называются первичными (управляющими). Те, которые вызываются нашей системой, называются вторичными (управляемыми). Это не важно знать, но зная это, вы будете казаться образованным 🤓

С точки зрения структуры решения, они работают лучше всего для меня:

Опять же, папка или проект — это то, что вы должны решить сами.

Просто следуйте ссылкам и убедитесь, что они не пересекаются там, где не должны:

2008 — «Лук»

Это будет жутковато, так что приготовьтесь 😨

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

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

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

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

Однако правило простое: любой внешний слой может зависеть только и только от внутренних слоев.

Не все так просто, а? 🤔 Я так и думал. Итак, давайте нарежем этот лук 🔪.

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

Приложение оборачивает только домен, так что это единственная зависимость, которую оно должно иметь.

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

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

Вот как это выглядит в теории. На практике корень вашей композиции (функция Main(), в которой регистрируются все зависимости и модули составляются вместе) будет частью уровня представления (ASP, WPF, CLI), поэтому диаграмма будет выглядеть следующим образом:

Вам это кажется знакомым? Это N-уровневая архитектура, но компоненты расположены в другом порядке.

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

2012 — «Чистая архитектура»

🎵🎵🎵
Есть человек по имени Дядя Боб,
Он самый чистоплотный кодер на работе,
Благодаря своим гибким движениям и архитектуре,
Он заставит ваш код сиять, как совершенно новый,
дядя Боб
🎵🎵🎵

Я имею в виду, что нельзя просто написать статью об архитектуре, не упомянув Роберта С. Мартина😅.

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

Шучу, оригинальных идей нынче не так много, все воруют друг у друга😉 Давайте посмотрим, что здесь нарыл Мартин:

Наш бедный Домен снова переименовали. Теперь это Объекты. Однако дело не только в этом. Это означает, что у вас не доменные службы и анемичные модели, а богатые классы с данными и поведением.

Интерфейсы для репозиториев и другие порты перемещены из домена в уровень приложения. Который, в свою очередь, получил более подходящее название — Use Cases.

Уровни представления и инфраструктуры остаются прежними. Однако Мартин также добавляет один дополнительный слой поверх него, который включает в себя фреймворки, DLL и другие внешние зависимости. Это не обязательно означает, что ваша БД будет иметь ссылку на объекты, это просто не позволяет вам иметь ссылку из внутренних слоев на эти внешние инструменты.

Еще раз, нет правила strcit. Вы можете добавить столько слоев, сколько вам нужно на любом уровне, который вы хотите. Поэтому, если вы хотите определить уровень для доменных служб, вы можете это сделать.

Мартин также нарисовал небольшую диаграмму рядом с архитектурой.

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

Попытка подчеркнуть, что поток выполнения (пунктирная линия) не всегда соответствует направлению зависимости (прямая линия), что является всего лишь принципом инверсии зависимости.

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

Обычно в ASP нет отдельного компонента для Presenter. Этим также занимается Контролер. Таким образом, вся диаграмма может быть представлена ​​в коде следующим образом:

class OrderController : ControllerBase, IInputPort, IOutputPort
{
    [HttpGet]
    public IActionResult Get(int id)
    {
        _getOrderUserCase.Execute(id);

        return DisplayOutputPortResult();
    }
}

Другие формы изоляции

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

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

Заключение

В этой статье мы обсудили N-уровневую, DDD, Hexagon, Onion и чистую архитектуры. Это не единственная существующая архитектура. Однако наиболее известными являются описанные. Возможно, вы также слышали о BCE, DCI и так далее.

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

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

Я надеюсь, что с этого момента каждый раз, когда вы создаете класс, просматриваете PR, разговариваете со своим колледжем, вы будете сознательно думать и задавать вопросы об этом 😉

💬 Напишите в комментариях, что я пропустил? Где я ошибся? Вас интересуют эти вещи?

✅ Подпишитесь, чтобы не пропустить следующие статьи

👏 Похлопайте, если считаете, что мои усилия стоят вашего времени

👨‍👦‍👦 Вы также можете поделиться этой статьей со своим другом. Поспорьте немного об этом. Известно, что истина рождается в споре

⬇️ Смотрите другие мои статьи.

☕️ Устройте мне кофе-брейк

🙃 Будьте решительны, оставайтесь сосредоточенными и продолжайте идти вперед