- BrainTools - https://www.braintools.ru -

От микроменеджмента до автопилота: 4 стадии рефакторинга AI-кода на примере десктопного приложения

От микроменеджмента до автопилота: 4 стадии рефакторинга AI-кода на примере десктопного приложения - 1

Реддит и Хабр забиты историями о том, как кто-то «написал приложение за вечер с помощью ChatGPT, вообще не зная программирования». Маркетологи называют это вайбкодингом — ты просто описываешь свои намерения, а ИИ выдает готовый продукт.

Я проверил, и вот мой спойлер: на масштабе чуть большем, чем программа на 500 строк, это не работает.

Август 2025 года. Мне понадобилась утилита со сложной логикой [1]: конвертер выгрузок Telegram (JSON) в чистый текст для LLM. Проект десктопный, с GUI, графиками и парсингом. Вместо того чтобы писать код руками, я провел эксперимент: стать техлидом для связки актуальных на тот момент моделей (Claude 4.0 + Gemini 2.5 + Cursor).

Я заранее дал им архитектуру. Они собрали первый MVP. А затем, чтобы этот «MVP» (нет) не сложился как карточный домик через неделю, мне пришлось четырежды инициировать глобальный рефакторинг, потратить 40 часов на борьбу с галлюцинациями вокруг Matplotlib и разгребать цикличные зависимости.

Эта статья — рефлексия и разбор полётов. Это история о том, почему в 2026 году главный навык инженера — это умение видеть деревья за лесом и вовремя сказать ИИ: «Нет, твоя архитектура никуда не годится, всё переделываем».

Архитектура на бумаге и монолит в реальности

Разработку я начал не с main.py [2]. Я скопировал структуру папок из своего старого проекта и попросил Claude: «Сделай так же, но реализуй полноценный Dependency Injection».

Нейросеть сгенерировала красивую файловую структуру. На бумаге всё выглядело как по учебнику: папки core/, presenters/, ui/, services/. Но при попытке добавить первую сложную фичу вылезла реальность — структурная связность была ужасающей.

  1. Иллюзия разделения слоев: Файлы main_window.py (логика окна) и main_window_ui.py (вёрстка) импортировали друг друга и наследовались друг от друга. Разделить их было невероятно трудной задачей — они срослись на большинстве уровней, полностью завися друг от друга, действуя как единый скрипт.

  2. Презентер-маршрутка: В MainPresenter нейросеть запихнула вообще всё: от логики чтения JSON до обработки кликов по координатам графика. Это был самый настоящий God Object, который по какой-то нелепой причине был назван презентером.

  3. DI для галочки: Контейнер внедрения зависимостей существовал, но 80% сервисов всё равно создавались через прямое new Service(). ИИ не прокидывал их через конструкторы, он ни капли не заботился о долгосрочной поддержке всего этого ужаса.

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

мем с FFMPEG/Left-pad, но в роли tkonverter presenter.py и изображает архитектуру аппы

Ловушка паттернов: почему ИИ смешивает бизнес-логику и UI

Самые большие провалы случились с наиболее «кастомными» задумками приложения. Мне нужен был интерактивный график статистики сообщений в стиле KDE Filelight. Я дал Gemini референсный код этого проекта на C++ и попросил по духу адаптировать идею для Python с моими хотелками.

Оригинальный KDE Filelight

Оригинальный KDE Filelight

Ошибка [4] №1: Выбор инструмента
И вот тут Gemini подложила мне свинью. Я спрашиваю: на чём рисовать будем? Она: «Matplotlib, так как там проще всего реализовать предложенную задумку». И я поверил… А это, оказывается, библиотека для учёных, а не для GUI (отсюда и тормоза в отрисовке), и даже когда я это осознал, то не хотел её выбрасывать, веря, что «ещё чуть-чуть — и мы сможем оптимизировать отрисовку графика». Мы потратили 40 часов, пытаясь заставить этот научный [5] комбайн работать в десктопном приложении.

Мини галерея баганных иттераций графа

Мини-галерея багованных итераций графа

Ошибка №2: Отсутствие доменной модели
Чтобы синхронизировать клики по графику и календарь экспорта, ИИ привязал бизнес-логику (какие сообщения пойдут в итоговый текстовый файл) к визуальной структуре UI-дерева графика (год/месяц/день как визуальные узлы) самым топорным способом из возможных.

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

Решение:

Мы потратили 40 часов на попытки заставить Matplotlib работать быстро и без багов: выстрадали логику соотнесения координат кликов курсора с визуальными сегментами, исправили рассинхрон стейтов, создали логику оптимизации количества сегментов для отрисовки. Но когда тормоза интерфейса стало слишком сложно игнорировать, мой внутренний перфекционизм пересилил страх [6] перед сменой библиотеки. За пару часов мы портировали отрисовку на нативный QGraphicsScene.

