Dev News от Максима Соснова
2.82K subscribers
15 photos
1.33K links
Привет! Меня зовут Максим Соснов и по утрам я читаю всякие разные дайджесты про фронтенд, разработку и управление разработкой. Самые интересные, по моему мнению, ссылки из этих дайджестов я кидаю в этот канал с небольшим описанием.

Контакт: @msosnov
Download Telegram
Дайджест за 2026-03-16 - 2026-03-20

Fastest Frontend Tooling for Humans & AI
Статья про замену инструментов вокруг разработки на более быстрые. Во-первых, это полезно разработчикам. А во-вторых, это ускоряет работу ИИ-агентов.

——————————————
👍1
Can't Maintain. Can you spot the better API?

"Не поддерживаемый" (Can't maintain) - сайт с короткими квизами, где надо выбрать более поддерживаемый вариант реализации JS или React-кода. При ответе краткий экскурс, почему один из вариантов более поддерживаемый, чем другой. Очень залипательный сайт.

https://cant-maintain.saschb2b.com

#development #javascript #quiz #react
🔥184👎1
Why is WebAssembly a second-class language on the web?

WebAssembly развивается с 2017 года, но все еще не стал полноценной частью веб-экосистемы. В статье Ryan Hunt объясняет, какие проблемы есть у современного WASM и что надо изменить, чтобы wasm стал популярен у разработчиков

Есть 2 основные проблемы, делающие WASM "неудобным":
1. Код из WASM не может напрямую работать с Web API. Для этого нужна JS прослойка, которая будет мостиком между WASM и Web API
2. WASM код нельзя загрузить никак, кроме как из JS-кода (что является следствием первой проблемы)

Вторую проблему уже решают в пропозале esm-integration. Он позволяет загружать wasm-модули как обычные js-модули

import { run } from "/module.wasm";

run();



<script type="module" src="/module.wasm"></script>



Но необходимость прослойки для работы с Web API все еще делает неудобной работу с Web API. Можно писать эту прослойку самому, но это а) не самая тривиальная работа; б) требует одновременно компетенций как в wasm, так и в web. Можно использовать embind или wasm-bindgen, но там тоже есть свои нюансы

Компиляторы, собирающие нативный код в WASM, не занимаются сборкой JS-кода для интеграции wasm в web-api - они лишь собирают wasm, а дальше разработчик сам должен написать мостик между WASM и Web API, если это требуется для приложения.

Также есть проблема, что даже если написать такой мостик, то от этого пострадает перформанс. В классическом бенчмарке TodoMVC wasm+JS оказался почти в 2 раза медленнее, чем wasm-код с доступом к web api.

Как решение этой проблемы предлагается WebAssembly Component - пропозал, разрабатываемый с 2021 года

WebAssembly Components:
- Могут быть созданы из разных языков программирования
- Могут быть запущены в разных рантаймах
- Могут использовать друг друга
- Могут напрямую вызывать Web API

Это позволит снизить порог входа для интеграции WASM в приложения.

https://hacks.mozilla.org/2026/02/making-webassembly-a-first-class-language-on-the-web/

#development #javascript #web #wasm
👍151
How we Rewrote 130K Lines from React to Svelte in Two Weeks

Команда strawberry за 2 недели переписала 130к строчек кода с React на Svelte с применением ИИ-агентов. Интересный кейс, про который можно и почитать. Хотя, конечно, тот факт, что ИИ-агенты хорошо справляются с переписыванием - давно не новость

Почему вообще понадобилось переезжать с React:
1. Strawberry использует несколько отдельный рендереров для разных компонентов своего браузера. Каждый компонент - отдельное React-приложение. Обновление этих приложений из главного процесса приводит к плохому UX.
2. Strawberry - это ИИ-стартап, знаете ли. ИИ-агенты, которые работают как ядро приложения, постоянно вызывают ререндер React-приложений.

В общем, React быстрый, но недостаточно быстрый для чуваков из Strawberry (хотя конечно больше похоже на то, что они просто решили не париться с оптимизацией ререндеров)

Отдельно забавляет подход, с которым начался процесс переписывания. Какое-то обсуждение через ADR, RFC или хотя бы тред - это все лишнее. Чел просто на один из дейликов пришел и сказал "смотрите, переписал уже 60% кодовой базы на Svelte". Живем в эру, где быстрее показать Proof of Concept, чем начать обсуждение какой-то инициативы.

