Skip to content

Мозаический подход

«Мозаика — это не просто сборка из частей. Это способ видеть целое через связи.»

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

Tip

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

Мозаичный подход возвращает смысл связям
он не про структуру ради структуры, а про осмысленное сопряжение компонентов


📖 Оглавление


1. Мозаичный подход основан на принципе от частного к общему

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

Принципы

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

Преимущества

  1. Параллельная разработка: разные разработчики из команды могут работать над своими этапами независимо.
  2. Минимизация ошибок: интеграция происходит только после локального тестирования.
  3. Упрощённое тестирование: каждый элемент проверяется отдельно (unit), а потом в связке (integration).
  4. Лёгкость масштабирования: систему можно расширять новыми “плитками” (stage).

Ниже рассмотрим ключевые компоненты проекта: pipeline, stage, router, service и utils.


2. Ключевые компоненты архитектуры

Базовая структура проекта, опирающегося на мозаичный подход

NameProject/
├─ pipeline/        ← ядро: содержит этапы (stage) и pipeline.py
├─ router/          ← управляет запуском пайплайна и логикой маршрутизации
├─ config.yaml      ← ключевые настройки проекта
├─ cli.py           ← точка входа для запуска через консоль
├─ README.md        ← описание проекта
…

Это только основа основ: ниже приведена полная расширенная структура с примерами и комментариями.

1. Что такое пайплайн

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

2. Структура этапа (Stage)

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

pipeline/
 ├── one_stage_<name>/
 │     ├── Stage1Service.py     # бизнес-логика этапа
 │     ├── __init__.py          # пакетный инициализатор
 │     └── ...
 ├── two_stage_<name>/
 │     └── ...
 └── pipeline.py                # задаёт последовательность выполнения

Каждый этап начинается с универсального префикса, отражающего его позицию в цепочке:

  • one_stage_... — первый этап
  • two_stage_... — второй этап
  • three_stage_... — третий этап
  • и так далее

💡 Почему текстовые, а не числовые обозначения:
цифры в названиях файлов и пакетов могут вызывать проблемы при импортах.
Поэтому используется текстовая нумерация (one, two, three и т.д.), которая безопасна для Python и читаема человеком. Название конкретного этапа придумывается кодекс-агентом, который пишет код,
либо разработчиком вручную — важно, чтобы имя отражало суть выполняемой задачи. Запуском этапа управляет StageServer — он активирует нужный модуль и, при необходимости,
обращается к функциям из папки utils/ (см. раздел 6. Бизнес-логика и техническая логика).

3. Service: исполнитель бизнес-логики

Service — это модуль или объект, который реализует бизнес-логику конкретного этапа (stage).
Он описывает что именно делает этот этап: собирает данные, анализирует, обрабатывает или публикует.
Для выполнения задач Service использует функции из utils/ — технические инструменты, отвечающие за «как сделать».

💡 Пример:
Внутри Stage1Service.py бизнес-логика собирает новости.
Для этого она вызывает функции из utils, которые читают файлы, форматируют текст и обращаются к API.

Отличие от роутера:
если Service — это «исполнитель» конкретного действия,
то роутер — это «диспетчер», который решает, какие сервисы и в какой последовательности запускать.

4. Роль роутера (router/)

Роутер — это управляющий модуль, который координирует выполнение всего пеплайна.
Он не содержит бизнес-логики, а только запускает нужные этапы (StageService.py) в нужной последовательности.

Обычно роутер появляется на завершающем этапе разработки, когда все stage уже готовы и протестированы отдельно.
На этом этапе router становится своего рода дирижёром, который просто вызывает каждый StageService.py
в порядке, заданном в pipeline.py.

Основные сценарии работы роутера: 1. Запуск всего пеплайна:
роутер считывает порядок из pipeline.py и запускает все этапы по очереди —
от первого (one_stage_...) до последнего (final_stage_...). 2. Запуск отдельного этапа:
можно вызвать конкретный stage напрямую — например, чтобы проверить новый модуль,
не прогоняя всю цепочку.

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

5. Организация utils

Папка utils — это техническое ядро проекта.
Здесь живёт техническая логика — универсальные функции, которые не зависят от конкретного этапа пеплайна и могут использоваться где угодно.
Если stage — это что делаем, то utils — это чем делаем.

💡 Другими словами: utils — это набор инструментов, не «знающих» контекста,
но умеющих выполнять стандартные операции: читать файлы, преобразовывать данные, форматировать текст, вызывать API и т.д.

Принцип организации:

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

Пример структуры utils/

utils/
 ├── io.py         # операции с файлами: чтение, запись, парсинг
 ├── net.py        # сетевые операции: запросы, API-вызовы
 ├── text.py       # работа с текстом: очистка, нормализация, токенизация
 ├── data.py       # обработка данных: JSON, CSV, словари
 └── system.py     # конфигурации, логи, вспомогательные системные вызовы