финальный вид графа

Финальный вид графа

Отдельно с ИИ мы переписали логику дат: вместо практически визуального «что экспортировать» появился явный набор выбранных дат (Set[QDate]), и бизнес-логика стала опираться на него же, а бонусом сам график превратился в тупую view, которая просто рисует этот набор.

Дизайн в итерациях и провал мультиагентных систем

О дизайне интерфейса

Claude сделал неплохой стартовый набросок UI, но он выглядел, мягко говоря, криво — как проект студента первого курса IT. Это не мой уровень ожиданий.

первая верстка окна программы

Первая верстка окна программы

Процесс доработки выглядел как диалог с очень быстрым, но безынициативным верстальщиком. Утрированный пример как это происходило:

  • Я: «Сделай три колонки».

  • ИИ: (Делает).

  • Я: «Превью снизу неудобно, перенеси наверх-справа, добавь разделитель».

  • ИИ: (Делает + ломает сигналы от свичей).

  • Я: «Markdown отрисовывается некрасиво стандартной библиотекой. Давай лучше заменим на HTML-рендеринг с кастомным CSS».

финальная верстка окна программы

Финальная верстка окна программы

Вывод: ИИ не придумает UX. Он сделает ровно тот минимум, который вы попросите. Чтобы получить современный интерфейс, мне пришлось итеративно «лепить» его словами и в процессе постигать дзен отладки, когда из-за быстрого прототипирования код регулярно и вполне закономерно ломался.

Про мультиагентов (Cursor)

На волне хайпа я попробовал запустить режим мультиагентов (это было ещё до финального рефакторинга, чтобы провести «стресс-тест»). У меня была конфигурация: один агент правит UI, второй работает по бизнес-логике, третий разрабатывает план дистрибуции под Flatpak и Windows.

Мой вердикт: для пет-проектов с плавающей архитектурой это полностью не работает.
После быстрого мерджа изменений от всех трёх агентов я смотрел на проект и совершенно не понимал: кто из них не справился, а кто выполнил работу только на 20%? Ты пишешь большое ТЗ на две страницы, агенты активно шуршат, а по итогу открываешь, смотришь: «да вроде всё осталось как было, UI тот же, но отпали иконки у кнопок и сломался парсер».

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

мем три человека паука

Четыре стадии рефакторинга: от микроменеджмента к автопилоту

Главный миф AI-кодинга: код пишется один раз. Реальность: рефакторинг с ИИ — это непрерывный процесс, где ваша роль эволюционирует по мере «взросления» кодовой базы.

За несколько месяцев я провёл четыре глобальных перестройки.

инфографика дорога между адейтами

Стадия 1: Ручное управление (Микроменеджмент)
Прототип работал, но внутри был упомянутый монолит. Я дал команду: «Разбей MainPresenter, раздели ответственность».

Мои ожидания: ИИ заменит 10 файлов, и всё будет работать, я наконец добавлю фичу, о которой думал последний час.
Реальность: 4+ критические ошибки при первом же запуске. Отвалились стили, перестали открываться диалоговые окна, сломалась асинхронщина. Повторные генерации с прошлого сохранения показали ровно тот же результат… Мне пришлось вручную ревьюить каждое изменение, собирать трейсы ошибок и мелкими шажками, на пару с агентом, всё это чинить. Процесс занял несколько дней, а добавление новых фичей постоянно откладывалось, что раздражало ещё больше, чем бесконечный процесс рефакторинга. На данном этапе ИИ требовал полного личного внимания [7].

Стадия 2: Изоляция компонентов
Второй раз был сфокусирован на выносе сложных кусков, таких как календарь и настройки, в композитные виджеты. Опыт [8] первого рефакторинга помог: я уже знал, где ИИ, скорее всего, схалтурит по глупости и каким образом сломает логику. За счёт этих знаний мы делали меньше итераций и двигались быстрее.

Стадия 3: Разделение слоев (Роль Архитектора)
На третий раз мы перешли к вычищению UI. База уже была в разы лучше, и я наконец мог давать высокоуровневые команды: «Вынеси всю логику парсинга Telegram JSON в отдельный слой Core. UI должен стать тупым и только дергать методы».
Количество циклов «правка–поломка–починка» ещё резче сократилось.