Как состоялось переписывание:
1. Были оформлены правила миграции, чтобы гарантировать, что ИИ-агенты пишут код "правильно". Короткие примеры правил: "Avoid $effect", "Prefer stores over component state", "Keep reactivity explicit."
2. За 1 раз переписывается одна фича
3. ИИ-агент читает правила, портирует код, тестирует код.
4. Старый код не удалялся, пока не была завершена миграция (чтобы при любых проблемах можно было поднять эталонные исходники и сравнить решение)
5. Часть библиотек отсутствует на svelte, поэтому пришлось их написать самим (через агентов конечно)

Какие результаты:
1. х2 ускорение
2. FCP уменьшился с 300мс до 124мс
3. Количество ререндеров в приложении уменьшилось в 10 раз
4. Удалили 56 неиспользуемых зависимостей


В общем, история, откровенно говоря, странная. Создается ощущение, что как использовался "тяп-ляп" подход при разработке на React, так и используется, просто повезло, что ИИ-агенты справились с рефакторингом. С другой стороны, хороший пример как можно сделать миграцию кодовой базы с применением ИИ-агентов



https://strawberrybrowser.com/blog/react-to-svelte

#development #javascript #react #svelte #migration #refactoring #ai
😁8💩6👍2
Дайджест за 2026-03-23 - 2026-03-27

Can't Maintain. Can you spot the better API?
"Не поддерживаемый" (Can't maintain) - сайт с короткими квизами, где надо выбрать более поддерживаемый вариант реализации JS или React-кода. При ответе краткий экскурс, почему один из вариантов более поддерживаемый, чем другой. Очень залипательный сайт.

Why is WebAssembly a second-class language on the web?
WebAssembly развивается с 2017 года, но все еще не стал полноценной частью веб-экосистемы. В статье Ryan Hunt объясняет, какие проблемы есть у современного WASM и что надо изменить, чтобы wasm стал популярен у разработчиков

How we Rewrote 130K Lines from React to Svelte in Two Weeks
Команда strawberry за 2 недели переписала 130к строчек кода с React на Svelte с применением ИИ-агентов. Интересный кейс, про который можно и почитать. Хотя, конечно, тот факт, что ИИ-агенты хорошо справляются с переписыванием - давно не новость

——————————————

Спасибо что читаете, ставите реакции, отмечаетесь в комментариях и рассказываете о канале друзьям и коллегам.

——————————————

Я работаю в Т-Банке и у нас идет активный найм. Если вам интересна работа в Т-Банке - переходите по ссылке и пишите в личку - отвечу на любые вопросы
4👍4
Reveal.js 6.0

Вышел новый релиз Reveal.js. Reveal.js — это инструментарий для создания веб-презентаций из кода. Основное важное изменение для релиза — нативная поддержка React. Теперь можно собирать интерактивные презентации на привычном стеке.

Я даже уже попробовал использовать. Может показаться смешным, но у нас в направлении есть своя презентация для фит-интервью. К нам приходят кандидаты, мы спрашиваем их про их опыт и всякое разное, а потом рассказываем про нас через презу. Но преза сделана на PowerPoint и не обновляется годами, потому что никто особо не хочет лезть править презентацию.

В общем, решил совместить приятное с полезным и отправил агента сначала мигрировать презентацию с pptx на reveal. Агент нашёл какой-то пакет для парсинга слайдов на Python и собрал базу для презентации. Результат простой миграции выглядит, конечно, достаточно убого.

Дальше пошли сплошные плюсы. Заставил агента через Chrome MCP провести ревью слайдов и исправить явные косяки. С этой задачей он справился: где-то выровнял, где-то увеличил, а где-то распределил контент по слайду.

Дальше пошёл самый кайф. Т. к. на слайдах были картинки, а тут у нас целый React, то почему бы не добавить интерактива? Описал, какой интерактив я ожидаю на слайдах, и вообще попросил все картинки из интернета заменить на что-то более живое.

Результат следующий: половина коллег сказали «вау, круто», другая половина оценила как «юзлес кринж». Считаю, главное, что мне нравится :)

Но как итог:
- Reveal.js норм ложится для создания интерактивных презентаций на React. Слайды с демками, кликабельные блоки, кастомные анимации любой сложности — всё можно сделать в Reveal.js.
- ИИ-агент с доступом к Chrome MCP вполне бодро может собрать презентацию сам по вашему контенту и с вашим видением.


