Завтра 23-го мая в четверг участвую в рулетке кейсов (чтобы это ни значило) по “плохой” архитектуре на Подлодке. Формат для меня на 100% новый. Что и как там будет, узнаем на месте. Но в качестве подготовки я собрал свои мысли про “Плохую архитектуру”.

🧠 Первое, что приходит на ум, “плохая” это архитектура, которая не отвечает требованиям заказчика здесь и сейчас. Функциональным или нефункциональным. Тут примеры могут быть у всех разные. Пропустили НФТ по нагрузке, не думали про безопасность, не поняли какие качели надо сделать и т.д. Если архитектура выполняет поставленные требования, но не соответствует вашим стандартам идеала, то она 100% не плохая.

⌛ Но ключевая история — это время. Оно не стоит на месте. Бизнес развивается, а значит и требования меняются. Отсюда делаем вывод, что плохая архитектура — это та, которая мешает изменениям. Формально запрос на изменения — это одно из требований, от которого сложно избавиться. Мы часто забываем, что software - это гибкая и мягкая история. Это не мост или здание. Софт выигрывает именно за счет скорости и возможности изменений под реалии бизнеса.

Давайте подумаем, что мешает изменениям?

🧩 Например, ошибочная декомпозиция на модули и сервисы. Очень полезный вопрос при разделении: сколько модулей будет изменено для реализации новой функциональности? Тут вспоминается paper Дэвида Парнаса 1972го года On the Criteria To Be Used in Decomposing Systems into Modules, где сравнивались 2 критерия. Предложенные разделения мне очень напоминают организацию по техническим слоям и бизнес доменам. Так как бизнес генерирует большинство изменений, то доменный подход потребует изменения меньшего набора модулей. А может быть и привлечения меньшего числа команд.

🔀 Другой пример, это сложный API и интеграции. Сложность часто возникает за счет большого количества вызовов, которые надо выполнить, чтобы получить результат. Например, сервис, который просто дает доступ к данным БД и не добавляет никакую полезную логику. То что иногда называют storage микросервисом. Стоит вспомнить главное назначение интерфейсов, а значит и API: скрыть сложную реализацию.

👁️‍🗨️ В свою очередь сложные API делают систему хрупкой. Небольшие изменения в одной части системы вызывают проблемы в других частях. Система легко “ломается” от минимальных изменений. Это чаще всего возникает от неявных связей. Или если мы в принципе не заботимся о качестве своих интеграций и контрактах:

  • С легкостью допускаем обратно несовместимое изменения в контракте и получаем недовольных клиентов
  • Меняем схему в БД (я подразумеваю, что это внутренняя скрытая реализация) - ломаем аналитику. А если не меняем схему — замедляем внедрение новых решений.

Что же можно со всем этим сделать?

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

🔎 Про модульность и сложность есть отличный доклад Влада Хононова: Сложность и модулярность две стороны одной медали. Влад предлагает метод, в котором мы должны балансировать между Low Coupling и High Cohesion избегая локальную и глобальную сложность. При этом он предлагает использовать 2 измерения: силу интеграции и расстояние. Данной теме можно уделить отдельную заметку.

📚 Про API я больше советую смотреть в API First подходы и проектировать простые интерфейсы, которые скрывают сложную реализацию, а не демонстрируют ее наружу. Читаем у John Ousterhout в A Philosophy of Software Design про глубокие модули и пытаемся расширить идею на уровень сервисов, как это сделал Влад в Learning Domain-Driven Design. А для контроля изменения архитектуры полезно ознакомиться с концепцией эволюционной архитектуры и фитнес функциями.

На сегодня все. Если почувствуете “плохую” архитектуру — теперь вы знаете в какую сторону копать.


Плохая архитектура?