Стадия 4: Автономия (Роль Заказчика)
К четвертому рефакторингу база стала чистой. Я поставил задачу: «Закончи DI. Убери все костыли, убедись, что слои независимы».
И тут случилось неожиданное. Агент начал находить неочевидные баги сам. Тир-лист достижений:

  1. Нашел само-инъекции (где DI-контейнер внедрял зависимости внутрь самого себя).

  2. Выявил «дыры» в инкапсуляции, где слои обращались друг к другу напрямую.

  3. Обнаружил классические гонки данных при быстром клике по UI и сам предложил решение с мьютексами и очередями событий.

Результат: ядро приложения стало настолько независимым, что я смог запустить конвертер в режиме CLI, вообще без импорта PyQt (без графической библиотеки).

От микроменеджмента до автопилота: 4 стадии рефакторинга AI-кода на примере десктопного приложения - 10

Мои выводы: новая реальность разработки

Разработка с помощью LLM — это не генерация кода. Это итеративное управление качеством и техническим долгом, который генерируется со сверхзвуковой скоростью.

  1. Критическое мышление [9] остается на вас. ИИ всегда предложит самое популярное, но не всегда самое верное решение (Matplotlib). Ваша задача — сказать «нет» и спроектировать правильную модель.

  2. Рефакторинг первичен. Сразу после прототипирования с той же ллм нужно действовать максимально внимательно и вручную контролировать первые изменения. И только когда каркас выстроен, нейросети можно доверять задачи «под ключ».

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

Простейший пример: я прошу сделать так, чтобы приложение запоминало свой размер и позицию на экране. ИИ честно пишет код. Из-за асинхронщины и состояния гонки в 5+ местах (непонятно, какой именно сервис закроет окно последним и чьи данные верны) стейт не сохраняется. Что делает ИИ? Вместо того чтобы сказать: «Чувак, у тебя тут гонка данных, если мы не починим архитектуру закрытия, мы никогда не сможем сделать это по Clean Code», он тратит 20$ контекста на то, чтобы написать гениальную внешнюю систему перехвата этих значений перед смертью процесса.

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

все окна проги в финальном виде

Во второй части: как я парсил 100-мегабайтные JSON из Telegram, боролся с лимитами контекста LLM и почему пришлось написать свой UI-тулкит.

Код: GitHub [10]

© 2026 ООО «МТ ФИНАНС»

Автор: Realife

Источник [11]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/26236

URLs in this post:

[1] логикой: http://www.braintools.ru/article/7640

[2] main.py: http://main.py

