Когнитивная сложность — это понятие, описывающее сложность процесса познания и мышления. Оно используется в разных областях: в психологии оно характеризует индивидуальную способность к восприятию и обработке информации. Более высокая когнитивная сложность означает, что система (будь то человек или программа) требует больше усилий для понимания и может быть трудной в поддержке.
Когнитивная сложность при проектировании приложения часто возникает из‑за смешения архитектуры кода и архитектуры приложения. В большинстве случаев эти термины никак не разделены, а также эти термины не имеют однозначного толкования, как по содержанию так и по контексту использования. В практике и литературе эти понятия часто используются как синонимы или в пересекающихся контекстах, что приводит к неоднозначности. В зависимости от контекста (например, обсуждение микросервисов, монолитов, паттернов проектирования или рефакторинга), один и тот же термин может обозначать как уровень организации кода, так и более высокий уровень организации приложения или системы. В профессиональной литературе и стандартах (например, TOGAF, ArchiMate) архитектура программного обеспечения охватывает оба аспекта и организацию кода, и организацию приложения, что еще больше стирает границы между этими понятиями.
Процессно-ориентированная архитектура приложения
В рамках этой статьи термин «Архитектура приложения» рассматривается исключительно как процессно‑ориентированная архитектура приложения.
Процессно‑ориентированная архитектура — это подход, при котором элементами архитектуры являются физические процессы ОС, а не абстрактные программные модули.
В такой архитектуре компоненты приложения описываются как отдельные процессы, а не как абстрактные функциональные модули внутри одного процесса.
Каждый процесс выполняет свою задачу и взаимодействует с другими процессами через механизмы межпроцессного взаимодействия (IPC): каналы, сокеты, очереди сообщений, разделяемую память и так далее.
Отличие процессно-ориентированной архитектуры (где элементы — физические процессы ОС) от сервис-ориентированной архитектуры (SOA)
Основное отличие процессно‑ориентированной архитектуры (где элементы — физические процессы ОС) от сервис‑ориентированной архитектуры (SOA) заключается в уровне абстракции, способе взаимодействия и области применения:
В процессно‑ориентированной архитектуре элементы — это физические процессы ОС, которые выполняют конкретные задачи и взаимодействуют через механизмы IPC (межпроцессное взаимодействие).
В SOA элементы — это сервисы, которые могут быть реализованы как процессы, потоки, или даже функции, но главное — они предоставляют бизнес‑функции через стандартизированные интерфейсы и не обязательно соответствуют отдельным процессам ОС.
В процессно‑ориентированной архитектуре взаимодействие между компонентами обычно происходит через IPC, сокеты, очереди сообщений и так далее, что связано с особенностями ОС.
В SOA взаимодействие между сервисами осуществляется через стандартные протоколы (например, HTTP, SOAP, REST), и часто используется шина сервисов (ESB) для управления взаимодействием.
Процессно‑ориентированная архитектура чаще применяется в системах, где требуется высокая изоляция, отказоустойчивость и управление ресурсами на уровне ОС (например, микроядерные ОС, распределённые системы).
SOA ориентирована на бизнес‑процессы и интеграцию приложений, обеспечивая многократное использование сервисов, гибкость и масштабируемость в корпоративных средах.
В процессно‑ориентированной архитектуре управление ресурсами и масштабированием происходит на уровне ОС, а сервисы могут быть жестко привязаны к конкретным процессам.
В SOA сервисы могут быть независимо развёрнуты, масштабированы и управляться централизованно через ESB или другие средства управления сервисами.
Таким образом, процессно‑ориентированная архитектура фокусируется на физических процессах ОС и их взаимодействии, тогда как SOA — на бизнес‑сервисах, стандартизированных интерфейсах и интеграции приложений на уровне бизнес‑процессов.
Итак, используя процессно‑оринетированную архитектуру в качестве архитектуры приложения, критически рассмотрим типичные высказывания, которые сложны для понимания и, к сожалению, часто воспринимаются как некий малосодержательный фон повествования.
Примеры высказываний, возникающих при смешении архитектуры кода и архитектуры приложения:
«Приложение использует микросервисную архитектуру, потому что у нас много классов.»
Правильно: «Приложение использует микросервисную архитектуру, потому что его компоненты развернуты как независимые сервисы, взаимодействующие по сети. Количество классов в коде не определяет архитектуру приложения.»«Наше приложение построено по принципу Clean Architecture, потому что у нас есть слои Presentation, Business и Data.»
Правильно: «Код приложения организован по принципу Clean Architecture, если слои кода соответствуют принципам инверсии зависимостей и чёткого разделения ответственностей. Архитектура приложения — это способ развертывания и взаимодействия компонентов, а не только структура кода.»«Мы используем архитектуру приложения MVC, потому что у нас есть контроллеры, сервисы и репозитории.»
Правильно: «Код приложения использует паттерн MVC, если разделение на контроллеры, представления и модели соответствует принципам MVC. Архитектура приложения — это способ организации компонентов приложения в среде выполнения, а не только структура классов.»«Наше приложение имеет архитектуру микросервисов, потому что у нас много модулей.»
Правильно: «Приложение имеет архитектуру микросервисов, если компоненты развернуты как отдельные процессы, взаимодействующие по сети. Количество модулей в коде не определяет архитектуру приложения.»«Мы используем архитектуру приложения N‑Tier, потому что у нас есть папки Presentation, Business и Data.»
Правильно: «Код приложения организован по принципу N‑Tier, если слои кода соответствуют принципам разделения ответственностей. Архитектура приложения — это способ развертывания и взаимодействия компонентов, а не только структура папок.»
Кроме проблем с коммуникацией существуют и другие проблемы.
Проблемы при смешении:
Разработчики могут применять архитектурные решения на уровне кода (например, сложные паттерны или декомпозицию классов), не учитывая общую архитектуру приложения, что приводит к излишней сложности и неочевидным зависимостям.
С другой стороны, принятие архитектурных решений без учета возможностей и ограничений кода может привести к непрактичным, трудно поддерживаемым решениям.
Смешение затрудняет понимание системы, увеличивает порог входа для новых участников команды и усложняет поддержку и развитие.
Как минимизировать когнитивную сложность:
Четко разделять уровни архитектурных решений: от глобальной структуры до деталей реализации.
Обеспечивать согласованность между архитектурой приложения и кода, чтобы изменения на одном уровне не нарушали целостность другого.
Таким образом, осознанное разделение архитектуры кода и архитектуры приложения — ключ к снижению когнитивной нагрузки и повышению качества архитектуры.
Далее разбираемся подробно.
Архитектура кода и архитектура приложения
Разница между архитектурой кода и архитектурой приложения заключается в уровне абстракции и контексте, в котором рассматриваются границы и структура системы.
Архитектура кода — это организация исходного кода на уровне логических границ, выраженных структурой файлов, модулей, классов, функций и других конструкций языка программирования. Эти границы определяются принципами проектирования, паттернами, стилем кода и стандартами организации проекта. Например, разделение на слои (presentation, business logic, data access), модульность, инкапсуляция, декомпозиция на микросервисы или компоненты — всё это проявляется на уровне исходного кода и не зависит от того, как код будет выполняться.
Архитектура приложения — это организация исполняемого процесса, то есть того, как компоненты системы взаимодействуют между собой в момент выполнения. В исполняемом процессе границы определяются технически: память (код, данные в стеке, данные в куче), процессы, потоки, ресурсы ОС и так далее Эти границы не обязательно соответствуют логическим границам исходного кода — например, разные модули могут быть загружены в один процесс, а один логический компонент может быть разнесён по нескольким процессам или машинам.
Один и тот же код может дублироваться в разных процессах, даже если в исходной кодовой базе он описан один раз. Например, библиотека вспомогательных функций может быть подключена к нескольким процессам (например микросервисам), и каждый из них будет использовать её независимо. Это не означает, что код физически дублируется в исходниках — он может быть собран в виде отдельной библиотеки и подключаться как зависимость. Однако на уровне архитектуры приложения каждый процесс, использующий эту библиотеку, будет иметь свою копию в своём окружении.
Когда код запускается и становится исполняемым процессом, логические границы исходного кода теряют своё значение, если только они не реализованы через технические границы (например, разные процессы, контейнеры, сервисы). Внутри процесса все данные и код существуют в едином адресном пространстве, и разделение происходит только по типу памяти (стек, куча) и по способу доступа к данным. Исходный код сохраняет свою структуру только как логическая модель, но не как физическая граница выполнения.
При проектировании архитектуры приложения важно понимать, что один и тот же код может быть задействован в нескольких процессах, и это влияет на масштабируемость, обновление и отладку системы.
Архитектура кода помогает минимизировать дублирование и обеспечить переиспользование, но архитектура приложения определяет, где и как этот код будет использоваться.
Смешение этих уровней приводит к когнитивной сложности — разработчики могут не видеть, как изменения в одной части архитектуры повлияют на другую.
Сравнительная таблица
Критерий |
Архитектура кода |
Архитектура приложения |
|---|---|---|
Уровень абстракции |
Логический, исходный код |
Технический, исполняемый процесс |
Границы |
Файлы, модули, классы, функции |
Процессы, потоки, память, ресурсы |
Структура |
Документы, конструкции языка |
Объекты ядра ОС: память, процессы, ресурсы |
Таким образом, архитектура кода это логическая модель, а архитектура приложения — техническая реализация этой модели в исполняемой среде.
Архитектура приложения
Архитектура приложения — это не просто набор всего исходного кода приложения, а организация исполняемых компонентов системы. Если архитектура кода строится из атомарных сущностей языка программирования, таких как операторы, функции и данные, то архитектура приложения строится из атомарных сущностей среды исполнения кода, объектов ядра операционной системы — процессов.
Процесс является минимальной единицей, внутри которой реализуется функциональность приложения, полностью или частично, и обеспечиваются изоляция, управление ресурсами и безопасность.
Архитектура кода фокусируется на логических границах: функции, классы, модули. Эти границы определяют, как организован исходный код, но не влияют напрямую на выполнение приложения — неважно на сколько методов в коде разложен алгоритм сортировки он будет выполнять свою работу. Архитектура приложения, напротив, определяет, как логические функции реализуются и взаимодействуют в реальной среде — через процессы, контейнеры, микросервисы.
Примеры:
В монолитной архитектуре вся логика приложения может быть реализована в одном процессе, и хотя логические функции выделены через структуру кода, но технически работают в рамках одного адресного пространства.
В микросервисной архитектуре каждая функция, а чаще набор функций, реализуется в отдельном процессе, что обеспечивает независимость, масштабируемость и отказоустойчивость для приложения в целом.
Процесс - атомарная единица архитектуры приложения
Процесс — это экземпляр исполняемой программы, который получает выделенные ресурсы операционной системы: память, файловые дескрипторы, потоки выполнения. Каждый процесс изолирован от других, что обеспечивает независимость и устойчивость системы. Внутри процесса могут быть реализованы любые логические функции приложения, но сам процесс определяет техническую границу, за которой не может быть прямого доступа к ресурсам другого процесса без специальных механизмов межпроцессного взаимодействия.
На практике часто один процесс выполняет несколько логических функций, которые можно выделить на уровне архитектуры кода. Например, в монолитном приложении один процесс может содержать слои представления, бизнес‑логики и доступа к данным. Такая организация кода позволяет быстро разрабатывать и запускать весь функционал приложения внутри одного процесса, но при масштабировании и необходимости независимого управления функциями возникает потребность в разделении функционала приложения на отдельные процессы.
Проектируя архитектуру приложения, архитектор обязан рассчитывать его работу под пиковую нагрузку, определять допустимый уровень задержек, планировать масштабирование процессов — горизонтальное (увеличение числа процессов) или вертикальное (увеличение ресурсов на процесс).
Проектирование процессов
Проектирование процессов — это ключевой этап архитектуры приложения, на котором определяются не только функции, но и технические характеристики каждого исполняемого компонента приложения.
При проектировании процесса учитываются четыре основных аспекта:
группа выполняемых функций
максимальная мощность процесса
способы взаимодействия с процессом
количество доступных ресурсов
Группа функций процесса
При проектировании процесса сначала определяется набор логических функций, которые он будет выполнять. Это могут быть задачи бизнес‑логики, обработка запросов, работа с данными или взаимодействие с внешними системами. Функции должны быть сгруппированы логически: например, все операции с пользователями могут быть вынесены в отдельный процесс, а обработка платежей — в другой. Такое разделение упрощает масштабирование, тестирование и поддержку.
Максимальная мощность процесса
Важно заранее оценить, какую нагрузку будет испытывать процесс: сколько CPU, памяти, дискового пространства и других ресурсов ему потребуется.
Это позволяет:
избежать перегрузки системы и сбоев из‑за нехватки ресурсов.
оптимизировать использование железа, особенно при работе в контейнерах или облаке.
планировать масштабирование: если нагрузка растёт, можно добавить больше процессов или перераспределить нагрузку между ними.
Способы взаимодействия с процессом
Процесс не существует изолированно — он должен взаимодействовать с другими процессами, внешними системами и пользователями.
Способы взаимодействия определяются:
интерфейсами (API, очереди сообщений, сокеты).
протоколами обмена данными.
механизмами синхронизации и обработки ошибок.
Количество доступных ресурсов
Основными ограничениями для любого процесса служат ресурсы, предоставляемые операционной системой:
CPU — количество операций, вычислительная мощность, доступная для процесса.
Память — объём оперативной памяти, необходимый для хранения данных и выполнения вычислений.
Диск — пространство для хранения файлов, журналов, временных данных; скорость доступа к данным.
Сеть — пропускная способность и доступность сетевых ресурсов для обмена с другими процессами и системами.
Ограничения ресурсов определяют, сколько полезной работы может выполнить процесс в единицу времени, то есть его производительность и какую нагрузку система способна выдержать без деградации производительности.
Ограничения по ресурсам и производительности влияют на то, как архитектура приложения делится на процессы, какие механизмы балансировки и мониторинга внедряются, как реализуются механизмы отказоустойчивости и защиты от перегрузки.
Проектирование процессов — это оптимизация использования ограниченных ресурсов для достижения максимальной полезной работы, с учётом требований к скорости и надёжности системы.
Архитектура кода
Архитектура кода определяет функционал решения, то есть набор задач, которые должна выполнять система. Она описывает, какие функции реализуются, как они объединяются в логические группы и как эти группы взаимодействуют между собой: например, через вызовы функций, интерфейсы, события или паттерны проектирования.
Группировка функций и их распределение по процессам
При проектировании архитектуры кода разработчики группируют функции по смыслу, ответственности или по принципу связности (например, все операции с пользователями — в один модуль, работа с базой — в другой). Эти группы функций могут быть реализованы в рамках одного процесса (например, в монолитном приложении) или распределены по нескольким процессам (например, в микросервисной архитектуре).
Архитектура кода сильно зависит от архитектуры приложения — разделение функционала на отдельные выполняемые процессы, напрямую влияет на архитектуру кода.
Особенно сильно архитектура приложения влияет на способы взаимодействия между группами функций:
внутрипроцессное взаимодействие
межпроцессное взаимодействие — требует дополнительного кода и использования специальных библиотек и компонентов
Таким образом, архитектура кода задаёт логическую структуру решения, а её реализация на уровне процессов определяет, как эта структура будет работать в реальной среде, с учётом ограничений и требований к производительности.
Проектирование кодовой базы
Архитектура кода строится с учётом ключевых ограничений, определяющих, как реализуется и поддерживается система. Эти ограничения включают выбранный технологический стек и квалификацию команды разработчиков.
Ограничения технологического стека
Выбранный стек технологий — языки программирования, библиотеки, фреймворки, системы хранения данных, кэширования, поиска и другие специализированные инструменты — задаёт рамки, в которых возможно проектирование и реализация кода.
Архитектура кода должна учитывать:
совместимость и ограничения используемых технологий.
возможности и ограничения библиотек и фреймворков.
ограничения на выбор решений для хранения и обработки данных.
Например, если выбрана микросервисная архитектура приложения, каждый сервис может использовать свой стек технологий, но при этом возрастает сложность координации и интеграции между сервисами. В монолите чаще требуется единый и согласованный стек для всех компонентов.
Ограничения квалификации команды
Архитектура кода также определяется уровнем знаний и навыков членов команды. Утверждение, что «код пишется для человека, а не для компьютера», означает, что важна читаемость, поддерживаемость и понятность кода.
Архитектура кода должна быть:
доступна для понимания и модификации текущей командой
соответствовать опыту и навыкам разработчиков, чтобы избежать технического долга и ошибок
Если команда не владеет определённым языком или инструментом, использование его в архитектуре кода приведёт к проблемам с поддержкой и развитием системы. Поэтому архитектура кода всегда должна учитывать не только технические, но и человеческие ограничения.
Взаимное влияние архитектуры приложения и архитектуры кода
Архитектура приложения и архитектура кода тесно связаны и оказывают взаимное влияние. Архитектура приложения определяет, как компоненты взаимодействуют в среде выполнения, а архитектура кода — как эти компоненты реализованы и организованы внутри.
Примеры взаимного влияния
Масштабируемость приложения и модульность кода
Если архитектура приложения предусматривает масштабирование (например, микросервисы), то код должен быть организован так, чтобы каждый сервис был автономным модулем с минимальной связностью и высокой когезией. Это влияет на выбор структуры кода: разделение на независимые пакеты, использование API, изоляция бизнес‑логики и данных. Если код не модульный, масштабирование приложения становится сложным и дорогостоящим.
Производительность кода и состав приложения
Архитектура приложения может предусматривать отдельные сервисы кэширования, использование очередей сообщений и оптимизацию взаимодействия между процессами для снижения задержек, но если оптимизация кода привела к значительному увеличению производительности приложения, то появляется возможность полностью исключить указанные дополнительные сервисы или снизить количество ресурсов для их работы.
Комментарии (6)

