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

Постановка вопроса

Для одноразового скрипта разница между языками сглаживается: AI знает синтаксис любого популярного языка достаточно хорошо, чтобы написать рабочий код. Прототип на Python, скрипт на Bash — без разницы.

Для продукта, который живёт годами — даже если его везёт один продукт-инженер, — разница огромная. Потому что AI усиливает свойства языка:

  • Если язык строгий и с сильными соглашениями — агент пишет ровно, а его ошибки ловятся компилятором и инструментами до вас.
  • Если язык даёт свободу интерпретаций — агент делает «по-своему» каждую сессию, и через полгода ваш собственный продукт состоит из десяти разных стилей, а галлюцинации всплывают в бою.

Для соло-инженера это даже важнее, чем для команды: у команды есть ревьюеры, которые поймают разнобой; у вас — только компилятор, инструменты и дисциплина приёмки. Язык — первая линия этой обороны. (Наблюдение из практики команды на 20+ инженеров подтверждает то же: один и тот же AI ведёт себя радикально по-разному на Java и на Python.)

Пять критериев AI-friendly языка

1. Объём в обучающей выборке

Крупные языки (Python, JavaScript, Java) представлены в обучающих данных моделей на порядки больше, чем редкие (Haskell, Erlang, Ada). Чем больше данных — тем точнее генерирует AI, тем меньше галлюцинаций.

Это самый банальный критерий. Но он один не определяет всё — иначе Python был бы безусловным лидером, а на практике он часто хуже Java для команды (об этом ниже).

2. Строгость типов