[3] Более интересная инфографика от Claude: https://mermaid.live/view#pako:eNqdWOtu3MYVfpUpgRQ2spJlSZblRWrAUYvCQJU6sJwArQqC2h2tWHNJguRavgKyFLVOpFi-NXYdAzJap3aKtFV0sTeytH6F4Sv4BepH6LkMueSSuw2iH6udM-fMnOt3zuw1o-bVpVE13ntP_CL9E-rv8ZLqqG21pw7jdTFaFWpX7cXLaku9jtfVodqKNwR8LMWrqg3kPbUfL8crILSVOWbWnXe8xdqCFURi5sNZV8Bf2JprBJa_IKQbBVd-P2u823y8JNTfVCf-s9oHcbUNZ3bguq1Z4w8sg39Ny3aJ-_5n9H3Yv_LBXHDs9LvNZ_8R6hUodqja6gD-g5rxTVSvLULfscKFCn4lJQ_g4B8qJAckWOyDVEcdiLdLD4R6A-q30eZ4Wfzaq4vfzv1R1qJUC-nWZ90eIyzfZ6X-IT4-4_uOXbMi23NzmrMSwPb2yQtxnhbna4GUeS7btSNz0QsuygBZN3bEWaDYlmNfpSM_pS1S_QiZuwPOX4Fv6LPIuyhd-6oMjmqf3FkHg-MN9TK-CwFbUz-wi95AiG6qffTxGli-BwsIMCzBeAjAMnqEfQFfcuot2m7dWyRb_7kpZi567iUZRDKYhlB8SnsD_dSySfSrb_7b3hAXzoojn9hykZV9-_gpEpGASh5yBEEDMQ2Z6QiiQGjAmgNQ_zbrd0jJtxLfQgMganti-pNzPytR2dRX334hLthmmeLs0-GWfTQnHi3IpiTR9VtiBhfTlms1dAzebT76i1AvMV_iu6juASjyUu3GK5SdmHHnAhlCkssgH-ea55rNRsD-OEDTzwJJn51PnMR7dUgDrxGSyL3vhHoA10IhQpB2VJvVTy8TFMd9cM4apLL2ZTteFRDrLZ3p8PU1qLtDuUNRfw0Vs0x5kh6U9wYF9rLvBZFZdxqc88_Er4jyS1KvwB7KKLLdRpgKPHguzmtaHxFwgnMltLsi978QZzStj0jNciDhrKArsiqmNK2PCLvTnGvZTl1yIDYeYiCY_0Om58QopwtxWbTrDRlxXJ5_K9Q9iMsuZAEi0FrRuMhr2jUs7sdf4228roq5VhR5blgRju1KU9btiBEqXLSjGoBXYNVtryLCWuA5zpwV6F3fdl0ZVERkN6WZihZuXZCOLwPW8at1vFdTquKCC2ai5DnI2KifxWXl7CdJwqX17wwglGd9yT4Ha62bcEldQUquEBZvQQK_hrLHFM7AN7aibv5DTiOUPxLqe6C-YlQbSooDMhxEBkJTzQskBeWv6JwpWIkjjDzvi8wxW0fLa7OJrJwBT4V6Qp1rD5tkIRJT5IIQsHw6lYG-0UNOmtqDPBiq7_HjTfwnUKZDdO7D2LymfzPE0K2xEJAe1-DBvYISSQFqvGFI6fSSGVM-TqhJV3n0HULJTewVdP0rCFSm20IbycAQrbO4WUyvEnfWUm8wZHwm1GMyGNvyEg4g6IJ4gzXESQEHFWgDHZpQKN4HpOArYOMZBkeDjni3effLIqYhWJt4KcPAv7oEyla-piGh0qxImtC8YTeSl6PiSSCDG3TOw2XOpcSWKd5LYvtigBu30ZJtbMyM2ZCB8QZ8Je5daoO7RSvChjnfjGjG-ByvbsowBJ-b817QtKLeatTqXjJbke0wNHxNTZjWbLMfeDU4hIw1I49Np9rbQnQr2p-GML0zzPhCPaNIHZD0MsWyiJDcNYJLdk0m5nBVpsS-5pAXAAAtLZj0Vk0bKJecDhZw0n2bkKoapCvgrqbvyMsD7k2k799mQlX4gNcA67Z7yYOzNGzbeI5JHBXRsJqy2GazvaZfnSSdkhWGurzDoIDlXziRxkOTRK7qmn8OmI3UM5qYVPh2MieUZWifjIZS72ZTMmC0Mw8FWG5D3iKedWjQKIJjBAOx6QIA8sS1I2aA8BGsf3xTAujxWgEkLYfhplBPsRfgqwQ-1-gRsAK510YvYQ5rm9fvwO2WGzo0Z4c8OB8iK1ckz8VQkvFtmu_IwFVwEtgi7OOT-Tk-exTbcqer2bHsbk7Mt6IFrfiXXIbHiMTFmBxgIi1feumW41nJNHP_G31Ez2ZZH4R3X_njy03gUQwNndaPmB4ijcg9NJ66dWhIiMiZ5w3vZQhiaHjo9PW3T1bFPFDDBVm_TudlVKTXwQdwTrfB4Io6JjPxvRkVYPAv7PT02sJ-2Rjj9plfCtb24ym9tB9zTyMezJzxfz-W7sw-mC87rA_mzM7ogzmzo3kmljxc4X7qGPHz9Fhm6_EZHZd25v4seaDrZiaJsU6MW2VbuonqLV5o36QtqbiZNh2d8l3enCyglJZN-DPS3c1eXTWo8m7euqI55fv_74gUebOIcI_m6Fv6aU2_HWxTR8CfWAjDVbtPGKiW-U1fPrFeZ4zEnpzMCM8e5mgMemdakTdT-GHjUeaHDf4VqkS5eB0HKcbwJcB9LrwE_TIFn8NjN332_4RSLByUj2VxvzdTSk7IpFlxV4e-NMxpWhWTJJOQJQWRuXFApegto2I0ArtuVKOgJSsGRA7YYGlcQ6FZg-HJqMLXupy3Wg68TmfdGyDmW-7vPK-ZSAZeq7FgVOctJ4RVy6_DrA1vcWjrXRaJj9Upr-VGRvUEnWBUrxmXjerQxMTI8MmJ8ROTJ8dHRsfGxyYrxhUgj58aGT4xenLi-OT4yOToyNjxGxXjKl06Njw6OXpq4sT4yKnJ8bGxkVGQwLezF0zzb6H0k-iN_wENKLoo

[4] Ошибка: http://www.braintools.ru/article/4192

[5] научный: http://www.braintools.ru/article/7634

[6] страх: http://www.braintools.ru/article/6134

[7] внимания: http://www.braintools.ru/article/7595

[8] Опыт: http://www.braintools.ru/article/6952

[9] мышление: http://www.braintools.ru/thinking

[10] GitHub: https://github.com/Loganavter/Tkonverter

[11] Источник: https://habr.com/ru/companies/ruvds/articles/1002598/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1002598

www.BrainTools.ru

Rambler's Top100