Привет! Меня зовут Азамат, я backend-разработчик в Циане. В работе мне часто приходится пересматривать архитектуру компонентов или проектировать её с нуля. Со временем у меня накопились подходы и наблюдения, которыми хочу поделиться.

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

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

Терминология

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

Чтобы говорить на одном языке, важно договориться о смыслах. Большую часть своих определений я позаимствовал у Роберта Мартина из книги «Чистая Архитектура», но адаптировал под свой опыт.

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

Модули/компоненты системы - Роберт Мартин определяет их как «единицу деплоя». Это не обязательно сервис или файл — это любая логическая часть системы, которую можно было бы выкатить отдельно: функция, класс, библиотека, микросервис или внешний сервис вроде базы данных или брокера сообщений.

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

Чтобы проектировать эффективно, важно договориться о терминах внутри команды — это помогает быстрее понимать друг друга.

С чего начинается проектирование

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

Перепроектирование в процессе работы — это нормально. Это и есть рефакторинг. Для него не нужны отдельные проекты и согласования, достаточно применять хорошие практики, которые описал Мартин Фаулер в книге «Рефакторинг».

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

Если вы видите существенный риск для дальнейшей разработки — это сигнал задуматься об архитектуре. В книге Design It! это состояние описано очень точно: «тянущее ощущение в животе» (глава 4, Let Risk Be Your Guide).

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

Вот несколько красных флагов, которые могут указывать на проблемы в архитектуре:

Высокие время или стоимость разработки:

  • Постоянные конфликты при слиянии веток.

  • Слишком много правок ради маленькой фичи.

  • Код сложно читать и долго в него погружаться.

  • Разработчики дублируют решения вместо переиспользования.

Высокий time-to-market для фич:

  • Долгий деплой.

  • Долгий прогон обязательных тестов.

  • Слишком много коммуникаций между командами даже на простых задачах.

Много багов (не всегда про архитектуру, но могут быть косвенные признаки):

  • Тесты сложно писать, тяжело поддерживать, они плохо читаются.

  • Даже при хорошем покрытии тесты не ловят баги.

  • В коде много неочевидных и избыточных связей.

Проблемы с производительностью. Чаще это связано с выбором инструментов (БД, алгоритмы, настройки), но иногда архитектура тоже мешает. Например, если вам нужны ACID-транзакции, разделение на два микросервиса сильно усложнит жизнь.

Описание проблемы

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

Сначала нужно определить, кто зависит от этой системы. Их ещё называют стэйкхолдерами. Обычно это:

  • Разработчики, которым уже неудобно работать или которым предстоит с ней работать.

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

  • Все остальные, кто завязан на систему или может повлиять на её развитие.

С этими людьми важно собрать информацию о текущих болях. Разработчики часто подскажут, где именно неудобно. Менеджеры помогут понять пользовательские сценарии, ограничения по времени и качеству (например, SLO), а также будущие планы, которые повлияют на архитектуру.

Полезно выяснить:

  • Какие задачи в системе встречаются чаще всего?

  • Какие части кода часто меняются, а какие — почти не трогают?

  • В каком направлении будет развиваться продукт и система?

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

Дополнительно стоит собрать типичные задачи для разработчиков. Это поможет оценить, насколько изменится TTM и сложность разработки задач в разных вариантах архитектуры.

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

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

Что влияет на архитектуру

Когда я проектирую архитектуру, я всегда держу перед глазами список факторов, которые стоит учесть. Во многом я опираюсь на книгу Design It! (глава 5), но дополнил её своими наблюдениями.

Первое — ограничения. Они бывают технические (например, язык, операционная система, СУБД) и бизнесовые (например, бюджет, сроки). Важно отличать реальные ограничения от тех, которые вы себе надумали, чтобы не загнать проект в ненужные рамки.

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

