Журналист берет интервью у миллионера:
- Что вам помогло добиться успеха?
- Убеждение, что сами по себе деньги не играют никакой роли. Важна только работа.
- И это убеждение помогло вам разбогатеть?
- Нет, я разбогател, когда сумел убедить в этом подчиненных
В хороших фреймворках IoC реализуют не через инъекцию, а неявно через контекст окружения.
Вот это - чушь. Я вам уже указывал на то, что Ambient Context (контекст окружения) является анти-паттерном для IoC и приводил ссылку на книгу "Dependency Injection Principles, Practices, and Patterns" от Steven van Deursen and Mark Seemann, с которой сталкивался каждый, кто хоть немного углублялся в принципы IoC. Там написано почему это так - см. пункт 5.3.
А вы продолжаете нести чушь в массы про "неявное лучше явного".
Контекст окружения имеет право на существование, но только когда его самого внедряют в объект (через конструктор или метод):
Ambient Context должен быть использован только в редчайших случаях. Для большинства случаев больше подходят внедрение в конструктор или внедрение в свойство, но у вас может быть реальный Cross-Cutting Concern, который загрязняет каждый API в вашем приложении, если вам нужно передать его всем сервисам.
А в вашем фреймворке вы загрязняете globals, используя его в качестве контекста и размещая в нём "вообще всё". Достаточно нажать F12 (DevTools) и запустить вот этот код на вашем любимом page.hyoo.ru, куда вы всех обычно посылаете:
(()=>{debugger})()
Вот это всё ваши объекты в глобальной области видимости (с префиксом $hyoo_ и $mol_):
Это всё - неявные зависимости, которые может использовать код, написанный, следуя вашим подходам (а может и не использовать, может использовать кто-то, кого использует ваш код, или его собственные зависимости и т.д.).
Не, ну лично вы, этот зоопарк сами писали и в нём разберётесь, если что крашнется, а человеку со стороны как в этих неявных зависимостях копаться?
Тупой вопрос: как вы мокать глобальное окружение в тестах собираетесь? Каждый раз пересобирая его, для каждого теста? Как это отразится на скорости тестов? Или каждый-всякий-любой может в глобальном окружение подменить объект моком? И на проде тоже?
ОК, я понимаю, что вы уже инвестировали в эту архитектуру большую часть своей жизни и вам просто некогда её переделывать. Очертите границы применимости вашего подхода и там рулите.
Но нести чушь про "в хороших фреймворках неявное лучше явного"... Неокрепшие умы и впрямь могут подумать, что передвигаться по улице лучше с закрытыми глазами, раз так говорит сам Карловский! ;)
Браво! В Святом Писании вы разбираетесь явно лучше, чем в современной теории разработки ПО. Я пишу на JS потому, что разрабы Пайтона сами же нарушили свой принцип №13, создав многолетний конфликт между версиями 2.7 & 3.x. Так что я сам выбираю принципы, которым "служить и поклоняться", просто в силу того, что я - человек, свободный в своём выборе. И как человек, достаточно давно практикующийся в этом, могу сказать, что как проповедник вы не очень.
"Явное лучше неявного" - это как аксиома в Евклидовой геометрии. Можно использовать разные аксиомы и строить разные геометрии. Но... геометрия Евклида популярна не потому, что она вернее всех других, а потому, что она тупо утилитарнее.
"Явное лучше неявного" понятно просто в силу того, что ходить по улице с открытыми глазами лучше, чем с закрытыми. Простые принципы сильны как раз своей наглядностью. Им можно следовать, можно не следовать, но чтобы отрицать их - нужно обладать недюжинным самомнением. И оно у вас есть.
Т.е., вы сейчас на полном серьёзе утверждаете, что принципы, на которых построен один из самых популярных на данный момент ЯП, по весу аргументации равноценны принципам, изложенным на одном из интернет-сайтов? Я восхищён и соглашаюсь с вами.
На первый вопрос ответ - уже научились. Мой личный опыт показывает, что GPT-чат может общаться с агентом через действия ("писать программы для выполнения HTTP-запросов"), анализировать ответ агента и изменять запрос в зависимости от ответа, если агент указал на невалидность входных данных. И выполнять запрос с новыми данными. Это уже есть.
2) Можно сравнивать кол-во потраченной энергии на выполнение действий. И не важно, из какого источника она. Меряем все, допустим в джоулях.
Присоединяюсь к вопросу коллеги @ris58h - в чём преимущество JWT перед sessionId в случае с монолитом на реакте, который дёргает API?
Вот просто для интереса открыл DevTools на этой же странице и посмотрел куки. Там этих id - немерено. Может, там и JWT есть, но они явно обычные идентификаторы не вытеснили.
Я, например, тоже не сильно вижу преимущества JWT перед sessionId вне микросервисов. В классическом монолите для аутентификации пользователей - так точно.
Когда проверяется реализуемая бизнес-функция, а не код, который её реализует. Функция может быть реализована в одном методе, в одном классе, в группе классов.
В юнит тестах не обязательно всё мокать, на мой взгляд.
Всё внешнее - обязательно, иначе это не юнит-тесты, а как раз уже функциональные.
При этом, с моей точки зрения, это ещё не интеграционные тесты, которые должны покрывать более широкий тракт от входа до выхода.
Согласен с такой точкой зрения. Интеграционные - это уже все компоненты в сборе, их взаимодействие с БД и прочими внешними акторами.
модуль не обязан быть мельчайшим фрагментом кода.
Сам смысл юнит-тестирования (модульного тестирования) - это проверка модуля на соответствие требованиям (спецификации) в отрыве от всего остального. Вот определение от ИИ: "Модульное тестирование — это процесс проверки отдельных частей кода (модулей) программы на корректность работы. Цель — удостовериться, что каждый компонент выполняет свои функции правильно, изолированно от других частей системы, обычно с использованием автоматизированных тестов."
В используемых мною ЯП (java, php, js) модулем, как правило, считается отдельный файл с кодом. Цель юнит-тестирования - проверка кода в файле оторвано от других файлов. Если вы тестируете два и более файла совместно, то это уже функциональное. Если вы с этим не согласны, то изложите ваше определение понятия "модульные тесты".
А вот 80% покрытия совершенно несложно обеспечить.
Если это делается за счёт функциональных тестов или интеграционных - welcome, как говорится. Но в этом случае % покрытия становится уже неактуальным. Всё равно, сколько кода покрывается, если приложение работает (или не работает) согласно требованиям. Вообще, лично я считаю, что эта метрика вредная - даёт ощущение ложной безопасности.
Спасибо за ссылку, почитаю на досуге
Пожалуйста, но это довольно древний текст по нынешним меркам :)
На сейчас я вижу, что юнит-тестирование (файл в отрыве от остальных) имеет смысл, если в команде есть очень активные, но не очень сообразительные члены (типа выпускников курсов "войти в айти за 2 недели" или ИИ-агентов). В других же случаях достаточно тестов функциональных, интеграционных, приёмочных и т.д., с полным игнором процента покрытия кода.
А как вы это понимаете? Юнит-тестирование - это по определению тестирование блока кода в отрыве от всего остального. Вы просто мокируете данному блоку его окружение. Поменялась спека - поменялся код блока и юнит-тест к нему. Если тест не проходит, то это значит, что либо код не соответствует спеке, либо тест, либо и то, и другое.
Если вы поменяли код с юнит-тестом и что-то упало в другом месте, то это уже не юнит-тестирование.
А вы не путаете юнит-тесты с функциональными и интеграционными? Вот они-то помогают экономить время и определить, что и где именно сломалось. Юнит-тестирование - это проверка "сферического коня в вакууме". Вы проверяете код в отрыве вообще от всего остального (замоканного).
Это имеет смысл делать только в случае, если у вас достаточно нетривиальный код со сложной спецификацией (куча условий и ветвлений внутри и минимум внешних зависимостей). Причём вам нужно сделать это один раз - при написании, а затем прогонять юнит-тест при рефакторинге, чтобы убедиться, что рефакторинг не сломал соответствие обновлённого кода старой спецификации. Насколько много в проекте на 10к+ строк такого нетривиального кода?
А теперь посчитайте время, которое у вас уходит на поддержание в актуальном состоянии юнит-тестов в проекте со 100% покрытием и с постоянно меняющимися требованиями?
Ходить по воде и разрабатывать по ТЗ — одинаково легко, если то и другое заморожено.
В 99% проектов условия меняются постоянно и на протяжении всей жизни проекта, включая стадию активной эксплуатации.
Да, я использую тестирование. В основном функциональное или приёмочное, когда нужно проверить работоспособность основных сценариев. Юнит-тестирование, как я уже говорил, только для функционала со сложной внутренней логикой. Свою точку зрения я изложил ещё лет 10 назад.
Могу только добавить, что с приходом ИИ и сгенерированного кода значение юнит-тестов может сильно поменяться. Но писать, запускать и читать юнит-тесты будут не люди, а ИИ-агенты. И эти процессы будут встроены в цепочку автоматизированной разработки приложений.
Правильные юнит-тесты экономят время разработки, так как практически полностью заменяют длительную отладку.
Это ложь. Юнит-тесты всего лишь гарантируют то, что код соответствует спецификации, существующей на момент написания кода. Изменилась спецификация - переписывай код и юнит-тесты. А уж про замену отладки юнит-тестами вообще смешно читать.
В зависимости от конфига выбираешь, какой из встроенных nodejs-серверов будет обрабатывать HTTP-запросы (их в node три: http, http2, https). Потом создаёшь, опять же, в зависимости от конфига, WebSocketServer и говоришь, что он работает в рамках уже существующего веб-сервера (перенаправляешь на него события onUpgrade). Таким образом, есть один веб-сервер который слушает один порт и может работать либо standalone (в деве), либо за проксирующим/балансирующим веб-сервером (на проде). Все три node-сервера по интерфейсам сопоставимы, а дальнейшему коду всё равно, как пришёл запрос (HTTP/1/2/S), вебсокеты немного в стороне, но тоже через тот же порт работают. Когда HTTP/1 - всё крутится.
Вот это - чушь. Я вам уже указывал на то, что Ambient Context (контекст окружения) является анти-паттерном для IoC и приводил ссылку на книгу "Dependency Injection Principles, Practices, and Patterns" от Steven van Deursen and Mark Seemann, с которой сталкивался каждый, кто хоть немного углублялся в принципы IoC. Там написано почему это так - см. пункт 5.3.
А вы продолжаете нести чушь в массы про "неявное лучше явного".
Контекст окружения имеет право на существование, но только когда его самого внедряют в объект (через конструктор или метод):
А в вашем фреймворке вы загрязняете
globals, используя его в качестве контекста и размещая в нём "вообще всё". Достаточно нажать F12 (DevTools) и запустить вот этот код на вашем любимом page.hyoo.ru, куда вы всех обычно посылаете:Вот это всё ваши объекты в глобальной области видимости (с префиксом
$hyoo_и$mol_):Это всё - неявные зависимости, которые может использовать код, написанный, следуя вашим подходам (а может и не использовать, может использовать кто-то, кого использует ваш код, или его собственные зависимости и т.д.).
Не, ну лично вы, этот зоопарк сами писали и в нём разберётесь, если что крашнется, а человеку со стороны как в этих неявных зависимостях копаться?
Тупой вопрос: как вы мокать глобальное окружение в тестах собираетесь? Каждый раз пересобирая его, для каждого теста? Как это отразится на скорости тестов? Или каждый-всякий-любой может в глобальном окружение подменить объект моком? И на проде тоже?
ОК, я понимаю, что вы уже инвестировали в эту архитектуру большую часть своей жизни и вам просто некогда её переделывать. Очертите границы применимости вашего подхода и там рулите.
Но нести чушь про "в хороших фреймворках неявное лучше явного"... Неокрепшие умы и впрямь могут подумать, что передвигаться по улице лучше с закрытыми глазами, раз так говорит сам Карловский! ;)
Браво! В Святом Писании вы разбираетесь явно лучше, чем в современной теории разработки ПО. Я пишу на JS потому, что разрабы Пайтона сами же нарушили свой принцип №13, создав многолетний конфликт между версиями 2.7 & 3.x. Так что я сам выбираю принципы, которым "служить и поклоняться", просто в силу того, что я - человек, свободный в своём выборе. И как человек, достаточно давно практикующийся в этом, могу сказать, что как проповедник вы не очень.
"Явное лучше неявного" - это как аксиома в Евклидовой геометрии. Можно использовать разные аксиомы и строить разные геометрии. Но... геометрия Евклида популярна не потому, что она вернее всех других, а потому, что она тупо утилитарнее.
"Явное лучше неявного" понятно просто в силу того, что ходить по улице с открытыми глазами лучше, чем с закрытыми. Простые принципы сильны как раз своей наглядностью. Им можно следовать, можно не следовать, но чтобы отрицать их - нужно обладать недюжинным самомнением. И оно у вас есть.
Я с вами уже согласился и соглашусь ещё раз.
Т.е., вы сейчас на полном серьёзе утверждаете, что принципы, на которых построен один из самых популярных на данный момент ЯП, по весу аргументации равноценны принципам, изложенным на одном из интернет-сайтов? Я восхищён и соглашаюсь с вами.
Потому что "явное лучше неявного" (см. пункт 2). Этому принципу более 25 лет, если что. Если он прошёл мимо вас - соболезную.
Обоснуйте. Чем неявное лучше явного?
Ну, насчёт катастрофы я бы так не преувеличивал. Моя кошка, например, не считает своё существование катастрофой :)
Спасибо за вопросы.
На первый вопрос ответ - уже научились. Мой личный опыт показывает, что GPT-чат может общаться с агентом через действия ("писать программы для выполнения HTTP-запросов"), анализировать ответ агента и изменять запрос в зависимости от ответа, если агент указал на невалидность входных данных. И выполнять запрос с новыми данными. Это уже есть.
2) Можно сравнивать кол-во потраченной энергии на выполнение действий. И не важно, из какого источника она. Меряем все, допустим в джоулях.
Интересно, как мне попала в ленту статья с 43-мя минусами? Я тоже так хочу!! Где узнать расценки?
Присоединяюсь к вопросу коллеги @ris58h - в чём преимущество JWT перед sessionId в случае с монолитом на реакте, который дёргает API?
Вот просто для интереса открыл DevTools на этой же странице и посмотрел куки. Там этих id - немерено. Может, там и JWT есть, но они явно обычные идентификаторы не вытеснили.
Я, например, тоже не сильно вижу преимущества JWT перед sessionId вне микросервисов. В классическом монолите для аутентификации пользователей - так точно.
Когда проверяется реализуемая бизнес-функция, а не код, который её реализует. Функция может быть реализована в одном методе, в одном классе, в группе классов.
Всё внешнее - обязательно, иначе это не юнит-тесты, а как раз уже функциональные.
Согласен с такой точкой зрения. Интеграционные - это уже все компоненты в сборе, их взаимодействие с БД и прочими внешними акторами.
Сам смысл юнит-тестирования (модульного тестирования) - это проверка модуля на соответствие требованиям (спецификации) в отрыве от всего остального. Вот определение от ИИ: "Модульное тестирование — это процесс проверки отдельных частей кода (модулей) программы на корректность работы. Цель — удостовериться, что каждый компонент выполняет свои функции правильно, изолированно от других частей системы, обычно с использованием автоматизированных тестов."
В используемых мною ЯП (java, php, js) модулем, как правило, считается отдельный файл с кодом. Цель юнит-тестирования - проверка кода в файле оторвано от других файлов. Если вы тестируете два и более файла совместно, то это уже функциональное. Если вы с этим не согласны, то изложите ваше определение понятия "модульные тесты".
Если это делается за счёт функциональных тестов или интеграционных - welcome, как говорится. Но в этом случае % покрытия становится уже неактуальным. Всё равно, сколько кода покрывается, если приложение работает (или не работает) согласно требованиям. Вообще, лично я считаю, что эта метрика вредная - даёт ощущение ложной безопасности.
Пожалуйста, но это довольно древний текст по нынешним меркам :)
На сейчас я вижу, что юнит-тестирование (файл в отрыве от остальных) имеет смысл, если в команде есть очень активные, но не очень сообразительные члены (типа выпускников курсов "войти в айти за 2 недели" или ИИ-агентов). В других же случаях достаточно тестов функциональных, интеграционных, приёмочных и т.д., с полным игнором процента покрытия кода.
Да, вы правы. Юнит-тесты хорошо показывают, что кто-то что-то где-то поменял.
А как вы это понимаете? Юнит-тестирование - это по определению тестирование блока кода в отрыве от всего остального. Вы просто мокируете данному блоку его окружение. Поменялась спека - поменялся код блока и юнит-тест к нему. Если тест не проходит, то это значит, что либо код не соответствует спеке, либо тест, либо и то, и другое.
Если вы поменяли код с юнит-тестом и что-то упало в другом месте, то это уже не юнит-тестирование.
А вы не путаете юнит-тесты с функциональными и интеграционными? Вот они-то помогают экономить время и определить, что и где именно сломалось. Юнит-тестирование - это проверка "сферического коня в вакууме". Вы проверяете код в отрыве вообще от всего остального (замоканного).
Это имеет смысл делать только в случае, если у вас достаточно нетривиальный код со сложной спецификацией (куча условий и ветвлений внутри и минимум внешних зависимостей). Причём вам нужно сделать это один раз - при написании, а затем прогонять юнит-тест при рефакторинге, чтобы убедиться, что рефакторинг не сломал соответствие обновлённого кода старой спецификации. Насколько много в проекте на 10к+ строк такого нетривиального кода?
А теперь посчитайте время, которое у вас уходит на поддержание в актуальном состоянии юнит-тестов в проекте со 100% покрытием и с постоянно меняющимися требованиями?
В 99% проектов условия меняются постоянно и на протяжении всей жизни проекта, включая стадию активной эксплуатации.
Да, я использую тестирование. В основном функциональное или приёмочное, когда нужно проверить работоспособность основных сценариев. Юнит-тестирование, как я уже говорил, только для функционала со сложной внутренней логикой. Свою точку зрения я изложил ещё лет 10 назад.
Могу только добавить, что с приходом ИИ и сгенерированного кода значение юнит-тестов может сильно поменяться. Но писать, запускать и читать юнит-тесты будут не люди, а ИИ-агенты. И эти процессы будут встроены в цепочку автоматизированной разработки приложений.
Это ложь. Юнит-тесты всего лишь гарантируют то, что код соответствует спецификации, существующей на момент написания кода. Изменилась спецификация - переписывай код и юнит-тесты. А уж про замену отладки юнит-тестами вообще смешно читать.
Идея была в том, чтобы app-сервер обслуживал всё HTTP'шное на одном порту. И для HTTP/1 это работает.
А вот это доказательство, что не ИИ писал - ИИ так не лажает.
Я тоже не вижу проблем, я просто спросил:
Как-то так:
В зависимости от конфига выбираешь, какой из встроенных nodejs-серверов будет обрабатывать HTTP-запросы (их в node три: http, http2, https). Потом создаёшь, опять же, в зависимости от конфига, WebSocketServer и говоришь, что он работает в рамках уже существующего веб-сервера (перенаправляешь на него события
onUpgrade). Таким образом, есть один веб-сервер который слушает один порт и может работать либо standalone (в деве), либо за проксирующим/балансирующим веб-сервером (на проде). Все три node-сервера по интерфейсам сопоставимы, а дальнейшему коду всё равно, как пришёл запрос (HTTP/1/2/S), вебсокеты немного в стороне, но тоже через тот же порт работают. Когда HTTP/1 - всё крутится.