Конспект лекции
Importance of Software Fundamentals and Code Quality
Importance of Software Fundamentals and Code Quality
Проблема подхода «от спецификации к коду» (Specs to Code)
Отступление от темы
Приветствую всех. У вас получается отличная конференция? Хорошо. Прекрасно. У меня есть послание для вас, которое, я надеюсь, станет утешением для тех, кто считает, что их набор навыков больше ничего не стоит в эту новую эпоху. Моё убеждение заключается в том, что фундаментальные основы программной инженерии сейчас важны как никогда ранее. Я преподаватель, и недавно я вел курс под названием «Claude Code для инженеров» — звучит довольно провокационно. И в процессе работы над этим курсом мне пришлось составить учебную программу по AI-программированию, что само по себе является своего рода кошмаром, потому что всё постоянно меняется, верно?
Существует распространенное мнение, что AI — это новая парадигма, и нам нужно отбросить все старые правила, чтобы освободить место для нового. На этой волне возникло целое движение, которое можно назвать «specs to code» (от спецификации к коду).
Суть подхода «specs to code» заключается в следующем: вы пишете спецификацию того, как должно работать приложение, а затем используете AI, чтобы превратить эту спецификацию в готовый программный код. Если в работе приложения обнаруживается проблема, вы не лезете исправлять сам код. Вместо этого вы возвращаетесь к спецификации, вносите в неё изменения, снова запускаете компилятор и получаете обновленный код.
Однако на практике этот процесс часто приводит к деградации качества продукта. При попытке следовать этому подходу, цикл итераций выглядит так:
- На основе спецификаций получается первичный код.
- При внесении правок и повторном запуске получается код хуже качеством.
- Следующая итерация дает еще более плохой код.
- В конечном итоге, после нескольких циклов запуска компилятора, на выходе получается «мусор» (garbage).
Таким образом, идея о том, что мы можем просто игнорировать код и позволить ему управлять самим собой, по сути, является лишь другой формой «vibe coding» (программирования «на ощущениях»). Этот подход не работает, так как попытки абстрагироваться от самого программного кода и полагаться исключительно на автоматическую генерацию по спецификациям приводит к потере контроля над качеством системы.
Роль фундаментальных основ разработки в эпоху ИИ
Для того чтобы понять, как улучшить работу LLM и не допустить генерации некачественного кода, необходимо обратиться к фундаментальным основам разработки. Понимание того, что именно делает код «плохим», прописано в таких классических работах, как «A Philosophy of Software Design» Джона Остерхаута.
В этой книге дается определение сложности (complexity): это все, что связано со структурой программной системы и делает ее трудной для понимания и модификации. Иными словами, плохая кодовая база — это та, которую сложно изменить. Если вы не можете внести изменения в систему, не провоцируя появление новых ошибок, значит, у вас плохая кодовая база. Хорошая же кодовая база, напротив, легко поддается изменениям.
Еще один важный фундаментальный концепт описан в книге «The Pragmatic Programmer» Дэвида Томаса и Эндрю Ханта — это программная энтропия (software entropy). Энтропия отражает идею о том, что вещи со временем стремятся к беспорядку, отдаляются друг от друга и разрушаются. Именно так ведут себя большинство программных систем: каждый раз, когда вы вносите изменения в код, думая только об этих локальных правках, а не о дизайне системы в целом, кодовая база неизбежно становится все хуже и хуже. Использование ИИ для генерации кода по спецификациям без учета этих принципов приводит к тому, что вы просто раз за разом «прогоняете компилятор», создавая при этом все более деградирующий код.
Отступление от темы
Лектор делает паузу, чтобы обратиться к аудитории: «Поднимите руку, если вы слышали фразу о том, что код — это дешево». После этого он продолжает основной тезис лекции.
Существует расхожее мнение, движущее движением «от спецификаций к коду», что «код — это дешево». Однако это утверждение неверно. На самом деле код не является дешевым; напротив, плохой код сегодня стоит дороже, чем когда-либо. Если у вас есть кодовая база, которую сложно изменять, вы не способны воспользоваться всеми преимуществами, которые может предложить ИИ. В хорошей кодовой базе ИИ работает крайне эффективно. Исходя из этого, хорошие кодовые базы важны как никогда, а значит, фундаментальные основы разработки имеют значение больше, чем когда-либо. Это и есть главный тезис данной лекции.
Establishing Shared Understanding and Ubiquitous Language
Устранение расхождений в понимании задачи: Метод опроса «Grill Me»
Одной из проблем, с которой можно столкнуться при работе с ИИ, является ситуация, когда «ИИ не сделал того, что я хотел». Лектор поясняет, что в основе этой проблемы лежит фундаментальная сложность: никто на самом деле не знает точно, чего он хочет. Взаимодействие с ИИ — это всегда процесс коммуникации, в ходе которого нейросеть пытается «выяснить», что именно вам нужно.
Для объяснения этого явления лектор обращается к книге Фредерика П. Брукса «The Design of Design». Когда два или более человека проектируют что-то вместе, между ними существует эфемерная, невидимая идея того, что именно они создают. Это называется Design Concept (концепция дизайна). Это не какой-то актив или файл в формате markdown, а невидимая теоретическая модель создаваемого объекта. Проблема заключается в том, что у пользователя и ИИ зачастую отсутствует общее понимание концепции дизайна.
Отступление от темы
Лектор кратко упоминает, что если вернуться к изучению хороших практик разработки программного обеспечения, можно найти много полезных решений для актуальных проблем с ИИ.
Чтобы решить эту проблему, лектор разработал простой навык (скилл), который называется /grill-me. Его суть заключается в следующем: «Интервьюируй меня безжалостно по каждому аспекту этого плана, пока мы не достигнем общего понимания. Пройди по каждой ветке дизайн-дерева (термин также взят из работы Фредерика П. Брукса), разрешая зависимости между решениями одно за другим».
Данный инструмент оказался очень популярным, получив более 13 000 звезд на GitHub. При использовании метода /grill-me ИИ может задать пользователю от 40 до 60, а иногда и более 100 вопросов, прежде чем стороны придут к общему пониманию.
Итогом этой беседы может стать создание полноценного плана разработки продукта. Более того, при необходимости небольшие изменения можно сразу трансформировать в список задач (issues), которые затем передаются в работу. Этот процесс лектор называет переходом в «режим плана» (Plan Mode). Лектор отмечает, что стандартный «режим планирования», который обычно используется перед написанием кода, часто бывает слишком поспешным: ИИ сразу пытается составить план и приступить к работе. Поэтому, по мнению лектора, гораздо эффективнее сначала достичь общего понимания через метод «безжалостного интервью».
Таким образом, первым важным советом является: «Перед тем как писать код, достигните общего дизайн-концепта».
Преодоление контекстных барьеров: Использование принципов DDD и единого языка
Второй режим отказа (Failure Mode #2) заключается в том, что искусственный интеллект слишком многословен (The AI is way too verbose). Разберем этот режим отказа подробнее. Проблема возникает тогда, когда искусственный интеллект начинает понимать техническую сторону своей работы, но при этом совершенно не понимает саму предметную область (домен).
По моему опыту, если вы долгое время работали разработчиком и сотрудничали с экспертом предметной области (domain expert) — человеком, который создает бизнес-требования или проектирует систему и хочет, чтобы вы построили для него определенное решение, — вам необходимо выработать некий общий язык взаимодействия. Если эксперты используют термины, которые вы не понимаете, вы будете испытывать трудности с их переносом в код, что неизбежно приведет к ошибкам в реализации. Таким образом, между разработчиком и экспертом предметной области всегда существует коммуникационный барьер.
Для преодоления этого барьера отлично подходит концепция предметно-ориентированного проектирования (Domain-Driven Design или DDD).
Отступление от темы
Я сам все еще нахожусь на пути изучения DDD, но абсолютно все, что я читаю об этой методологии, очень сильно откликается в моем личном опыте. Мне действительно нравится этот подход.
Одним из ключевых понятий в Domain-Driven Design является единый язык (ubiquitous language). Эрик Эванс в своей книге «Domain-Driven Design» дает следующее определение: «Благодаря единому языку (ubiquitous language) разговоры между разработчиками и выражения в коде основываются на одной и той же модели предметной области».
Суть единого языка заключается в создании и фиксации общего набора терминов, которые используете и вы, и искусственный интеллект. Вы фокусируетесь на этих конкретных терминах, четко определяете их значение и используете их постоянно: в коде, при обсуждении кода, при общении с бизнес-экспертами и, в данном случае, при взаимодействии с искусственным интеллектом.
Для реализации этого подхода на практике можно создать в проекте специальную папку /ubiquitous-language или отдельный файл UBIQUITOUS_LANGUAGE.md. Процесс выглядит следующим образом: вы сканируете свою кодовую базу, анализируете предметную область и создаете файл глоссария, в котором простым человеческим языком даете определения всем ключевым терминам и понятиям.
Затем этот файл передается искусственному интеллекту в качестве контекста. Вы также можете держать его открытым для себя. Я постоянно держу этот файл открытым, когда пишу промпты для ИИ или занимаюсь проектированием архитектуры.
Анализируя ход рассуждений искусственного интеллекта, я заметил, что такой подход не просто улучшает качество планирования. Он заставляет ИИ рассуждать гораздо более чисто и структурированно. В результате итоговая техническая реализация становится гораздо ближе к тому, что вы изначально планировали. Это действительно отличный рабочий прием.
Таким образом, второй совет заключается в следующем: создавайте единый язык (ubiquitous language).
Fast Feedback Loops and Test-Driven Development (TDD)
Получение обратной связи при работе с ИИ
Представим ситуацию, когда вы наладили контакт с ИИ и точно знаете, что именно хотите создать. ИИ строит именно то, что вам нужно, но созданный им код не работает. Поднимите руки, если с вами это когда-либо случалось. Да, код действительно не работает.
В данном случае есть очевидный способ улучшить ситуацию — использовать петли обратной связи (feedback loops). Для этого можно применять следующие инструменты:
- Статическая типизация (Static Types). Если вы не используете TypeScript, это [неясный фрагмент].
- Доступ к браузеру (Browser Access). Если вы создаете веб-приложение и не даете ИИ-агенту возможность заглянуть в браузер и посмотреть на происходящее, он не сможет полноценно оценить результат работы.
- Автоматизированные тесты (Automated Tests). ИИ также обязательно нуждается в автоматических тестах.
Основная проблема, которую мы здесь наблюдаем, заключается в том, что ИИ не умеет правильно использовать эти каналы обратной связи. Он не извлекает из них столько же пользы, сколько извлек бы хороший разработчик-человек.
Ошибка №4: Слишком большой объем работы за один раз
ИИ склонен делать слишком много вещей одновременно (doing way too much at once). Он генерирует огромные объемы кода и только после этого спохватывается: «Ой, на самом деле мне, вероятно, следовало сначала проверить типы» или «Да, возможно, стоило запустить тест для этого фрагмента» или совершает иные подобные действия.
В книге «Программист-прагматик» (The Pragmatic Programmer) авторы Дэвид Томас (David Thomas) и Эндрю Хант (Andrew Hunt) называют такое поведение «ездой быстрее света собственных фар» (outrunning your headlights). По сути, это означает, что вы едете слишком быстро, хотя скорость получения обратной связи — это ваш ограничитель скорости. Это означает, что вы должны тестировать код непосредственно по мере его написания, совершая небольшие, обдуманные шаги. ИИ по умолчанию справляется с этим крайне плохо.
Разработка через тестирование (TDD) с использованием LLM
Третий навык — это TDD (разработка через тестирование). Вам следует использовать разработку через тестирование, потому что TDD заставляет LLM делать действительно маленькие шаги: сначала вы создаете тест, затем заставляете этот тест проходить, а после этого проводите рефакторинг кода, чтобы сделать его красивее и продумать архитектуру.
Проблема здесь заключается в том, что тестирование — это очень сложно. Тестирование всегда было сложной задачей для всех. Причина этого кроется в большом количестве различных решений, которые необходимо принимать при написании теста.
Вам необходимо решить:
- Насколько крупным должен быть юнит (unit)?
- Что именно нужно мокать (mock)?
- Какие варианты поведения (behaviors) тестировать в первую очередь?
Все эти решения взаимосвязаны. Если вы тестируете очень крупный юнит, например, все огромное приложение целиком, то тест может оказаться весьма нестабильным (flaky), и вы, возможно, не захотите тестировать так много вариантов поведения. Если же вы тестируете только этот конкретный юнит, вам необходимо замокать его. Все это тесно связано друг с другом.
Я думаю об этом на протяжении многих лет, всей своей карьеры в разработке. И мы замечаем следующее: хорошие кодовые базы (codebases) — это те кодовые базы, которые легко тестировать. Здесь мы возвращаемся к идее о том, что качество кода имеет огромное значение. Чем [лучше] ваши кодовые базы [неясный фрагмент, в оригинале Whisper выдал ошибочный текст на валлийском языке], потому что когда вы можете дать больше [контекста] для LLM, она генерирует отличный код.
Modular Architecture and Strategic System Design
Глубокие модули и понимание кода искусственным интеллектом
При обсуждении того, что делает кодовую базу качественной, необходимо обратиться к идеям Джона Остерхаута (John Ousterhout). Ключевая концепция заключается в использовании глубоких модулей (deep modules).
Глубокие модули — это такие модули, которые предоставляют много функциональности через простой интерфейс. В идеале следует стремиться к небольшому количеству таких модулей с простыми связями между ними. Они скрывают сложность внутри себя, и хотя при необходимости вы можете изучить их внутреннее устройство, в повседневной работе это не требуется — можно просто пользоваться интерфейсом.
Напротив, существуют поверхностные модули (shallow modules), которые обладают малым объемом функциональности, но имеют сложный интерфейс, по сути, «выставляя напоказ» свою сложность.
Когда кодовая база состоит из множества мелких и разрозненных фрагментов («блобов»), возникает проблема при работе с искусственным интеллектом. ИИ становится трудно ориентироваться в таком коде и «понимать» его. В результате возникают ситуации, когда ИИ не осознает, что именно делает ваш код. Он пытается генерировать или дополнять код, но из-за того, что структура не оптимизирована и фрагментирована, он не может вовремя получить доступ к нужному модулю, не понимает всех зависимостей или логических связей, что приводит к ошибкам.
Отступление от темы
Лектор в ходе объяснения делает паузы, упоминает необходимость сделать фотографию слайда, а также описывает свои действия с визуальными элементами презентации, переключаясь между схемами на экране.
Чтобы исправить эту ситуацию и превратить хаотичную структуру в упорядоченную, необходимо стремиться к архитектуре, где высокоуровневые вычисления и логика находятся «наверху». В такой системе вы сохраняете контроль над дизайном и качественным проектированием — это те аспекты, где человек должен принимать решения. А вот непосредственную реализацию (написание кода) можно делегировать искусственному интеллекту.
Процесс улучшения кодовой базы довольно сложен, но он состоит из набора последовательных и безопасных шагов. Необходимо искать возможности для рефакторинга: выявлять фрагменты кода, логически связанные между собой, и объединять их в единые глубокие модули. Это позволяет ИИ лучше «видеть» контекст и эффективнее работать с кодовой базой.
Управление сложностью, TDD и взаимодействие с ИИ
Когда код организован в виде тестируемых модулей, работа с ним становится более управляемой, так как границы вокруг этого кода четко определены и просты. Процесс выглядит следующим образом: вы пишете тесты для интерфейса, проверяете его работу через этот интерфейс, и на этом задача решена. Это и есть рабочий процесс в рамках TDD (Test-Driven Development).
Failure Mode #6: My Brain Hurts
Однако даже при работающих циклах обратной связи может возникнуть проблема, которую можно описать как Failure Mode #6: My Brain Hurts («Мой мозг кипит»). Бывает так, что информация поступает непрерывно, и вы способны выдавать больше кода, чем когда-либо прежде, но ваше восприятие за этим не поспевает.
Отступление от темы
Поднимите руку, если вы когда-либо в своей карьере разработчика чувствовали себя более перегруженными, чем сейчас. Да, я тоже, если честно.
Эта ситуация создаёт среду, в которой вашему сознанию становится всё труднее справляться с нагрузкой. Проблема в том, что и вам, и AI (искусственному интеллекту) необходимо удерживать весь объём этой информации в голове. Но предложенный подход с модульностью значительно упрощает чтение и понимание системы. Это позволяет сосредоточиться на понимании самих модулей или их границ, которые действительно важны.
Tip #5: Design the interface, delegate the implementation
В связи с этим крайне важен следующий совет — Design the interface, delegate the implementation («Проектируйте интерфейс, делегируйте реализацию»). Вы можете спроектировать интерфейс модуля, но при этом не погружаться глубоко в детали реализации и не тратить много времени на их ревью. Такой подход применим к менее критичным частям вашего приложения. Разумеется, это не сработает с критически важными вещами, такими как финансовые операции или другие высокорисковые зоны, но во многих обычных модулях вам не нужно досконально знать подробности реализации.
Важно лишь, чтобы у модуля были тестируемые границы (testable boundaries), чтобы вы понимали его интерфейс и могли взаимодействовать с ним извне. Такой метод помогает сохранять когнитивные ресурсы, поскольку позволяет отстраниться и дать AI работать с тем, что находится внутри этого «большого блоба» (реализации). Вы тестируете систему снаружи и проверяете результат.
Module Awareness и проектирование систем
Для эффективного взаимодействия с кодом на уровне модулей используются инструменты Module Awareness, такие как:
/grill-me(для глубокого разбора кода);/write-a-prd(написание документа с требованиями);/prd-to-issues(превращение требований в конкретные задачи/issues).
Как говорил Kent Beck в книге Extreme Programming Explained: «Invest in the design of the system every day» (Инвестируйте в дизайн системы каждый день). Это фундаментальный принцип, который в эпоху работы с ИИ становится еще более значимым, так как именно качественное проектирование интерфейсов позволяет эффективно делегировать написание реализации нейросетям.
Стратегическое проектирование и роль разработчика
Пятый совет заключается в необходимости изучения и применения навыков проектирования. Это означает, что при планировании и написании кода мы должны глубоко осознавать структуру модулей, из которых состоит наша система. Мы должны знать «карту» этой системы настолько хорошо, чтобы она стала частью нашего повседневного языка программирования. Необходимо проектировать и строить модули с учётом их будущего развития.
Процесс проектирования — это постоянная работа с модулями и понимание того, как они изменяются с течением времени. В этом контексте стоит обратиться к идее Кента Бека (Kent Beck) о необходимости «инвестировать в проектирование системы каждый день». Это важный момент, так как при работе с кодом, который генерирует ИИ, мы часто совершаем ошибку, не инвестируя в проектирование системы напрямую, а просто принимая код «как есть» и позволяя ему существовать без должного структурирования.
Важно осознавать, что одного написания кода недостаточно. Если мы рассматриваем ИИ как исполнителя, выполняющего «тактическую» работу — подобно сержанту на графике, который вносит конкретные изменения в код, — то за этим процессом должен стоять человек. Нам необходим кто-то, кто мыслит на стратегическом уровне. Этим человеком являетесь вы. Это требует фундаментальных навыков, которые мы использовали на протяжении последних двадцати лет и даже дольше.
Отступление от темы
Если вас интересуют навыки, о которых шла речь в лекции, вы можете найти их в репозитории на GitHub: Matt Pocock Skills. Если вам интересно обучение или вы хотите обсудить эти темы, вы можете найти меня в Twitter или на сайте aihero.dev, где я собрал ресурсы для изучения. Спасибо большое, надеюсь, это поможет вам обрести компетентность в новую эру ИИ и вы сможете добиться значимых результатов.













