Третье — качественные атрибуты. Это свойства, которые сильно влияют на архитектуру:

  • Во время разработки: изменяемость, тестируемость, переиспользуемость, скорость вывода фич (time-to-market).

  • Во время эксплуатации: доступность, надёжность, производительность, масштабируемость, безопасность.

  • Дополнительно: простота, поддерживаемость, управляемость, обучаемость.

Также на архитектуру влияет организационная структура. По закону Конвея, архитектура часто повторяет, как устроены команды и как они взаимодействуют — даже если вы этого не планируете.

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

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

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

Составление вариантов архитектуры

Когда мы думаем об архитектуре, у нас почти всегда уже есть в голове какое-то предварительное решение. Например, если для добавления фичи приходится править кучу микросервисов и из-за этого растёт time-to-market, первая мысль — может, стоит их объединить? Но тут же всплывает новая проблема: один из этих сервисов используют другие системы. Если объединить всё в один, другие системы начнут тянуть в себя лишние зависимости, и общая сложность вырастет.

Так и строится процесс: от проблемы — к решению, от решения — к новым проблемам. Мы перебираем варианты и ищем тот, который максимально снимает боль или оставляет только те проблемы, с которыми можно спокойно жить. Важно честно проверять плюсы и минусы каждого варианта.

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

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

Принципы проектирования

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

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

Когда стоит разделять компоненты:

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

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

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

А зависит от Б, хотя мог бы зависеть только от Б1
А зависит от Б, хотя мог бы зависеть только от Б1
  • Ещё признак, который усиливает прошлый, это если от Б1 зависит несколько компонентов, или потенциально будут от него зависеть. Т.е. его хотят отдельно переиспользовать в других частях системы. Б1 явно кандидат на выделение. Схема ниже:

Б1 кандидат на отделение
Б1 кандидат на отделение
  • Часть знания дублируется в других компонентах. Скорее всего это та часть, которую, если выделить, то она будет переиспользована.

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

Когда наоборот стоит объединять:

  • Для выполнения проекта часто приходится менять несколько компонентов и деплоить их по отдельности. Объединение поможет сократить количество деплоев и упростить тестирование.

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

Архитектура — это баланс. Иногда выгодно разделять, иногда — объединять. Баланс со временем меняется: бизнес меняет приоритеты, команды растут, система развивается. Архитектуру приходится пересматривать, и это нормально.

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

DDD и чистая (луковичная) архитектура

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

Эти подходы особенно полезны, когда нет жёстких требований к высокой производительности и нет необходимости экономить на железе любой ценой.

Чистая архитектура добавляет много слоёв и абстракций. В системах с простой логикой это может привести к избыточной сложности: вы потратите время на поддержку слоёв, которые вам не нужны. Иногда это даже мешает — например, при работе с ACID-транзакциями или при оптимизациях.

Если сложна только техническая реализация, но бизнес-логика простая (например, сложные SQL-запросы, работа с памятью, оптимизация сетевых вызовов), DDD вряд ли принесёт пользу.

Простой пример: у вас веб-приложение, где нужно просто найти запись в базе и вернуть результат. В этом случае DDD только усложнит жизнь: придётся заводить доменные сущности, поднимать дополнительные слои, загружать данные целиком, даже если нужны только два поля. Без DDD вы бы просто написали запрос и вернули нужные данные парой строк. В таких проектах чаще всего достаточно обычного разделения на контроллеры и DTO.

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

Устойчивые и неустойчивые компоненты

Полезный архитектурный принцип — делить компоненты на устойчивые и неустойчивые.

  • Если компонент почти ни от кого не зависит, но на него завязано много других — это устойчивый компонент.

  • Если компонент сам зависит от кучи всего, но на него почти никто не ссылается — это неустойчивый компонент.

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

Пример устойчивого и неустойчивого компонента
Пример устойчивого и неустойчивого компонента

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

В DDD этот принцип активно используется: доменную область стараются изолировать, сделать независимой и стабильной. Боб Мартин подробно писал об этом в «Чистой архитектуре».

