Start herePart 3 of 4

Жизнь приложения, написанного за выходные

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

Жизнь приложения, написанного за выходные

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

Пятница, 18:42 — абзац вместо спецификации

Всё техзадание, ровно как было набрано:

Мы с 7 друзьями едем кататься на лыжах в феврале, и я устал от таблицы. Хочу приложение, где любой из группы может добавить расход, который он оплатил (ски-пассы, продукты, бензин, ужины), отметить, на кого он распространяется, и в любой момент увидеть сводку «кто кому должен», чтобы в конце мы могли рассчитаться с минимальным числом переводов. Всё в EUR. Должно хорошо работать на телефонах, потому что добавлять записи будем прямо на склонах.

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

18:46 — четыре минуты спустя возвращается план от архитектора. Шесть фич, одиннадцать подзадач:

# Фича
0 Каркас приложения и навигация — mobile-first, нижние вкладки
1 Поездка и участники — 8 друзей, настраиваемые имена
2 Добавить расход — кто оплатил, за что, сумма, на кого распространяется
3 Лента расходов и балансы
4 Расчёт — минимум переводов, чтобы обнулить все балансы
5 Доводка и проверка — засеять демо-данные, протестировать математику от и до

Все три неявных требования вошли в план, плюс одно, о котором никто не просил: протестировать математику от и до. План — это контракт, а не вайб: каждая подзадача объявляет файлы, которые создаст, и критерии приёмки, по которым её будут судить. Судить объективно: компиляторами и пробами, а не моделью, которая оценивает сама себя.

18:52 — план утверждён одним словом («да»).

18:52:15 — инфраструктура появляется раньше первой строчки кода

Через шесть секунд после утверждения, ещё до того как агент что-либо написал, у проекта есть: собственный namespace в Kubernetes с квотами, собственная ветка PostgreSQL (копирование при записи, мгновенная, с масштабированием до нуля), скаффолд React + tRPC и схема базы данных из плана. Provisioning — это детерминированный код платформы, а не работа агента: агент здесь — наименее доверенный компонент, и ему выдают меблированную комнату, а не ящик с инструментами рядом с дата-центром.

18:52 → 21:11 — сборка, как всё было на самом деле

Вот что агент на самом деле делает со своим бюджетом, согласно журналу инструментов этого запуска:

Что Доля шагов
Написание кода ~24%
Проверка — проверки типов, живые контрактные пробы, прогоны тестов внутри пода, headless-браузинг ~27%
Чтение контекста ~29%
Ведение плана (которое заодно и запускает проверку) ~15%
Прямые SQL-проверки против собственной базы данных ~4%

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

Обрезанный файл перехватили на проверке. На шаге наполнения данными агент однажды выдал db/seed.ts длиной 176 символов — сбой модели, который «успешно прошёл» бы как запись файла. Контроль на выдаче файла отбраковал его как вырожденный; повтор записал настоящий файл. Работа платформы — следить за тем, чтобы плохой день модели не скомпилировался в продукт.

Подзадача честно провалилась. Страница управления участниками сожгла три шага, не записав ни одного из объявленных файлов, и scope-gate отказался её засчитывать: статус failing, доказательство — «completed 3 steps without writing any of its declared files». Никакого ложного зелёного. На следующем проходе анти-спиральный толчок выбил агента из диагностической петли на шаге 11 — и страница приземлилась: пять файлов, тесты зелёные.

Математику проверили в SQL. В плане было сказано протестировать расчёт от и до, поэтому агент засеял восемь участников и дюжину расходов, а затем прогнал запросы WITH balances AS (...) напрямую против своей ветки, чтобы убедиться, что план переводов обнуляет каждый баланс — после чего пропатчил собственный набор тестов там, где они расходились. Приложение поставляется вместе с этим набором тестов; оно родилось тестируемым.