https://github.com/hakimel/reveal.js/releases/tag/6.0.0

#development #javascript #react #revealjs #presentation #release #ai #agents
👍5🔥1
Next.js 16.2

Вышел релиз Next.js 16.2. Кратные ускорения (400% ускорение старта при разработке и 50% ускорение рендеринга), правки в Turbopack и адаптация фреймворка для AI. Ещё новая дефолтная страница для 500 ошибки.

Что прикольного завезли:

Логирование отработки серверных функций во время разработки. Теперь, если отрабатывает серверная функция, то логируется имя и путь до функции, аргументы, скорость ответа и связь с обработкой конкретного эндпоинта.

Удобное отображение диффа между серверной и браузерной разметкой, когда разъехалась гидрация. За это однозначный лайк. Также более удобное отображение ошибок в dev overlay.

Я бы не писал в канал, если бы не отдельные телодвижения в релизе для ИИ-агентов.

Что конкретно сделали:

Теперь при создании нового приложения через create-next-app создаётся Agents.md. В файле написано, что это Next.js репозиторий и необходимо смотреть доку в node_modules/next/dist/docs. Это сделано потому что, по исследованию, наличие доки по фреймворку рядом с кодом позволяет агентам достигать лучших результатов в бенчмарках.

Сделали так, что теперь логи из браузера будут показываться в терминале по умолчанию. Это также сделано для удобства агентов, чтобы им проще было работать с логами.

При старте сервера Next.js пишет в lock-файл PID процесса. Если попытаться стартануть новый сервер, то Next.js не позволяет это сделать и говорит, что сервер уже запущен. Это также полезно для агентов, которые любят запустить приложение с десяток раз.

Сделали DevTools для агентов. Можно получать инфу из DevTools через CLI. В целом, как будто ИИ-агенты и так могут это делать через MCP или прямое или почти прямое использование CDP через CLI, но встроенная в фреймворк возможность так делать, конечно, удобнее для массового использования.

Выглядит неплохо. Мы, конечно, догадывались, что фреймворки и библиотеки будут адаптироваться к ИИ-инструментам. Но интересно наблюдать за реальной адаптацией большого фреймворка.


https://nextjs.org/blog/next-16-2

#development #javascript #react #nextjs #turbopack #release #ai #agents #devtools
14👍3
Анонс TypeScript 6.0

Анонс последнего мажорного релиза TypeScript на текущем стеке. Напомню, скоро TS-компилятор перепишут на Go, и это будет 7-я версия языка. 6-я версия — переходная. В рамках неё можно подготовиться: избавиться от настроек, которые не будут поддерживаться, и поставить настройки, которые приводят поведение компилятора к новому поведению.

Можно ставить в планы по техническим работам обновление TypeScript.


https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/

#development #typescript #release #microsoft
🔥102
Дайджест за 2026-03-30 - 2026-04-03

Reveal.js 6.0
Вышел новый релиз Reveal.js. Reveal.js — это инструментарий для создания веб-презентаций из кода. Основное важное изменение для релиза — нативная поддержка React. Теперь можно собирать интерактивные презентации на привычном стеке.

Next.js 16.2
Вышел релиз Next.js 16.2. Кратные ускорения (400% ускорение старта при разработке и 50% ускорение рендеринга), правки в Turbopack и адаптация фреймворка для AI. Ещё новая дефолтная страница для 500 ошибки.

Анонс TypeScript 6.0
Анонс последнего мажорного релиза TypeScript на текущем стеке. Напомню, скоро TS-компилятор перепишут на Go, и это будет 7-я версия языка. 6-я версия — переходная. В рамках неё можно подготовиться: избавиться от настроек, которые не будут поддерживаться, и поставить настройки, которые приводят поведение компилятора к новому поведению.

——————————————

Спасибо что читаете, ставите реакции, отмечаетесь в комментариях и рассказываете о канале друзьям и коллегам.

——————————————

Я работаю в Т-Банке и у нас идет активный найм. Если вам интересна работа в Т-Банке - переходите по ссылке и пишите в личку - отвечу на любые вопросы
👍7
Start naming your useEffect functions, you will thank me later

Огромная статья, в которой очень простой месседж — именуй чёртовы колбэки в useEffect.

