За последнее время в канал добавилось много новых людей — добро пожаловать! 💫
Здесь я в основном выкладываю статьи и посты с разбором всяких интересных технологических загогулин (в последнее время особенно много по Node.js). Но сегодня решила разбавить контент мемом)
У меня, признаюсь, есть одна проблема — я не очень хорошо знаю английский. Поэтому иногда, чтобы побыстрее найти ответ, перевожу статьи или куски документации через переводчик. И конечно, он часто выдает перлы. Подвезла вам некоторые из них (последний не имеет ничего общего с разработкой, но тоже смешон).
Здесь я в основном выкладываю статьи и посты с разбором всяких интересных технологических загогулин (в последнее время особенно много по Node.js). Но сегодня решила разбавить контент мемом)
У меня, признаюсь, есть одна проблема — я не очень хорошо знаю английский. Поэтому иногда, чтобы побыстрее найти ответ, перевожу статьи или куски документации через переводчик. И конечно, он часто выдает перлы. Подвезла вам некоторые из них (последний не имеет ничего общего с разработкой, но тоже смешон).
❤13😁5👏3🔥1😢1
Сборка мусора в Node.js
Когда мы говорим о сборке мусора в JavaScript, мы имеем в виду то, как это реализовано в движке. В случае и Node.js, и большинства браузеров (например, Chrome) речь идёт про один и тот же механизм: сборку мусора в V8.
Сердцем движка V8 является Generational GC — поколенческая сборка мусора. Её основная идея: объекты, которые живут долго, — редкость, большинство умирает вскоре после появления (феномен “высокой детской смертности”). Чтобы использовать это наблюдение, V8 делит память (heap) на поколения:
- New space — молодое поколение. Здесь появляются все новые объекты. Это небольшая область памяти, которую можно быстро и часто очищать.
- Old space — старое поколение. Если объект прожил несколько циклов сборки в New space и всё ещё нужен — его «повышают» и переносят сюда. Эта область больше по размеру и чистится реже.
Внутри New space работает Scavenge — быстрый алгоритм копирования. Его реализация основана на двух зонах:
- From-space — где живут текущие объекты.
- To-space — пустая зона, куда будут скопированы только «живые» объекты.
Когда запускается сборка, GC перебирает объекты из from-space, и те, которые всё ещё достижимы (то есть на них есть ссылки), копируются в to-space. Остальные просто забываются — они исчезают вместе со старой областью. Затем роли зон меняются. Такой подход прост и быстр: не нужно ничего удалять, достаточно скопировать нужное.
Но этот трюк работает, пока объектов немного — он отлично подходит для New space, где всё ещё «свежее». А вот для Old space он неэффективен: там уже много данных, копировать всё — слишком дорого.
Для старого поколения V8 использует алгоритмы Mark-Sweep и Mark-Compact:
- Mark-Sweep: сначала проходит по графу объектов, помечая «живые». Потом всё, что не помечено, удаляется. Это экономно по времени, но может оставить фрагментированное пространство.
- Mark-Compact: дополнительно уплотняет память, передвигая объекты в один конец heap-а, чтобы не оставалось дыр. Это происходит небыстро, но снижает фрагментацию.
Обе эти стратегии медленнее, чем Scavenge, но подходят для устойчивых структур данных, которые не хочется копировать по несколько раз.
Чтобы сборка не вызывала внезапных тормозов, V8 применяет ещё и инкрементальные и конкурентные оптимизации:
- Incremental GC разбивает большие этапы сборки на мелкие порции и выполняет их между основными задачами.
- Concurrent GC работает в отдельных потоках, параллельно с кодом, стараясь вообще не останавливать исполнение.
Таким образом, сборка мусора в V8 — это не один алгоритм, а комбинация техник, каждая из которых применяется в нужное время и в нужном месте.
И, в отличие от браузеров, в Node.js у нас есть возможность чуть больше контролировать процесс: если запустить скрипт с флагом
#startpoint_dev_nodejs
Когда мы говорим о сборке мусора в JavaScript, мы имеем в виду то, как это реализовано в движке. В случае и Node.js, и большинства браузеров (например, Chrome) речь идёт про один и тот же механизм: сборку мусора в V8.
Сердцем движка V8 является Generational GC — поколенческая сборка мусора. Её основная идея: объекты, которые живут долго, — редкость, большинство умирает вскоре после появления (феномен “высокой детской смертности”). Чтобы использовать это наблюдение, V8 делит память (heap) на поколения:
- New space — молодое поколение. Здесь появляются все новые объекты. Это небольшая область памяти, которую можно быстро и часто очищать.
- Old space — старое поколение. Если объект прожил несколько циклов сборки в New space и всё ещё нужен — его «повышают» и переносят сюда. Эта область больше по размеру и чистится реже.
Внутри New space работает Scavenge — быстрый алгоритм копирования. Его реализация основана на двух зонах:
- From-space — где живут текущие объекты.
- To-space — пустая зона, куда будут скопированы только «живые» объекты.
Когда запускается сборка, GC перебирает объекты из from-space, и те, которые всё ещё достижимы (то есть на них есть ссылки), копируются в to-space. Остальные просто забываются — они исчезают вместе со старой областью. Затем роли зон меняются. Такой подход прост и быстр: не нужно ничего удалять, достаточно скопировать нужное.
Но этот трюк работает, пока объектов немного — он отлично подходит для New space, где всё ещё «свежее». А вот для Old space он неэффективен: там уже много данных, копировать всё — слишком дорого.
Для старого поколения V8 использует алгоритмы Mark-Sweep и Mark-Compact:
- Mark-Sweep: сначала проходит по графу объектов, помечая «живые». Потом всё, что не помечено, удаляется. Это экономно по времени, но может оставить фрагментированное пространство.
- Mark-Compact: дополнительно уплотняет память, передвигая объекты в один конец heap-а, чтобы не оставалось дыр. Это происходит небыстро, но снижает фрагментацию.
Обе эти стратегии медленнее, чем Scavenge, но подходят для устойчивых структур данных, которые не хочется копировать по несколько раз.
Чтобы сборка не вызывала внезапных тормозов, V8 применяет ещё и инкрементальные и конкурентные оптимизации:
- Incremental GC разбивает большие этапы сборки на мелкие порции и выполняет их между основными задачами.
- Concurrent GC работает в отдельных потоках, параллельно с кодом, стараясь вообще не останавливать исполнение.
Таким образом, сборка мусора в V8 — это не один алгоритм, а комбинация техник, каждая из которых применяется в нужное время и в нужном месте.
И, в отличие от браузеров, в Node.js у нас есть возможность чуть больше контролировать процесс: если запустить скрипт с флагом
--expose-gc
, можно вручную вызывать в коде global.gc()
— это бывает полезно, например, в нагрузочных тестах, о которых мы, кстати, говорили совсем недавно)#startpoint_dev_nodejs
👍11🔥4❤1
Недавно увидела в одной статье аббревиатуру REPL, которая оказалась для меня на первый взгляд незнакомой. Но на самом деле, я знаю, что это такое, и хочу, чтобы теперь знали и вы)
REPL — это Read–Eval–Print–Loop: интерактивная оболочка, в которой можно писать JavaScript-код построчно, и он сразу выполняется. Похоже на консоль в инструментах разработчика в браузере.
Когда мы просто запускаем
Неожиданность для меня была в другом. В Node.js есть отдельный модуль для REPL. С его помощью можно встроить собственный REPL прямо в код, например, для дебага приложения.
Такой подход используется и в NestJS. Запустить REPL там можно командой
А волшебный доступ ко всем сервисам приложения реализуется с помощью дополнения контекста repl. Вот так можно сделать свой микро-repl с доступными в контексте переменными и функциями:
Вывод будет вот такой:
#startpoint_dev_nodejs
REPL — это Read–Eval–Print–Loop: интерактивная оболочка, в которой можно писать JavaScript-код построчно, и он сразу выполняется. Похоже на консоль в инструментах разработчика в браузере.
Когда мы просто запускаем
node
в терминале и дальше можем писать разные команды вида 2 + 2
— вот это и есть REPL.Неожиданность для меня была в другом. В Node.js есть отдельный модуль для REPL. С его помощью можно встроить собственный REPL прямо в код, например, для дебага приложения.
Такой подход используется и в NestJS. Запустить REPL там можно командой
npm run start -- --entryFile repl
, если заранее настроен файл repl.ts (документация). Там можно получить доступ к инстансам сервисов и вызывать их методы руками. И для реализации такого механизма NestJS как раз использует модуль repl, исходники можно посмотреть тут.А волшебный доступ ко всем сервисам приложения реализуется с помощью дополнения контекста repl. Вот так можно сделать свой микро-repl с доступными в контексте переменными и функциями:
import repl from 'node:repl';
const context = {
hello: 'world',
add: (a, b) => a + b,
};
const r = repl.start('> ');
Object.assign(r.context, context)
Вывод будет вот такой:
node repl-test.js
> hello
'world'
> add(2, 3)
5
>
#startpoint_dev_nodejs
🔥17👍4❤2
Что происходит при старте Node.js?
Когда мы запускаем
1. Инициализация C++-окружения
Node настраивает V8 (движок JavaScript) и инициализирует libuv (который отвечает, в частности, за event loop). Также здесь парсятся аргументы командной строки (
2. Передача управления JS-модулям
Далее Node загружает свои «системные» JS-модули — те, что реализуют, как работать с require и import, как находить зависимости, как всё это грузить. Он также создаёт JS-контекст: тут появляются global, process, console и прочие глобальные объекты и функции, которые всегда доступны.
3. Выполнение скрипта
Теперь Node готов исполнить
4. Запуск Event Loop
Когда синхронная часть кода отработала, Node передаёт управление libuv: стартует event loop, который начинает обрабатывать таймеры, сетевые события и т.д.
#startpoint_dev_nodejs
Когда мы запускаем
node index.js
, Node проходит несколько этапов:1. Инициализация C++-окружения
Node настраивает V8 (движок JavaScript) и инициализирует libuv (который отвечает, в частности, за event loop). Также здесь парсятся аргументы командной строки (
--inspect
, --require
и др.).2. Передача управления JS-модулям
Далее Node загружает свои «системные» JS-модули — те, что реализуют, как работать с require и import, как находить зависимости, как всё это грузить. Он также создаёт JS-контекст: тут появляются global, process, console и прочие глобальные объекты и функции, которые всегда доступны.
3. Выполнение скрипта
Теперь Node готов исполнить
index.js
. Всё, что мы написали (включая синхронные импорты), выполняется сразу, до того, как event loop заработает.4. Запуск Event Loop
Когда синхронная часть кода отработала, Node передаёт управление libuv: стартует event loop, который начинает обрабатывать таймеры, сетевые события и т.д.
#startpoint_dev_nodejs
✍11❤5🔥4👍1
Из чего состоит память в Node.js?
Любой процесс в Node.js использует несколько разделов памяти:
- Стек (stack) — область для хранения вызовов функций и локальных переменных, управляется ОС.
- Куча (heap) — основная память для JS-объектов, управляется движком V8 и сборщиком мусора (GC).
- Нативная память — сюда входят буферы (Buffer в Node.js), C++-addons, другие служебные сущности (для libuv, Event Loop и т.д.).
Все эти разделы вместе образуют RSS (Resident Set Size) — общий объём памяти, выделенный процессу ОС.
Чтобы посмотреть, сколько памяти сейчас используется, можно вызвать
Этот метод возвращает объект с такими полями:
- rss — вся память процесса, включая всё нативное.
- heapTotal — объём JS-кучи, зарезервированный V8.
- heapUsed — реально используемая память в куче.
- external — нативная память.
- arrayBuffers — конкретно память ArrayBuffer и Buffer (часть external).
#startpoint_dev_nodejs
Любой процесс в Node.js использует несколько разделов памяти:
- Стек (stack) — область для хранения вызовов функций и локальных переменных, управляется ОС.
- Куча (heap) — основная память для JS-объектов, управляется движком V8 и сборщиком мусора (GC).
- Нативная память — сюда входят буферы (Buffer в Node.js), C++-addons, другие служебные сущности (для libuv, Event Loop и т.д.).
Все эти разделы вместе образуют RSS (Resident Set Size) — общий объём памяти, выделенный процессу ОС.
Чтобы посмотреть, сколько памяти сейчас используется, можно вызвать
process.memoryUsage()
.Этот метод возвращает объект с такими полями:
- rss — вся память процесса, включая всё нативное.
- heapTotal — объём JS-кучи, зарезервированный V8.
- heapUsed — реально используемая память в куче.
- external — нативная память.
- arrayBuffers — конкретно память ArrayBuffer и Buffer (часть external).
#startpoint_dev_nodejs
❤9👍8
Вы не ждали, а мы припёрлись тут опять с циклом статей.
Как же мне понравилось разбираться в каком-то вопросе путём ресёрча и написания статьи на эту тему. Так я, после цикла про Event Loop, когда меня в очередной раз занесло в исходники Node.js, решила чуть лучше познакомиться с libuv — той самой культовой библиотекой, на которой, кажется, построен весь Node.js. На этот раз, по моим планам, он должен получиться короче, буквально на 3 (может 4) статьи.
Как принято говорить на ютубе, заваривайте себе чаёк или кофеёк, и присоединяйтесь, будем постигать libuv вместе 💫
Погружение в libuv. Часть 1. Зачем он нужен?
#startpoint_dev_nodejs
Как же мне понравилось разбираться в каком-то вопросе путём ресёрча и написания статьи на эту тему. Так я, после цикла про Event Loop, когда меня в очередной раз занесло в исходники Node.js, решила чуть лучше познакомиться с libuv — той самой культовой библиотекой, на которой, кажется, построен весь Node.js. На этот раз, по моим планам, он должен получиться короче, буквально на 3 (может 4) статьи.
Как принято говорить на ютубе, заваривайте себе чаёк или кофеёк, и присоединяйтесь, будем постигать libuv вместе 💫
Погружение в libuv. Часть 1. Зачем он нужен?
#startpoint_dev_nodejs
Telegraph
Погружение в libuv. Часть 1. Зачем он нужен?
Anastasia Kotova Введение Как мы знаем, Node.js состоит не только из JavaScript-модулей, написанных специально для серверной разработки. Под капотом он использует две важнейшие составляющие: движок V8, отвечающий за быстрое выполнение JavaScript-кода, и библиотеку…
❤15🎉4🔥1
Продолжение цикла про libuv. На этот раз полезем прямо в кишки операционных систем ⚰️
Как бы мне ни хотелось обойти эту тему стороной, но реализация неблокирующего ввода-вывода — это не просто внутренняя деталь, а один из главных столпов и libuv, и всего Node.js.
Обещаю, дальше будет легче!)
Погружение в libuv. Часть 2. Неблокирующий ввод-вывод.
#startpoint_dev_nodejs
Как бы мне ни хотелось обойти эту тему стороной, но реализация неблокирующего ввода-вывода — это не просто внутренняя деталь, а один из главных столпов и libuv, и всего Node.js.
Обещаю, дальше будет легче!)
Погружение в libuv. Часть 2. Неблокирующий ввод-вывод.
#startpoint_dev_nodejs
Telegraph
Погружение в libuv. Часть 2. Неблокирующий ввод-вывод.
Предыдущие части Погружение в libuv. Часть 1. Зачем он нужен? Как бы нам ни хотелось пройти по лёгкому пути, чтобы разобраться, как работает Event Loop в libuv и на чём вообще держится Node.js, — придётся чуть-чуть углубиться в устройство операционных систем.…
🔥11❤1
Продолжаю покорять сцены конференций — на этот раз уже оффлайн и в Минске! 🎤
Выступаю на Яндекс.Субботнике с докладом о том, как мы провели большое техническое обновление без остановки разработки 💫
Будет и трансляция — так что можно смотреть из любой точки мира.
Чтобы прийти лично или подключиться онлайн, достаточно зарегистрироваться:
🔗 https://events.yandex.ru/events/ya-subbotnik-2025-07-26
Выступаю на Яндекс.Субботнике с докладом о том, как мы провели большое техническое обновление без остановки разработки 💫
Будет и трансляция — так что можно смотреть из любой точки мира.
Чтобы прийти лично или подключиться онлайн, достаточно зарегистрироваться:
🔗 https://events.yandex.ru/events/ya-subbotnik-2025-07-26
Я.Субботник по разработке интерфейсов
Митап для фронтенд-разработчиков пройдёт в Минске и онлайн 26 июля
🔥16❤3
Третья часть про libuv. Смотрим, как реализован Event Loop внутри libuv, и как с этим жить простому разработчику.
Погружение в libuv. Часть 3. Опять Event Loop.
#startpoint_dev_nodejs
Погружение в libuv. Часть 3. Опять Event Loop.
#startpoint_dev_nodejs
Telegraph
Погружение в libuv. Часть 3. Опять Event Loop.
Предыдущие части Погружение в libuv. Часть 1. Зачем он нужен? Погружение в libuv. Часть 2. Неблокирующий ввод-вывод. Мы уже говорили про Event Loop в Node.js в отдельном цикле статей. Там мы рассмотрели, какие фазы цикла существуют. В этой статье мы сосредоточимся…
🔥12
Завершающая часть цикла про libuv здесь!
Рассмотрим некоторые другие интересные функции libuv, и поговорим про их использование внутри Node.js.
Погружение в libuv. Часть 4. Другие функции.
#startpoint_dev_nodejs
Рассмотрим некоторые другие интересные функции libuv, и поговорим про их использование внутри Node.js.
Погружение в libuv. Часть 4. Другие функции.
#startpoint_dev_nodejs
Telegraph
Погружение в libuv. Часть 4. Другие функции.
Предыдущие части Погружение в libuv. Часть 1. Зачем он нужен? Погружение в libuv. Часть 2. Неблокирующий ввод-вывод. Погружение в libuv. Часть 3. Опять Event Loop. Помимо работы с Event Loop, которая, безусловно, является центральной частью libuv, библиотека…
🔥7
Настя Котова // Frontend & Node.js
Продолжаю покорять сцены конференций — на этот раз уже оффлайн и в Минске! 🎤 Выступаю на Яндекс.Субботнике с докладом о том, как мы провели большое техническое обновление без остановки разработки 💫 Будет и трансляция — так что можно смотреть из любой точки…
Уже завтра я выступаю в Минске 💫 Регистрируйтесь, доклад можно будет также посмотреть онлайн в трансляции.
🔥10❤3
Анастасия Котова 23.07.pdf
4.9 MB
В эту субботу я впервые выступила на внешней конференции оффлайн — том самом Я.Субботнике, про который писала здесь.
Прочитала доклад, понетворкалась (нетворкинг — это вообще супер), и наконец-то пришла в себя после долгого перелета из Минска домой в Белград.
Теперь делюсь ссылками на полезные материалы и приклыдываю свои слайды:
👉 Материалы с последнего слайда
👉 Запись трансляции
Если у вас остались (или, может, появились новые) вопросы — пишите мне в личку @startpoint_forl, в сообщения этого канала или в комментарии под этим постом.
А если просто хотите поддержать мой боевой дух — поставьте реакцию, мне будет очень приятно ❤️
Прочитала доклад, понетворкалась (нетворкинг — это вообще супер), и наконец-то пришла в себя после долгого перелета из Минска домой в Белград.
Теперь делюсь ссылками на полезные материалы и приклыдываю свои слайды:
👉 Материалы с последнего слайда
👉 Запись трансляции
Если у вас остались (или, может, появились новые) вопросы — пишите мне в личку @startpoint_forl, в сообщения этого канала или в комментарии под этим постом.
А если просто хотите поддержать мой боевой дух — поставьте реакцию, мне будет очень приятно ❤️
❤31🔥6❤🔥1
Вы когда-нибудь пользовались corepack?
Corepack — экспериментальный инструмент в экосистеме Node.js для управления версиями менеджеров пакетов (npm, yarn, pnpm) в проектах.
По сути, он позволяет жёстко контролировать, какой именно пакетный менеджер и в какой версии используется. Сейчас corepack поставляется вместе с Node.js, но начиная с версии 25 перестанет быть его частью.
Я всего один раз видела использование corepack на проекте и читала о нём довольно противоречивые отзывы. С одной стороны, кому-то он помогает гарантировать нужную версию пакетного менеджера — особенно при сборке Docker-образов в CI. С другой — кажется избыточным (шутки про “пакетный менеджер для пакетных менеджеров”).
В Dockerfile при использовании corepack это может выглядеть так:
Да, это защищает от необходимости вручную указывать версию pnpm, но при этом установка нужной версии менеджера всё равно должна происходить.
К тому же, после исключения corepack из Node.js, он больше не будет ставиться по умолчанию — его придётся устанавливать отдельно, с указанием версии.
В общем, лично я пока так и не прониклась этим инструментом — его преимущества не кажутся мне весомыми.
Если у вас был другой опыт — пишите в комментариях, может, я что-то упускаю.
Corepack — экспериментальный инструмент в экосистеме Node.js для управления версиями менеджеров пакетов (npm, yarn, pnpm) в проектах.
По сути, он позволяет жёстко контролировать, какой именно пакетный менеджер и в какой версии используется. Сейчас corepack поставляется вместе с Node.js, но начиная с версии 25 перестанет быть его частью.
Я всего один раз видела использование corepack на проекте и читала о нём довольно противоречивые отзывы. С одной стороны, кому-то он помогает гарантировать нужную версию пакетного менеджера — особенно при сборке Docker-образов в CI. С другой — кажется избыточным (шутки про “пакетный менеджер для пакетных менеджеров”).
В Dockerfile при использовании corepack это может выглядеть так:
FROM node:18-alpine
# Включаем corepack
RUN corepack enable
WORKDIR /app
# Копируем package.json (с указанием packageManager)
COPY package.json package-lock.json ./
# Corepack автоматически использует нужную версию pnpm
RUN corepack pnpm install --frozen-lockfile
Да, это защищает от необходимости вручную указывать версию pnpm, но при этом установка нужной версии менеджера всё равно должна происходить.
К тому же, после исключения corepack из Node.js, он больше не будет ставиться по умолчанию — его придётся устанавливать отдельно, с указанием версии.
В общем, лично я пока так и не прониклась этим инструментом — его преимущества не кажутся мне весомыми.
Если у вас был другой опыт — пишите в комментариях, может, я что-то упускаю.
🤔8❤1
Минутка саморекламы: в этом году я выступаю на FrontendConf!
Буду рассказывать про нехайповую, но, на мой взгляд, интересную тему — нативные модули в Node.js.
Даже официальный анонс уже вышел, так что больше скрывать не буду:
https://t.me/FrontendConfChannel/1197
Буду рассказывать про нехайповую, но, на мой взгляд, интересную тему — нативные модули в Node.js.
Даже официальный анонс уже вышел, так что больше скрывать не буду:
https://t.me/FrontendConfChannel/1197
Telegram
FrontendConf конференция
Что бизнесу тормоз, то разработчику боль
Медленные интерфейсы, CI по часу, дев-сервер еле дышит.
Как писать быстрые интерфейсы, ускорять сборку и запуск, отлаживать узкие места и делать отказоустойчивые системы? Об этом всем поговорим в рамках нашей секции…
Медленные интерфейсы, CI по часу, дев-сервер еле дышит.
Как писать быстрые интерфейсы, ускорять сборку и запуск, отлаживать узкие места и делать отказоустойчивые системы? Об этом всем поговорим в рамках нашей секции…
🔥13❤5
В своём докладе я рассказывала о том, как мы обновляли легаси-проект, вместо того чтобы переписывать его с нуля.
Да, доклад назывался «Не переписывай — обнови», и я действительно продвигаю эту идею. Но и сама не раз попадала в ситуации, когда обновление невозможно. Чаще всего это касается старых проектов, написанных не на чём-то из «большой тройки» (React, Angular, Vue). В таких случаях зачастую просто не остаётся другого выхода, кроме как переписывать всё заново.
Если проект построен на кастомном фреймворке или устаревшем решении, то он обречён на тяжёлую поддержку: современные библиотеки не интегрируются или делают это через боль, разработчики стараются обходить такие задачи стороной (типичная оценка «10 sp за простой баг» и привет вечный бэклог), а ещё продать такой проект при найме будет крайне сложно.
Совсем другое дело, если проект написан на React, пусть даже на версиях 16 или 17. Здесь ключевое преимущество в том, что обновление не требует перестраивать архитектуру и саму идеологию кода: как были компоненты — так они и остаются. Да, классовые, но это те же самые компоненты, которые можно переписывать и переносить постепенно, параллельно занимаясь и продуктовыми задачами.
На старте обновления важно сосредоточиться на тех вещах, которые напрямую влияют на то, как вы пишете код, и которые открывают путь к новым фичам. В нашем случае это было, например, внедрение нового стейт-менеджера. Как только эти базовые блоки обновлены, новые компоненты можно писать уже по современным подходам, а старые переписывать постепенно, по мере необходимости. А такие задачи, как переезд с Webpack на Vite или обновление сборки в целом, можно отложить на потом — они не меняют сам код и не блокируют разработку.
Вопрос, который мне задали на докладе, оказался очень в точку: что делать, если проект стареет быстрее, чем вы его обновляете? Тут важно определить для себя критерии «легаси». Например, если у вас библиотека пятой версии, а недавно вышла шестая — это не значит, что проект мгновенно стал легаси. Но если версия 5 уже три года официально считается устаревшей и реально мешает работе (замедляет сборку или использует подходы, которые давно вышли из употребления, как это было с классами против функциональных компонентов), вот тогда пора действовать.
И напоследок. Если у вас всё же тот самый первый вариант, когда переписывать приходится с нуля, продумайте стратегию постепенного перехода. На одном из проектов мы буквально переписывали его «по страницам». Да, и это проходило не без проблем, но так задачу можно было декомпозировать и оценивать. Параллельно брали продуктовые истории — иногда в новые страницы, иногда даже в старые (компромиссы неизбежны).
Никто не согласится на план «нам нужен год, никакие фичи не делаем, и не факт, что даже уложимся». Любое обновление должно быть разбито на понятные этапы. Так и прогресс виден: не как мифические «0 и вдруг 100%», а постепенно, по шагам. И для команды, и для менеджмента это куда легче и понятнее.
Да, доклад назывался «Не переписывай — обнови», и я действительно продвигаю эту идею. Но и сама не раз попадала в ситуации, когда обновление невозможно. Чаще всего это касается старых проектов, написанных не на чём-то из «большой тройки» (React, Angular, Vue). В таких случаях зачастую просто не остаётся другого выхода, кроме как переписывать всё заново.
Если проект построен на кастомном фреймворке или устаревшем решении, то он обречён на тяжёлую поддержку: современные библиотеки не интегрируются или делают это через боль, разработчики стараются обходить такие задачи стороной (типичная оценка «10 sp за простой баг» и привет вечный бэклог), а ещё продать такой проект при найме будет крайне сложно.
Совсем другое дело, если проект написан на React, пусть даже на версиях 16 или 17. Здесь ключевое преимущество в том, что обновление не требует перестраивать архитектуру и саму идеологию кода: как были компоненты — так они и остаются. Да, классовые, но это те же самые компоненты, которые можно переписывать и переносить постепенно, параллельно занимаясь и продуктовыми задачами.
На старте обновления важно сосредоточиться на тех вещах, которые напрямую влияют на то, как вы пишете код, и которые открывают путь к новым фичам. В нашем случае это было, например, внедрение нового стейт-менеджера. Как только эти базовые блоки обновлены, новые компоненты можно писать уже по современным подходам, а старые переписывать постепенно, по мере необходимости. А такие задачи, как переезд с Webpack на Vite или обновление сборки в целом, можно отложить на потом — они не меняют сам код и не блокируют разработку.
Вопрос, который мне задали на докладе, оказался очень в точку: что делать, если проект стареет быстрее, чем вы его обновляете? Тут важно определить для себя критерии «легаси». Например, если у вас библиотека пятой версии, а недавно вышла шестая — это не значит, что проект мгновенно стал легаси. Но если версия 5 уже три года официально считается устаревшей и реально мешает работе (замедляет сборку или использует подходы, которые давно вышли из употребления, как это было с классами против функциональных компонентов), вот тогда пора действовать.
И напоследок. Если у вас всё же тот самый первый вариант, когда переписывать приходится с нуля, продумайте стратегию постепенного перехода. На одном из проектов мы буквально переписывали его «по страницам». Да, и это проходило не без проблем, но так задачу можно было декомпозировать и оценивать. Параллельно брали продуктовые истории — иногда в новые страницы, иногда даже в старые (компромиссы неизбежны).
Никто не согласится на план «нам нужен год, никакие фичи не делаем, и не факт, что даже уложимся». Любое обновление должно быть разбито на понятные этапы. Так и прогресс виден: не как мифические «0 и вдруг 100%», а постепенно, по шагам. И для команды, и для менеджмента это куда легче и понятнее.
❤7🔥4👍1😁1
Хоть я последнее время и залипаю в Node.js, но трушным фронтендом тоже занимаюсь.
Вот, например, на днях впервые использовала фичу container queries в CSS.
Сценарий: у нас в интерфейсе есть блок, который пользователь может растягивать по ширине — прямо мышкой, за ползунок. А в этом блоке лежит таблица, и в ней хочется скрывать некоторые колонки, если блок слишком узкий.
Обычно мы пишем media-выражения, завязываясь на ширину всего экрана, но тут нужна ширина конкретного компонента. Хвала богам CSS, мы живем в 2025 году, и в наше время есть такая фича, как container queries в CSS.
Как это работает (если вы ещё не успели попробовать)
1. Определяем контейнер (родительский элемент):
2. Пишем запрос (
3. Вы восхитительны!
Самое крутое, что у этой фичи хорошая браузерная поддержка. Значит, можно брать — и делать.
Может, я и не открыла Америку, но как человек, который до сих пор пребывает в лёгком шоке от того, что IE11 умел в grid-ы, я каждый раз радуюсь, когда новые возможности CSS можно использовать на проде. Так что, может и вы порадуетесь сегодня вместе со мной:)
Вот, например, на днях впервые использовала фичу container queries в CSS.
Сценарий: у нас в интерфейсе есть блок, который пользователь может растягивать по ширине — прямо мышкой, за ползунок. А в этом блоке лежит таблица, и в ней хочется скрывать некоторые колонки, если блок слишком узкий.
Обычно мы пишем media-выражения, завязываясь на ширину всего экрана, но тут нужна ширина конкретного компонента. Хвала богам CSS, мы живем в 2025 году, и в наше время есть такая фича, как container queries в CSS.
Как это работает (если вы ещё не успели попробовать)
1. Определяем контейнер (родительский элемент):
.container {
container-type: inline-size;/* Отслеживает ширину */
container-name: my-container;/* Опционально: имя для обращения */
}
2. Пишем запрос (
@container
):@container my-container (max-width: 600px) {
.child-element {
font-size: 14px;
}
}
3. Вы восхитительны!
Самое крутое, что у этой фичи хорошая браузерная поддержка. Значит, можно брать — и делать.
Может, я и не открыла Америку, но как человек, который до сих пор пребывает в лёгком шоке от того, что IE11 умел в grid-ы, я каждый раз радуюсь, когда новые возможности CSS можно использовать на проде. Так что, может и вы порадуетесь сегодня вместе со мной:)
❤19🔥6✍2