Comments 59
Работал с Nest.js в 2021-2023. Похожее впечатление от него. Потом я присоединился к другому проекту, где заказчику навязали всё сделать на AWS Lambda + MongoDB Atlas, то есть 100% serverless, и я, протестировав в такой среде знакомый Nest.js, как-то приуныл. Жалкий hello world бандлился в сотни килобайт и запускался пол-секунды. А таких лямбда-бандлов предполагалось много (ужасная архитектура в плане времени отклика безотносительно фреймворков, но сейчас речь не об этом).
Короче, решили не брать Nest.js, а запилить всё "прям так". Мы вдобавок ещё и без ORM/ODM обошлись - между JS и MongoDB практически нет impedance mismatch, ради которого стоило бы тащить мапперы. Поначалу я ещё сомневался - куда, мол, без DI и всего такого. Но быстро выяснилось, что так тоже можно, причём с покрытием юнит-тестами около 95%.
Справедливости ради, Nest.js честно навязывает свой подход, как и должен делать opinionated фреймворк. В этом есть плюс по консистентности решений.
Справедливое замечание у вас в конце. Без фреймворка все делают (и ведь делают, увы) "кто во что горазд". А так как было модно все заливать толпами джуниоров - результаты "впечатляют".
В GO кстати похожая ситуация - "зачем нам фреймворки, у нас либы и сейчас мы всё напишем". В итоге умудряются даже два соседних микросервиса написать по-разному.
Ну вы нашли что в лямды тянуть ;)
Не обижайтесь, но тут не нэст плохой, а ваш выбор. Посмотрите Шемсединова у хекслета, где они ноду в целом обсуждают
Я люблю NestJS нежной любовью, но точно могу сказать, что он уродливый монстр
Однако в статье не раскрыто ни одной действительно значащей причины, почему это так
Например:
1) в последние пару лет NestJS не развивается и очень сильно отстал от тенденций развития TypeScript'а
2) в нём не хватает огромного количества базовых вещей: валидация и сериализация, как пример
3) для REST-, WebSocket- и GraphQL-контроллеров фреймворк используют вообще разные подходы, хотя никто не мешал унифицировать
А что вместо него, с DI?
с DI?
Зачем?
Профдеформация. Писать бекенд как Symfony который как Spring. DDD и все такое.
Печально) Попробуйте ради разнообразия скинуть оковы, удивитесь насколько минималистичный и красивый код можно писать, а главное не write-only
Вы отвечаете не на тот вопрос. Получается, DI альтернатив NestJS нет?
Получается, DI альтернатив NestJS нет?
Есть) В других языках, ну или написать свою альтернативу в JS. Но вообще концепция DI чужеродная для JS.
Но если пофигу на производительность, которая ниже плинтуса, кучу лишнего кода, в кайф простые вещи превращать в сложны и т.п., то и нет смысла смотреть на альтернативы, можно дальше "кайфовать" на nestjs и не париться. Ну или просто сменить язык, на такой, где изначально принято что простые вещи должны быть сложными и монструозными.
В ангуляре везде DI как бэ
В ангуляре везде DI как бэ
И что? Это всего лишь ангуляр как бэ. В react, vue, svelte и т.д. и т.п. нет DI как бэ. И вообще в JS проектах в очень сильно подавляющем большинстве случаев нет DI как бэ. Ибо это противоестественно, в целом как и angular, для ценителей с очень специфическими вкусами)
Внедрение зависимостей можно реализовывать по разному. Суть, это предоставление для компонента геттеров, которые позволяют предсказуемо получать экземпляры сервисов. Поэтому и контекст в реакт, и провайд/инжект во вью - это механизмы DI.
Да и в целом, внедрение зависимостей никаким образом не противоестественно использовать в JS программах. Все зависит от реализации.
которые позволяют предсказуемо получать экземпляры сервисов
import { myService } from 'services/service'
Это не предсказуемо? Каждый раз будет какой-то рандомный сервис подсовываться?) Как раз таки через DI мы можем рандомный сервисы пропихивать, вот там да, реально не предсказуемо.
Внедрение зависимостей можно реализовывать по разному
Поэтому и контекст в реакт
Не надо путать DI и контекст выполнения, это разные вещи, он на то и называется контекст, то, что некоторые индивидумы используют как React.Context как DI/стейт менеджер и т.п., это уже сугубо их проблемы и их мировоззрение. По сути контекст в реакте нужен именно для понимания контекста выполнения, а не для того, что в нем были зависимости, которые мы просто можем импортировать.

