Что такое архитектура системы, как её понимают в 2023

Вчерашнее обсуждение на нашем методсовете показало, что выпускники даже "Системного менеджмента и стратегирования" прошлых лет оказались не знакомы с изменениями в архитектурной работе. Все уже слышали, что "инженерии требований нет", но вот по части архитектуры практически все делают следующие ошибки:
-- путают концепцию системы и архитектуру системы (тем более что раньше была архитектура системы, а концепции системы не было, сейчас есть и то, и другое)
-- путают системное описание и концепцию системы (а концепцию системы путают с архитектурой системы)
-- плохо представляют основной формы, в которой выражется архитектура (а именно, ADR)
-- считают архитектора одним из разработчиков (а он не разработчик, и чаще всего в продуктивном конфликте с разработчиками, а отношение к разработчикам у него -- governance)
-- … и этот список можно продолжать.

Тема архитектуры начинает упоминаться в "Системном мышлении", а затем продолжается в "Системной инженерии" и "Системном менеджменте", так что к концу второго семестра у студентов уже достаточно понимания, чем занят архитектор (в том числе орг-архитектор), хотя вряд ли студент может нормально выполнять работу архитектора. С другой стороны, если читать помянутые в курсе книжки и иметь какой-то производственный опыт, то можно разобраться -- и пробовать себя как архитектора. Есть там несколько засад на этом пути (например, основные идеи нового подхода к архитектуре разработаны главным образом для software architecture, для "железных" и организационных систем многое сегодня придётся додумывать самому, фронтир ещё не дошёл в достаточной мере, чтобы выпустились новые книжки -- но уже понятно, что дойдёт).

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

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

В самом конце 2022 года вышло 2 издание "Building evolutionary architectures" (есть в z-library), первое было в 2017 году, но в тексте курса я ещё это не отметил, не буду править и тут, но знайте, что архитектурное знание продолжает быстро-быстро развиваться.

Архитектура: было «про трудно изменяемое», стало «про облегчение изменений»
Архитектор — это на древнегреческом «главный строитель», arkitekton, αρχι-(arkhi-, «главный») +‎ τέκτων (téktōn, «строитель»). Он определял что и как строить, а также следил за рабочими-строителями. Дальше понятие архитектуры перешло во все остальные виды инженерии, при этом понятие непрерывно менялось и было удивительно трудно определяемым, хотя во всех этих понятиях оставалось указание на архитектуру как определение структуры (структура — это понимание, как система разделена на части, прямая отсылка к системности), определение чего-то важного, чем бы оно ни было (Ralf Johnson), а также принятие решений по основным принципам организации системы (ибо выяснилось, что не всегда понятно про части системы, но можно сформулировать принципы появления этих частей. Например, так устроен интернет, и именно такое определение было дано в ISO 42010:2011).

В 2017-2022 году понятие архитектуры, архитектурной практики и роли архитектора претерпели значительные изменения, прежде всего в программной инженерии, а дальше это изменение будет всё больше и больше ощущаться во всех остальных видах инженерии (с лагом примерно 10 лет):

  • Архитектор начал заниматься не всем важным, а только тем важным, что входило в его concerns/«предметы интереса»/«важные характеристики», к которым отнесли всезвозможные -ости/-ilities. Эти архитектурные характеристики иногда называют «нефункциональными требованиями», но это не требования, а предметы интереса (требования вообще по факту исчезли из инженерии), но даже не это плохо: плохо использование слова «нефункциональные», никто ведь не хочет заниматься чем бы то ни было, у чего нет функции/назначения. И это не «требования качества», потому как никакого отношения к качеству у этих характеристик нет, это оказались совершенно особенные предметы интереса, архитектурные.
  • Задачей архитектора стало нахождение архитектурных решений (architectural decisions), которые стали пониматься, как решения, гарантирующие оптимальные значения архитектурных характеристик (а не функциональных характеристик, связанных с domain). Тем самым задачи архитектора чётко были отделены от задач разработчиков/developers/прикладных инженеров для domain: прикладные инженеры делают систему, которая обеспечивает функциональность для самых разных проектных ролей, а системные архитекторы принимают решения, которые направляют деятельность разработчиков так, чтобы достичь оптимума/баланса в архитектурных характеристиках.
  • Изменился сам состав архитектурных характеристик. Так, по John Ralf в архитектуру входило всё важное, что бы это ни было. Важное определялось как то, что трудно менять: при альтернативном прохождении развилки в какой-то концепции системы пришлось бы переделывать всю систему. Скажем, принимается решение использовать реактивный двигатель, а не турбореактивный двигатель — и всё, самолёт нужно переделывать, вот такое решение называлось архитектурным, и требования для него (скажем, скорость самолёта, которая связана со звуковым барьером, возможность преодолеть который зависит от типа двигателя) назывались тоже архитектурными. Вот такие решения сейчас оказались связанными с функциями системы в её предметной области и стали решениями разработчиков. А у архитектора появилась архитектурная характеристика evolvability/развиваемость, которая как раз и означает возможность «изменять трудноизменяемое»: гарантирует, что архитектура системы позволяет легко менять даже важные решения разработчиков.

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

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

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

