Компонентная разработка vs «Durex-код» 📘 Памятка инженера Metabot 1️⃣ В чём разница подходов Скриптовый подход Компонентный подход Код вставляется прямо в сценарий Сценарий использует готовый компонент Telegram-логика торчит в webhook-скрипте Telegram спрятан внутри плагина Сценарист не может этим пользоваться Сценарист работает декларативно Нет чёткого контракта Есть входы, выходы, параметры Разовое решение Переиспользуемый модуль Зависит от конкретного проекта Доставляется в любой проект 2️⃣ Что такое «Durex-код» Durex-код — это: код, написанный «под задачу» код, который нельзя переиспользовать код, который живёт только в одном скрипте код, который нарушает контракты код, который смешивает логику канала, бизнес-логику и UX Это не плохо. Иногда это допустимо. Но это не архитектурный стиль Metabot. 3️⃣ Что такое компонентный стиль Metabot Компонент — это: атомарная команда с чёткими входами с чёткими выходами с понятным поведением с изолированной зоной ответственности со спрятанной инженерной сложностью Пример: const VoiceInput = require('Common.Voice.VoiceInput') return VoiceInput.expect({ code: "orion_profiling_q1_voice", lead, successScript: "orion_profiling_q2", cancelScript: "orion_profiling_cancelled", targetAttr: "orion_profiling_q1_text", sourceAttr: "orion_profiling_q1_voice_url", extraAttrs: { active_agent: "orion", voice_context: "orion_profiling_q1", input_mode: "profiling" }, processorScript: "System_VoiceInput_Processor", stt: { provider: "openai", options: { model: "whisper-1", language: "ru" }, asyncResponse: true, tokenKey: "OPENAI_API_KEY" } }) Сценарист видит: targetAttr sourceAttr successScript cancelScript stt-параметры Он не видит: Telegram API file_id webhook структуру async механику OpenAI SDK Это декларативный стиль. 4️⃣ Что такое декларативный подход Декларативный подход — это: Мы описываем ЧТО должно произойти, а не КАК это происходит. Сценарист пишет: Ожидай голос. Перейди в success. Сохрани результат. А не: Проверь payload.message.voice Достань file_id Сходи в Telegram API Отправь в STT Подожди callback Распарси JSON 5️⃣ Принципы компонентной разработки Metabot 1. Чёткий контракт Каждый компонент обязан иметь: входные параметры выходные данные предсказуемое поведение задокументированные переходы 2. Нет неявной передачи данных ❌ Плохо: memory.foo = 123 Потом в другом месте: memory.foo Это разрыв контракта. ✔ Правильно: вход через параметры управляемый выход, например, через targetAttr всё прозрачно 3. Одна зона ответственности Пример: VoiceInput: отвечает за голосовой ввод не отвечает за каналы не отвечает за Telegram ArtifactResolver: отвечает за извлечение артефактов из всех каналов не отвечает за STT не отвечает за сценарий 4. Никаких «всё в один файл» Если логика растёт — создаём слой. Пример: Был Telegram-код внутри VoiceInput Появился Max Вместо if/else-ада — создаём Channel.ArtifactResolver Это инженерный подход. 5. Повторное использование — обязательное требование Если модуль нельзя переиспользовать — это не компонент. Компонент должен быть: переносимым подключаемым поставляемым как плагин 6️⃣ Почему это важно Сценаристам проще Интеграторам проще Код чище Проекты масштабируются Плагины можно доставлять в разные компании Мы получаем архитектурную степень свободы И самое интересное: ⏱ По времени это занимает примерно столько же. Разница — в мышлении. 6.1 🔓 Декларативный стиль = расширяемая палитра Metabot Декларативный подход — это не только «красиво». Это позволяет нам: расширять палитру компонентов развивать low-code платформу строить визуальные конструкторы делать архитектуру масштабируемой Сейчас в Metabot есть ~21 атомарная команда. Примеры: SendMessage SendImage SendFile Input VoiceInput TransferToOperator RunScript и т.д. Каждый компонент: имеет входы имеет выходы имеет чёткие параметры ведёт себя предсказуемо Это позволяет: 1️⃣ Легко расширять платформу Добавили новый компонент → он сразу становится частью палитры. 2️⃣ Делать визуальные конструкторы Если у компонента есть вход/выход — можно рисовать схемы. 3️⃣ Строить workflow-системы Компоненты становятся узлами графа. 4️⃣ Делать экспортируемые решения Компонент можно доставить в другой проект. 6.2 🧱 Атомарность = возможность визуализации Если компонент описан как: чёрный ящик с чёткими входами с чёткими выходами его можно: визуализировать соединять стрелками использовать в low-code использовать в no-code переносить между проектами Если код: размазан по скриптам читает memory меняет глобальные объекты зависит от webhook структуры его нельзя: визуализировать стандартизировать масштабировать 7️⃣ Архитектор vs Скриптовик Скриптовик думает: Мне нужно сделать, чтобы работало. Архитектор думает: Как сделать, чтобы это работало в 10 проектах. 8️⃣ Как использовать это как AI-чеклист Можно кидать в AI вместе с кодом и спрашивать перед коммитом: Есть ли здесь чёткий контракт? Понятен ли этот код сценаристу? Есть ли неявная передача данных? Нарушена ли зона ответственности? Можно ли переиспользовать этот код? Можно ли этот код вынести в компонент? Можно ли визуализировать это поведение как узел workflow? Является ли это Durex-кодом или системным модулем? Если на 3+ вопроса ответ «нет» — ты пишешь Durex. 9️⃣ Когда допустим Durex-код Иногда допустимо: разовая миграция временный костыль hotfix Но: он не должен становиться системой он не должен множиться он не должен ломать архитектуру 1️⃣0️⃣ Когда допустимо писать код в скрипте Код в скрипте допускается. Но только если соблюдены условия. ✔ Допустимые случаи 1️⃣ Абсолютно разовая логика временная миграция одноразовый расчёт локальный pipeline подсчёт баллов простая условная логика Пример: if (lead.getAttr("score") > 10) { return bot.run({ script_code: "vip_branch" }) } Это допустимо. 2️⃣ Логика понятна сценаристу Если сценарист: может прочитать может понять может отредактировать — код допустим. Если сценарист не может понять код — код не должен находиться в сценарии. Исключение — системные вещи без которых абсолютно нельзя обойтись, например, вызов плагинов. 3️⃣ Логика не нарушает архитектуру Допустимый код: не читает неявные memory не зависит от глобальных переменных не создаёт скрытых зависимостей не нарушает контракт компонентов ❌ Недопустимый Durex-код Код нельзя писать в сценарии, если: он сложный он интеграционный он работает с API он обрабатывает webhook он содержит асинхронную логику он требует инженерного уровня знаний Такой код должен быть: вынесен в плагин спрятан под компонент задокументирован переиспользуем 1️⃣1️⃣ Финальная мысль Metabot — это не набор скриптов. Это: палитра компонентов декларативный конструктор платформа Если ты пишешь код, который нельзя вынести в палитру — ты... выпускаешь Durex. Если ты пишешь код, который расширяет палитру — ты работаешь как инженер платформы. P.S. Почему «Durex»? Компонент — это капитал: инвестиция и актив, который ставится на баланс. Его можно переиспользовать, масштабировать и доставлять в десятках проектов — он создаёт системную ценность. А разовый скрипт — это расход периода: проект сделали, прибыль получили — но актива не появилось. Работу сделали один раз, в следующем проекте — делаем то же самое заново. Все при деле, задача выполняется, но капитал не создаётся.