Я тимлид/техлид. И могу сказать, что инициатива снизу приветствуется, но её очень мало. Конечно, бывают и случаи, когда приходится отказывать, если профит от инициативы сомнителен, либо приведёт к проблемам в будущем.
Ну и… полезные идеи появляются только тогда, когда ты в этом котле поварился немного, а не сразу.
Да, но часто на местах лучше видна боль, и, тем более, она лучше видна новичкам, которые совсем недавно видели как оно может быть иначе в другой компании.
Очень рад был бы услышать про ваш опыт, расскажите?
Я его и описал выше. Я не могу говорить о реальных кейсах в реальных компаниях — всё это попадает под NDA. Но вот почти так оно всё и было. На самом деле на позиции тимлида/техлида я отчаянно ищу людей, готовых прийти с хорошей полезной идеей и, тем более, внедрить её.
Всё же мой опыт говорит, что есть разные большие компании. И те, где можно донести идеи снизу — отличный выбор, если вы хотите искать точки роста. Да, конечно, это и способ построить карьеру.
Не всегда профессиональные задачи ограничиваются вёрсткой. В современных реалиях это и сборка проекта и какой-никакой бэкенд на node.js. Как я сказал, сейчас уже можно и на Windows, но ещё несколько лет назад это было очень больно.
В импорте класса реализации. Мы прошиваем высокоуровневые политики знанием о низкоуровневых. Да, внутри одного слоя мы можем пользоваться прямыми импортами классов, но между слоями такого быть не должно.
Где AbstractFooService — это класс, который используется как интерфейс.
Я же привожу в статье точно такой же пример решения через абстрактный класс.
Это похоже на отсебятину, не проверенную ни временем, ни обсуждениями хотя бы на хабре.
Я привожу ссылку на литературу, ту же самую, на которую ссылается и Фаулер. Речь не идёт о Java, проблема именно в выбрасывании исключения как средстве управления поведением кода.
Не представляю о чем идет речь, когда вы говорите «ни JavaScript, ни TypeScript не дают гарантий, что исключение будет обработано.»
В отличие от Java мы не можем гарантировать, что потребитель нашего кода напишет обработчик наших исключений. Мы никак не можем декларировать, что наш код выбрасывает исключения определённого типа и они должны быть декларированы.
Например, почему бы сервисы, интерсепторы или гарды не отнести к Domain (то есть к бизнес логике)?
Потому что в этом случае фреймворк проникнет в домен. Это усложнит написание тестов, это прошьёт код фреймворком и мы не сможем относительно дёшево сбежать с Nest в случае проблем с теми же декораторами.
почему вы считаете, что задача разработчиков фреймворков «навсегда привязать вас к себе»?
Достаточно послушать доклады разработчиков. Для них выгодно, чтобы мы оставались потребителем фреймворка, пусть несознательно, но всегда будут гнуть в эту сторону.
По-вашему, как можно «удобно организовать логику уровня приложения» не используя инструментов фреймворка?
Я привожу пример с реализацией гексагонального паттерна, когда бизнес-логика полностью отделена от фреймворка.
В целом не я придумал этот подход, о нём постоянно говорит тот же Роберт Мартин. Фреймворк должен быть всего лишь заменяемой деталью вашей архитектуры.
Посмотрел вебинар — действительно, многие вещи пересекаются. Вот что заитересовало (я не раскрывал этот момент в посте) — ты предлагаешь отказаться полностью от кластеризации силами встроенного модуля cluster в node.js и, тем более, (не к ночи будет помянут) pm2, поднимая worker_threads каждый на отдельном порту. Но кто в этом случае будет заниматься балансировкой? В эксплуатацию передаётся приложение с набором портов и просьбой добавить балансер?
И, второй вопрос, как поступать в случае контейнеризации? Положить один «большой» процесс с кучей worker_threads в контейнер и поставить балансировщик? Мы хотели двигаться в несколько иную сторону, выделяя каждый процесс (воркер) в отдельный контейнер и масштабируясь контейнерами. Схожий подход описан в Node.js Design Patterns, даже в самой свежей её редакции.
Конечно в каждом конкретном случае надо отдельно оценивать какой вариант даст больше выходы, проводя нагрузочные стрельбы. Отдавать часть вычислений в параллельный воркер и забирать назад действительно дорого, но отдавать инфраструктурные задачи (те же подготовки метрик для Prometheus и API для его обслуживания), отделяя от треда, обслуживающего непосредственно пользовательские запросы выгодно.
Трансфер данных воркерам тоже не бесплатно, и вероятно дороже.
По IPC да, но, к счастью, теперь у нас есть worker threads с более дешёвой коммуникацией через shared memory.
Вынос операции в чанки немного разгрузит event loop от голодания, но не даст настоящей параллельности, мы всё равно будем вынуждены делать все операции в том же потоке. Да, можно скейлить горизонтально, но вынос в отдельный тред эффективнее — само по себе дробление это не бесплатная операция, мы забиваем очереди event loop. Разделив разные операции по разным воркерам мы сможем их эффективно масштабировать. Например, для того же форматирования логов хватит одного воркера при 8 обслуживающих пользовательские запросы и т.д.
Да, но часто на местах лучше видна боль, и, тем более, она лучше видна новичкам, которые совсем недавно видели как оно может быть иначе в другой компании.
Я его и описал выше. Я не могу говорить о реальных кейсах в реальных компаниях — всё это попадает под NDA. Но вот почти так оно всё и было. На самом деле на позиции тимлида/техлида я отчаянно ищу людей, готовых прийти с хорошей полезной идеей и, тем более, внедрить её.
Я не призывал радоваться тому, что есть, наоборот, нужно искать в проблемах возможности для собственного роста.
Стоило добавить, что и с названиями должностей в компании был полный бардак :)
В импорте класса реализации. Мы прошиваем высокоуровневые политики знанием о низкоуровневых. Да, внутри одного слоя мы можем пользоваться прямыми импортами классов, но между слоями такого быть не должно.
Я же привожу в статье точно такой же пример решения через абстрактный класс.
Я привожу ссылку на литературу, ту же самую, на которую ссылается и Фаулер. Речь не идёт о Java, проблема именно в выбрасывании исключения как средстве управления поведением кода.
В отличие от Java мы не можем гарантировать, что потребитель нашего кода напишет обработчик наших исключений. Мы никак не можем декларировать, что наш код выбрасывает исключения определённого типа и они должны быть декларированы.
Потому что в этом случае фреймворк проникнет в домен. Это усложнит написание тестов, это прошьёт код фреймворком и мы не сможем относительно дёшево сбежать с Nest в случае проблем с теми же декораторами.
Достаточно послушать доклады разработчиков. Для них выгодно, чтобы мы оставались потребителем фреймворка, пусть несознательно, но всегда будут гнуть в эту сторону.
Я привожу пример с реализацией гексагонального паттерна, когда бизнес-логика полностью отделена от фреймворка.
В целом не я придумал этот подход, о нём постоянно говорит тот же Роберт Мартин. Фреймворк должен быть всего лишь заменяемой деталью вашей архитектуры.
И, второй вопрос, как поступать в случае контейнеризации? Положить один «большой» процесс с кучей worker_threads в контейнер и поставить балансировщик? Мы хотели двигаться в несколько иную сторону, выделяя каждый процесс (воркер) в отдельный контейнер и масштабируясь контейнерами. Схожий подход описан в Node.js Design Patterns, даже в самой свежей её редакции.
По IPC да, но, к счастью, теперь у нас есть worker threads с более дешёвой коммуникацией через shared memory.