В чём суть. Есть две большие причины именовать колбэки в useEffect.

Первая: самодокументирующийся код. useEffect(() => {}) говорит о том, как мы запускаем код (при изменениях чего-то), но не говорит о том, что там запускается и почему.

При изучении такого кода необходимо погрузиться в код, потратить дополнительные когнитивные усилия, чтобы его понять.

Намного лучше, если разработчик сразу даст имя колбэку в useEffect, которое позволит быстро понять, что тут происходит. Если компонент простой и useEffect тоже простой, то проблема незаметна. Но если в компоненте есть 5–6 useEffect, то понять, зачем они нужны, может быть не так-то просто.

Автор даёт в статье пример компонента, который общается по WebSocket и синхронизирует состояние сущности.

Пример useEffect с именованным колбэком:

useEffect(function resetStockOnLocationChange() {
if (prevLocationId.current !== locationId) {
setStock([]);
prevLocationId.current = locationId;
}
}, [locationId]);


Привычка давать имена колбэкам позволяет на берегу обнаружить проблемы с ответственностью. Сложно дать имена колбэкам, которые делают либо слишком много, либо слишком мало.

Вторая причина для именования колбэков чисто прагматичная. Лучше в инструментарии и в стек-трейсах видеть at resetStockOnLocationChange, чем at anonymous.

В общем, именуйте колбэки в useEffect. Это бесплатно и сразу делает вашу жизнь лучше. Можно ещё написать или найти ESLint-правило, которое не даст коммитить анонимные useEffect.


https://neciudan.dev/name-your-effects

#development #javascript #react #hooks #useeffect #best-practices #article
👍273💩3
Rewriting our Rust WASM Parser in TypeScript

OpenUI сделали парсер на Rust и компилировали его в WASM. Rust же быстрый, но недостаточно. Какое-то время оптимизировали его, пытались ускорить, но по итогу оказалось, что реализация на TypeScript работает быстрее.

Причина банальна — очень много потерь на передачу данных между JS и WASM. Как ни пытайся оптимизировать эту передачу данных, всё равно проиграешь решению без передачи. Что в итоге и сделали — переписали парсер один в один на TypeScript и ускорились в разы.

Очередное напоминание, что в текущих реалиях WASM хорош для тяжёлых задач (например, видеопроцессинг) и для переноса нативного кода в веб, но плохо подходит для ускорения приложений, если нужно передавать много данных между WASM и JS.

Также хорошее напоминание, что если садишься оптимизировать что-то, надо исследовать возможности для оптимизации максимально широко, а не концентрируясь только в каком-то одном этапе.


https://www.openui.com/blog/rust-wasm-parser

#development #typescript #rust #wasm #performance #parser #openui #article
👍9😱4
Дайджест за 2026-04-06 - 2026-04-08

Start naming your useEffect functions, you will thank me later
Огромная статья, в которой очень простой месседж — именуй чёртовы колбэки в useEffect.

Rewriting our Rust WASM Parser in TypeScript
OpenUI сделали парсер на Rust и компилировали его в WASM. Rust же быстрый, но недостаточно. Какое-то время оптимизировали его, пытались ускорить, но по итогу оказалось, что реализация на TypeScript работает быстрее.

——————————————

Спасибо что читаете, ставите реакции, отмечаетесь в комментариях и рассказываете о канале друзьям и коллегам.

——————————————

Я работаю в Т-Банке и у нас идет активный найм. Если вам интересна работа в Т-Банке - переходите по ссылке и пишите в личку - отвечу на любые вопросы
👍8
You can't cancel a JavaScript promise (except sometimes you can)

Статья от Inngest про то, как можно отменить исполнение Promise. По прочтению оказалось, что не совсем отмена, но тем не менее интересно.

С момента стандартизации Promise и async/await сообщество требует возможности отменить Promise, но решения пока нет.

Если вам нужны отменяемые асинхронные операции, у вас, по сути, есть 2 пути:

Первый способ: использовать генераторы. Они прекрасно для этого подходят (т.к. генераторы отдают поток управления во вне, в вызывающий их код), но сообщество не очень любит их использовать. async/await гораздо удобнее


Второй способ: кидать ошибку типа InterruptedError из приостанавливаемого кода, но тогда надо уметь ее везде обрабатывать.

Что придумали в Inngest. У них какой-то немного странный фреймворк - они описывают workflow как шаги (steps)