Сохранение вариантов использования и их разнообразия

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

На старте лучше оставлять побольше гибкости — пока не станет понятно, что ограничения действительно оправданы.

Например, вы хотите внедрить event-driven архитектуру и сразу строить её на RabbitMQ. Но, возможно, стоит подождать. Можно начать с локальной событийной шины внутри одного процесса — это проще и дешевле. А вдруг через полгода появится требование проводить несколько операций атомарно в одной транзакции? С RabbitMQ вам придётся реализовывать распределённые транзакции, например через паттерн saga. Это дорого и сложно. В локальной архитектуре этой проблемы бы просто не было.

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

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

Вывод

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

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

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

  • Роберт Мартин — Чистая архитектура

  • Michael Keeling — Design It!: From Programmer to Software Architect

  • Мартин Фаулер — Рефакторинг: улучшение существующего кода

  • John Ousterhout — A Philosophy of Software Design (о ней я даже писал заметки на Хабре)

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

Комментарии (17)


  1. Dhwtj
    01.07.2025 10:42

    Архитектура — это всё, что критично для долговременного успеха системы.

    Техническая архитектура — это всё, что критично для долгосрочного успеха системы на уровне технологий

    Поэтому, начинать надо всё же с понимания желаемых архитектурных свойств и параметров проекта, а не с этих ваших компонентов

    1. Производительность

    2. Масштабируемость

    3. Надежность

    4. Доступность

    5. Сопровождаемость

    6. Безопасность

    7. Расширяемость

    8. Тестируемость

    9. Наблюдаемость

    10. Стоимость


    1. garipovazamat Автор
      01.07.2025 10:42

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

      Вы пишите

      начинать надо всё же с понимания желаемых архитектурных свойств

      Но как понять какие свойства желаемые? Тут и приходится разбираться, а какие цели у бизнеса, какие проекты ещё могут возникнуть ближайшее время. Это я как раз и описываю в главе "Описание проблемы".
      Другой вопрос, а когда вообще стоит задаться вопросом полного перепроектирования архитектуры? Не будем же мы при необходимости например добавления новой фичи этим заниматься каждый раз. Поэтому я описал это раньше в главе "С чего начинается проектирование" и мне показалось логичным начать именно с этого.


      1. Dhwtj
        01.07.2025 10:42

        Проект и продукт это совсем разные вещи. И я говорю продукт=система


  1. Dhwtj
    01.07.2025 10:42

    Инфоцыганство ака консалтинг надоело уже. Живые примеры давай!


    1. garipovazamat Автор
      01.07.2025 10:42

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


      1. Dhwtj
        01.07.2025 10:42

        Фаулер это инфоцыган или нет?

        Он писал книги в период когда уже давно не записался практикой


        1. garipovazamat Автор
          01.07.2025 10:42

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

          Если вы с чем то не согласны с фаулером в его книге Рефакторинг, дайте конкретику.


  1. SolidSnack
    01.07.2025 10:42

    Эти подходы особенно полезны, когда нет жёстких требований к высокой производительности и нет необходимости экономить на железе любой ценой.

    ???? Тут точно речь про DDD и чисто луковичную архитектуру?)

    Микросервис всему голова... Только вот ходят легенды что это обычно куча маленьких монолитов.


    1. garipovazamat Автор
      01.07.2025 10:42

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


      1. SolidSnack
        01.07.2025 10:42

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


        1. garipovazamat Автор
          01.07.2025 10:42

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

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

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

          Поэтому тут вопрос насколько правильно вы подходите к этому отделению.


          1. SolidSnack
            01.07.2025 10:42

            Я не знаю что такое распределенный монолит. Как по мне история монолит/микросервис полуинфоциганская. До появления докеров никто не называл приложение монолитом, а решение его проблем микросервисом, это веение моды (как и JS везде, но тут не только мода, продвижение языка тоже играет большую роль).

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

            Да, это хороший пример для выделения функционала в отдельный какой-то сервис. Но я это делал на условном рэбите и до повсеместного продвижения микросервисов. Но с другой стороны рассылку можно отделить в отдельный программный модуль рядом с приложением. По сути изменится взаимодействие (был условный gRPC, станет межпроцессным). Мне кажется тут только в вопросе масштабирования и адаптации под нагрузку выигрывает микросервис, а так те же яйца только в профиль.

            Скажите, а как на микросервисах с подключением к базе данных? Каждый сервис которому нужна БД пишет свое? (Слышал и про такое) или есть микросервис базы данных в который все ходят?


            1. garipovazamat Автор
              01.07.2025 10:42

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

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


              1. SolidSnack
                01.07.2025 10:42

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

                Про базы данных прикольно конечно, в монолите бывает взглянешь на базу из 200 таблиц и только унынием наполняешься, а тут ещё по базам бегай собирай все логику во едино. И получается что на уровне базы (баз данных?) сложнее настраивать бизнес процессы (если это вообще реально, внешние ключи на базу к другому микросервису?:))

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


                1. garipovazamat Автор
                  01.07.2025 10:42

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


                  1. SolidSnack
                    01.07.2025 10:42

                    Про либы я говорю "и тому подобное" после ОС :)

                    При хорошей архитектуре внутри приложения тоже все хорошо мокается и тестируется. Тесты на всю систему и не надо делать, если вы хотите проверить нотификатор.

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


  1. totsamiynixon
    01.07.2025 10:42

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

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

    А дальше те же проблемы, что и в жизни. Бухгалтерия делает индексацию стоимости товара в своей системе (например система 1С). Далее необходимо донести эту информацию до отдела продаж (обслуживает модули CRM и модуль каталог) - пока информация ещё не дошла, продажники с задержкой будет продавать по старым ценам. То же самое с отделом маркетинга. Это демонстрация естественной проблемы не консистентности данных и для неё в компании уже есть решение.

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

    Модуль - это какой-то логический отдел в компании, какой-то домен: бухгалтерия, охрана труда, отдел продаж, отдел маркетинга. Можно дробить модули над под модули вроде "бонусная программа", "обратная связь" и ТД для модуля "отдел маркетинга".

    Монолит - это все отделы в одном лице: и бухгалтерия, и отдел продаж, и отдел маркетинга. Хостит большинство модулей и под модулей в системе. Четкого понимания модулей и под модулей зачастую нет. Реализация по принципу - работает и ладно. Даёт быстрый старт, но при необходимости масштабироваться придется отреылексировать и этот оверхэд часто недооценивают.

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

    Микросервис - это один отдел со своими знаниями, независимыми базами и ТД. Хостит один или несколько логических модулей. Минимально хостит один под модуль. Как и любом предприятии необходимость в отделах появляется, когда происходит дисбаланс в объеме работы. Т.е. на завод может быть 2 бухгалтера, но 100 рабочих у станка.

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

    Message Broker - это внутренняя почтовая служба. Когда отдел бухгалтерии оставляет "приказ об изменении стоимости товара" в почтовом ящике, брокер обучен, в какие отделы нужно это доставить.

    Outbox - записал в ежедневнике или повесил стикер и переводчески просматриваешь заметки или стикеры.

    Поэтому в коде нужно налаживать коммуникации между модулями, а не инстансами сервисов. Сегодня модуль часть монолита, завтра часть макросервиса под отдел/домен, послезавтра часть модуль вынесен в микросервис для точечного горизонтального масштабирования. В идеале когда меняется модель хостинга модуля просто обновить service discovery и все.

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

    Вывод: подробили на модули, решили, надо ли этому модулю отдельный специализированный исполнитель (машина / человек) или можно объединить пару модулей в одном исполнителе (машина / человек) и задали конфигурацию кубера.