Вообще, сама идея о том, что архитектура должна помогать системе быть легкоизменяемой в разработке, а не наоборот, класть в основу что-то неизменяемое, а ещё идея о том, что архитектура сама по себе должна меняться по ходу разработки и даже уже эксплуатации, а не определяться поближе к началу проекта как что-то «основное и незыблемое» — вот эта идея была в инженерии достаточно революционна. Впервые подробно эта идея изложена в книжке 2017 года «Building Evolutionary Architectures» на примере программной архитектуры для корпоративного программного обеспечения (софт для поддержки работы предприятий — бухгалтерия, маркетинг и т.д.):

В этой книге обращается внимание на то, что архитектура не разрабатывается сейчас «после требований, но до изготовления/строительства», а тоже меняется по мере того, как постоянно меняются требования (это 2017 год, требования ещё были довольно распространены, но признавалось, что «они постоянно меняются») и ещё отслеживаются изменения в самой разработке. В книге подробно обсуждается, что evolvability/развиваемость системы становится существенной архитектурной характеристикой/предметом архитектурного интереса, и архитектура связана не только с принципами организации самой системы, но и с принципами организации её создателя через закон Конвея и обратный манёвр Конвея. Закон Конвея — это что структура системы обязательно отразит оргструктуру предприятия-создателя, а обратный манёвр Конвея — что вы должны разработать лучшую структуру системы, а потом изменить структуру предприятия-создателя системы так, чтобы она отражала разработанную лучшую структуру системы. Если не выполнить обратного манёвра Конвея, то через закон Конвея организационная структура обязательно приведёт к ухудшению разработанной лучшей структуры, и система будет неуспешна.

Архитектурные характеристики
Окончательно новый подход к архитектуре на примере программной архитектуры для корпоративного софта был сформулирован в книге «Fundamentals of Software Architecture», 2020. Ещё раз повторим обложку этой книги, ибо она наиболее полно раскрывает на сегодня современный подход к архитектурной работе как отдельной практике (эта книга была в предыдущей главе дана, когда объяснялось, что «всё в инженерии — это прохождение развилок», это было обобщение первого закона архитектуры из этой книги):

В этой книге чётко говорится о различении прикладных разработчиков (developers) и архитекторов (architect): предметы интереса разработчиков лежат в реализации функциональности каким-то кодом, а интересы архитектора очень специфические архитектурные: важные/архитектурные характеристики, которые относятся не столько к функциональности системы в её предметной области, сколько к общим характеристикам работы и создания (характеристики не только времени эксплуатации, но и времени создания!), которые делают систему успешной или неуспешной. Скажем, если система отлично справляется со своими функциями, но вам недоступна (плохие значения характеристики доступности/availability), то систему нельзя считать успешной. Когда-то на заре интернета поисковые системы были реализованы на огромных серверах Sun, но поскольку к ним обращались одновременно тысячи пользователей, они по факту были недоступными: ответа от них было нельзя дождаться. Это как попасть в город со знаменитым музеем на один день, и обнаружить, что в этот музей очередь на пять дней! Вроде музей есть, и работает, но из-за очереди нельзя попасть! И дальше начинаются разговоры о том, что легко спутать производительность и доступность (скажем, музей в городе может пропустить за день сколько хочешь человек, очереди нет и в принципе быть не может, но только работает этот музей по субботам 2 часа с 14 часов до 16 часов, а в другое время просто закрыт).

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