async function myWorkflow(step) {
console.log(" Workflow: top");

const data = await step.run("fetch", () => {
console.log(" Step: fetch");
return [1, 2, 3];
});

const processed = await step.run("process", () => {
console.log(" Step: process");
return data.map((n) => n * 2);
});

console.log(" Workflow: complete", processed);
}



Который затем исполняется
async function main() {
// In-memory store of completed step results
const stepState = new Map();

// Keep entering the workflow function until it's done
let done = false;
let i = 0;
while (!done) {
console.log(`Run ${i}:`);
done = await execute(myWorkflow, stepState);
console.log("--------------------------------");
i++;
}
}


При этом функция execute после выполнения каждого step кеширует результат работы step, затем приостанавливает workflow и вызывает новый запуск workflow. Это очень упрощенно, в Inngest SDK все сложнее, но смысл примерно такой.

Поэтому есть потребность обрывать исполнение workflow. Для этого используется интересный хак: после выполнения первого незакешированного step функция execute подменяет результат выполнения так, чтобы возвращался Promise, который никогда не завершится

// Hang forever
return new Promise(() => {});


Затем ссылка на конкретный запуск workflow теряется и, оказывается, в NodeJS сборщик мусора видит, что есть функция, на которую нет ссылок и которая никогда не выполнится потому что ожидает завершения промиса, который никогда не завершится. Сборщик мусора удаляет из памяти функцию и все что с ней связано.

В общем, максимально странное решение и, если честно, немного удивительно что это вообще работает. Но, как говорится, если это работает - это не глупо. Запоминаем и используем с осторожностью в nodejs коде.

https://www.inngest.com/blog/hanging-promises-for-control-flow

#development #javascript #Promise
😱83😁1
boneyard - Pixel-perfect skeleton loading screens, extracted from your real UI. No manual measurement, no hand-tuned placeholders.

В названии ссылки в общем-то все написано. Библиотека, автоматически создающая скелетоны для ваших экранов. Есть адаптеры на React, Preact, Vue, Svelte 5, Angular, React Native.

Использование такое
import { Skeleton } from 'boneyard-js/react'

function BlogPage() {
const { data, isLoading } = useFetch('/api/post')
return (
<Skeleton name="blog-card" loading={isLoading}>
{data && <BlogCard data={data} />}
</Skeleton>
)
}


Как это работает:
- Вы запускаете сайт
- Запускаете специальную команду npx boneyard-js build
- Она находит все Skeleton и делает снапшот разметки, который сохраняется в bones.json
- Информация из bones.json используется для построения скелетонов

Выглядит прикольно

https://github.com/0xGF/boneyard

#development #javascript #library #skeletons
🔥153
Post Mortem: axios npm supply chain compromise

Axios опубликовали пост-мортем про взлом Axios, в котором опубликованы причины, таймлайн и предпринимаемые действия для предотвращения такого в будущем

Что случилось:
- В середине марта началась атака через социальную инженерию на мейнтейнера
- 30 марта была опубликована взломанная версия plain-crypto-js
- 31 марта (через 19 часов) был опубликован axios с plain-crypto-js
- Через 40 минут сообщество начало репортить проблему, но злоумышленники удаляли эти репорты (у них был доступ к аккаунту мейнтейнера)
- Через час после публикации опубликован пул реквест с депрекейтом "плохих" версий axios
- Еще через полтора часа опубликованные версии были удалены с npm

Выученные уроки:
- Публикация с личных аккаунтов - это риск. Переходят на OIDC
- Нет автоматики, которая бы обнаруживала неавторизованные публикации
- Мейнтейнеры популярных пакетов - активные цели для социальной инженерии. Нужно быть гипер-бдительными в отношении таких мейнтейнеров и таких пакетов

https://github.com/axios/axios/issues/10636

#development #javascript #axios #postMortems #security #npm
👍4
Дайджест за 2026-04-13 - 2026-04-17

You can't cancel a JavaScript promise (except sometimes you can)
Статья от Inngest про то, как можно отменить исполнение Promise. По прочтению оказалось, что не совсем отмена, но тем не менее интересно.

boneyard - Pixel-perfect skeleton loading screens, extracted from your real UI. No manual measurement, no hand-tuned placeholders.
В названии ссылки в общем-то все написано. Библиотека, автоматически создающая скелетоны для ваших экранов. Есть адаптеры на React, Preact, Vue, Svelte 5, Angular, React Native.