RieSet
19.11.2025 20:15Как мне кажется, когнитивную сложность надо начинать снижать с упрощения стиля изложения подобных документов.
По полгода тратится, чтобы формулировки были максимально точными и без ошибок.
Это когда в школах учебники по математике переусложнены, потому что автор не хочет выглядеть дилетантом в глазах коллег-математиков, хотя пишет книгу для семилетних детей.
При такой сложности текста оперативка типичного разработчика кончается на третьей странице, у дизайнера — на первой. Руководитель разработки со всей ответственностью прочтет всё и, может, что-то запомнит.
Надо делать так, чтобы придуманная архитектура была понятна всем: заказчикам, разработчикам, тестировщикам и дизайнерам. А для этого надо выйти за пределы формата.

antonb73 Автор
19.11.2025 20:15Здраствуйте. Спасибо, что уделили время. Надеюсь статья вам понравилась, или хотя бы принесла пользу, любую.
Думал как ответить на вашу просьбу - писать проще. Надумал на целую книгу про Жизнь в коллективе людей, отношения в социальных группах, созависимость и авторитет, социальный статус как суррогат знаний...
Лучше я отвечу просто - это не я такой, это жизнь такая :)
Прошу не злится и понять. Желаю вам всего наилучшего!
Если совсем упростить, то статья про:
1) Как проектировать приложения не перегружая мозг
2) Для этого понимаем, что наше приложение при запуске будет состоять из одного или более объектов ОС - процесса
3) Давайте при проектировании приложения сразу спроектируем наши процессы - они всё равно будут, так лучше подумать о них заранее
4) Чтобы лучше понимать друг друга будем говорить - архитектура приложения или архитектура кода
5) Описываю, какие аспекты оказывают ключевое влияние при проектировании архитектуры приложения и архитектуры кода
Как то так
RieSet
19.11.2025 20:15Вот тут и суть. С 15-летним опытом в IT я с трудом понимаю, что зашифровано в этих словах.
Я уверен, что в этих формулировках накопленный опыт, боль и желание сделать хорошо.
Но, например, разработчиков из поколения Z сложно заставить прочесть даже одну страницу инструкции по процессам. А сидеть и расшифровывать для них этот документ не стал бы.
У этой работы есть целевая аудитория. И задача — эффективно и быстро создать продукт и уменьшить лишнюю коммуникацию и уточнения. Если не ориентироваться на аудиторию и задачу, даже самую хорошую документацию выкинут, к сожалению.
itGuevara
Может быть есть где-то путеводитель (классификатор) по всем этим Х - ориентированным архитектурам? Наподобие этого, но более полный, например, включая функциональное и автоматное (А.Шалыто) программирование, событийно - / процессно - ориентированные архитектуры.
Также хотелось бы чтобы эта "процессно-ориентированная архитектура" была более строгим формализмом показана.
К термину "процессно-ориентированная архитектура" по смыслу ближе дальнейшее развитие BPMN до no code (из схемы процесса - готовое приложение), т.е. где будет повышена на порядок формализация workflow, добавлены docflow (его вообще нет) и другое - вплоть до встроенного в IDE редактора онтологий (типа protege). Условно: код программы будет выглядеть как граф знаний.
t38c3j
https://github.com/denyspoltorak/metapatterns
antonb73 Автор
Я бы сам с удовольствием таким пользовался, но пока что все очень зыбко, все делят пространство абстракций на свои блоки, границы которых не совпадают.
Думаю это общая проблема человеческого мышления, которое очень плохо воспринимает абстракции над абстакциями.
Смысл статьи - рассказать, что проектирование приложения, как набора процессов ОС и проектирование кода вещи разные, но сильно взаимосвязанные.