Да и в целом, внедрение зависимостей никаким образом не противоестественно использовать в JS программах.
import { myService } from 'services/service'
Противоестественно, ведь их можно просто импортировать.
Про то, что тогда в тестах не подсунешь фейковый сервис, извините, для меня ценность таких тестов нулевая. Какой смысл тестировать фейковую программу, которая не будет работать в реальных условиях. Я это уже видел многократно и на разных проектах, ой, у нас зеленые тесты, круто, а прод не работает, как же так. Это все равно что тестировать АПИ просто на то, что код 200 вернулся, значит всё ок. Или отдельно протестировать функции, которые работают по отдельности, а в реальном запросе, когда вызывается цепочка этих функций все идёт по одному месту. Unit тесты уместны только для разработки узко направленных библиотек, а не реальных бизнес проектов где 100500 взаимосвязей, цепочек и сайд эффектов. Для реальных бизнес проектов только ручное тестирование и высокоуровневые e2e тесты канают, остальное детский сад и трата времени в пустую.
Это не предсказуемо? Каждый раз будет какой-то рандомный сервис подсовываться?) Как раз таки через DI мы можем рандомный сервисы пропихивать, вот там да, реально не предсказуемо.
Если речь идет о кодинге на уровне интерфейсов, а не реализации разное поведение сервисов при сохранении интерфейса никак не противоречит работе клиентского кода.
Ваш вариант, это кодинг на уровне реализации. Вы четко зашиваете в коде какую реализацию сервиса вы используете.
Не надо путать DI и контекст выполнения, это разные вещи, он на то и называется контекст, то, что некоторые индивидумы используют как React.Context как DI/стейт менеджер и т.п., это уже сугубо их проблемы и их мировоззрение.
DI и есть, контекст выполнения. Просто по определению. Внедрение зависимостей - вам ни о чем не говорит? Через import вы внедряете их явно, а через, например, контекст реакта вы внедряете их в зависимости от текущих требований к программе.
По сути контекст в реакте нужен именно для понимания контекста выполнения, а не для того, что в нем были зависимости, которые мы просто можем импортировать.
Мы все что угодно можем писать на уровне реализации и импортировать в каждый файл. Именно поэтому и важна семантика.
import { myService } from 'services/service'
Противоестественно, ведь их можно просто импортировать.
Что такое "сервис" в вашей программе по смыслу? Если для вас любой код - это просто модуль. То да, можете его сколько угодно раз импортировать. Но если для вам появляются такие сущности как сервисы, которые должны создаваться по требованию, иметь разные поведения в зависимости разных условий, зависеть от других таких же сервисов, то одних модулей вам не хватит.
Про то, что тогда в тестах не подсунешь фейковый сервис, извините, для меня ценность таких тестов нулевая. Какой смысл тестировать фейковую программу, которая не будет работать в реальных условиях.
А вы не пишите тесты ради тестов. В частности, а что тогда тестирует такой тест, если он не работает в реальных условиях?
Тест как раз и должен отражать поведение в реальных условиях. А как этого добиться подходы могут быть разные.
Unit тесты уместны только для разработки узко направленных библиотек, а не реальных бизнес проектов где 100500 взаимосвязей, цепочек и сайд эффектов.
Очень грустненько, если вы так думаете.
Для реальных бизнес проектов только ручное тестирование и высокоуровневые e2e тесты канают, остальное детский сад и трата времени в пустую.
Это как? Прокликиваете всю программу, когда меняете одну фичу?)
Очень грустненько, если вы так думаете.
Увы, розовых очков не ношу, я реалист и знаю как всё устроено.
Но если для вам появляются такие сущности как сервисы, которые должны создаваться по требованию, иметь разные поведения в зависимости разных условий, зависеть от других таких же сервисов, то одних модулей вам не хватит.
Мне нет) И никогда) Я не усложняю простые вещи ради усложнения ни при каких условиях. Я порицаю такой подход. KISS и YAGNI наше все. У меня все всегда предельно очевидно и просто.
DI и есть, контекст выполнения
Dependency - это зависимость. Допустим для хэндлера GET /me
мне нужен коннект к базе данных, это и есть зависимость(dependency).
Контекст это некая сущность, например объект, который рождается в момент получения того же запроса GET /something
и проходит через всю цепочку промежуточных функций, например в этом объекте есть информация о том, авторизован ли пользователь, какая у него и т.п. А когда запрос завершается и мы отправляет ответ, то этот контекст умирает. А вот наша зависимость, например коннект к базе данных не умирает, он живёт всегда пока наше приложение поднято и не является чем-то уникальным для каждого конкретного запроса.
Ваш вариант, это кодинг на уровне реализации. Вы четко зашиваете в коде какую реализацию сервиса вы используете.
Разумеется, ибо это максимально очевидный, наглядный и простой подход. Никаких загадок, всё строго и понятно, всем всегда и сразу.
Мы же не говорим про библиотечные методы и их разработку, где условно интерфейс Stream у сети и файловой системы может совпадать. Мы говорим о разработке конкретных приложений с бизнес логикой.
Мне нет) И никогда) Я не усложняю простые вещи ради усложнения ни при каких условиях. Я порицаю такой подход. Я порицаю такой подход. KISS и YAGNI наше все. У меня все всегда предельно очевидно и просто.
После ваших откровений про модульные тесты, меня это совершенно не удивляет. Если для вас 100500 зависимостей и сайд эффектов причина по которой вы не можете написать выразительные тесты для тестирования корректного поведения модуля, то, очевидно, перед вами такие задачи уже стояли, но вы не смогли дать удобное и понятное решение. Видимо поэтому, вы решили от этих задач отказаться, или нет?
Вы понимаете, просто для примера, что ручное тестирование всего и вся только потому, что вы не смогли победить сложность 100500 зависимостей и сайдэффектов и спроектировать систему, которую можно модульно протестировать на корректность - это характеристика вашей системы?
Вы правильно заметили, что для "узкоспециализированных" библиотек нужны юнит тесты, только вот именно ваши прямые руки и голова помешают вам ваше приложение так же спроектировать, что бы оно состояло из узкоспециализированных частей, которые можно и все таки нужно тестировать на корректность не запуская долгий процесс e2e или ручного тестирования.
Dependency - это зависимость. Допустим для хэндлера GET /me мне нужен коннект к базе данных, это и есть зависимость(dependency).Контекст это некая сущность, например объект, который рождается в момент получения того же запроса GET /something и проходит через всю цепочку промежуточных функций, например в этом объекте есть информация о том, авторизован ли пользователь, какая у него и т.п. А когда запрос завершается и мы отправляет ответ, то этот контекст умирает. А вот наша зависимость, например коннект к базе данных не умирает, он живёт всегда пока наше приложение поднято и не является чем-то уникальным для каждого конкретного запроса.
А для чего вы все это написали? По вашей логике, вот нужен вам коннект к БД и вы импортируете что-то из какого то модуля, да? А потом, типа это убирается? Потом идет снова запрос и снова убирается? А в случае с сервисом на все запросы к БД уже создан один раз сервис? Так? Т.е. в вашем случае коннект создается 1000 раз, а в альтернативном один раз? И что в этом плохого?
Я действительно не понял посыл всего этого.
Разумеется, ибо это максимально очевидный, наглядный и простой подход.
Для чего? Я когда писал, просто размышлял о задачах, которым это может потребоваться. Вы хотите сказать, что никогда ни для кого не было и не будет задач, которым это может потребоваться? Если да, то сильное заявление. В противном случае, вы держите в голове какие-то свои задачи, которым ваш подход действительно дает ощутимую пользу. Т.е. без описания задачи это просто один из подходов. Можно или не нужно так делать, очевидный/наглядный/простой - это уже все будет зависеть только от задачи.
Мы же не говорим про библиотечные методы и их разработку, где условно интерфейс Stream у сети и файловой системы может совпадать. Мы говорим о разработке конкретных приложений с бизнес логикой.
Нет, мы ни о каких конкретных приложениях не говорим. Мы в общем рассуждаем какие могут быть задачи и какие могут быть решения.
Ваше решение имеет место быть. Полно задач, которым оно хорошо подходит. Но на этих задачах мир клином не сошелся. Я со своей стороны так же не утверждаю, что прям обязательно любое приложение должно использовать определенный набор технологий вот они. Нет.
Не можете справится с модульным тестированием? Считаете что оно не дает вам уверенности? Хотите все делать максимально просто, а потом перекладывать все на монструозное e2e? Так тоже можно.
Напоминаю, началось все с:
В react, vue, svelte и т.д. и т.п. нет DI как бэ. И вообще в JS проектах в очень сильно подавляющем большинстве случаев нет DI как бэ.
На что я просто указал, что это чепуха. А уж приплетать сюда js было просто ни к селу ни к городу.
Если для вас 100500 зависимостей и сайд эффектов причина по которой вы не можете написать выразительные тесты для тестирования корректного поведения модуля
Это причина, по которой unit тестами, тестируя отдельные функции, а не приложение целиком невозможно добиться того, чтобы тесты реально могли отражать тот факт, что приложение работает. Поэтому верхнеуровневые e2e тесты и ручное тестирование это единственное что может дать гарантии в реальном мире. Ибо мы говорим не про библиотеку.
очевидно, перед вами такие задачи уже стояли, но вы не смогли дать удобное и понятное решение
Почему же? У меня все прекрасно работало и работает, просто я тестирую приложение верхнеуровнево и эти тесты сразу же охватывают всё. Я экономлю кучу времени, я занимаюсь разработкой, а не работаю тестировщиком вместо этого) Решение по мне очень удобное и понятное. Ты проверяешь конкретно работу АПИ, а не фантики в которые подсовываются фейковые данные, фейковые модули т.п.
Видимо поэтому, вы решили от этих задач отказаться, или нет?
Нет, зачем от них отказываться, просто для меня они не являются проблемой, ибо я следую KISS и YAGNI и у меня сложность не умножается в 10раз, а равна по сути сложности бизнес логики, т.е. мой коэффициент сложности приложения около 1, т.е. всё всегда максимально просто, насколько это возможно для данной бизнес логики приложения. А вот если бы я использовал nest, orm и ещё 100500 лишних переусложненный и абстракций, то коэффициент сложности уже был бы 10 и выше.
Вы понимаете, просто для примера, что ручное тестирование всего и вся только потому, что вы не смогли победить сложность 100500 зависимостей и сайдэффектов и спроектировать систему, которую можно модульно протестировать на корректность - это характеристика вашей системы?
Никто не говорит что ручное тестирование на каждый чих, мы говорим о комплексном тестировании, где мы реально может гарантировать корректную работу. А это совокупность e2e + ручное, опять же под ручным я имею ввиду не в ручную АПИ тыкать, а смотреть сразу связку клиент сервер. Ну опять же, я то 100500 зависимостей побеждаю, потому что e2e, а вот unit'ами их просто невозможно победить, ну либо вся ваша работа будет в написании бесконечных тестов) И потом при изменении бизнес логики лавинообразное падении тысячи unit тестов, вместо падения от силы десятка e2e) Посчитайте насколько проще и быстрее e2e подправить и на сколько тысячи упавших юнитов)
Вы правильно заметили, что для "узкоспециализированных" библиотек нужны юнит тесты, только вот именно ваши прямые руки и голова помешают вам ваше приложение так же спроектировать, что бы оно состояло из узкоспециализированных частей, которые можно и все таки нужно тестировать на корректность не запуская долгий процесс e2e или ручного тестирования.
Если отбросить реальность и жить в розовом мире, где бизнес логика приложения простая как 2х2, и максимум сложности там это просто CRUD, то да, вообще легко. Но блин, реальность просто не дает такой возможности.
А для чего вы все это написали? По вашей логике, вот нужен вам коннект к БД и вы импортируете что-то из какого то модуля, да? А потом, типа это убирается? Потом идет снова запрос и снова убирается?
Нет, наоборот, коннект живёт всегда, и не привязан к жизненному циклу запроса. Этим dependency и отличается от context.
Т.е. в вашем случае коннект создается 1000 раз, а в альтернативном один раз? И что в этом плохого?
Да нет же, он именно 1 раз создается и живёт всегда. Потому что это зависимость. А контекст создается и умирает вместе с каждым запросом.