☝️Важно:
utils никогда не должны «знать», какой конкретный stage их вызывает.
Это делает их чистыми, независимыми и переиспользуемыми —
как строительные блоки, из которых можно собирать любую систему.


3. Полная структура проекта

Ниже приведена полная структура проекта, который реализует мозаичный подход.
Она отражает базовый стандарт организации директорий и файлов, принятый в рамках Технического стандарта U.L.I. Каждый элемент этой структуры соотносится с компонентами, описанными выше: пеплайном, этапами, сервисами, роутером и утилитами. Для оформления описания проекта рекомендуется использовать шаблон 📄 README-template

Основная структура проекта (база)

NameProject/
 └── pipeline/                        
       ├── one_stage_<name>/          # этап 1 пайплайна
       │     ├── Stage1Service.py     # скрипт запуска этапа 
       │     ├── __init__.py        
       │     └── ...                  # все подмодули,этапа 
       ├── two_stage_<name>/       
       │     ├── Stage2Service.py    
       │     ├── __init__.py
       │     └── ...
       ├── three_stage_<name>/        # этап 3 пайплайна
       │     ├── Stage3Service.py     
       │     ├── __init__.py
       │     └── ...
       └── pipeline.py                

 ├── router/                           ← Роутер
 │     └── routes.py                   
 ├── utils/                            ← Технические утилиты
 │     ├── io/                         ← Ввод/вывод
 │     ├── net/                        ← Сетевые операции
 │     ├── text/                       ← Текстовые операции 
 │     ├── data/                       ← Работа с данными 
 │     └── system/                     ← Логирование, конфиг
 ├── logs                              ← Логи системы
 ├── scripts/                      

 ├── tests                             ← Тесты
 ├── upgrades                          ← Апгрейды
 ├── connectors                        ← Подключения
 ├── statistics       
 ├── config.yaml                       ← Главные настройки
 ├── cli.py                            ← Точка входа
 ├── README.md                         ← Описание проекта
 ├── Directory_structure.txt           ← Структура директории
 ├── Makefile                 
 └── __init__.py                      
Опциональные элементы, которые зависят от проекта
NameProject/
 ├── presets/                     ← Пресеты (опционально)
 │     ├── default_config.yaml    ← Конфигурации по умолчанию
 │     └── README.md              ← Описание изменений
 ├── data/                        ← Данные (опционально)
 ├── 🗂️ Chronology_versions/      ← Описание версий проекта
 ├── templates/                   ← Шаблоны (опционально)
 └── bootstrap/                   ← Инициализация

📘 Пояснение к отдельным папкам проекта

📜 scripts/

Папка scripts содержит самостоятельные исполняемые скрипты, которые работают вне основного пеплайна. В классической IT-практике сюда помещаются служебные и утилитарные сценарии, выполняющие отдельные задачи: от очистки временных файлов и пересборки данных до тестовых вызовов API и прототипов будущих функций. Эти скрипты могут использовать общие модули из utils/, но не зависят от конкретных stage. Таким образом, scripts/ служит пространством для автономных решений и временных инструментов, которые со временем могут быть интегрированы в основной пеплайн как полноценные этапы.

upgrades/

Папка upgrades служит временным пространством для хранения мелких апгрейдов, правок и патчей, возникающих между версиями проекта (например, v1.1, v1.2, v1.3).
В неё помещаются изменения, для которых пока не определено точное место. Когда таких улучшений накапливается достаточно (формируется “критическая масса”), при переходе на новую крупную версию проекта (v2.0, v3.0 и т.д.) содержимое upgrades/ разбирается: часть изменений встраивается в существующие stage (если логика дополняет уже имеющийся этап); часть оформляется как новые stage (если апгрейд стал самостоятельным шагом); в исключительных случаях формируется новый pipeline (если изменения создают новую производственную ветвь проекта). Таким образом, upgrades/ обеспечивает гибкость между версиями и позволяет вносить оперативные улучшения без нарушения целостности структуры пайплайна.

🟡 Важно: папка upgrades/ создаётся и начинает использоваться только после перехода проекта на версию 2.0 и выше.
Она «оживает» тогда, когда в Redmon (или в файле версионности) зафиксировано, что текущая версия проекта ≥ 2.0 — то есть система уже вступила в фазу активных апгрейдов и промежуточных улучшений.

🔌 connectors/

Папка connectors/ — это локальная граница интеграций внутри конкретного проекта.

Здесь размещаются адаптеры к внешним сервисам и системам: Telegram, VK, GitHub, Google Docs, OpenAI, webhook, внешним API и другим интеграционным точкам. Каждый connector прячет технические детали взаимодействия: токены, URL, SDK, HTTP-запросы, retries, форматы ответа и обработку ошибок.