Операционные (времени эксплуатации системы) предметы интереса, которые пересекаются во многом с предметами интереса ответственных за изготовление, ремонт и эксплуатацию (в программной инженерии это DevOps, и многочисленные варианты XOps):

  • Доступность/availability: часы работы системы (скажем, 24 часа в сутки 7 дней в неделю, и на сколько она может закрываться на профилактику, ремонт, отдых персонала)
  • Непрерывность/continuity: оргвозможность восстановиться после какой-то катастрофы (наводнение, удар молнии, война).
  • Производительность/performance: включает и устойчивость к постоянной нагрузке, и устойчивость к пиковым нагрузкам (часто выделяют как отдельный предмет интереса — эластичность/elasticity), и частоту обращений к функциям системы, и время ответа на запросы, и требования к запасу мощности. Удовлетворение ожиданий по производительности само по себе будет отдельным приключением в разработке, может потребовать экстраординарных решений в части архитектуры.
  • Возможность восстановления/ recoverability: с какой скоростью в случае катастрофы всё восстановится? Бэкапы, дублирование оборудования — это всё тут.
  • Надёжность и безопасность/reliability and safety: если что-то поломается, то это никому не должно повредить (никто не должен быть покалечен или убит, или никто не должен потерять большие деньги).
  • Устойчивость/robustness (у «железных» инженеров чаще resilience) — возможность хоть как-то работать и обрабатывать неизбежные ошибки в критических ситуациях, когда произошли довольно крупные поломки (скажем, пропало интернет-соединение, или выключилось энергопитание, или пошёл дым из компьютерного блока).
  • Масштабируемость/возможность наращивать производительность по мере возрастания числа пользователей или интенсивности их запросов.

Характеристики времени создания:

  • Конфигурируемость/configurability — возможность пользователю поменять конфигурацию системы самому через удобный пользовательский интерфейс.
  • Расширяемость/extencibility — насколько легко добавлять новую функциональность.
  • Устанавливаемость/installability — насколько легко устанавливать систему в самых разных вариантах использования.
  • Повторное использование/leverability and reuse — насколько легко переиспользовать систему в разных проектах.
  • Локализация/localization — поддержка множества языков, единиц измерения, часовых поясов
  • Сопровождаемость/maintainability — как легко обслуживать систему по ходу её эксплуатации?
  • Переносимость/portability — как легко перенести систему в другое окружение (например, на другую платформу, программное обеспечение на другую операционную систему).
  • Поддерживаемость/supportability — уровень технической поддержки, который ожидается для системы: как быстро отзываются, что могут поправить, сколько стоит.
  • Возможность апгрейда/upgradability — как легко и быстро перейти с одной версии системы на другую, будут ли вообще доступны следующие версии.

Этих характеристик, конечно, много больше. Например, прайвеси/privacy, безопасность/security, которые как предметы интереса архитектор имеет общие со специалистами по безопасности. ISO 25010 Product Quality Characteristics архитектурные характеристики называет характеристиками качества, и предлагает свой список [1], но первым пунктом там стоит «1. Functional suitability», как «уместность функциональности», то есть насколько система выполняет ожидаемые от неё функции. И вот это предмет заботы прикладных инженеров. А вот остальные группы характеристик там как раз архитектурные. И тут нужно сказать, что каждая «сводная характеристика» тут разбивается на множество.

Так, часто поминается «возможность положиться на систему»/dependability как набор более дробных характеристик: availability, reliability, maintainability, durability, safety and security как один вариант, или availability, reliability, safety, integrity (сопротивление к несанкционированным изменениям), maintainability, и ещё бывают разные другие варианты.

Современный тренд — это работа с метриками для каждой характеристики. Для программного обеспечения эти метрики замеряются специальными тестами, которые называют функция соответствия/fit function (термин взят из эволюции: система развивается в виде последовательных своих версий в ходе длинного проекта). Fit function это по сути тест, только не на безошибочность выполнения функции (такие тесты делают разработчики), а на безошибочность выполнения решений архитектора (в надежде, что эти решения ведут к успеху: у архитектора тоже гипотезы, а не полная уверенность! Он тоже будет менять свои решения по ходу разработки!).

Лучший способ разобраться со всеми этими характеристиками — это понять, как они мониторятся (постоянно измеряются) в ходе проекта. Для программных проектов на эту тему написана отдельная книжка «Software Architecture Metrics», 2022:

Если же у вас другие виды систем и/или какие-то другие метрики, то напомним про существование книги «How to Measure Anything: Finding the Value of Intangibles in Business», 2014:

Архитектор в своей работе думает ровно об этих архитектурных характеристиках системы основное своё время, примерно так же, как прикладной инженер думает о функциональных характеристиках. Он лично беседует со всеми внешними проектными ролями, чтобы разобраться, какие значения этих характеристик должны быть, чтобы система была успешна. Хороший совет: сосредоточиться не на всех этих характеристиках/предметах интереса, а только на реально необходимых для успеха системы! Например, ограничиться всего тремя предметами архитектурного интереса, а остальные отбросить. Это рекомендация книги «Fundamentals of Software Architecture», но со всеми оговорками, что это число и сам состав отобранных архитектурных характеристик сильно зависит от конкретной ситуации в проекте. И дальше нужно принять архитектурные решения, которые позволяют для достижения успешности системы удовлетворить именно эти наиболее важные архитектурные интересы, а не вообще все (что невозможно). Для этого архитектор (равно как и разработчик) много общается с внешними проектными ролями и понимает ситуацию, в которой происходит эксплуатация и разработка системы (они связаны через закон Конвея).

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

Результатом работы архитектора будет набор архитектурных решений, которые касаются разбивки системы на модули/конструктивные объекты и определение способов связи между модулями. Главная цель — это провести границу между модулями так, чтобы внутри границы связи между подмодулями были плотными (про связи внутри модуля говорят как про cohesiveness, а между модулями как coupling). Если система вся получилась несвязной/незацепленной, невзаимодействующей, то беда: эмерджентные свойства (функция системы в том числе) появляется как раз из взаимодействия частей. Нет взаимодействия — нет системы. Если вся система чрезвычайно связана, то

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

Например, если вы хотите повторно использовать какой-то фрагмент кода программы (в 90е годы была ценность reuse, «повторного использования», выноса за скобки любой функциональности и реализации её один раз, «отсутствие дублирования»), то неожиданно оказывается, что ошибка в этом фрагменте влияет на выполнение всей программы во всех местах его использования — скажем, в 1000 мест. А если вы занимаетесь улучшением этого фрагмента, то улучшение его исполнения для 3 случаев из этого задействования может привести к ухудшению для остальных 997 случаев изо всех 1000 (динамическая связность). А если меняете интерфейс (в архитектуре часто говорят «контракт», упирая на то, что интерфейс должен быть стабилен), так это требует изменения во всей тысяче модулей (статическая связность). Так что мы имеем тут U-образную «экономическую кривую» полезности уровня зацепления: связность в системе должна быть не слишком маленькой, но и не слишком большой. Архитектурные решения ищут оптимум, для этого проходят самые разные развилки в группировке функций по модулям.

Архитектура тем самым не сводится к каким-то структурным (то есть «разбиения на части») диаграммам, а сводится к набору архитектурных решений по прохождению архитектурных развилок (trade-offs), прежде всего:

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

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

Лучшая практика по оформлению архитектурных решений на сегодня — это запись архитектурного решения (ADR, architectural decision record, предложены Michael Nygard в 2011 году [2]). Это документ на пару страниц текста, имеющий следующий формат (текст пишется в виде рассказа для разработчиков):

  • Заголовок/title — короткое имя для принятого решения.
  • Ситуация: описывает различные соображения в части влияния на архитектурные характеристики, в том числе именно тут описываются конфликты разных системных уровней, которые требуют оптимизации.
  • Решение: что делать, чтобы достичь предположительного квазиоптимума (например, использовать какой-то архитектурный стиль или стандарт для межмодульного интерфейса)
  • Статус: это предложение, это обязательно для выполнения, это решение уже отменено каким-то другим предложением (всё меняется, в том числе архитектурные решения)
  • Последствия: что ожидается после реализации решения, в том числе «позитивные» (скажем, «производительность вырастет впятеро») и отрицательные (скажем, «вносить изменения придётся не в один, а в три разных модуля»).

Про принятие архитектурных решений путём прохождения развилок на примере корпоративного программного обеспечения в крупных компаниях, где требуется обеспечить высокую скорость разработки и высокую производительность (распараллеливание работы между вычислителями) говорится в книге «Software Architecture: The Hard Parts».