Для чего? Я когда писал, просто размышлял о задачах, которым это может потребоваться. Вы хотите сказать, что никогда ни для кого не было и не будет задач, которым это может потребоваться? Если да, то сильное заявление. В противном случае, вы держите в голове какие-то свои задачи, которым ваш подход действительно дает ощутимую пользу. Т.е. без описания задачи это просто один из подходов. Можно или не нужно так делать, очевидный/наглядный/простой - это уже все будет зависеть только от задачи.
Я не беру в расчет 0.01% от всех задач, которые мы решаем в 99.99% случаев, в них моего подхода более чем достаточно и он с головой себя оправдывает. Но да, может однажды в карьере появиться задача в которой, в которой DI действительно будет лучше, но шанс что такая задача встанет, крайне мал, поэтому и существует принцип YAGNI.
Ваше решение имеет место быть. Полно задач, которым оно хорошо подходит. Но на этих задачах мир клином не сошелся.
Согласен, просто таких задач подавляющее большинство. Но не абсолютные 100%, да. Я исхожу чисто из разряда статистической реальности, только и всего.
Я со своей стороны так же не утверждаю, что прям обязательно любое приложение должно использовать определенный набор технологий вот они
Логично, только если будет реально в этом потребность, в противном случае это будет во вред. Просто многие люди даже не пытаются думать, они сразу бездумно берут некий набор и на нем фигачат всё что угодно) Увидели что в каких-то вакансиях написано NestJS, значит только по этой причине они будут его брать. Увы и ах, люди такие люди)
Не можете справится с модульным тестированием? Считаете что оно не дает вам уверенности? Хотите все делать максимально просто, а потом перекладывать все на монструозное e2e? Так тоже можно.
Когда я пишу библиотеки, то легко справляюсь unit'ами и они там идеально подходят и вообще must have, но в приложениях для бизнеса я не могу им довериться сильнее чем e2e, плюс e2e дает мне гораздо больше свободы в плане того как я могу писать код. Код мне важнее тестов и скорости тестов) Пусть моё приложение будет быстрым, а тесты не самыми быстрыми, чем наоборот, приложение будет медленным, а тесты быстрыми)
Это причина, по которой unit тестами, тестируя отдельные функции, а не приложение целиком невозможно добиться того, чтобы тесты реально могли отражать тот факт, что приложение работает.
Не нужно подменять понятия. Модульный тест тестирует конкретную функциональность и он должен дать уверенность в корректной работе этой функциональности. Поэтому причем тут приложение целиком?
Поэтому верхнеуровневые e2e тесты и ручное тестирование это единственное что может дать гарантии в реальном мире. Ибо мы говорим не про библиотеку.
Гарантии чего? Назначение модульного теста фичи и e2e теста различное. Они используются на разных этапах разработки ПО.
Почему же? У меня все прекрасно работало и работает, просто я тестирую приложение верхнеуровнево и эти тесты сразу же охватывают всё.
Вот именно поэтому.
Я экономлю кучу времени, я занимаюсь разработкой, а не работаю тестировщиком вместо этого)
Да вроде как вы как раз и описываете работу для тестировщика. К е2е тестам предъявляются требования реализация, которых разработчику совсем не обязательна для решения задачи. Если же вы пишете именно такие тесты, то вы явно тянете на себя одеяло.
Решение по мне очень удобное и понятное. Ты проверяешь конкретно работу АПИ, а не фантики в которые подсовываются фейковые данные, фейковые модули т.п.
Я об этом уже говорил выше. Задачи бывают разные. Никакие конкретные задачи мы не обсуждаем. Поэтому вполне возможно, что у вас удобно и понятно. Никто не спорит.
Нет, зачем от них отказываться, просто для меня они не являются проблемой, ибо я следую KISS и YAGNI и у меня сложность не умножается в 10раз, а равна по сути сложности бизнес логики, т.е. мой коэффициент сложности приложения около 1, т.е. всё всегда максимально просто, насколько это возможно для данной бизнес логики приложения. А вот если бы я использовал nest, orm и ещё 100500 лишних переусложненный и абстракций, то коэффициент сложности уже был бы 10 и выше.
Очень может быть. Вы это все к тому, что у всех остальных разработчиков ровно те же самые задачи, что и у вас? Вот сомневаюсь я.
Никто не говорит что ручное тестирование на каждый чих, мы говорим о комплексном тестировании, где мы реально может гарантировать корректную работу. А это совокупность e2e + ручное, опять же под ручным я имею ввиду не в ручную АПИ тыкать, а смотреть сразу связку клиент сервер.
Корректную работу чего? Фичи? Подсистемы? Кто имеет право менять эти тесты? Где они лежат? Тестировщик так же с ними работает? Или у вас идет дублирование, когда и тестировщики и разработчики делают по сути одно и тоже, но в разных репозиториях? Беря на себя функции тестировщиков как вы с ними делите обязанности?
Ну опять же, я то 100500 зависимостей побеждаю, потому что e2e, а вот unit'ами их просто невозможно победить, ну либо вся ваша работа будет в написании бесконечных тестов) И потом при изменении бизнес логики лавинообразное падении тысячи unit тестов, вместо падения от силы десятка e2e) Посчитайте насколько проще и быстрее e2e подправить и на сколько тысячи упавших юнитов)
Если мы начинаем касаться изменения бизнес логики, то это уже точно про архитектуру. А это означает, что какие-то изменения должны быть предвидены, а значит и ПО написанное по контракту не будет требовать переписывания целых подсистем и тестов.
Если отбросить реальность и жить в розовом мире, где бизнес логика приложения простая как 2х2, и максимум сложности там это просто CRUD, то да, вообще легко. Но блин, реальность просто не дает такой возможности.
Неужели? А вас почитаешь и ни за что так и не подумаешь.
Да нет же, он именно 1 раз создается и живёт всегда. Потому что это зависимость. А контекст создается и умирает вместе с каждым запросом.
Так я у вас и спрашиваю, кто и что у вас живет и умирает? Если у вас коннект, живет всегда, то что мешает сервису? Или что? Я вообще не понимаю, что вы хотите сказать.
Я не беру в расчет 0.01% от всех задач, которые мы решаем в 99.99% случаев, в них моего подхода более чем достаточно и он с головой себя оправдывает. Но да, может однажды в карьере появиться задача в которой, в которой DI действительно будет лучше, но шанс что такая задача встанет, крайне мал, поэтому и существует принцип YAGNI.
Ну, т.е. вы, все таки, говорите только про себя?
Согласен, просто таких задач подавляющее большинство. Но не абсолютные 100%, да. Я исхожу чисто из разряда статистической реальности, только и всего.
Если их подавляющее большинство дайте тогда какое-нибудь исследование на эту тему. А то на деле все как то наоборот. Мощные вреймворки не то что не умирают, а наоборот набирают популярность с новой силой.
Логично, только если будет реально в этом потребность, в противном случае это будет во вред. Просто многие люди даже не пытаются думать, они сразу бездумно берут некий набор и на нем фигачат всё что угодно) Увидели что в каких-то вакансиях написано NestJS, значит только по этой причине они будут его брать. Увы и ах, люди такие люди)
Вот это называется вода. Где-то что-то кто-то зачем-то когда-то взял, так делать не надо. Вот что вы только что сказали.
Когда я пишу библиотеки, то легко справляюсь unit'ами и они там идеально подходят и вообще must have, но в приложениях для бизнеса я не могу им довериться сильнее чем e2e, плюс e2e дает мне гораздо больше свободы в плане того как я могу писать код. Код мне важнее тестов и скорости тестов) Пусть моё приложение будет быстрым, а тесты не самыми быстрыми, чем наоборот, приложение будет медленным, а тесты быстрыми)
Мы уже это проходили, выглядит как характеристика вашего ПО. Если для вас тут проблемы нет, значит все замечательно. Но вот так вот без конкретных задач - это просто информация к размышлению, что где-то как-то может быть работает.
Не нужно подменять понятия. Модульный тест тестирует конкретную функциональность и он должен дать уверенность в корректной работе этой функциональности. Поэтому причем тут приложение целиком?
Ну вот я делаю запрос POST /api/v1/goods
с разными параметрами, позитивными и негативными, это не unit тесты. А таких методов допустим 50 и вот для каждого метода написанные такие тесты, вот они и покрывают всё приложение целиком.
Гарантии чего? Назначение модульного теста фичи и e2e теста различное. Они используются на разных этапах разработки ПО.
Гарантии того, что условный метод POST /api/v1/car
будет работать исправно. А не так, что функции по отдельности которые участвуют в работе этого метода работают исправно, но при реальном запросе что-то идёт не так. И я одним тестом по сути закрываю сразу условно 10 тестов, 10 тестами этого мета, закрываю условно 100 unit тестов для этого метода)
Очень может быть. Вы это все к тому, что у всех остальных разработчиков ровно те же самые задачи, что и у вас? Вот сомневаюсь я.
Нет конечно, но чисто статистически в 99.9% они у всех разработчиков бэкенда REST API плюс минус схожи. И для них вообще не нежно никакое DI. Вот в чем цимус.
Беря на себя функции тестировщиков как вы с ними делите обязанности?
Не, в идеале это просто делает автотестер, но мы говорим про абстракную ситуацию где разработчик тестирует, вот я говорю как я тестирую АПИ.
Если мы начинаем касаться изменения бизнес логики, то это уже точно про архитектуру. А это означает, что какие-то изменения должны быть предвидены, а значит и ПО написанное по контракту не будет требовать переписывания целых подсистем и тестов.
А это смотря как изменяется бизнес логика, она может незначительно меняться, а может конкретно, так что тут воля случая.
Так я у вас и спрашиваю, кто и что у вас живет и умирает? Если у вас коннект, живет всегда, то что мешает сервису? Или что? Я вообще не понимаю, что вы хотите сказать.
То, что для вас context и dependency это одно и то же, а это разные вещи.
Если их подавляющее большинство дайте тогда какое-нибудь исследование на эту тему. А то на деле все как то наоборот. Мощные вреймворки не то что не умирают, а наоборот набирают популярность с новой силой.
Хоть 1 задача в которой будет божественен NestJS, и обосрется Express?
Ну вот я делаю запрос POST /api/v1/goods с разными параметрами, позитивными и негативными, это не unit тесты. А таких методов допустим 50 и вот для каждого метода написанные такие тесты, вот они и покрывают всё приложение целиком.
Если вы для тестирования какой-то функциональности поднимаете все подсистемы, которые задействованы в сценарии и пробегаетесь по сценарию от начала и до конца - это e2e.
Гарантии того, что условный метод POST /api/v1/car будет работать исправно. А не так, что функции по отдельности которые участвуют в работе этого метода работают исправно, но при реальном запросе что-то идёт не так. И я одним тестом по сути закрываю сразу условно 10 тестов, 10 тестами этого мета, закрываю условно 100 unit тестов для этого метода)
Как я уже говорил, у модульных тестов несколько целей. Одна из них - это проверка корректности при разработке. Модульные тесты можно использовать и при отладке.
е2е - это неудобный инструмент для этих целей. Я подозреваю, что речь идет о тестах, которые написаны уже после того как написан код.
Нет конечно, но чисто статистически в 99.9% они у всех разработчиков бэкенда REST API плюс минус схожи. И для них вообще не нежно никакое DI. Вот в чем цимус.
Я не знаю о какой статистике вы говорите. Во первых, как я уже говорил Ваша статистика до сих пор не отменила ни одного фрейворка ни для одного языка. Какие-нибудь Ларавелы, Симфони никуда не исчезли, а наоборот получают новые версии и проекты. Это раз. Во вторых, какое это имеет отношение к той ерунде сказанной о DI с которой все началось?
Что это за статистика?
Не, в идеале это просто делает автотестер, но мы говорим про абстракную ситуацию где разработчик тестирует, вот я говорю как я тестирую АПИ.
Разработчик разрабатывает. И тесты - это такой же инструмент разработки как и все другие. Это автоматизированный инструмент проверки корректности модуля. Если смотреть на тесты именно с этой стороны, то разработчику нужен удобный инструмент, удобная архитектура, которая позволит удобно задавать состояния связных систем, что бы проверить все состояния разрабатываемого модуля. Разработчику не нужно проверять корректность всех остальных модулей, поэтому никаких причин иметь запущенные боевые версии всех подсистем у него нет.
А вот e2e как раз и позволяет проверять совместную работу боевых систем. Только вот для этого уже быть разработаны модули, корректность работы которых проверена.
А это смотря как изменяется бизнес логика, она может незначительно меняться, а может конкретно, так что тут воля случая.
Нет, тут не воля случая. Разрабатывая велосипед вам вдруг не нужно будет переделывать его в ракету. А если это произошло - это уже проблема, которую нужно решать не на уровне написания кода, а на уровне разработки приложения, когда обсуждаются бизнес требования.
То, что для вас context и dependency это одно и то же, а это разные вещи.
Это разные вещи, если вы говорите про конкретные реализации в языке, фрейворке и т.п. Но я сразу обозначит о чем идет речь. Соответствующие подсистемы Реакт и Вью как раз и нужны для того, что бы внедрять в компоненты зависимости. Что бы вы не внедряли - это уже само по себе отделяет поставщика от потребителя. Всегда. Вы можете сделать как хотите, т.е. кодить на уровне реализации, а можете внедрять соответствующие интерфейсы.
Это два подхода, выбирайте, который удобнее. И они оба сейчас есть повсеместно. Это не выдумка, не попытка натянуть сову на глобус - это уже просто есть.
Хоть 1 задача в которой будет божественен NestJS, и обосрется Express?
Так у меня не стоит задачи сравнивать в вакууме два фрэймворка. Но, из того как вы поставили вопрос следовать может все что угодно. Например, Nest дает определенный подход к организации файловой структуры. А так как Express подобного не предлагает, легко превратить приложение в файл-помойку. Все зависит от разработчика.
Какие-нибудь Ларавелы, Симфони никуда не исчезли, а наоборот получают новые версии и проекты
Это вообще даже близко не говорит о том, что это не гуано. У нас как бы до сих пор продают ниву которая со времен 80ых. И что теперь, это значит что она лучше крузака?)
Во вторых, какое это имеет отношение к той ерунде сказанной о DI с которой все началось?
Код без DI чище и приятнее, это как минимум.
Только вот для этого уже быть разработаны модули, корректность работы которых проверена.
Ну да, я и разрабатываю модули сразу чтобы они корректно работали, в противном случае это просто промежуточная дев версия в стадии разработки.
Все зависит от разработчика.
Вот это самое главное, в прямых руках nest и ему подобное тупо мешает и вставляет палки в колеса.
Валидация и сериализация есть из коробки
https://docs.nestjs.com/techniques/validation
https://docs.nestjs.com/techniques/serialization
Под капотом class-validator и class-transformer
+ декораторы openapi
NEST.js — уродливый монстр или мощный энтерпрайз?
Однозначно уродливый и крайне медленный монстр.
Тоже отказались от него, спустя 3 года. Ад конфликтующих зависимостей, куча откровенного мусора в node modules (каким-то образом туда даже попадали фротнэндовые библиотеки) плюс баги в graphql federation. Обновление до следующей версии каждый раз эти танцы с бубном. Использование rxjs в каждом углу не впечатляло, когда можно было обойтись обычным декоратором. Доходило до абсурда - когда для добавление аутентификации по jwt устанавливался пасспорт, jwt библиотека и обертка пасспорт под nestjs с кучей бойлерплейт кода, на тот момент это была рекомендуемая ими конфигурация. А всего-то кода там на 5 строчек без этой требухи. Хотя надо признаться, что другого такого универсального фреймворка под ноду нет. В итоге взяли «низкоуровневые» библиотеки, добавили немного вокруг них обвязки для удобства, и с этим благополучно живем.
Сразу скажу, что вижу в статье определенную пользу. Но понять смысл некоторых вещей мне с лету не удалось, поэтому оставлю несколько вопросов и предложений.
Плюс — это язык строго типизированный
TS тоже строго типизированный. То, что там типизация структурная этого не отменяет. Единственное, что нарушает строгую типизацию - это повсеместное использование any. Скорее всего, вы имете в виду противопоставление структурной и явной типизации.
Эти особенности порождают всякие специфические концепции и паттерны, типа SOLID, где часть про интерфейсы слабо применима к TypeScript или Golang.
Что тут вы имеете в виду вообще не понял. Нужно больше контекста.
Или вот паттерн Singletone – вещь абсолютно бессмысленная в JS/TS.
Такая же фигня. Нужно больше контекста. Просто по определению, паттерн проектирования любой - это описание задачи, решение задачи и разбор плюсов, минусов. При этом реализация на конкретном языке может быть разная с учетом этого языка.
Импортированный файл (модуль) – всегда singletone и если вы в модуле вместо класса экспортировали его экземпляр, то это тоже автоматически singletone.
Тут тоже больше контекста нужно. Всем этим вы что хотели сказать? Понятно, что на js любой литерал объекта уже сингтон, но сам паттерн синглтона в конкретном фреймворке вместе с другими паттернами позволяет получить однообразный, предсказуемый способ создания конкретного экземпляра по требованию. Иными словами, вот нужен вам какой-то сервис и он создается ровно когда вы к нему обращаетесь, а не сразу когда вы его импортируете из файла. Иными словами какие задачи решают "singletone" которые вы привели?
В результате вся эта стилистика, напоминающая Spring мало уместна в JS и не способна ничего дать, кроме ложного ощущения причастности к большому “энтерпрайзу”.
Не понял как вы к этому выводу пришли. Ну да, структурная типизация. Ну, да все синглтоны. А когда то вообще TS не было и все, то что сейчас пишут на TS, сильно короче могли написать на JS.
Как мешает излишняя сложность?
Т.е. все что вам мешает - это не высокий порог входа. Не избыточное количество обслуживающего кода. А проблемы с map файлами и проблемы с зависимостями пакетов? Как то это все не сильно связано со всем тем текстом, который шел до этого.
По моему, статья как то слишком сумбурно написана и важные вещи так и остались лиш схематично обозначенными. И вместо этого, часть текста просто переливание из пустого в порожнее.
Скорее всего, вы имете в виду противопоставление структурной и явной типизации.
я думал "явная", это когда надо указывать тип переменной при инициации (он не выводится из присвоения). Я имел в виду - когда отсутствует приведение типов, вроде это называют "сильной" или "строгой" типизацией
Что вы имеете в виду про SOLID.
Принцип Interface segregation из SOLID рекомендует использовать много специализированных интерфейсов вместо одного обобщённого. Для того, чтобы "скармливать" методам более разнообразные данные в условиях сильной типизации. Ту же самую задачу решает структурная типизация, применяемая и в TS и в Go. Т.е. интерфейс "сегрегировать" можно, но при этом его можно не имплементировать вообще
Singletone - переводится как "одиночка", а любой импорт в JS'e импортируется один раз, а объекты передаются по ссылке, автоматически оставаясь одиночками. Именно его "одиночность" я и имею в виду
сервис создается ровно когда вы к нему обращаетесь
В принципе, вы правы, просто мне привычнее такое называть "ленивой загрузкой" / deffered / или on-demand. Но если смысл синглтона именно в отложенной инициации, то он имеет смысл и в JS. Но тогда выходит, что его применение другое и более редкое
А когда то вообще TS не было ... сильно короче могли написать на JS.
Ну вот TS, как мне кажется, полезен и решает задачи, которые голый JS не может решить в принципе, а имитация сильной типизации из Джавы уже никаких дополнительных задач не решает.
Т.е. все что вам мешает - это не высокий порог входа. Не избыточное количество обслуживающего кода а...
Вы совершенно правы, для меня это серьёзное препятствие для внедрения. Постеснялся это написать из-за определённой субъективности - некоторым почему-то нравится показная сложность
некоторым почему-то нравится показная сложность
Никогда не понимал и не пойму таких людей, которые элементарные вещи усложняют так, что без бутылки не разберешься. Скорее всего это обусловлено банально их невежеством и не понимаем самой сути происходящего, что именно мы должны сделать скажем для обработки запроса. Казалось бы, пришел запрос GET /api/users?limit=100
, ну что может быть проще
0) Провалидируй входные данные
1) Сделай запрос в БД
2) Отдай ответ в виде JSON
Почему некоторые индивидуумы эту процедуру превращают в 7 кругов ада? И с умным видом говорят что они делают все правильно. Загадка.
я думал "явная", это когда надо указывать тип переменной при инициации (он не выводится из присвоения). Я имел в виду - когда отсутствует приведение типов, вроде это называют "сильной" или "строгой" типизацией
Приведение типов тут ни при чем. Вы имели в виду сопоставление номинальной и структурной типизации. При номинальной типизации тип берется из объявления/имени типа. Таким образом если объявления типов не совпадают, то считается, что типы разные. При структурной типизации при проверке типов проверяется структура, а не объявление. У меня просто из головы вылетело слово "номинальная", поэтому я так и сказал. Но и в том и другом случае, типизация строгая, т.е. нельзя переменной одного типа назначить другой тип. В JS типизация не строгая, поэтому вполне можно переменной хранящий, например, число присвоить строку.
Принцип Interface segregation из SOLID рекомендует использовать много специализированных интерфейсов вместо одного обобщённого. Для того, чтобы "скармливать" методам более разнообразные данные в условиях сильной типизации.
Солид он про смысл того, что вы делаете. И данный принцип в первую очередь про то, что бы было понятно какую задачу выполняет данный интерфейс. Например
interface InputProps {
label?: string
value?: string
onChange?: (v: string) => void
}
Это нам мало о чем говорит. Но вот если мы предположим, что нам нужен был управляемый и неуправляемый компонент Input, тогда мы можем этот интерфейс разделить
interface InputControlledProps {
label?: string
value: string
onChange: (v: string) => void
}
interface InputUnControlledProps {
label?: string
initialValue?: string
onChange?: (v: string) => void
}
type Props = InputControlledProps | InputUnControlledProps
А можно пойти дальше, и сделать два компонента и у каждого будет свой интерфейс. Вот про это Солид.
Ту же самую задачу решает структурная типизация, применяемая и в TS и в Go. Т.е. интерфейс "сегрегировать" можно, но при этом его можно не имплементировать вообще
Сама по себе структурная типизация тут вообще ни при чем.
В принципе, вы правы, просто мне привычнее такое называть "ленивой загрузкой" / deffered / или on-demand. Но если смысл синглтона именно в отложенной инициации, то он имеет смысл и в JS. Но тогда выходит, что его применение другое и более редкое
Загружаться они все могут сразу, а вот инициализироваться именно по требованию. Это и есть on-demand. Оно не редкое, поэтому я и говорю, что нужно навалить контекста.
Ну вот TS, как мне кажется, полезен и решает задачи, которые голый JS не может решить в принципе, а имитация сильной типизации из Джавы уже никаких дополнительных задач не решает.
Я подозреваю, что тут вы имеете в виду решение определенных задач крупного приложения. И тогда вполне резонно, что вашему приложению, команде, бизнесу такие решения задач не подходят.
Вы совершенно правы, для меня это серьёзное препятствие для внедрения. Постеснялся это написать из-за определённой субъективности - некоторым почему-то нравится показная сложность
Какая же она показная, если это реальная сложность? Когда вы берете фреймворк уровня приложения, то очевидно должны разобраться с теми концепциями, которые лежат в его основе. Потом с реализациями этих концепций. При этом держать в голове, а нужно ли вообще в вашем приложении все это.
очень хочется увидеть не большой пример проекта с нест и без нест пусть на REST, так как проблемы неста многие узнают после 3х месяцев разработки, но альтернатива - это писать свой мини нест, и это обычно стопорит и народ остается в нест, до тех пор пока в проекте не происходит смены лида с текущего на некого джун+ который просто выкидывает нест и пишет свой набор велосипедов под конкретный проект
в итоге в этот проект сложно нанимать людей, так как никто не хочет заниматься нонейм великом
и когда этот горе джун+ уходит через пол года компании приходится как-то жить с этим великом долго
можешь сделать репозиторий в гитхаб, монорепа где два проекта с нест и без нест?
Ну оптимальным REST я считаю Fastify+TypeScript+Knex, организация кода в парадигме DDD, в гитхаб пока не выкладывал. У меня была мысль написать про DDD+Fastify. После вашего комента вероятно придётся сделать еще и на гитхабе scaffold-проект. Для НЕСТа честно, говоря не планировал поскольку для себя считаю его бесперспективным и возвращаться к нему не хочется.
который просто выкидывает нест и пишет свой набор велосипедов под конкретный проект
в итоге в этот проект сложно нанимать людей, так как никто не хочет заниматься нонейм великом
Т.е. выкинуть уродца nest, заменить на express/fastify/koa/hapi это всё, фиаско?))) Так делают только дурачки и т.п.?
можешь сделать репозиторий в гитхаб, монорепа где два проекта с нест и без нест?
Есть такая штука, называется мысленный эксперимент. Неужели не очевидно как будет выглядеть код на nest и на fastify/express и т.п. Ведь судя по вашим рассуждениям, где вы называете тех, кто пишет инструменты - "свой набор велосипедов", "с которым никто не хочет заниматься нонейм великом" и в этом духе, значит вы настолько шикарный специалист(который не сможет написать аналог express/nest и т.п., но зато в первых рядах высмеивает тех, кто может) что для вас это не должно составить никакого труда, просто закрыл глаза и сразу код перед тобой.
Свой велосипед любой может написать, в этом ничего сложного нет
Просто нужно учитывать то как потом людей искать на проект, и как люди после велосипеда будут работу искать
Нест дает архитектуру и некий стандарт по написанию кода
Я как работник приходя в контору с нестом сразу могу приступить к работе, мне не нужно изучать как использовать велосипед, и тем более как в нём реализовывать что то новое которое не вписывается в текущую архитектуру и нужно будет сидеть ломать голову придумывать и тратить время, а контора не очень любит оплачивать такие вещи и придётся быстро на коленке чет накостылить
Я как контора при найме людей предпочту специалистов у которых в голове уже есть некая структура и они не будут тратить время на изобретение и починку своих велосипедов, и мне нужно чтобы человек максимально быстро начал разрабатывать бизнес функционал и легко вошёл в текущий процесс разработки
А пример я просил, так как если человек написал некий свой мини нест, то не грех бы им поделится, а не просто говорить что выкинули нест и стало круто, а может и не выкинули, или проект был очень маленький и на мини несте не выйдет красиво написать чет большое с кучей микро сервисов
Свой велосипед любой может написать, в этом ничего сложного нет
Ну да ну да, знаем мы таких, с таким мышлением. Это же стандартная психология, сам не способен - критикуй тех, кто способен и таким образом думай что ты лучше.
Ваш любимы нест, такой же велосипед, очнитесь, посмотрите на историю языков и их фреймворков/библиотек.
Все "проблемы" которые "решает" нест уже были решены за многие годы до его появления многими другими языками, а если про Nodejs говорить, то express/koa/hapi решили всё это за долго до появления нест.
Просто нужно учитывать то как потом людей искать на проект, и как люди после велосипеда будут работу искать
Вы рассуждаете как на 0% программист и как на 100% промысловик.
Нест дает архитектуру и некий стандарт по написанию кода
Отвратительную архитектуру
Отвратительный "стандарт" по написанию говнокода максимально громоздкого и переусложенного
Нест даёт отвратительную производительность, она просто ничтожная. Но с другой стороны промысловикам на это начхать, им главное чтобы ЗП платили, а остальное не важно.
Да, по истине хороший инструмент конечно.
Я как работник приходя в контору с нестом сразу могу приступить к работе
Т.е. придя на проект где есть Express/Fastify вы не сможете приступить к работе?)) Ведь эти инструменты максимально простые и покрывают 1000% сценариев.
мне не нужно изучать как использовать велосипед
Зачем промысловику вообще понимать что как устроено, как вообще можно реализовывать те или иные аспекты.
и тем более как в нём реализовывать что то новое
Разумеется, ведь для промысловика реализовать что-то самому это из разряда не возможного, всё что умеет промысловик это взять библиотеку, а если такой библиотеки нет, то промысловик тут бессилен и просто меняет работу.
которое не вписывается в текущую архитектуру
Что?)) С чего вы это вообще решили? Что вы вообще знаете об архитектуре?)
и нужно будет сидеть ломать голову придумывать и тратить время
Слова истинного промысловика
а контора не очень любит оплачивать такие вещи
Зато любит оплачивать нест, где разработка идёт в 2-3 раза медленнее чем с Express, а ещё надо в 2 раза больше мощностей чтобы выдержать ту же нагрузку что express. И кого вместо проекта в проде через пол года, контора получаем проект в проде через полтора года, вместо проекта силами 1 разраба, получаем проект силами 3-5 разрабов. Че-то математика вообще не сходится.
6мес 400к = 2.4млн
18мес * 3чел по 400к = 21.6млн
Вообще не сходится на порядок
Я как контора при найме людей предпочту специалистов у которых в голове уже есть некая структура
Ага) Промысловиков))) Очень талантливые разработчики они, мы знаем))
Ещё пару лет назад выбирал на чём писать черновики простых проектов и смотрел в сторону Nest. Всего пары примеров из статей хватило чтобы выбрать просто Express + Typescript и больше никогда про этого уродца не вспоминать.
Даже больше скажу, чаще всего и вовсе проще накидать то что хочет заказчик на JS, а уже потом, если проект усложняется, накидывать на него TS. Это всё упрощает в разы, а на простых проектах все ошибки обычно сразу видно.
>вызваны архитектурой языка.
А я то думал методогией разработки. Каким образом у языка может образоваться высшее строительство ?
Мне кажется что сравнивать Nest с Express и Fastify, это как сравнивать Angular с React и Vue. Как в первом, так и во втором случае вы выбираете инструмент под определенную задачу. Если вы какой-то не ведомой причине решили писать очень крупный проект на Node.js, тогда, наверное Nest покажется логичным выбором. Как и выбор Angular для написания Энтерпрайз фронтенда. Только в отличие от фронтенда, на бекенде есть .Net и Java со Spring Boot, которые куда больше подходят для этих целей. Вот и получается что гвозди пытаются забивать лопатой. Не верно выбирают инструмент.
Если вы какой-то не ведомой причине решили писать очень крупный проект на Node.js, тогда, наверное Nest покажется логичным выбором
Эммм, с чего это? С того что он максимально медленный на сколько это вообще возможно? С того что код который он хочет чтобы писали используя его максимально неприятный и чрезмерно перегруженный? По каким таким мифическим причинам очень крупный проект на Express или Fastify хоть на грамм может уступить nest? Я вижу только сплошные плюсы по всем фронтам у Express и Fastify и сплошные минусы у nest. Тем более камон, быть бэкенд разработчиком и вообще ставить производительность на последнее место, ну это как бы вообще странно, это разве инженерный подход? Я вот себя бы вообще не уважал когда преднамеренно убиваю производительность если бы взял nest и ещё не приведи душу ORM какую нибудь, это будет вообще комбо.
Как и выбор Angular для написания Энтерпрайз фронтенда.
Что?)) Вы из тех кто эту чушь где-то прочитали в 2015 году и поверили в нее?)) Я думал уже таких не осталось) Яндекс, Vk, Mail.rum Ozon, WB и т.д. и тп это вообще не энтерпрайз, это так, лэндинг, не более. Опять же, с чего это вдруг React или Vue могут быть хуже? Вообще причин 0, только в кривых руках, но в кривых руках всё будет отвратное, и уж тем более Angular, даже при прямых руках на его код без слез не взглянешь.
Только в отличие от фронтенда, на бекенде есть .Net и Java со Spring Boot, которые куда больше подходят для этих целей.
А вот и нет. У TS например очень развита система типов, чем далеко не все могут похвастаться. В плане производительности он легко обойдет Java и .Net, опять же если делать всё по человечески, а не брать nest и orm. Если смотреть на баланс удобства/скорости разработки/производительности, то по сути Node.js это золотая середина, а если вместо node запускать код используя Bun, то ещё за бесплатно примерно +20% производительности капает(проверял лично) в реальных условиях, REST API с запросами в БД и т.п., RPS в среднем на 20% увеличивается.
Вот и получается что гвозди пытаются забивать лопатой. Не верно выбирают инструмент.
Nest да, это крайне плохой и неудачный инструмент. Fastify или Express - прекрасный (баланс удобства, скорости разработки, производительности, минимальном кол-ве лишнего говнокода и т.п.).
Извините, мне кажется вы не поняли что я имел ввиду. Если вам интересно, я могу поделиться своим опытом и наблюдениями. Мне кажется это будет полезно для расширения кругозора.
А вообще, уже давно заметил что middle разработчику, который считает себя super senior, доказывать что-то это очень не благодарная работа. Они знают абсолютно все на свете с опытом работы в 3-5 лет и 1-2 проектов в 1-2 компаниях.
А вообще, уже давно заметил что middle разработчику, который считает себя super senior, доказывать что-то это очень не благодарная работа. Они знают абсолютно все на свете с опытом работы в 3-5 лет и 1-2 проектов в 1-2 компаниях.
Я с 2012 года в коммерческой разработке и за плечами больше 20ти проектов, и больше 8ми компаний
Если вам интересно, я могу поделиться своим опытом и наблюдениями. Мне кажется это будет полезно для расширения кругозора.
Разумеется интересно, у меня кругозор без границ, я не мыслю узколобо.
доказывать что-то это очень не благодарная работа
Ну вы даже не пытались конечно) У вас у увидел лишь "аргументы" из разряда, Java и .NET подходят лучше просто потому что. Якобы nodejs чем-то обелен и якобы на Java и .NET можно сделать то, чего нельзя на ноде. Плюс опять же якобы для больших проектов лучше angular или nest, они что, позволяют сделать то, что нельзя сделать с помощью react или express? Конечно нет, даже наоборот nest и angular накладывают ограничения. связывают руки, вставляют палки в колеса, про то, что на код при их использовании без слез и бутылки водки не взглянешь это я вообще молчу, просто месиво реальное в котором полезного кода 20% всё остальное это борьба с самими angular или nest.
И вот только не надо выдавать это за плюс, потому что плюсом такие вещи могут считать кто-то угодно, но явно даже не близко талантливые разработчики. Это всё равно что считать за плюс когда ты без разрешения не можешь выйти из дома и пойти туда, куда сам хочешь. Я с самого начала когда ещё писал на PHP уже презирал Symfony т.к. она сверх медленная, накладывает неудобства и ограничения, а если ее ещё с Doctrine ORM ее использовать, то это вообще труба, ну реально без шуток там 0 производительности, они в десятки раз медленнее чем код здорового человека. Разумеется я сразу написала своё решение которое потом годами со мной из проекта в проект ходило, было максимально быстрым и удобным в использовании. И ладно бы если бы за ущемление производительности я получал удобство, скорость и кайф в написании кода, как например в сделке Assembler vs Node.js) Но нет же, я по сути используя nest получаю только минусы, и "бонусом" производительность ниже плинтуса, а этой ой как "приятно" для настоящего разработчика, а не промысловика, которому пофигу на всё, который мериться со всем и терпит всё, лишь бы просто ЗП платили.
он максимально медленный на сколько это вообще возможно
А в чем медлительность? Речь про транспиляцию, запуск или время ответов? На практике не замечаю с этим никаких проблем.
максимально неприятный и чрезмерно перегруженный
Как пишущий на несте, я с этим не согласен.
По каким таким мифическим причинам очень крупный проект на Express или Fastify хоть на грамм может уступить nest?
Сам по себе проект в вакууме уступить не может, все зависит от того, как он реализован. Но нест однозначно гораздно удобнее.
Я вижу только сплошные плюсы по всем фронтам у Express и Fastify и сплошные минусы у nest.
Вообще это очень странное сравнение, ведь express и fastify это скорее библиотеки, а nest полноценный фреймворк (который под капотом использует тот же express или fastify)
А в чем медлительность?
Не думайте об этом, оно вам не надо.
Как пишущий на несте, я с этим не согласен.
Ещё бы)
Но нест однозначно гораздно удобнее.
Как же иначе)
Вообще это очень странное сравнение, ведь express и fastify это скорее библиотеки, а nest полноценный фреймворк
express/fastify/nest/koa/hapi и т.п. решают абсолютно одну и ту же задачу. Так что сравнение не странное. Нет ничего, что может nest и чего не может тот же express или fastify.
То, что на nest навешали сверху всяких кривых "решений" из коробки, не делает его лучше. Ибо вы если адекватный разработчик, у вас уже много лет есть все эти решения, которые работаю так же, а скорее всего лучше и быстрее, только с express или fastify.
У меня например ещё в 2017 году уже было вообще все для express, и валидатор и квери билдер для постгреса, и враппер для более удобной работы с rabbitmq и вообще всё что только хочешь, ибо эти вещи базовые и элементарные. И разработка всегда шла как по маслу, минимум кода, максимум скорости и удобства. На любой запрос, если вдруг у меня не было решения, я его просто писал и всё, это изи. Это и есть разработка. А позиция брать под каждый чих библиотеку и фреймворк, это кто угодно, но не разработчик.
“Бунтующие” зависимости - это не проблема NestJS, это проблема пакет менеджера, который всеми силами пытается сохранить зависимости, но получается у него крайне плохо(особенно это чувствуется в workspaceses). По моему личному опыту проблемы с зависимостями возникают когда мажорная версия выходит и начинается пляска с зависимостями. Обычно достаточно подождать пару недель и всё стабилизируется.
И да, Nest не умеет работать в workspaces, если в node_modules есть несколько разных версий пакета nestjs/core и nestjs/common, тут конечно же приходится плясать)
Нест часто требует к известным библиотекам свои враперы, увеличивая количество зависимостей, которые на чистом экспрессе/фастифае были бы не нужны. плюс как-то получается что node_modules у одного и того же сервера на Несте жирнее чем на фастифае. Поэтому чисто статистически на Несте эта проблема возникает чаще. Честно говоря, на фастифае такого вообще не видел, а на Несте регулярно. На экпрессе тоже наверняка проблем меньше, просто давно на нём не писал
Лично я почти никогда не ставлю пакеты-обертки, потому что почти всегда они написаны криво. Проще и лучше всегда писать динамические модули самому
Разрабатывал и на Express и на Fastify, сейчас в основном на Nest и нравится мне это гораздо больше за счет готовых решений. Можно очень быстро и удобно настроить авторизацию, валидацию, сериализацию, работу с бд, генерацию документации. Очень удобно работать с DI, очень удобно писать автотесты. С зависимостями не возникало проблем, если прям старье не ставить + всегда нужно фиксировать версии. Конечно можно и на Express все грамотно сделать, но это явно сложнее и дольше.
Раз