Ещё один честный момент: на полпути по плану первый запуск упёрся в бюджет по шагам. Бюджет — это предохранитель, а не обещание, что каждый план уместится в один проход — поэтому запуск отложил пять проверенных подзадач, закоммитил их и встал на паузу в 19:53, прямо об этом сообщив. Затем он ждал — не вычисляя, не выставляя счёт, не притворяясь, что работает — 35 минут, пока в 20:28 не забрёл человек и не набрал «continue». Второй запуск подхватил цепочку там, где журнал зафиксировал остановку, пропустил всё уже проверенное и доделал оставшиеся шесть. (Он также повторил страницу, которая провалилась — там и случилось анти-спиральное спасение, описанное выше.)

21:11 — готово. Одиннадцать из одиннадцати подзадач прошли. Часы на стене показывают 2 ч 19 мин от утверждения до готовности, но полчаса из этого платформа просто ждала, замороженная посреди плана, пока человек не вернётся с ужина. Фактическое рабочее время агента — около 1 ч 45 мин. Релизный коммит привязан к точной позиции в логе базы данных (bdc2258 @ LSN 0/21933A8), что звучит как мелочь, пока вам не понадобится, чтобы код и данные путешествовали во времени вместе.

Вот это приложение, в продакшене, сфотографированное тем же headless-браузером Chromium, который платформа использует для собственных runtime-проверок:

Ski Trip 2025 — mobile home screen: total spend €2,561.10, 11 expenses, per-person balance, recent expenses list, bottom tab navigation Settle Up screen — who owes who with the fewest payments: 8 members' balances and a plan of 7 transfers moving €1,076.33

Экран расчёта — это та самая недоописанная пятничная фраза, доведённая до продукта: «кто кому должен… с минимальным числом переводов» превратилось в восемь балансов и план из 7 переводов — минимум для восьми человек, поскольку любой граф расчётов требует не более n−1 рёбер. А если присмотреться к отрицательным суммам, то прямо в кадре уже видна следующая итерация: удвоенный знак минус. Баг-репорт во вторник будет одним предложением, как и прошлый.

21:28 — первый баг находит человек

Тыкая в превью: два странных участника с именем «x», у которых есть балансы, и нет никакой возможности их удалить. Сообщено так, как человек реально сообщает о таком:

I see some strange users x which have a non zero balance but I don't see any expenses associated to them. And I can't delete them.

Диагноз — это история про автоматический QA: во время runtime-верификации headless-браузер агента вводил данные в настоящую форму добавления участника, и тестовые участники там застряли. Их удаление вскрыло реальный пробел в дизайне — участники, на которых ссылаются разбивки расходов, были защищены внешним ключом, а у интерфейса не было ответа.

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

Это и есть тот цикл итераций, вокруг которого построена платформа: баг приходит как предложение, фикс приходит как проверенный коммит, а человек на склонах так и не увидел ни одного стек-трейса.

23:00 — во сколько обходится готовое приложение выходного дня

Счёт за вечер, из таблиц учёта:

  • Сборка: ~4,8 млн токенов через кодовую модель за два запуска и итерацию с фиксом — примерно $3,50 чистой стоимости модели за фулстек-приложение с тестами и засеянными данными.
  • Простой: через 148 секунд после последнего keepalive платформа заморозила контейнер приложения на уровне cgroup — это самое приложение, из этой самой истории, в свой первый тихий вечер освободило 201 МБ RAM в своп. Его compute базы данных масштабировался до нуля отдельно. Простаивающая идея выходного дня по умолчанию стоит фактически ноль, сколь угодно долго.

Таблица умерла в 18:42. К ужину было приложение с проверенной математикой, собственной веткой базы данных, набором тестов и нулевой стоимостью простоя — и никому из участников поездки не нужно знать, что такое LSN.

Чего превью пока не обещает

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

Это вторая часть истории этого приложения. Механизмы уже описаны в Акте 2 — просто это приложение их ещё не прожило. Проживёт к воскресенью.

Создавай на той самой платформе, о которой эти посты.

Опиши своё приложение простыми словами — Adorable напишет код, настроит базу данных и выкатит его в онлайн.

Начать бесплатно