Все записи
6 мин

Почему веб-версия так долго, если уже есть Telegram Mini App: где код реально переиспользуется, а где нет

вайбкодингархитектураtelegram-боты

Если вы пришли сюда с тем же вопросом, что мучил меня, то короткий ответ такой: нельзя просто взять готовый Telegram Mini App и за вечер превратить его в публичную веб-версию, и дело тут не в лени и не в том, что кто-то усложняет на ровном месте. У меня уже был полностью рабочий мини-апп для Картары, со стилем, дизайном и всем функционалом, но когда я начал делать веб того же продукта, переиспользовать получилось почти только бэкенд и буквально один маленький UI-хук, а весь остальной интерфейс пришлось собирать заново. И вот почему так выходит, я разобрал по слоям, чтобы вы не наступили на те же грабли.

Я ведь и сам сначала был уверен, что это вопрос на пять минут. Прямо так и спрашивал у своего AI-агента: почему у нас есть мини-апп, стиль, дизайн и функционал, но под веб всё это сделать вдруг так сложно и долго? И добавлял: почему нельзя ту же логику Картары взять из мини-аппа, чего там вообще придумывать? Логика-то одна, продукт один, чего там переделывать. А когда мне в ответ начали объяснять про границы и слои, я честно написал, что нихуя не врубаюсь и что это он как будто усложняет. Так что если вам кажется, что разработчик или ваш ИИ набивает себе часы на ровном месте, я вас понимаю, сам там был.

Почему вообще встал этот вопрос

Самое обидное, что я ведь заранее говорил про переиспользование. И когда дошло до дела, у меня вырвалось логичное «а почему раньше-то это не обсуждали, я вроде же и так говорил про переиспользование». В голове у меня была простая картинка: есть один продукт, у него есть лицо в Telegram, а веб — это просто то же лицо, только в браузере. Бери и копируй.

А проблема в том, что Telegram Mini App и веб — это не один интерфейс в двух местах, а два разных продукта, которые случайно похожи внешне. Мини-апп живёт внутри Телеграма, он знает кто вы по данным от самого Телеграма, он встроен в чужое приложение с его правилами, жестами и ограничениями. Веб живёт сам по себе, у него своя авторизация через сессию, свой роутинг, свои размеры экрана, своё поведение клавиатуры. Снаружи кажется, что это близнецы, а внутри это два разных организма, у которых общий только желудок — бэкенд.

Вместо того чтобы кодить, я собрал консилиум

Я мог бы тупо начать копировать компоненты и через два дня упереться в стену. Но вместо этого сделал то, что у меня давно стало рабочим инструментом, — собрал консилиум. Если коротко, это когда я по одному вопросу запускаю целую команду AI-экспертов с разными ролями, и они независимо разбирают тему с разных сторон, а я потом читаю и принимаю решение. В этот раз я поднял восемь ролей на двух разных моделях, Claude и Codex как равные агенты, итого шестнадцать голосов на одну тему — где проходят границы переиспользования между мини-аппом и вебом.

Звучит как из пушки по воробьям, понимаю. Но цена ошибки тут не пять минут, а потенциально неделя в неправильном направлении, когда ты сначала всё свалил в кучу и пошарил, а потом мучительно расшиваешь связи. У меня уже был похожий заход, когда я собрал консилиум из шести экспертов и забыл добавить туда самого пользователя, так что я научился собирать состав пожирнее и под задачу. Шестнадцать голосов за вечер стоят мне копейки, а сэкономить могут реально много времени.

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

Трёхслойная архитектура, которая всё расставила по местам

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

Почему это важно и почему нельзя было взять из мини-аппа? Потому что у Telegram Mini App такого деления просто нет. Там оболочка — это сам Телеграм, авторизация — это данные от Телеграма, а размеры и поведение диктует мобильный контейнер. Перенести компонент из мини-аппа в веб — это не скопировать файл, это вырвать орган из одного тела и пытаться пришить к другому, у которого другая кровь. Можно, конечно, но крови будет много, и проще вырастить свой.

Где меня поймали на почти-вранье

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

Вот вам и весь масштаб переиспользования на UI-слое: из пяти заявленных утилит выжила одна, и та крошечная. Если бы я поверил красивой цифре и начал планировать веб «на базе пяти готовых кусков», я бы потом неделю выяснял, почему ничего не стыкуется. Это, кстати, типичная ловушка вайбкодинга и разработки с ИИ в целом: агент с готовностью пишет «переиспользуем компоненты», а ты потом обнаруживаешь, что переиспользовать там нечего, кроме названия.

А вот где переиспользование реально сработало

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

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

Что я из этого вынес

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

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