Бизнес-логика проекта не должна напрямую знать, как устроен внешний сервис. Вместо этого она вызывает понятные функции уровня проекта: send_operator_message(), publish_post(), load_source_doc(), create_issue() и т.д. Конкретная реализация вызова Telegram, VK, GitHub или OpenAI остаётся внутри connectors/.

Пример локальной структуры:

project/
├── core/          # бизнес-логика проекта
├── connectors/    # адаптеры к внешним сервисам
├── config.py
└── config.toml

Важно: connectors/ не является общей библиотекой для всего DETai-org. Не следует создавать один глобальный каталог connectors/ и подключать его во все проекты: это создаёт неявную связанность между проектами.

Общий код выносится только после того, как один и тот же адаптер стабильно повторился в нескольких проектах и его контракт стал понятен. В этом случае он оформляется не как общий connectors/, а как отдельный пакет или репозиторий, например detai-integrations, detai-common, detai-clients или отдельный репозиторий под конкретную интеграцию.

🧪 tests/

Папка tests содержит систему проверок, выстроенную по принципу мозаичной инкрементальной сборки. Каждый этап — например, one_Stage_<name>/, запускаемый через Stage1Service.py, — тестируется изолированно (unit-тесты) для проверки корректности выполнения своей логики. Лишь убедившись, что все stage работают корректно, выполняются mock-тесты, которые имитируют взаимодействие между этапами и проверяют корректность передачи данных, контрактов и последовательности выполнения, гарантируя, что любой stage пайплайна можно заменить или обновить без нарушения целостности всего проекта.

🗂️ Chronology_versions/

Папка Chronology_versions хранит описание эволюции проекта — феноменологию изменений между версиями. Здесь фиксируется не только содержательная динамика (какие смыслы, задачи и подходы менялись), но и технологическая хронология, которую можно проанализировать через Codex: какие stage были изменены, какие добавлены, какие, возможно, преобразовались в новые. В редких случаях отмечаются и появления новых pipeline, если они возникли как результат накопленных обновлений и логического роста системы.

В заключение: применение мозаичного подхода

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

  • Микросервисной архитектуре — независимые сервисы объединяются в систему.
  • CI/CD-процессах — этапы сборки, тестирования и деплоя выполняются последовательно и автономно.
  • Тестировании — от юнит-тестов (проверка отдельных функций) к интеграционным (проверка связей).

Для унификации описаний проектов рекомендуется использовать шаблон 📄 README-template, основанный на том что описано в этом документе.



Дополнительные материалы

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

Бизнес-логика 🆚 техническая логика

Характеристика Бизнес-логика Техническая логика
Что делает Решает смысловую задачу (что нужно системе) Реализует технические операции (как это сделать)
Где живёт Внутри stage/service.py Внутри utils/
Примеры собрать новости, рассчитать рейтинг, отправить пост читать файл, форматировать текст, вызвать API
Меняется при изменении целей проекта ✅ Да ❌ Нет
Переиспользуется в других проектах Иногда Часто

Идея:
utils — это сервисы нижнего уровня.
Если stage — это «плитка бизнес-уровня», то utils — это «инфраструктурный слой», поддерживающий все плитки.


Типы проектов и где применима мозаика

Тип проекта Суть Подходит ли мозаичная архитектура Почему
🧩 Сценарные / логические системы цепочки шагов, сценарии, обработка данных ✅ идеально каждый этап — отдельный stage (обработка, анализ, фильтрация, постинг и т.д.)
🤖 Боты и ассистенты взаимодействие с пользователем, обработка ответов, логика ветвлений ✅ подходит каждый тест, опрос или сценарий можно оформить как отдельный stage или пайплайн
⚙️ Интеграционные системы сбор, обработка и передача данных между сервисами ✅ подходит каждый этап — источник, обработчик или отправитель
🧠 ML / Data Science проекты анализ и обучение моделей на данных ⚙️ частично можно использовать stage-подход, но лучше классическая DS-структура (data/raw → processed → models)
🌐 Web-приложения и сайты интерфейс, сервер, API ⚙️ частично архитектура мозаики может использоваться внутри backend-логики, но не для фронтенда
🎮 Игровые / UX-проекты визуальные сцены, пользовательские взаимодействия 🚫 нет нужна сцено- или объектная структура, мозаика слишком жёсткая
📊 Отчётные / статические проекты отчёты, визуализации, дашборды 🚫 нет нет этапности, это просто визуальный слой

Как определить границу пеплайн❓

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

Вопрос Если ответ «да» → остаётся в пеплайн Если «нет» → создаём новый пеплайн
1. Зависит ли этап напрямую от результата предыдущего? ✅ да ❌ нет
2. Логика этапов объединена одной целью? ✅ да ❌ нет
3. Можно ли протестировать цепочку целиком как один сценарий? ✅ да ❌ нет

Если хотя бы на два вопроса ответ «нет» — это новый пеплайн.

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

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


Документ подготовлен в соответствии с архитектурными принципами мозаичного подхода и стандартом U.L.I. v1.0.