Выглядит так что речь идет о вайбкодинге, где архитектура проекта превращается в black box. В этом случаи без четкого разделения на слои, явного распределения ответственности и DI, вы очень быстро получите сверхсвязанный, тяжелый спагетти-монолит.
В итоге каждая новая доработка будет стоить в разы дороже предыдущей, а на поддержку и бесконечный рефакторинг уйдет гораздо больше ресурсов (тех самых токенов), чем на внедрение проверенных паттернов с самого начала. Системы такого масштаба держатся исключительно на слабой связанности компонентов.
Интересная позиция. Покажите, пожалуйста, пример кода: как в вашей парадигме один класс использует другой без применения DI и сервис-локатора, сохраняя при этом слабую связанность (loose coupling)?
Возможно ли протестировать ваши классы изолированно?
Аргумент «все ai вам скажут что di это зло» не является техническим. Если безоговорочно принимать ответы LLM за архитектурные решения, это превращает работу с AI скорее в «религию», чем в инженерный анализ.
На мой взгляд, AI полезен не для перекладывания ответственности за результат, а для поиска вариантов, сравнения компромиссов и проверки решений. Финальное решение всё равно должно опираться на понимание предметной области, требований и рисков.
Тем более в AI-first приложениях зависимости никуда не исчезают. Отказ от DI просто переносит их в глобальные imports, скрытые singleton’ы, service locator, неявное состояние и runtime инициализацию. Архитектура от этого не становится чище.
Поэтому «di это зло» слишком общее утверждение. Плохой DI — зло. Собственно, значительная часть статьи как раз об этом.
Да, service = inject(UserService) выглядит лаконично. Однако это именно тот компромисс, о котором я писал в разделе «Магия автосвязывания vs Строгость компилятора». Angular делает разрешение зависимостей неявным и переносит часть рисков в runtime. Если провайдер не зарегистрирован, токен указан неверно или inject() вызван вне контекста инъекции — вы узнаете об этом только в runtime.
В InferDI фокус принципиально другой: приоритетом является не внешняя простота, а проверяемость DI-графа на этапе компиляции TypeScript. Да, зависимости нужно явно описывать в Composition Root и визуально это выглядит менее эффектно, но зато компилятор строго валидирует ключи, типы, порядок аргументов конструктора и lifetime-связи. Это осознанный инженерный выбор в пользу надежности.
API Angular действительно изящнее в месте использования. Но InferDI предлагает другую эстетику — архитектурную надежность и статические гарантий до запуска приложения.
По интерфейсам — в Angular тоже их нельзя использовать как DI token, потому что они исчезают после компиляции. Angular решает это через InjectionToken<T>, а InferDI через аналогичную регистрацию по Symbol('token').
Да, в $mol действительно сильный архитектурный приём: проблема решается не дополнительными проверками DI-графа, а самой моделью контекста.
Но у этого подхода есть цена: нужно принять целую парадигму $mol: ambient context, реактивные мемоизированные свойства и жизненный цикл объектов через дерево зависимостей. То есть приложение должно быть написано в этой модели.
Поэтому я бы разделил эти подходы так: $mol делает такую ошибку невыразимой через архитектуру всего приложения, а InferDI через тип DI-графа внутри обычной TypeScript-архитектуры. Это разные уровни решения одной и той же проблемы.
Нет, раньше не встречал @tinkoff/dippy, спасибо за пример. Посмотрел — интересная реализация.
Но как раз в рамках статьи я говорю о другом ожидании от DI в 2026 году. TypeScript сегодня может намного больше, чем просто типизировать отдельный token или provider. Поэтому современный DI-контейнер, на мой взгляд, должен использовать всю мощь TypeScript, чтобы давать максимум статических гарантий ещё до запуска приложения.
DI не должен добавлять новые источники ошибок: незарегистрированные зависимости, ошибки в списке constructor-зависимостей, случайные singleton → scoped/request зависимости. Напротив, он должен помогать сводить такие проблемы к минимуму на этапе компиляции.
В этом смысле Dippy не позволяет компилятору проверить корректность всего DI-графа до запуска приложения.
Согласен с вами в одном важном моменте: в runtime TypeScript типы действительно так же отсутствуют, как и JSDoc, но для InferDI ключевая ценность не в runtime, а в том, что TypeScript успевает проверить граф до запуска приложения и запретить некорректный граф на этапе компиляции: неправильный порядок зависимостей, отсутствующий ключ, несовпадение constructor signature, singleton → scoped/transient и т.д.
Ваш подход, насколько я понял, делает ставку на runtime-конвенции и модульный resolver. Это сильная идея для pure JS. InferDI же сознательно идёт в другую сторону, только явный Composition Root, потому что именно он становится типом графа.
Выглядит так что речь идет о вайбкодинге, где архитектура проекта превращается в black box. В этом случаи без четкого разделения на слои, явного распределения ответственности и DI, вы очень быстро получите сверхсвязанный, тяжелый спагетти-монолит.
В итоге каждая новая доработка будет стоить в разы дороже предыдущей, а на поддержку и бесконечный рефакторинг уйдет гораздо больше ресурсов (тех самых токенов), чем на внедрение проверенных паттернов с самого начала. Системы такого масштаба держатся исключительно на слабой связанности компонентов.
Интересная позиция. Покажите, пожалуйста, пример кода: как в вашей парадигме один класс использует другой без применения DI и сервис-локатора, сохраняя при этом слабую связанность (loose coupling)?
Возможно ли протестировать ваши классы изолированно?
Аргумент «все ai вам скажут что di это зло» не является техническим. Если безоговорочно принимать ответы LLM за архитектурные решения, это превращает работу с AI скорее в «религию», чем в инженерный анализ.
На мой взгляд, AI полезен не для перекладывания ответственности за результат, а для поиска вариантов, сравнения компромиссов и проверки решений. Финальное решение всё равно должно опираться на понимание предметной области, требований и рисков.
Тем более в AI-first приложениях зависимости никуда не исчезают. Отказ от DI просто переносит их в глобальные imports, скрытые singleton’ы, service locator, неявное состояние и runtime инициализацию. Архитектура от этого не становится чище.
Поэтому «di это зло» слишком общее утверждение. Плохой DI — зло. Собственно, значительная часть статьи как раз об этом.
Да,
service = inject(UserService)выглядит лаконично. Однако это именно тот компромисс, о котором я писал в разделе «Магия автосвязывания vs Строгость компилятора». Angular делает разрешение зависимостей неявным и переносит часть рисков в runtime. Если провайдер не зарегистрирован, токен указан неверно илиinject()вызван вне контекста инъекции — вы узнаете об этом только в runtime.В InferDI фокус принципиально другой: приоритетом является не внешняя простота, а проверяемость DI-графа на этапе компиляции TypeScript. Да, зависимости нужно явно описывать в Composition Root и визуально это выглядит менее эффектно, но зато компилятор строго валидирует ключи, типы, порядок аргументов конструктора и lifetime-связи. Это осознанный инженерный выбор в пользу надежности.
API Angular действительно изящнее в месте использования. Но InferDI предлагает другую эстетику — архитектурную надежность и статические гарантий до запуска приложения.
По интерфейсам — в Angular тоже их нельзя использовать как DI token, потому что они исчезают после компиляции. Angular решает это через
InjectionToken<T>, а InferDI через аналогичную регистрацию поSymbol('token').Да, в
$molдействительно сильный архитектурный приём: проблема решается не дополнительными проверками DI-графа, а самой моделью контекста.Но у этого подхода есть цена: нужно принять целую парадигму
$mol: ambient context, реактивные мемоизированные свойства и жизненный цикл объектов через дерево зависимостей. То есть приложение должно быть написано в этой модели.Поэтому я бы разделил эти подходы так:
$molделает такую ошибку невыразимой через архитектуру всего приложения, а InferDI через тип DI-графа внутри обычной TypeScript-архитектуры. Это разные уровни решения одной и той же проблемы.Нет, раньше не встречал
@tinkoff/dippy, спасибо за пример. Посмотрел — интересная реализация.Но как раз в рамках статьи я говорю о другом ожидании от DI в 2026 году. TypeScript сегодня может намного больше, чем просто типизировать отдельный token или provider. Поэтому современный DI-контейнер, на мой взгляд, должен использовать всю мощь TypeScript, чтобы давать максимум статических гарантий ещё до запуска приложения.
DI не должен добавлять новые источники ошибок: незарегистрированные зависимости, ошибки в списке constructor-зависимостей, случайные
singleton→scoped/requestзависимости. Напротив, он должен помогать сводить такие проблемы к минимуму на этапе компиляции.В этом смысле Dippy не позволяет компилятору проверить корректность всего DI-графа до запуска приложения.
Посмотрел
teqfw/di- спасибо интересный подход.Согласен с вами в одном важном моменте: в runtime TypeScript типы действительно так же отсутствуют, как и JSDoc, но для InferDI ключевая ценность не в runtime, а в том, что TypeScript успевает проверить граф до запуска приложения и запретить некорректный граф на этапе компиляции: неправильный порядок зависимостей, отсутствующий ключ, несовпадение constructor signature,
singleton → scoped/transientи т.д.Ваш подход, насколько я понял, делает ставку на runtime-конвенции и модульный resolver. Это сильная идея для pure JS. InferDI же сознательно идёт в другую сторону, только явный Composition Root, потому что именно он становится типом графа.