Сильно типизированные языки (Java, Kotlin, TypeScript, Rust, C#) ловят галлюцинации AI на этапе компиляции. AI выдумал метод findFirstByXyz — компилятор не нашёл, ошибка немедленно. Дёшево чинится.

Слабо типизированные (Python, JavaScript, Ruby) обнаруживают такие галлюцинации во время работы. Тест прошёл основной сценарий, в боевой среде через неделю — AttributeError: 'NoneType' object has no attribute 'foo'. Дорого.

Парадокс: Python с его 1-м местом по объёму обучающих данных проигрывает Java на третьем месте именно из-за этой разницы. AI пишет на Python больше галлюцинаций, и они дольше живут.

3. Сила соглашений

Чем меньше способов «как правильно» — тем меньше расхождений между разработчиками и сессиями AI. У Go — один способ форматировать код (gofmt), один способ разрешать зависимости (go modules), один способ обрабатывать ошибки (if err != nil). У Scala или Ruby — каждый второй проект изобретает свои встроенные мини-языки.

Java здесь в середине: Spring Boot задаёт сильные соглашения, но без него и без явного свода правил кода получаются разнокалиберные сервисы. С методологией и исполняемым стандартом — правилами, которые агент применяет на каждом PR — эта проблема решается: дисциплина поверх языка.

TypeScript с фреймворком (Angular, NestJS) ведёт себя похоже на Java со Spring — соглашения делают AI ровнее. Без фреймворка чистый Node.js даёт больше шума.

4. Объём кода и плотность синтаксиса

Часто звучит: «для AI же главное — поменьше кода, токенов меньше, контекста легче». Это миф наполовину. Разделим — что реально верно, а что заблуждение.

Что правда

  • Шаблонный код, написанный руками — реально нагрузка. AI пишет геттер getUserId() { return userId; } тысячный раз, тратит токены, иногда промахивается. Кодогенерация (Lombok в Java, data class в Kotlin, dataclass в Python, struct embedding в Go) снимает это начисто.
  • Длинный файл с противоречиями — больше шансов на разнобой. AI помнит начало файла, забывает середину, в конце противоречит сам себе. Здесь короче = лучше.
  • Меньше скрытого поведения — явная семантика снижает шанс галлюцинаций.

Что миф (и почему)

1. AI не страдает от объёма как человек. Контекстные окна 200K–1M токенов. 100 vs 1000 строк — для AI это почти то же самое. Программист уставший после 1000 строк делает ошибки. AI — нет.

2. Точность AI зависит от ЯВНОСТИ, не от КРАТКОСТИ. Явные аннотации и типы (например, @Transactional, @PreAuthorize в Spring; декораторы в NestJS; Protocol в Python) делают код длиннее, но каждое решение видно локально. AI прочитал 20 строк handler-а и понял всё. Haskell на 5 строк выглядит элегантно, но половина поведения выводится из типов в других файлах — AI следует цепочкам, путается чаще.

3. Краткость через метапрограммирование = катастрофа. Ruby User.find_by_email_and_active_and_role(email, true, "admin") короче Java, но это method_missing — метода реально не существует, он создаётся на лету из имени. AI генерирует похожие вызовы, иногда они работают, иногда нет. На Java тот же вызов был бы repository.findByEmailAndActiveAndRole(...) — длиннее, но AI видит, существует ли метод в интерфейсе. Ошибиться сложнее.

4. Исходник короткий vs скомпилированный — разные вещи. Кодогенерация на этапе компиляции (Lombok @Data в Java, data class в Kotlin) позволяет писать короткий исходник с явной семантикой — без ручного геттера/сеттера/equals/hashCode. AI видит исходник (короткий) И типы поведения (явные через аннотацию). Это лучшее из двух миров.

5. Метрика не «строки», а «сколько контекста надо удержать на одну операцию». Handler на 30 строк — AI читает 30 строк, всё. Scala с implicit conversions на 10 строк — AI должен знать, какие неявные преобразования типов действуют в данном месте, какие приоритеты, как они складываются. Это поиск по нескольким файлам и контексту проекта.

Сладкое место

Минимум исходного кода + максимум явной семантики. Как этого достигают:

  • Java + Lombok + records + jOOQ-generated — в исходниках 30–40% от объёма «голой» Java, семантика остаётся явной (типы, аннотации видны).
  • Kotlin + Springdata class + nullable-типы делают то же нативно. Чуть короче Java+Lombok, чуть менее прозрачно.
  • Go — стандартная библиотека и соглашения намеренно скучные. Один способ написать всё. AI пишет очень предсказуемо, потому что вариантов мало.
  • TypeScript + NestJS — декораторы делают то же, что Spring-аннотации. Объём средний, семантика явная.
  • Python + Pydantic + mypyBaseModel и строгие type hints приближают поведение к сильно типизированным языкам.

Что не работает для уменьшения кода без потери AI-friendly свойств:

  • Встроенные мини-языки и метапрограммирование. Scala с неявными преобразованиями типов, Ruby с method_missing, Python с метаклассами — AI теряет нить, потому что половина поведения скрыта.
  • Магия с горячей перезагрузкой (Spring без аннотаций, чисто YAML-конфиг). Источник правды размыт между кодом и конфигом.

Короткая формула: AI любит явный код + минимум шаблонного повторения. Не «короткий синтаксис», не «магия которая короче». Кодогенерация на этапе компиляции — отлично. Динамическая магия во время работы — плохо.

Java vs Go в эпоху AI: что реально различает

До AI скорость написания была реальным критерием выбора. Расклад был такой:

  • Python — самый быстрый: динамическая типизация, минимум церемонии, прототип за полдня.
  • Spring Boot Java — догоняет за счёт аннотаций и кодогенерации (Lombok убирает повторяющийся код, jOOQ генерирует доступ к БД, MapStruct — мапперы между слоями). На сложной доменной модели часто быстрее Python, потому что структура задана фреймворком, а не изобретается заново.
  • Go — посередине: быстрый для сетевых сервисов, но многословная обработка ошибок (if err != nil в каждом вызове) и долгое отсутствие дженериков (до 1.18) замедляли сложный домен.
  • «Голая» Java без фреймворков — реально медленная, отсюда устоявшийся стереотип «Java многословна».

Сейчас, когда пишет AI, разница в скорости стёрта. Python, Spring Boot Java, Go — все пишутся примерно за одинаковое время. Скорость набора больше не главный критерий выбора.

Что остаётся:

КритерийJava (Spring + Lombok)Go
Объём в обучающей выборке✅ Один из лидеров✅ Большой объём, особенно облачные сервисы
Сложность доменной модели✅ Records, sealed types, дженерики, инструменты для DDD🟡 Простая система типов, дженерики свежие, агрегаты DDD получаются костыльными
Соглашения и единообразие🟡 Много фреймворков, но Spring Boot доминирует✅ Один способ всего (gofmt, обработка ошибок, modules)
Глубина анализа кода✅ Уровень IntelliJ, ArchUnit, Spotbugs🟡 vet, golangci-lint — хорошо, но менее глубоко
Стартап / память / холодный запуск🟡 JVM прогревается секунды✅ Бинарь стартует моментально
Экосистема для домена✅ Spring, Hibernate, jOOQ, MapStruct, Resilience4j🟡 Меньше вариантов для сложной бизнес-логики
Готовность для регулируемых отраслей✅ Доминирует в банках, госкомпаниях🟡 В некоторых индустриях считается «новым», требует обоснования

Что выбирать когда:

Берите Java, если:

  • Сложная доменная модель с инвариантами и доменными событиями (территория DDD)
  • Долгоживущий продукт на годы с командой 10+ человек
  • Регулируемая отрасль (банки, госкомпании, медицина)
  • Нужна глубокая интеграция с корпоративным стеком (SSO, аудит, мониторинг)
  • Зрелый доменный уровень (DDD + Hexagonal)

Берите Go, если:

  • Сетевые сервисы, шлюзы, прокси, инфраструктурные утилиты
  • Высокая пропускная способность с простой бизнес-логикой (CRUD, ETL)
  • Микросервис с быстрым холодным стартом (serverless-функции, контейнер с автомасштабированием)
  • Маленькая команда (2–4 человека), которой важна низкая когнитивная нагрузка
  • Конкурентный код с естественной укладкой на goroutine + канал

Гибридная модель (часто встречаю в реальности):

  • Java/Kotlin для доменных сервисов (Order, Catalog, Payment) — там, где сложная логика
  • Go для периферии — шлюз, проксирование, лёгкие точки входа, инфраструктурные сервисы
  • Команда понимает оба, но методологические правила (общая методология, DDD) применяются прежде всего на сложных доменных сервисах. Go-сервисы наследуют общие соглашения, но не требуют полного набора инструментария.

В этой картине вопрос «Java или Go» — не «и/или», а «где что». Раньше выбор языка диктовался скоростью разработки одного программиста. Сейчас — характеристиками задачи и зрелостью экосистемы под неё.

5. Качество и строгость инструментария

Линтеры, форматтеры, статический анализ, проверка типов, анализ зависимостей. Чем строже инструменты — тем быстрее обратная связь от AI-кода в команду.

Java тут вне конкуренции: Spotbugs, Checkstyle, ArchUnit, анализ уровня IntelliJ. AI пишет — пять инструментов проверяют до запуска тестов.

Python догоняет (mypy, ruff, bandit), но экосистема разрозненна: каждая команда выбирает свой набор, AI не знает заранее.

JavaScript / TypeScript — ESLint + Prettier + tsc — стандарт.

Сравнительная таблица: AI-friendliness языка для команды

Шкала: ✅ хорошо для AI в команде, 🟡 терпимо, ⚠️ нужны компенсирующие меры.

ЯзыкОбъём в обучающих данныхТипизацияСоглашенияИнструментарийИтог для команды
Java (Spring Boot)
TypeScript (NestJS/Next)
Kotlin (Spring/Ktor)
Go
C# (.NET)
Python (с типами + ruff + mypy)🟡⚠️🟡🟡
JavaScript (без TS)⚠️⚠️🟡⚠️
Rust🟡🟡
Swift🟡🟡
C++🟡⚠️🟡⚠️
Scala🟡⚠️🟡⚠️
Haskell⚠️🟡🟡⚠️
Ruby (Rails)🟡⚠️🟡⚠️
PHP⚠️⚠️⚠️⚠️

«⚠️ Нужны компенсирующие меры» = язык можно использовать, но команде нужно явно вкладываться в дополнительный инструментарий и правила, иначе AI создаст хаос быстрее, чем его поймает разбор кода.

Что это значит на практике

Если вы можете выбирать стек

Берите из топ-тира: Java, TypeScript, Kotlin, Go, C#. Это не «модные» языки, это языки, у которых AI-friendly характеристики не нужно докручивать руками.

Особое наблюдение про Java: вопреки её репутации «многословный и устаревший», она оказалась сильным выбором именно для эпохи AI. Spring Boot задаёт соглашения, Lombok убирает повторяющийся код, jOOQ генерирует доступ к БД, ArchUnit проверяет архитектуру, а анализ уровня IntelliJ замыкает цепочку обратной связи — AI на этом стеке работает максимально стабильно. Посмотрите на крупные финтех- и онлайн-ритейл-команды, которые делают эксперименты с AI: большинство на Java/Kotlin, не на «модном» Rust или Python.

Если вы уже не можете

Что компенсирует слабый язык:

Python в команде:

  • Обязательные type hints на всю кодовую базу + mypy в CI как блокирующий
  • ruff с настройками строже стандартных
  • Тесты с pytest на 100% бизнес-логики (не «покрытие 80%», а «каждая бизнес-функция протестирована»)
  • Pydantic для всех DTO/моделей — как замена сильной типизации
  • pre-commit hooks с локальным mypy + ruff

JavaScript в команде:

  • Перейти на TypeScript. Если нельзя — JSDoc с типами + tsc в режиме проверки, чтобы хотя бы что-то типизировать.
  • Строгий ESLint (airbnb-typescript или standard-with-typescript)
  • Husky + lint-staged для pre-commit

C++ в команде:

  • Современный диалект (C++17+), запрет на raw new/delete
  • clang-tidy в строгом режиме, sanitizers на всех CI-прогонах
  • AddressSanitizer, ThreadSanitizer — обязательно в тестах
  • Header-only где можно, чтобы AI не путался в include-цепях

Идея общая: сильный язык даёт AI-friendly среду из коробки, слабый язык требует ручной достройки. Команда платит инженерное время за компенсацию.

Если у вас многоязычная команда

Самый дорогой случай. AI-стиль в каждом языке свой, единообразие между языками невозможно, ревьюер должен помнить N разных стандартов.

Решения:

  • Один основной язык для бизнес-логики, остальные для специализированных задач (Python для ML, Go для сетевого I/O). Чёткая граница.
  • Один набор архитектурных принципов (единая методология) поверх всех языков. Конкретный код разный, философия одна.
  • Исполняемые правила под каждый язык отдельно. Это инвестиция, но окупается на больших командах.

Что не влияет (вопреки распространённому мнению)

  • Возраст языка. Java старше Rust на 20 лет. По дружелюбию к AI Java впереди — потому что больше обучающих данных, сильнее соглашения, мощнее инструменты.
  • Производительность. AI пишет одинаково корректный код и на «быстром» Rust, и на «медленном» Python. Скорость работы — отдельный вопрос.
  • «Современность». Scala и Haskell — современнее Java по системе типов. Но AI на них слабее, потому что обучающих данных меньше и соглашения разрознены.
  • Личные предпочтения команды. Это эмоциональный фактор, не инженерный. Предпочтения важны для удержания и найма, но к дружелюбию к AI отношения не имеют.

Связь с методологией

Методология может поддерживать несколько языков: Java/Spring, Go, Node.js/TypeScript и Python покрыты стандартами persistence, code-style и test-strategy. Подход работает на каждом из них с языко-специфическим инструментарием.

Java/Spring остаётся наиболее зрелым треком: полный набор инструментов (Lombok, jOOQ, Spring Boot, MapStruct, ArchUnit) даёт AI стабильные идиоматические шаблоны, а требования аудита в регулируемых отраслях (банки, госкомпании) делают Java де-факто стандартом для таких команд.

Для Kotlin, Go, TypeScript/Node, Python — архитектурные принципы (UseCase + Handler + Repository, спецификация-как-код, исполняемые правила для разбора AI-кода) применимы полностью. Конкретные инструменты и правила — языко-специфические.

Если стек уже выбран — смотрите раздел «Если вы уже не можете» выше.

Что с этим делать

Продукт-инженеру, начинающему свой продукт:

  1. Выбирайте из топ-тира: Java/Kotlin, TypeScript, Go, C#. Ваш продукт — не прототип на выходные; через полгода в нём будут десятки сессий агента, и язык — то, что удержит их согласованными.
  2. Не берите «что быстрее набросать» (Python без типов, чистый JavaScript) для продукта всерьёз. Компенсация слабостей языка — это ваше же время: инструментарий, правила, ловля галлюцинаций в бою вместо компиляции.
  3. Не берите Rust, Scala, Haskell «потому что интересно». AI на них заметно слабее — а он ваша рабочая сила.
  4. Полный стек одного языка (например, TypeScript на клиенте и сервере, или Java-бэкенд + TS-фронт) проще держать в голове и в правилах агента, чем зоопарк.

Тимлиду нового сервиса: то же самое, плюс — не выбирайте слабый язык «потому что команда знает»: цена компенсации — минимум 20-30% инженерного времени на специализированный инструментарий.

Если языков несколько (бэкенд + фронт, или портфель сервисов): один основной язык для бизнес-логики, остальные — для специализированных задач, с чёткой границей; единые архитектурные принципы поверх всех; правила для агента — под каждый язык отдельно.

Что дальше

Язык выбран — дальше учимся ставить агенту задачу на нём: срез → контракт, исполняемый стандарт, который держит качество на объёме. Архитектура серверного приложения от старта до прода — выбор начальной архитектуры.