В статье “What Is Code?” Unmesh Joshi разводит две роли кода.
Код — это инструкции для машины. Производить такие инструкции становится дешевле: языковые модели всё лучше справляются с генерацией исполняемого кода. Но код — это ещё и концептуальная модель: словарь, имена, границы, отношения, абстракции и инварианты, через которые люди понимают систему.
С приходом LLM вторая роль становится не менее, а более важной. Хорошая кодовая база даёт модели устойчивые понятия, на которые можно опереться. Чёткие имена, выверенные границы, тесты, типы и инварианты становятся частью контекста. Они задают рамку, внутри которой модель работает.
Из этого следует важное следствие второго порядка:
Раньше технический долг был трением. Теперь он стал промптом.
До LLM плохая архитектура вредила в основном тем, что замедляла людей. Запутанный код делал каждое изменение дороже. Разработчикам приходилось больше читать, держать в голове больше случайной сложности, чаще задавать вопросы, обходить старые компромиссы. Технический долг был налогом на будущие изменения.
Это и сейчас правда. Но это уже не вся правда.
Технический долг и раньше умел воспроизводить сам себя — через человеческие привычки и локальный прецедент. Разработчик копирует то, что лежит рядом. Новый код повторяет старый. Плохие решения расходятся по примеру. LLM не создают эту динамику — они её ускоряют. То, что раньше распространялось со скоростью человеческого внимания, теперь распространяется со скоростью генерации.
В разработке с LLM существующая кодовая база — это уже не только объект изменений. Это ещё и набор сигналов: имена, модули, интерфейсы, тесты, паттерны вызовов, локальные соглашения — всё это подсказывает модели, какой код здесь уместен.
В здоровой кодовой базе это работает на пользу. Код сужает пространство поиска. Учит модель локальному словарю. Делает одни варианты вероятнее, другие — менее вероятными.
Но обратное тоже верно.
В деградировавшей кодовой базе модель не видит в техническом долге долг. Она видит примеры. Видит прецедент. Видит стиль, который надо продолжать.
Размытая граница становится паттерном.
Имя, вводящее в заблуждение, становится словарём.
Фальшивая абстракция становится архитектурой.
Отсутствующий инвариант становится разрешением.
Обычный технический долг — это проблема стоимости изменений. Он замедляет работу. Генеративный технический долг — это ещё и проблема распределения вероятностей: он меняет то, какой код будет написан следующим.
Вот где появляется мультипликатор. Плохая структура портит контекст. Испорченный контекст ведёт к худшему сгенерированному коду. Этот код ещё сильнее портит структуру. Система начинает воспроизводить собственную путаницу.
Это родственно когнитивному долгу, но не тождественно ему. Когнитивный долг накапливается, когда команда пользуется абстракциями, которые перестала понимать. Генеративный долг накапливается, когда в кодовой базе живут спутанные понятия, которые модель склонна продолжать использовать.
Когнитивный долг — про то, что команда больше не понимает. Генеративный долг — про то, что модель теперь склонна воспроизводить.
Если код — это контекст, то архитектура становится способом направлять модель. И это меняет ценность рефакторинга.
Рефакторинг, который проясняет доменное понятие, помогает не только следующему человеку, читающему код. Он улучшает кодовую базу как промпт. Тест, в который зашит инвариант, не просто ловит регрессии. Он учит модель тому, что нарушать нельзя. Точно названная граница меняет то, что будущий сгенерированный код посчитает само собой разумеющимся.
Раньше плохая архитектура делала следующее изменение тяжелее. Теперь она ещё и учит машину делать следующее изменение неправильно — тем же самым способом.
Comments