Вот пример архитектурного решения из этой книги, оно относится к разбивке на модули:

  • ADR: Общий сервис для назначения и маршрутизации заявок
  • Ситуация: когда заявка создана и принята системой, она должна быть назначена эксперту и затем маршрутизирована на мобильное устройство этого эксперта. Это может быть сделано одним общим сервисом назначения заявок или отдельными сервисами назначения и маршрутизации.
  • Решение: Мы создадим один общий сервис для функций назначения и маршрутизации заявки. Заявки немедленно маршрутизируются эксплуатационному эксперту как только они назначены, так что эти две операции тесно связаны и зависят друг от друга. Обе функции должны масштабироваться одинаково, поэтому нет никакой разницы по производительности между этими двумя сервисами, и нет никаких обратных зависимостей между этими функциями. Так как обе функции полностью зависят одна от другой, устойчивость к отказам не является поводом реализовывать их отдельно. Если эти две функции разделить, то потребуется организовывать между ними поток работ, и это даст дополнительные проблемы с производительностью, устойчивостью к отказам, а также возможные проблемы с надёжностью.
  • Следствия: Изменения алгоритма назначения (эти изменения происходят на регулярной основе) и изменения механизма маршрутизации (нечастые изменения) могут потребовать тестирования и разворачивания обеих функций, результат будет в возрастающем объеме тестирования и рисках разворачивания.

В этом примере не приведён статус, ибо это «проект из книжки» (в реальном проекте нужно указывать статус, ставить архитектурные решения под контроль конфигурации).

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

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

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

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

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

Если заранее непонятно, кто когда что подаёт на вход мясорубки и где её будут эксплуатировать, то выполнение контракта (контрактом/contract называют правила взаимодействия на интерфейсе с модулем, иногда это же называют протоколом) должна проверять мясорубка. В тех случаях, когда Вася тоже проверяет то, что он даёт мясорубке, возникает дублирование. Но в архитектуре есть принцип, что в большинстве случаев развязывание/расцепление/decoupling модулей важнее отсутствия дублирования.

Так как же надо? Если делаете публичный сервис, то лучше бы мониторить то, что подаётся на вход, вести логи для ловли ошибок (кто когда почему подал на вход мясорубки гвозди: это не должно повториться!). Если модуль выполняет чётко определённую функцию, должен работать сверхбыстро, то проверки входных объектов для обработки (сырья, информации) в нём не должно быть, это дорого. Но выходные проверки лучше бы делать. Ну, или добиваться такой работы, чтобы выходные проверки были не нужны «по определению», но такое придётся доказывать (писать обоснования). Однозначного ответа «как надо» нет, всё зависит от вашего проекта, и даже конкретной ситуации в вашем проекте (сегодня оптимальный ответ будет один, а через год в этой же системе ответ будет другим — и придётся всё переделывать. Это нормально, это и есть развитие/evolving системы и её архитектуры).

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

Понятие межмодульной связи довольно сложное, и это один из основных объектов, с которым работает архитектор. У вас радиотехническое устройство. Правильно ли будет, если вы все резисторы поместите на одну плату, конденсаторы на другую плату, катушки::модуль индуктивности::сервис на третью плату? Заметим, что в предприятии более чем часто делают «отдел со всеми программистами», «отдел со всеми юристами», и хорошо, что не делают «отдел со всеми менеджерами» (рассуждение по той же линии: «они все там одного типа, с одним образованием, пусть сидят вместе). Это ведь ровно такой же архитектурный вопрос, архитектура-то универсальное понятие для всех типов систем.

Или на одной плате должен быть «усилитель высокой частоты», а на другой плате «усилитель низкой частоты» и все резисторы-конденсаторы-катушки индуктивности должны быть там? Или нужно преодолеть огромные трудности и сделать всё на одной гигантской плате, но это «объединение в один модуль» потребует перестройки всего производства? Такой путь, например, был выбран в попытке сделать один чип на 2.6 триллиона транзисторов: целью было получить максимальную производительность, и отчасти это даже удалось, но пришлось решать множество нестандартных проблем, типа отвести 3.5КВт тепла с площади чипа размером примерно с листок А4 [3].

[1] https://www.perforce.com/blog/qac/what-is-iso-25010
[2] https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions
[3] https://www.cerebras.net/blog/cerebras-wafer-scale-engine-inducted-into-the-computer-history-museum/