Post Mortem: axios npm supply chain compromise
Axios опубликовали пост-мортем про взлом Axios, в котором опубликованы причины, таймлайн и предпринимаемые действия для предотвращения такого в будущем

——————————————

Спасибо что читаете, ставите реакции, отмечаетесь в комментариях и рассказываете о канале друзьям и коллегам.

——————————————

Я работаю в Т-Банке и у нас идет активный найм. Если вам интересна работа в Т-Банке - переходите по ссылке и пишите в личку - отвечу на любые вопросы
4
MarkItDown

Microsoft выпустила пакет на Python, который преобразует всё в Markdown, что очень полезно для работы с ИИ-агентами. Умеет преобразовывать PDF, PowerPoint, Word, Excel, картинки, аудио, HTML, epub и другие файлы.

https://github.com/microsoft/markitdown

#development #ai #python #markdown #mcp
👍9
The Vertical Codebase

Статья про то, почему структура components / hooks / utils / types плохо масштабируется. Автор предлагает раскладывать код не по техническому типу, а по доменам: не components/someWidget.tsx + utils/someWidget.ts + types/someWidget.ts, а просто все widget-related в some-widget/.

Основная мысль очень простая: код, который меняется вместе, должен лежать рядом. Тем не менее, горизонтальная организация файлов до сих пор очень популярна: это когда для каждого типа сущности есть отдельная папка, в которой плоским списком файлов лежат все сущности этого типа.

В чём проблема горизонтальной структуры:
- код группируется по техническому признаку, а не по смыслу.
- код одной продуктовой области размазывается по разным папкам, и даже маленькая правка требует бегать по дереву проекта
- utils со временем просто превращается в помойку
- границы между модулями размываются, и любая фича начинает тянуть зависимости откуда угодно
- сложно настроить овнерство над кодом. Допустим, команда отвечает за какой-то домен. Если все ее файлы раскиданы по куче плоских папок, то настройка codeowners превращается в квест.

И это проблемы не только кода, но и организационной структуры. Закон Конвея говорит, что архитектура повторяет структуру организации. Соответственно, если мы выделяем команду на какой-то домен, то этот домен должен быть отражен и в архитектуре, и, в том числе, в структуре систем, компонентов, файлов.

Взамен предлагается группировать код по вертикальным слайсам, доменам:
- группировать код по смыслу: dashboard, widgets, profiling, pageFilters
- общий код тоже оформлять как отдельные вертикали, если это реально самостоятельный домен, а не скидывать все в бездонный shared
- явно обозначать public API модулей и закрывать внутренности через exports, workspace-пакеты, Nx rules, eslint-plugin-boundaries и т.д.

Почему деление по вертикальным слайсам лучше:
- меньше когнитивная нагрузка. Если надо исследовать что-то в домене, вы просто исследуете папку, связанную с доменом, а не исследуете весь репозиторий в поиске всех файлов
- можно легко найти ответственных за каждый домен
- видны зависимости между модулями

Но при этом работать с таким делением сложнее на этапе проектирования. Необходимо думать про границы модулей, про зависимости и ответственность модуля.

Кто-то может спросить: "А зачем это надо в эру пост-кодинга с ИИ, ИИ со всем разберется". Возможно, в эру пост-кодинга это будет работать, но сейчас даже ИИ-агентам проще работать с понятными границами. Хорошая архитектура становится более важной, чем раньше.

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


https://tkdodo.eu/blog/the-vertical-codebase

#development #frontend #architecture #monorepo
👍201
How I Resolved 15K Circular Dependencies

Очень хорошая инженерная история про то, как в огромном Nx-монорепозитории (7 млн строк кода, 1000+ проектов) год вычищали 15 тысяч циклических зависимостей между проектами. Важно, что речь именно про project-level cycles на уровне Nx, а не про file-level импорты. Циклы в таких зависимостях ломают incremental builds, ухудшают кеширование и в целом ухудшают понимание зависимостей в системе.

Проблема 1: циклы были невидимы для Nx

Причина в том, что реальные path aliases жили не в tsconfig.base.json, а в отдельных tsconfig проектах. Nx же использует tsconfig.base.json и поэтому не видел реальных зависимостей.