Два

Три

Четыре

Против

Просто до свидания. И это только hello world, в реальной жизни кол-во "кода" на nest стабильно раза в 3-4 больше чем на Express. И уровень уродливости кода с nest удивит даже самых отпетых мазохистов)
Конечно можно и на Express все грамотно сделать, но это явно сложнее и дольше.
Ага, обязательно) Безумно сложно и супер долго))
Разрабатывал и на Express и на Fastify
Уверены?) Я как бы тоже, в том числе и на php и на go, и после них всех NestJS это прям фу, причем конкретное фу. Это как всю жизнь бегать в спортивных кроссовках, мягких, удобных, лёгких, сам решал куда бежать и бежать ли вообще, может хочется идти, а тут тебе нацепили валенки залитые свинцом килограмм по 6 и сказали, вот кайфуй. Мы тоже так ходим в таких. значит это нормально, а то, что ты считаешь что кроссовки лучше, это просто ты такой дурачок, а вот мы умные.
Очень удобно работать с DI
Да уж) Прям безумно удобно))) Не то, что это вашиimport { someThing } from 'some/thing';
Это же ппц как не удобно, громоздко, да и вообще черт ногу сломит))) Толи дело через 10 файлов и через 10 колен я буду пробрасывать себе всякий мусор, вот это по кайфу.
Просто до свидания. И это только hello world, в реальной жизни кол-во "кода" на nest стабильно раза в 3-4 больше чем на Express.
Если у вас "Hello World" - это строка текста, то и в инфраструктуре Nest это тоже будет строкой текста. Поэтому вы должны были остановится на шаге три. Но если у вас это нечто производимое чем-то, то и в случае Express вы так же должны были написать сами сервис и внедрить его в ваш обработчик.
Далее, что бы не иметь бесконечную простыню, которая будет обрабатывать все запросы, как в вашем случае, в нест это выделено в отдельный файл. Очень сильно сомневаюсь, что даже в среднем приложении вы будете держать все это в одном файле, а значит даже для вашего примера, вы должны были организовать код так, что бы обработчик "Hello World" находится в отдельном месте.
Таким образом, если откинуть то как вы подменили понятия, то в случае с нест как минимум решена проблема с файловой и логической организацией, а вашем примере вы с одной стороны неправильно поняли семантику "Hello World", а с другой свалили все в одну кучу, чего в реальном проекте скорее всего не будет.
Ну естественно routes в отдельной папке, hanlders в отдельной, middlewares в отдельной) Всё разбито на уровне логики и здравого смысла. Тут дело в том, что самого кода надо минимум, т.е. вообще без лишнего мусора. И писать сам этот код легко, ты по сути только делаешь то, что нужно, а не пытаешь угодишь nest'у.app.get(`/api/v1/me`, authOnlyMiddleware, UserMehandler)
;
И всё, у нас зарегистрирован роут, он закрыт авторизацией и назначена функция handler которая его обработает. Всё в что касается эндпоинта сразу видно, всё супер очевидно, просто и ноль мусора.
Ну естественно routes в отдельной папке, hanlders в отдельной, middlewares в отдельной) Всё разбито на уровне логики и здравого смысла.
А почему тогда в примере с Нест вы сделали больше чем нужно, а в примере с Экспресс не сделали вообще ничего? Если вы хотели показать, что-то из реального мира На примере хэлловорд, то стоило тогда то, что в Нест есть из коробки в ваш пример добавить ручками. Что бы с одной стороны решались одни и те же задачи, а с другой сами задачи были тесно связаны с тем, что будет в реальном проекте.
Хэллоуворд они же тоже разные бывают.
Тут дело в том, что самого кода надо минимум, т.е. вообще без лишнего мусора.
Как мы убедились на вашем примере обязательно нужно проговаривать задачу. Потому что тот минимум кода, который вы использовали для хэлловорд на экспрессе не решает тех задач, которые уже решены в примере с Нест. И задачи эти, в любом случае, нужно будет решить, даже в небольшом приложении.
А по поводу мусора, даже в данном примере с хэллоуворд на несте шаг четыре - это полностью мусор, но не потому что Нест, а потому что вы этот мусор сами же и сделали.
app.get(/api/v1/me, authOnlyMiddleware, UserMehandler)
Ну, т.е. HelloWorldHandler в отдельный файл. /api/v1/me
в несте бы вы так, скорее всего, писать не стали и префикс вынесли в шапку контроллера, и тогда на экспрессе у вас было бы
const prefix = '/api/v1'
app.get(`${prefex}/me`, authOnlyMiddleware, UserMehandler)
Или это другое?
Мы вот поговорили и у вас уже код на экспрессе вырос до нескольких файлов и на несколько строчек, а код на несте наоборот сократился на один файл и несколько строчек.
Мазохисту не очевидно что иглы себе под ногти засовывать это не хорошо.
Я понимаю, промысловикам вообще начхать на чем писать и какой говнокод, с какой скоростью он будет работать и т.п. Их интересует только один вопрос, чтобы ЗП платили.
Для меня более чем очевидно что nest это максимально уродливый говнокод, с кучей лишнего бойлерплейта, все самый простые вещи доведены до абсурда и превращены в сложные и монструозные, связывает руки, навязывает свою ущербную архитектуру, и как вишенка на торте он самый медленный из всех решений какие только есть. А если ещё ORM ему в пару дать, так это вообще пиши пропало. Таких людей я тоже не понимаю, в чем проблема написать SELECT запрос руками? А для insert/update для пущего удобства 1 раз в жизни написал просто query builder или если не умеешь, взял уже кем-то написанный и вуаля.
Итого перформанс на дне(это не фронт, на бэке это намного важнее), качество и красота кода на дне, скорость разработки на дне, удобство разработки на дне, утопаем в бесконечных @@@@@
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
@Injectable()
@Controller()
@Get()
и ещё бесконечное кол-во @@@@@@ над каждым полем повсюду.
Зачем мне платить эту цену за дно по всем фронтам?
Я выбираю максимальный перформанс(fastify или своё решение, аля express, только работающее со скоростью http.createServer), минимальное кол-во кода и максимальная простота кода.
И ещё, представим ситуацию, что вдруг на nest код будет приятный и т.п., но как инженер я себя никогда не буду уважать если возьму его, уже только из-за того, что он максимально медленный. Т.е. он не работает на пределах возможности Node.js с минимальным оверхедом, а он просто позорит node.js и ставит его производительность на колени.
А к чему вы все это накатали, не пойму? Я всего лишь внес немного ясности в ваши же примеры. Ну да, после этого оказалось, что выбранный пример не сильно то демонстрирует вашу точку зрения.
Вполне возможно, что все что вы говорите имеет место быть в ваших программах. Если же вы хотите как то это дело обобщить, то одних громких выражений и кривых примеров явно недостаточно. И про производительность сделать отдельную часть.
Если вы любите Нест, то хотел давно задать вопрос. (Не подумайте, тут нет никакого подвоха), я действительно не очень понимаю, в чём вообще удобство DI на ноде? В джаве понятно - там по-другому не очень получается - надо импортировать класс из него делать инстанс, а если синглтон, то с бубнами - всё это отдаётся фреймворку. А в ноде сделал инстанс от репозитория в файле (модуле) этого репозитория, его экспортнул - вот у тебя и зависимость-синглтон в одну строчку (Injectable Default). Можно придумать зачем это на фронте - может в течении текущего сеанса тебе какая-то зависимость вообще не понадобится, так зачем от неё сразу делать инстанс. Но на REST-сервере вряд ли такое имеет смысл. Чего дополнительного дают декораторы Injectable со скоупами. В (моём личном эстетическом) представлении это только делает код очень неявным, но может я что-то упускаю, случайно не столкнулся с ситуацией где это действительно "бомба". Спасибо.
NEST.js — уродливый монстр или мощный энтерпрайз?