Решение:
- собрать синтетический tsconfig.base.json, в который временно сводятся реальные aliases со всего репозитория
- скормить этот конфиг Nx, чтобы он начал работать с реальным графом зависимостей

Проблема 2: Анализировать циклические зависимости в таком большом проекте сложно

Если считать циклы в лоб, то цифра циклов быстро улетает до миллиардов из-за сложных и транзитивных зависимостей. Использовать это для анализа невозможно.

Решение:
- отказаться от идеи идеального подсчета
- сделать fuzzy detector, который считает не все возможные циклы, а репрезентативное множество.
- использовать детектор для мониторинга

Проблема 3: Нужно остановить появление новых циклов, но при этом не мешать разработчикам работать с проектом

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

Решение:
- признать, что не все, что автоматика помечает как проблема - реальная проблема
- завести чеклист, который помечает ребро в графе как "реально плохое". Затем завести список таких ребер
- ронять PR только если он приносит новое плохое ребро

Если при анализе PR видно, что появился новый цикл через уже известное плохое ребро, то проблема не в PR, а в уже существующем техдолге.

Проблема 4: сами циклы все равно надо было как-то чинить

Тут серебряной пули не нашлось. По сути, решение каждого цикла — это небольшое архитектурное решение.

На практике все решения можно было поделить на 3 категории:
- Вынести код в shared проект, на который ссылаются текущие проекты. Это 70% кейсов
- Дублирование констант, енамов, интерфейсов в текущие проекты, вместо импортов
- Слияние проектов. Иногда оказывалось, что проекты так переплетены друг с другом, что это, по сути, один проект. В этом случае их сливали

Главный паттерн, который автор в итоге признает самым полезным: это выделение явных контрактов + inversion of control. То есть реализации должны зависеть не друг от друга, а от контрактов, интерфейсов и токенов.

Они выделили отдельные проекты-контракты, которые содержат все енамы, константы, интерфейсы, токены для DI. Эти проекты-контракты имплементируются проектом-имплементацией и импортируются другими проектами.

Эта история не только про технику, но и про людей. Чтобы решить проблему, приходилось:
- Учить инженеров работать "правильно"
- Влиять на команды без прямого управления
- Постоянно общаться с разными инженерами, которые являются экспертами в разных областях проекта
- Выстраивать план разрушения циклов в проекте с мониторингом, анализом наиболее перспективных направлений и планированием работ

Уроки, которые вынес автор из этой истории:
- Если тулинг не видит проблемы, а вы видите - почините тулинг (или сделайте свой)
- Лучше иметь хоть какой-то мониторинг проблемы, чем идеальный
- Правила не должны наказывать за "правильную" работу
- Контракты и IoC - хорошая практика
- Большие рефакторинги - это не только про технику, но и про лидерские качества т.к. надо всех обучить, со всеми договориться, уметь влиять на команды

https://stefanhaas.xyz/article/15k-circular-dependencies/

#development #architecture #nx #monorepo #refactoring #circularDependencies
🔥11💩2👍1😁1
Дайджест за 2026-04-20 - 2026-04-24

MarkItDown
Microsoft выпустила пакет на Python, который преобразует всё в Markdown, что очень полезно для работы с ИИ-агентами. Умеет преобразовывать PDF, PowerPoint, Word, Excel, картинки, аудио, HTML, epub и другие файлы.

The Vertical Codebase
Статья про то, почему структура components / hooks / utils / types плохо масштабируется. Автор предлагает раскладывать код не по техническому типу, а по доменам: не components/someWidget.tsx + utils/someWidget.ts + types/someWidget.ts, а просто все widget-related в some-widget/.

How I Resolved 15K Circular Dependencies
Очень хорошая инженерная история про то, как в огромном Nx-монорепозитории (7 млн строк кода, 1000+ проектов) год вычищали 15 тысяч циклических зависимостей между проектами. Важно, что речь именно про project-level cycles на уровне Nx, а не про file-level импорты. Циклы в таких зависимостях ломают incremental builds, ухудшают кеширование и в целом ухудшают понимание зависимостей в системе.

——————————————

Спасибо что читаете, ставите реакции, отмечаетесь в комментариях и рассказываете о канале друзьям и коллегам.

——————————————

Я работаю в Т-Банке и у нас идет активный найм. Если вам интересна работа в Т-Банке - переходите по ссылке и пишите в личку - отвечу на любые вопросы
👍91