Re[55]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 07.03.22 13:57
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

I>>Я про дизайн, а ты мне про архитектуру


НС>У тебя эьто разные понятия? Тогда в чем отличие?



https://www.geeksforgeeks.org/difference-between-software-design-and-software-architecture/

I>>Если у тебя жирные конские контроллеры,


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


Т.е. когда я показываю пример, что контроллер должен быть, условно, 5 строчек, линейным, тривиальным, тебе видится, что я предлагаю сделать их жирными и конскими?
До тебя что, это не доходит, или ты снова поиграть захотел? Играй без меня.

I>> то надо или много интеграционных тестов, тогда много времени


НС>Опять непонятно. Как от размера контроллера зависит количество интеграционных тестов?


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

Как я вижу, у многих команд это вариант нормы — всё пихать в контроллер, и писать тучи интеграцинных тестов. Этакая перевернутая пирамида тестов — чем выше уровень, тем больше тестов

> Интеграционный тест тестирует сервис как черный ящик, поэтому особенности его внутреннего устройства на объем тестов влиять не должны. Только объем функционала сервиса. А он вроде как от внутреннего дизайна не зависит особо, не?


Что значит "объем функционала" ? Вот как именно ты собираешься валидацию, это же часть бл, тестировать ? Можно поподробнее?
Вот скажем, у нас для валидации входа есть 1..10тыс явных и неявных правил.
Предполагаю, ты будешь делать вот так:
1 подымаешь тот кролик, что долго стартует
2 пишешь и запускаешь 1..10 тыс запросов что бы покрыть только основные кейсы валидации
3 п2 повторить для каждого роута/метода АПИ

На мой взгляд валидацию нужно тестировать иначе, и я уже показывал.Еще раз
— убрать всё что можно в метаданные, например, валидация туда отлично убирается
— юнит тесты схемы
— wiring тест энв-контроллер-метод-метаданые. Хотя такой тест сильно похож на юнит-тест, это все таки интеграционный.
— вместо 1..10 тысяч тестов, пишем всего 1..10 единиц тестов на каждый метод/роут АПИ

I>>Есть и другой вариант, изменить дизайн, а именно — контроллер сделать коротким, линейным, тривиальным, вынести все или в компоненты, или, что лучше, в метаданные.

I>>В таком случае нет необходимости гонять все тесты логики/поведения через интеграционные

НС>Т.е. ты тоже предлагаешь надеятся на авось, что компонентные тесты выловят все проблемы?


Я предлагаю вспомнить пирамиду тестов и её смысл:
Проблемы в логике надо покрывать юнит-тестами, они дают максимально возможное покрытие и максимальные гарантии. Тестировать интеграцию юнит-тестами смысла нет, гарантий не даёт.
Проблемы в интеграции — интеграционными разных сортов. Логику тестировать интеграциоными смысла никакого нет — гарантии сильнее не станут.
Re[53]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 07.03.22 14:18
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>e2e говорит о том, позволяет ли твоя интеграция выполнить сценарии. Собственно в мелких вещах e2e не просто дырявые, а буквально решето — комментируешь пол-парсера, а e2e зеленые. Зато если чуточку поменяешь wiring, e2e встаёт колом. Это говорит о том, что e2e проверяют именно интеграцию.

I>·>35=0 тоже встанет колом. И юзеры в проде тоже встанут колом. Так и запишем, юзеры — проверяют именно интеграцию. User Driven Integration Testing!
I>Поскольку, с твоих слов, вы тестируете интеграцию моками, то да, ваши юзеры тестируют интеграцию
Я это не утверждал. Я утверждал, что мы не тестируем в проде.

I>>>Отсюда ясно, что вместо п1 и п2 нужно говорить о вероятности. А стало быть и о вероятости появления багов на проде.

I>·>Тесты которые дают зелёный цвет в препроде должны без всяких вероятностей давать зелёный цвет в проде. Если это не так, то это серьёзная бага и надо фиксить.
I>Баги не в курсе, что они вам чего то дожны. Баг это штука всегда сильно вероятностная, т.к. в современном софти количество путей выполнения исчисляется в астрономических единицах.
Тесты нам должны. А если какие-то тесты нам ничего не должны, то мы зря на них тратим время.

I>>>·>Да я понял. Вы не можете обеспечить качество продукта в pre-prod, вот и приходится гонять в прод.

I>>>Наоборот.
I>·>Что наоборот?
I>Можем. Обеспечиваем. т.к. тесты это всего лишь вероятность. И фиксы это тоже вероятность. И код ревью это тоже вероятность.
I>Одна проблема — посчитать эту вероятность пока нет матана. Разве что голословно, как у тебя.
Ок. Но что это меняет? Обеспечение качества продукта (quality assurance) тоже вероятностная величина. Цель всего этого действа уменьшить риски (ака вероятности), а не создать идеально безбажный продукт. Но если хочешь, могу переформулировать:
Вы не можете обеспечить вероятность достаточного качества продукта в pre-prod, вот и приходится гонять в прод.

I>>>Элеменартно — ты думаешь, что с авторизатором все хорошо, а он, этот авторизатор, не тот. Или ты не в курсе, что фиксун мальца в ём поправил // todo: fix after vacation

I>·>fix что? Почему это в пре-проде не ловится?
I>Я уже приводил большой список, почему это может быть. До кучи бд прода, депенденсы как правило имеют другий цикл жизни, и в тамошней бд к примеру, может накапливаться чорт знает что.
Так разберитесь, чтобы было не чёрт знает что, а то что надо.
Например, можно организовать процесс копирования бд из прод в препрод (возможно с санитизацией) чтобы можно было спокойно гонять тесты и отлаживать, имея на руках прод-like данные.

I>Например, фиксанул ты препрод, ну скажем, баг с попаданием битых данных в queue, а на проде, внезапно, оказалось, время жизни таких записей исчисляется не часами, а годами, потому, что есть еще один баг, и вариантов битых записей не три, как у ты думал, а 10, из которых 7 будут срабатывать разад два в год.

В том-то и дело — _внезапно_. Анализируйте все эти внезапности и боритесь с ними. Более того, неясно как прогон тестов в проде может в принципе поймать "срабатывать разад два в год", разве что случайно повезёт, что с учётом упомянутых тобой "10^14" случаев — должно быть астрономическое везение.

I>>>То есть, дали небольшой тиражик, посмотрели как RC ведет себя вживую.

I>·>Это не прод. Эти "выделенные юзеры" называются "бета-тестеры" и живут в отдельном от прода окружении. Если ты называешь бета-тестирование "работа в проде", то ты просто жонглируешь терминами.
I>Наоборот, это именно реальные юзеры на своем обычном окружении. И разница между RC и Release исключительно в версии — 7.0.1943-RC 7.0.1944
У них обычно, как минимум, другой T&C, они аккцептят больше рисков. Т.е. по сути тестеры. Суть-то одна: бета-тестеры — не реальные пользователи.

I>Забвно, что релиз-кандидат у тебя бетой стал. Ну-ну.

Официально зовут "beta-release", т.е. опять терминологическая разница, "beta-release" это то что перед "final release" и по сути "pre-release", что не далеко от "release candidate".

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

I>·>Но им не пользуются юзеры и он не лежит в проде.
I>Наоборот — пользуются. Если быстро выявлены проблемы, сразу вместо 7.0.0 будет релизнут какой нибудь 7.0.0.1
Нет, обычно даже две странички для скачивания. Вот тот же chrome: вот релиз, а вот бета.
Релиз обычно используется реальными юзерами, а бета — для тех, кто хочет найти баги в своём софте до официального выхода следующей версии хрома.

I>А вообще — смотри на версионирование нынешник вещей навроде вындоуса — просто 10.0.19044

Последняя циферка это обычно номер билда в CI, и к релизности отношения не имеет.

I>>>Это и есть проблема. И именно по этому тебе надо мокать.

I>·>Это не проблема, это цель приложения — дёргать 3rd party систему. А мокать нужно потому, что реальную систему во время разработки и тестирования дёргать нельзя.
I>Нету такой цели — дергать другую систему. Есть цель
I>1. конкретная проводка
I>2. соблюдение налогового законодательства
Ясен пень. Это цель на уровне FRD. Ты же не тест для docx файла пишешь, ты пишешь код, притом тест — это тоже код. Следовательно в каком-то месте у тебя будет некий боевой код который что-то дёргает для обеспечения данной цели. И ещё где-то будет тестовый код, который проверяет, что цель обеспечена, и этот код будет ассертить что это самое нечто было дёрнуто. Почему в рамках обсуждаемой темы мы не можем условиться, что это нечто — метод trackHim — мне неясно. Если хочется, пусть это будет некий условный rabbitMq.basicPublish() если тебе так понятнее.

I>>>·>Ок. Попробую с другой стороны. Расскажи что дальше происходит с евентом, посланным из MoneyService в реальном приложении в проде? Покажи на уровне кода.

I>>>Что напишешь, то и будет. На уровне юнит-тестов мы проверяем, что работает паблик API. А вот всё, что ты подклеишь к эвенту, проверяется интеграционным тестом, который нужен в любом случае.
I>·>Покажи на уровне кода.
I>and notification $налоговая is succeed
Ок. К чему это привязывается?

I>>>Написано будет так "должно уведомлять налоговую о всех транзакциях суммой больше ..."

I>·>Верно. И чему это будет соответствовать в коде? Посылка сообщения ThresholdExceeded налоговую не уведомляет. Т.е. ты показал код, который решает какую-то свою задачу, а не ту, что в требованиях.
I>Разумеется. Будет еще небольшой wiring код, ровно как у тебя в примере, и вот там будет подкидываться связка.
Покажи, без зависимости от 3rd party library, как ты требуешь. И покажи как ты это тестируешь.

I>>>Это примерно то, как будет выглядеть твоя задача в реальности. Ну вот вызвал ты hmrc, а он зафейлился, а трансфер уже прошел. Как быть? Налоговая не поверит, что это фейл твоей софтины, для неё это уклонение что влечет штрафы и тебя, и юзера.

I>·>Если он зафейлится, то кинется исключение из метода trackHim и трансфер не выполнится (это, к слову, элементарно покрывается ю-тестом). Если класс Hmrc лежащий в library предоставленный самой hmrc не выполняет контракт, то это не наша проблема.
I>На самом деле это не повод фейлить трансфер. Это повод повторить уведомление налоговой со временем. А то сервис налоговой может начать блокировать работу твоей системы.
Это ты сочиняешь требования на ходу. Повод-неповод, это определяется FRD, а не евентами.
В любом случае, евенты всё равно не нужны. Реализация trackHim это всё может обеспечивать у себя вунутре, это не надо выворачивать через евенты. trackHim вместо реального вызова может, например, класть это дело в persistent queue, и фейлом будет считаться уже, например, что случилась ошибка в этом самом queue в момент persistence. Если у тебя очередь поломана, то транферы ты делать не можешь всё равно, иначе потеряются уведомления в налоговку.
Суть в том, что это никоим образом не должно беспокоить MoneyService — он дёрнул метод, если метод не крешнулся, то можно продолжать трансфер.

I>И вот это юнит-тестами не проверяется

Юнит-тестами самого MoneyService, ясен пень не проверяется. Но проверяется юнит-тестами соответствующего компонента, который заботиться о доставке уведомлений.

I>Зато здесь помогут те самые интеграционные тест — симулируем косяк налоговой, типа "а пусть фарвол блокирует", и тогда "нотификация ушла спустя 10с после возобновления"

I>или "пока налоговая недоступна, очередь хранит нотификации"
Как ты собрался симулировать косяк налоговой в проде?

I>>>И вот проблема — сообщили в налоговую минуя твой интерфейс.

I>>>Какого цвета будут тесты?
I>·>Сообщили как, телепатией? Напоминаю, trackHim — это интерфейс налоговой, а не мой.
I>Мало ли, что там фиксун придумал. Он "фремворками не пользуюсь у меня 10 лет опыта, да и вообще, там всё на сокетах", намастырил на коленке запрос, ему так понятнее, да и отослал.
Тогда красным. Нефиг всякую наколенность в прод сувать.

I>>>Разумеется, потому что другой дизайн. Уведомление налоговой проверяется кучкой интеграционных тестов, которые, например, будут симулировать различные фейлы и проверять, что нотификация будет доставлена успешно.

I>·>Верно, но моего MoneyService это не касается. Тестировать свою библиотеку будет сама налоговка.
I>Ога. И снова налоговой придется мейнтейнить твой файрвол.
Мой фаерволл проверяется пингами-хартбитами и прочим мониторингом. Как выяснилось, мониторинг всё равно необходим. И-тесты в проде ничем не помогут, т.к. конфигурация прод сети никак не связана с моими релизами и запуск "run test" никто не обещает.

I>>>зеленые, там тоже камент "todo: потом"

I>·>А чем тебе поможет интеграционный тест с "todo: потом"?
I>Мне поможет например e2e тест, овнершип которых находится у других людей, и там просто так не закоментишь.
Так оказывается у вас длинный список людей, которые проверяют каждый фикс

I>>>То есть, в ошибках фиксуна на вашем проекте виноваты мы? А ты, ловкач!

I>·>Да. Если кто-то может втихушку закинуть какашку прямо на прод, то у вас что-то не то с процессами.
I>Фиксуны они вездесущие. Ну и мержи/ребейзы никто не отменял.
А как же овнершип?

I>>>Это часть взаимодействия.

I>·>[словоблудие поскипано]
I>·>Define "взаимодействие"
I>Процесс воздействия объектов друг на друга. Очевидно, в моем дизайне есть явный интерфейс, который описывает вход, параметры, и выход — возвращаемое значение и событие.
У меня тоже явный интерфейс. Просто у меня уведомление сокрыто от консьюмеров интерфейса, в соответствии с бизнес-требованиями. У тебя оно торчит наружу, чисто шоб было.

Напомню, в ООП — вызов метода это единственный способ воздействия объектов друг на друга. И твоё событие — это тоже объект. И подписка на события — это тоже вызов метода.

I>·>Ты хочешь что-то неявно передавать как попало что-ли? Чтобы было чем заняться интеграционным тестам?

I>До тебя не доходит, что интеграционный тест нужен по причине взаимодействия с налоговой? Есть такое взаимодействие — нужен тест интеграции.
I>Еще раз — мок не заменяет ни один интеграционный тест, нисколько.
Это out-of-scope моего примера. Интеграция с налоговой может быть протестирована в рамках Hmrc класса.

I>>>На основании требований.

I>·>В требовании было ровно одно, ты сам процитировал: "должно уведомлять налоговую" (не десять налоговых, не "можно", а "должно"). На основании чего конкретно ты решил, что нужен pub-sub евент?
I>Выбрал конкретный дизайн — провел границы компонентов, выявил точки взаимодействия, описал для этого интерфейс.
На основании чего конкретно ты выбрал этот конкретный дизайн с pub-sub евентом?

I>>>Именно! Тогда и моки не нужны. И это более сильные гарантии, т.к. важные особенности поведени мы экспозим наружу явно. И вместо проверок вида "как используется" мы можем взять "что такое", "чем является".

I>·>Т.е. евенты нахрен не нужны. ЧТД.
I>Буквально — языковая фича event может и не нужна, а вот функциональная возможность уведомлений — нужна. И крайне важно, что бы она явно фигурировала в самом интерфейсе.
Нужна для чего? Важно для чего?

I>>>С т.з. количества вызовов — один в один. С т.з. деклараций — эвенты выигрывают.

I>·>За счёт чего выигрывают? Допустим вот декларация ифейса: interface Hmrc{void trackHim(int);}. Покажи соответствующий евент.
I>Уже было, много раз
I>
I>   $thresholdExceeded: Source<ThresholdExceeded>; 
I>

Здесь нет декларации ThresholdExceeded. Выигрыш-то в чём?

I>>>·>Угу. Т.е. эквивалентно. Ещё раз повторюсь — вызов метода — частный случай евента.

I>>>Частный, всё происходит унутре, и проверки соответственно нужны "как используется", что есть хрупкий дизайн.
I>·>Что "всё"?
I>Логическая связь между hmrc и transfer в твоем варианте дизайна находится в самой реализации, больше нигде этого нет, ну еще в каментах, если ты их пишешь.
Кажется понял. Ты имеешь в виду, что у меня от hmrc зависит класс MoneyService, а не его метод transfer. Правильно? Я не вижу в проблемы. В требованиях и написано как раз что MoneyService должен уведомлять, а не transfer. Например, добавление второго метода batchTransfer в сервис ничего не меняет с т.з. уведомлений в налоговку.

I>>> Ну и дичь. Без фремворков ты будешь писать низкоуровневый код вида "ожидать сокет — читать сокет — писать в сокет" или "создать сокет — писать в сокет"

I>·>Если библиотеку для работы с конкретным протоколом ты называешь фреймворком, мы опять разошлись в терминологии.
I>Сейчас все делается фремворками — Swing, Hibernate, и тд.
I>API описывается в терминах какого либо фремворка.
Жуть. API обычно описывается на уровне протокола-транспорта. REST там или FIX или gRPC или ещё чего.
Хотелось бы посмотреть API описанное в терминах Swing или Hibernate... гы.

I>>>·>Не знаю как у вас, но у нас вероятность нахождения багов ниже в проде, чем в пре-проде.

I>>>Уже прогресс — сдвиг с "багов нет" на "вероятности". Неплохо.
I>·>Причём тут необнаруженные баги-то?! Если мы говорим о "run test", то значит есть тест, и значит баги уже обнаружены и пофикшены. Вероятность того, что "run test" в проде что-то найдёт — 0, просто по дизайну процесса разработки и тестирования.
I>Это заблуждение. Баг описывается в терминах внешнего поведения, а не "вот это значение надо закаментить". А раз так, то на это поведение влияет хрен-знает-скольки-лион факторов.
Не понимаю почему поведение кода должно принципиально отличаться pre-prod vs prod.

I>>>Очень даже принципиально. набор публичных методов + конструктор + каменты это называется "реализация"

I>·>void qwer(Xyz xyz) — вот скажи, тут Xyz класс или интерфейс? Не заглядывая в декларацию и без рефлекии ты сможешь хоть как-то отличить? Так вот в моём куске кода так и было, для MoneyService имя Hmrc было просто типом где можно звать публичные методы. Всё.
I>Ты привел конкретный пример, его и рассматриваем. Ты ведь настаиваешь, что это типичный код. И с ним проблемы. Неужели непонятно?
Верно, если рассмотреть конкретный пример MoneyService то внезапно выяснится, что совершенно неважно Hmrc — это класс или интерфейс, но ты упорно прикопался к этому, хотя на конкретный пример это вообще никак не влияет. Код и тест MoneyService для ифейса и класса Hmrc будет идентичным.

I>>>Ага, выбросил и оставил только то, что лично тебе удобно

I>·>Что значит "удобно"? Я оставил то, что в спеке. Я не хочу рассматривать все возможные решения переовда денег. А то мы так и можем до спора что лучше WesternUnion или Bitcoin.
I>Спека на бизнес-задачу, а не на класс, алё! Все 4 варианта позволяют решить ту же задачу, что и у тебя.
Ясен пень. И мой 0-й вариант тоже позволяет решить задачу. И кода в моём варианте меньше чем каждом из твоих 4-х.

I>>>·>Наконец-то какой-то конкретный код. Теперь пожалуйста доработай свой код, чтобы не выпускать наружу тот факт, что нам нужно посылать конкретный ThresholdExceeded. Это детали реализации.

I>>>Именно, что детали.
I>·>Верно. Неясно накой ты их вынес наружу.
I>Что в коде — детали, и как я вызову эвент — тоже детали. Снаружи — паблик АПИ, он явно описывает ключевые вещи.
Ключевой момент transfer — перевод денег. Уведомления в налоговку — детали реализации. Зачем факт того, что евент может посылаться выносить в паблик АПИ MoneyService? Откуда ты это взял? Это вообще может быть секрет, и клиентам это не положено знать, вдруг эти уведомления часть Anti Money Laundry и их разглашать в принципе нельзя?

I>>>Опаньки — условий то может быть много а раз так, то это тянет на разделение ответсвенности — сервис для трансфера, и те самые полиси, про которые я тебе уже говорил.

I>·>Для тебя опаньки, а у меня ничего не меняется. Для небольшого множества условий можно прямо в MoneyService написать, если что-то сложее пары ифов, то можно вынести отдельно добавится зависимость этого самого полиси в этот самый MoneyService. Для консумеров ничего не поменяется.
I>Это смотря какая цель. Если цель изолировать консумеров полностью, выбираем один вариант, если цель сообщить консумерам о важных последствия, выбираем второй вариант.
То что сообщается консумерам должно быть инкапсулировано в Result, "someRepId" какой-нибудь, который transfer возвращает. Зачем события-то? Уведомление в налоговку — обязанность MoneyService, а не его консумеров. Делая [result, event] ты неявно передаёшь ответственность передачи уведомлений консумерам. Теперь ты должен интеграционно тестировать _всех_ консумеров, что они завайрены правильно, что они таки передают этот event куда надо, а не теряют на полпути.

I>>>Раскрой глаза — пользователи знают только о том, что можно превышение некоего порога можно наблюдать снаружи.

I>·>_Зачем_ им это знать? им деньги переводить надо, на пороги им побарабану.
I>Я про пользователей, т.е. консумеров конкретного класса. Мало ли для чего они захотят уведомлемния получать — руководство, бухгалтерию, аудит, логи и тд. Или ты собираешься на каждый кейс создавать свой сервис с отдельным composition root ?
Не знаю. Требования были вполне конкретными. Не знаю откуда ты придумал про бухгалтерию.

I>·>Для пользователей MoneySerivce пофиг на вызов налоговой. Это легальное обязательство функционирования MoneyService, что он должен уведомлять налоговку об определённых транферах. Ты когда в своём банке перевод делаешь, ты знаешь какие вызовы куда делаются?

I>Как минимум, мне обязаны сообщить о последствиях, включая уведомления налоговой и тд.
Не обязаны. В лучшем случае ты об этом узнаешь поставив подпись в договоре с банком.

I>>>·>Где определение ThresholdExceeded и куда это потом сувать?

I>>>
I>·>Шо?
I>Мы снова наблюдаем нежелание посмотреть ну хотя бы в C#
ThresholdExceeded это часть C#-языка??! Я хочу посмотреть конкретный код.

I>>>Про фремворк я рассказал подробно и пояснил, чем разработка фремворка отличается от продуктовой. Тебе ссылку на репозиторий дать или что?

I>·>Ок, если я в своём примере переименую классы, чтобы это было не MoneyService а FrameworkStuff, это что-то принципиально изменит?
I>Фремворк это не просто класс или либа, это расширение языка библиотечными методами для решения некотороного семейства задач на конкретном слое.
I>Отсюда ясно, что твой MoneyService как его ни назови, фремворком быть не может.
I>А вот та хрень, которой ты АПИ описываешь, на которой у тебя апликейшн построен, это и есть фремворк.
За шарп не скажу, то java язык достаточно хороший, чтобы на нём писать без расширений.

I>>>Отсюда следует, что именно ты считаешь тестовые аккаунты моками.

I>·>Я имел в виду, чтобы какие-то определённые аккаунты были тестовыми, сервисы их должны распознавать и менять своё поведение на заданное. Т.е. сервисы для тестовых аккаунтов ведут себя как моки. Иными словами, использование тестовых аккаунтов это по сути использование моков.
I>Не тестовых аккаунтов, а тестовых сервисов. Это НС такие сервисы считает моковыми, типа Mailtrap. Я не согласен с таким определением, т.к. слово мок размывается.
В чём принципиальная разница между моком и тестовым сервисом? Какая принципиальная разница verify(mailSenderMock).sendMail(X) или mailTrapApi.verifyMailSent(X)?
У тебя тестовые сервисы работают в проде? Иначе как ты запускаешь "run test -P e2e" проде?

I>>>Сервис. Именно он обладает поведением.

I>·>Т.е. сервис должен мочить хотя бы часть своего поведения.
I>Вот-вот, сначала ты пишешь, что сервис должен мочить, а потом говоришь что не считаешь моки обязательными. Надо бы определиться.
Я считаю моки необязательными??! Ты где такое прочитал? Я их считаю неизбежными. Без моков полноценно тестировать в принципе нельзя.

I>На мой взгляд мокать надо только если не можешь по какой либо причине протестировать иначе, см http://rsdn.org/forum/flame.comp/8218388.1
Автор: Ikemefula
Дата: 03.03.22

"Иначе" всегда есть возможность протестировать — на юзерах Цель-то обнаруживать ошибки как можно раньше. Идеал — в процессе набора кода: "не компилится, значит не работает".

I>>>Конкретно — что за тесты, какой уровень тестирования, какой подход? Ты забыл, что доступа к конфигу у тебя нет.

I>·>Конфиг это не магический артефакт, а, условно говоря, текстовый файлик. Он либо валиден, либо нет. Все варианты того что принципиально может оказаться там в проде — ты можешь контролировать и тестировать до выкатки в прод. Если там окажется что-то неожиданное — приложение может проверить при запуске и упасть, что завалит выкатку в релиз.
I>И валидация это не магия, а обычный кусочек кода. Неожиданные вещи совсем необязательно приведут к падению. Примеры уже приводил.
Это верно для всего. В том числе и что юзер вводит в поле ввода. Нажал неожиданно не ту кнопку и всё навернулось в проде. Неясно чем баги в конфиге должны принципиально отличаться от багов в самом приложении.

I>>>Это всего лишь вероятность. Следовательно, есть вероятность, что баг попадет на прод.

I>>>Согласен?
I>·>Вероятность чего? Тест либо зелёный, либо красный.
I>Код не говорит тебе, сколько причин у бага. И часть этих причин могут быть связаны именно с продом. Более того — далеко не факт, что ты знаешь все это.
Если устранение причины X не устраняет данную проблему в проде, значит мы сделали неверный root cause анализ. Нужно идти на второй круг — находим причину Y, репродьюсим в тестовом окружении, правим, прогоняем тесты, релизим.

I>>>И дальше делать с этим риском, как им управлять, алё? Первое срабатывание бага, уронит, условно, самолёт. Потом приходят к тебе и видят, что ты знал за проблему. Гыгы.

I>·>Ты что-то опять контекст теряешь. Было: "при многочисленных одновременных запросах с одного юзера файрвол начинает резать запросы на запись". Какая первая бага? Какой самолёт?
I>А что, это принципиальная разница, уронить прод и уронить самолет? Цена ошибки "уронить прод" может исчисляться человеческими жизнями.
Я перестал поспевать за твоей мыслью. "начинает резать запросы" — ты же заявил, что это уже в баклоге, т.е. это уже упавший самолёт.

I>>>Вообще то это называется неявная, т.к. реальная связь следует исключительно из реализации ну или каментов.

I>·>Что такое "реальная связь", бывают ли нереальные связи и какие комменты?
I>Реальная, это значит фактическая.
А какая ещё связь бывает? Эмоциональная?

I>>> Похоже, религия мешает глянуть да разобраться.

I>·>И что там особенного-то? +=?
I>Эвенты позволяют строить более гибкий дизайн, который легче тестировать, легче отслеживать связи, легче изменять. Все это по причине того, что явно обозначают поведение в интерфейсе.
I>Соответственно, у нас более глубокая изоляция компонентов. Отдельно логика, отдельно взаимодействие, отдельно интеграция.
Тебе не удалось это продемонстрировать. Скорее наоборот. Твой код и тесты стали на порядок сложнее.

I>>>Посмотри, что пришло на смену.

I>·>Уйдёт туда же. Эту фигню притаскивают ui-девелоперы с ихними on_button1_click.
I>https://en.wikipedia.org/wiki/Async/await
I>Это все корутины.
node/js для бывших VB-разработчиков.

I>>>Очевидно, что есть, в интеграционном коде, там где обрабатывается конкретный юз кейс. Мало ли для чего нотификация используется

I>·>Я этот код не видел. Код в студию, с тестами.
I>
I>   useCase() {  
I>        ...   
I>    const [result, event] = this.svc.transfer();
I>        this.auditQueue.send(event);

I>    return result; 
I>   }
I>

I>И никаких моков queue нам не надо — в интеграционном тесте мы можем прочесть и убедиться, что все хорошо.
У тебя нет тут реализации требования, что MoneyService посылает уведомление. Тут у тебя он только генерирует, а за посылку сообщения должны отвечать консьюмеры сервиса.

I>сам useCase юнитами покрывать не нужно, он должен быть

Зато теперь ещё ты создал необходимость писать и интеграционный тест.

I>>>Фиксуны всегда откуда то берутся, их процессы как раз не сдерживают. В этом и проблема.

I>·>Тесты в проде сдерживают? Гы.
I>Тесты в проде это часть административных мер, таких же как и code review.
I>Если мы знаем, что сценарий прошел на проде, значит вероятность известных багов низка, и риски можно принять.
Верно. Но ты опять доказываешь необходимость запуска тестов в проде необходимостью запусков тестов в проде.
Тесты в пре-проде это тоже часть административных мер. И это означает, что вероятность известных багов в проде низка, и риски можно принять.

I>>>Юнит-тесты для сценариев фейла не годятся. А для прода надо проверить сценарии, в т.ч. и фейла.

I>·>Юнит-тесты как раз идеальны для сценариев фейла.
I>Ок, покажи мне юнит-тест вида "сообщения в налоговую никогда не теряются и накапливаются в очереди если внешняя сеть недоступна, трансферы проходят как положено, аудит это подтверждает, после возобновления работы внешней сети сообщения достигают источника за время x"
Элементарно: условно что-то вроде verify(persistentQueue).sendMessage(X). За гарантированную доставку отвечает mq-брокер и у него есть свои тесты.

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

I>·>Тест либо красный, либо зелёный. Цвет теста зависит от кода, а не от того, где он запускается. Вероятность может быть лишь в том, что мы пофиксили что-то не то, неправильно воспроизвели проблему или не так поняли суть бага.
I>Алё! Еще в 70х стало известно, что для сложного софта количество путей выполнения исчисляется астрономическими числами.
I>Отсюда ясно, что покрыл тестом, скажем, 1000000 путей. Как быть с остальными 10^14 — 1000000 путями ?
И поэтому и придумали разделение на юниты и ю-тесты, чтобы N*M сводить к N+M.

I>>>Ну и колхоз. Ты всерьез не в курсе, что уже давно известно решение?

I>·>Это, как минимум, не всем подходит. Для одной небольшой конторы стоимость оборудования прода была с кучей нулей... удваивать как-то накладно, мягко говоря. Для тестинга было более скромное оборудование.
I>Стоимость рабочей силы намного больше.
Верно. И рабочая сила тратит меньше времени тестируя всё у себя локально, чем ждёт когда оно провалится где-то в проде, куда разрабы ходят только "по праздникам".

I>>> Старая версия прода обслуживает юзеров. Новая версия пока еще нет. Переключим лоадбалансер — все придет в норму. ДО этого можем проверять этот прод сколько угодно.

I>·>А Hhmrc сервис-то настоящий прод или не очень прод?
I>Настоящий.
А налоговке точно понравится, что вы их спамите их прод каким-то левым трафиком?

I>·>Мне неважно что конкретно в конфиге прода. Мне важно то, что чтобы там ни было, у меня будет ожидаемая реакция — креш при старте от невалидного конфига, лампочки мониторинга при ошибках в окружении, етс.

I>Это ведь не просто так. Что бы лампочка загорелась, ктото должен скрипт написать "если вот такой запрос то жди +1 в счетчике hmrc иначе запаливай лампочку".
Не знаю что за "скрипт" ты имеешь в виду. Простой код и ю-тест к нему.

I>Упс, мы выяснили, что hmrc должен не только налоговую уведомлять, но и счетчик мейнтенйнить...

I>Чуешь, куда все идет?
Куда-то в область бурной фантазии. Какой счётчик?!

I>·>Если кто-то явно в конфиге прода пропишет noop, то это либо саботаж, либо так и надо. Это проблемы эксплуатации, а не разработки. Если что, внесение изменений в прод-конфиг — это отдельный сложный процесс со своими аппруверами и прочими свистоплясками.

I>В том процессе я так понял, ошибки тоже архитектурно невозможны?
Архитектурные ошибки процесса эксплуатации?! А что это такое?

I>>>Через какое время L2 support начнет подозревать, чтото идет не так?

I>·>Неясно что ловить ты собрался.
I>Отсутствие вызовов hmrc в течение первых часов эксплуатации. собственно, подсказка выше.
А почему ты решил что они должны быть? Может все только мелкими переводами балуются? Если соединение с hmrc установлено и пинги идут, значит всё работает в соответствии с установленным режимом эксплуатации. Если кто-то явно поменял режим в noop и ещё кто-то это явно заапрувил, значит так и надо, девам это знать и не положено по должности.

I>>>А эвент это и есть обратный вызов. Ты лучше посчитай издержки потока на создание, отправку одного единственного потока и прием ответа.

I>·>"потока"? Я не понял что ты имеешь в виду.
I>поток = thread, т.е. CPU. Попробуй, посчитай. Я вот таким несколько лет занимался, потому и знаю.
Какое это отношение имеет к вызовам метода и событиям? Что такое поток отправляющий поток (см. подчёркнутое)? Накой вообще потоки постоянно создавать?! Короче, я нихрена не понял.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[54]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 07.03.22 16:52
Оценка:
Здравствуйте, ·, Вы писали:

I>>Баги не в курсе, что они вам чего то дожны. Баг это штука всегда сильно вероятностная, т.к. в современном софти количество путей выполнения исчисляется в астрономических единицах.

·>Тесты нам должны. А если какие-то тесты нам ничего не должны, то мы зря на них тратим время.

Вот-вот. Тут главное избавиться от иллюзии про 100% гарантии вида
1. нет багов/уязвимостей (зафикшены,необнаруженых итд)
2. все причины установлены

I>>Одна проблема — посчитать эту вероятность пока нет матана. Разве что голословно, как у тебя.

·>Ок. Но что это меняет?

Багфикс и тестирование всего лишь уменьшают вероятность, не могут исключить проблему полностью. Условно — всегда есть другой, неизвестный тебе путь, который приведет к тому же результату.

I>>Я уже приводил большой список, почему это может быть. До кучи бд прода, депенденсы как правило имеют другий цикл жизни, и в тамошней бд к примеру, может накапливаться чорт знает что.

·>Так разберитесь, чтобы было не чёрт знает что, а то что надо.
·>Например, можно организовать процесс копирования бд из прод в препрод (возможно с санитизацией) чтобы можно было спокойно гонять тесты и отлаживать, имея на руках прод-like данные.

Как я сказал выше — 100% гарантий никогда не бывает. Единственное исключение — нет бага/уязвимости только если прод физически выключить.


I>>Например, фиксанул ты препрод, ну скажем, баг с попаданием битых данных в queue, а на проде, внезапно, оказалось, время жизни таких записей исчисляется не часами, а годами, потому, что есть еще один баг, и вариантов битых записей не три, как у ты думал, а 10, из которых 7 будут срабатывать разад два в год.

·>В том-то и дело — _внезапно_. Анализируйте все эти внезапности и боритесь с ними.

Это опять же не дает 100% гарантии. Время всегда ограничено. Если ты анализировал X часов эти внезапности, то это значит, что в это время ты не смотрел в другую сторону.
Все просто — невозможно 100% времени тратить на 100% направлений.

I>>Наоборот, это именно реальные юзеры на своем обычном окружении. И разница между RC и Release исключительно в версии — 7.0.1943-RC 7.0.1944

·>У них обычно, как минимум, другой T&C, они аккцептят больше рисков. Т.е. по сути тестеры. Суть-то одна: бета-тестеры — не реальные пользователи.

Да не гони, это именно обычные пользователи.

Кроме того, кейс с immutable deployment — его специально делают на тот случай, что бы сделать быстрый откат.

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

I>>Забвно, что релиз-кандидат у тебя бетой стал. Ну-ну.

·>Официально зовут "beta-release", т.е. опять терминологическая разница, "beta-release" это то что перед "final release" и по сути "pre-release", что не далеко от "release candidate".

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

I>>Наоборот — пользуются. Если быстро выявлены проблемы, сразу вместо 7.0.0 будет релизнут какой нибудь 7.0.0.1

·>Нет, обычно даже две странички для скачивания.

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

I>>А вообще — смотри на версионирование нынешник вещей навроде вындоуса — просто 10.0.19044

·>Последняя циферка это обычно номер билда в CI, и к релизности отношения не имеет.

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


·>Ясен пень. Это цель на уровне FRD. Ты же не тест для docx файла пишешь, ты пишешь код, притом тест — это тоже код. Следовательно в каком-то месте у тебя будет некий боевой код который что-то дёргает для обеспечения данной цели.


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

I>>·>Покажи на уровне кода.

I>>and notification $налоговая is succeed
·>Ок. К чему это привязывается?

Да как угодно. Это, к слову, e2e тест, система от прода отличается только конфигом, никаких моков здесь уже нет.
Кстати, забавно, что ты скипнул весь тест и оставил в нем одну строчку.

I>>Разумеется. Будет еще небольшой wiring код, ровно как у тебя в примере, и вот там будет подкидываться связка.

·>Покажи, без зависимости от 3rd party library, как ты требуешь. И покажи как ты это тестируешь

Ты нормальный? Этот вайринг код и будет связывать зависимости с тем компонентов. Тест я уже показал — раскрой глаза.
Цель использования эвента — максимальное развязывание компонентов.

I>>На самом деле это не повод фейлить трансфер. Это повод повторить уведомление налоговой со временем. А то сервис налоговой может начать блокировать работу твоей системы.

·>Это ты сочиняешь требования на ходу. Повод-неповод, это определяется FRD, а не евентами.

Просто пример, который под твоё "решение" не подходит

·>В любом случае, евенты всё равно не нужны. Реализация trackHim это всё может обеспечивать у себя вунутре


Может. А может и нет. Зависит от конкретной архитектуры. Эвенты — это инструмент, который позволяет развязать компоненты, облегчить интеграцию.

I>>И вот это юнит-тестами не проверяется

·>Юнит-тестами самого MoneyService, ясен пень не проверяется. Но проверяется юнит-тестами соответствующего компонента, который заботиться о доставке уведомлений.

Снова у тебя юнит-тесты вместо интеграционных

I>>Зато здесь помогут те самые интеграционные тест — симулируем косяк налоговой, типа "а пусть фарвол блокирует", и тогда "нотификация ушла спустя 10с после возобновления"

I>>или "пока налоговая недоступна, очередь хранит нотификации"
·>Как ты собрался симулировать косяк налоговой в проде?

Точно так же, как симулируются фейлы на уровне системы.

I>>Мало ли, что там фиксун придумал. Он "фремворками не пользуюсь у меня 10 лет опыта, да и вообще, там всё на сокетах", намастырил на коленке запрос, ему так понятнее, да и отослал.

·>Тогда красным. Нефиг всякую наколенность в прод сувать.

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

I>>Ога. И снова налоговой придется мейнтейнить твой файрвол.

·>Мой фаерволл проверяется пингами-хартбитами и прочим мониторингом. Как выяснилось, мониторинг всё равно необходим. И-тесты в проде ничем не помогут, т.к. конфигурация прод сети никак не связана с моими релизами и запуск "run test" никто не обещает.

А кто говорит, что мониторинг не нужен? Тесты прода это быстрый тест на то, что в нем выполнимы сценарии юзеров.
Мало ли, деплоймент поднялся с какими то мелкими багами. Самое правильно — задетектить по быстрому, откатить деплой, фиксануть, передеплоить.

I>>Мне поможет например e2e тест, овнершип которых находится у других людей, и там просто так не закоментишь.

·>Так оказывается у вас длинный список людей, которые проверяют каждый фикс :facepalm

Где ты видишь про длинный список? Я всего то про овнершип. Вот скажем, если овнершип e2e у меня, то тебе придется объяснить мне, на кой ляд ты хочешь закаментить степ в сценарии.

I>>Фиксуны они вездесущие. Ну и мержи/ребейзы никто не отменял.

·>А как же овнершип?

А что овнершип?

I>>Процесс воздействия объектов друг на друга. Очевидно, в моем дизайне есть явный интерфейс, который описывает вход, параметры, и выход — возвращаемое значение и событие.

·>У меня тоже явный интерфейс. Просто у меня уведомление сокрыто от консьюмеров интерфейса, в соответствии с бизнес-требованиями. У тебя оно торчит наружу, чисто шоб было.

Нету такого в бизнес-треботвания, как "скрывать важные вещи от консумеров интерфейса".

·>Напомню, в ООП — вызов метода это единственный способ воздействия объектов друг на друга. И твоё событие — это тоже объект. И подписка на события — это тоже вызов метода.


Именно. А воздействовать можно исключительно через интерфейс. Я предпочитаю иметь в интерфейсе явную связь,а у тебя "по бизнес требованиям надо усё упрятать поглубже"

I>>Еще раз — мок не заменяет ни один интеграционный тест, нисколько.

·>Это out-of-scope моего примера. Интеграция с налоговой может быть протестирована в рамках Hmrc класса.

В рамках класса ты никакую интеграцию не проверишь. У нас кроме логи куча всего — wiring, di, config, bootstrap, composition root, use case, environment, policies, proxy, firevall, audit, instrumentation и тд
Вот это всё надо проверить вместе взятой. Отсюда ясно, что "в рамках класса" этого нет и быть не может.

I>>Выбрал конкретный дизайн — провел границы компонентов, выявил точки взаимодействия, описал для этого интерфейс.

·>На основании чего конкретно ты выбрал этот конкретный дизайн с pub-sub евентом?

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

Разумеется, взгляд из каменного века даст иную картину — окажется, буквально, что таким методом нам мамонта не убить

I>>Буквально — языковая фича event может и не нужна, а вот функциональная возможность уведомлений — нужна. И крайне важно, что бы она явно фигурировала в самом интерфейсе.

·>Нужна для чего? Важно для чего?

Использование, чтение, анализ кода, поиск проблем, инструментирование, аудит и тд.

I>>Уже было, много раз

I>>
I>>   $thresholdExceeded: Source<ThresholdExceeded>; 
I>>

·>Здесь нет декларации ThresholdExceeded. Выигрыш-то в чём?

В том, что ThresholdExceeded объявлен в терминах моего компонента, а не в единицах какой то 3rd party либы.
Соответственно, нам не надо мастырить игрушечный контекст на моках, что покрыть функционал.

I>>Логическая связь между hmrc и transfer в твоем варианте дизайна находится в самой реализации, больше нигде этого нет, ну еще в каментах, если ты их пишешь.

·>Кажется понял. Ты имеешь в виду, что у меня от hmrc зависит класс MoneyService, а не его метод transfer. Правильно? Я не вижу в проблемы.

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


I>>API описывается в терминах какого либо фремворка.

·>Жуть. API обычно описывается на уровне протокола-транспорта. REST там или FIX или gRPC или ещё чего.

Это описание http контроллера. Его задача очистить вход от протокольного мусора. Для graphql есть свое описание, для gRPC — своё. Это уже состоявшаяся реальность.
Все это обычно пишется или генерируется по описанию апи.

I>>Это заблуждение. Баг описывается в терминах внешнего поведения, а не "вот это значение надо закаментить". А раз так, то на это поведение влияет хрен-знает-скольки-лион факторов.

·>Не понимаю почему поведение кода должно принципиально отличаться pre-prod vs prod.


отличается конфигурация
отличается цикл жизни зависимостей
отличается энвайрмент, сам по себе

I>>Ты привел конкретный пример, его и рассматриваем. Ты ведь настаиваешь, что это типичный код. И с ним проблемы. Неужели непонятно?

·>Верно, если рассмотреть конкретный пример MoneyService то внезапно выяснится, что совершенно неважно Hmrc — это класс или интерфейс, но ты упорно прикопался к этому, хотя на конкретный пример это вообще никак не влияет. Код и тест MoneyService для ифейса и класса Hmrc будет идентичным.

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

Соответсвенно, в общем случае тебе нужен интерфейс, + моки, + тесты вида "проверим, что унутре вызвалось вот так"

На эвентах будет иначе- "проверим, что унутре вызвали вон то" у нас не будет, т.к. не будет зависимости, и мокать "htmr.trackHim(321).willReturn" тоже не надо.

I>>Спека на бизнес-задачу, а не на класс, алё! Все 4 варианта позволяют решить ту же задачу, что и у тебя.

·>Ясен пень. И мой 0-й вариант тоже позволяет решить задачу. И кода в моём варианте меньше чем каждом из твоих 4-х.

Если закрыть глаза на интерфейсы, моки и тесты "а вот как всё унутре"....

I>>Что в коде — детали, и как я вызову эвент — тоже детали. Снаружи — паблик АПИ, он явно описывает ключевые вещи.

·>Ключевой момент transfer — перевод денег. Уведомления в налоговку — детали реализации. Зачем факт того, что евент может посылаться выносить в паблик АПИ MoneyService? Откуда ты это взял? Это вообще может быть секрет, и клиентам это не положено знать, вдруг эти уведомления часть Anti Money Laundry и их разглашать в принципе нельзя?

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

·>То что сообщается консумерам должно быть инкапсулировано в Result, "someRepId" какой-нибудь, который transfer возвращает. Зачем события-то? Уведомление в налоговку — обязанность MoneyService, а не его консумеров. Делая [result, event] ты неявно передаёшь ответственность передачи уведомлений консумерам.


Правильно, у одного консумера так, у другого — эдак. Мало ли, юз кейсы какие.

I>>Я про пользователей, т.е. консумеров конкретного класса. Мало ли для чего они захотят уведомлемния получать — руководство, бухгалтерию, аудит, логи и тд. Или ты собираешься на каждый кейс создавать свой сервис с отдельным composition root ?

·>Не знаю. Требования были вполне конкретными. Не знаю откуда ты придумал про бухгалтерию.

Ну так не тебе одному же условия задачи менять.

I>>Как минимум, мне обязаны сообщить о последствиях, включая уведомления налоговой и тд.

·>Не обязаны. В лучшем случае ты об этом узнаешь поставив подпись в договоре с банком.

Ну и дикая страна у вас.

I>>Мы снова наблюдаем нежелание посмотреть ну хотя бы в C#

·>ThresholdExceeded это часть C#-языка??! Я хочу посмотреть конкретный код.

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

I>>А вот та хрень, которой ты АПИ описываешь, на которой у тебя апликейшн построен, это и есть фремворк.

·>За шарп не скажу, то java язык достаточно хороший, чтобы на нём писать без расширений.

И потому в джава поголовно используют spring и hybernate?

·>У тебя тестовые сервисы работают в проде? Иначе как ты запускаешь "run test -P e2e" проде?


Похоже, пошли по кругу. Уже объяснял.

·>Без моков полноценно тестировать в принципе нельзя.


Без моков нельзя
— зафиксировать исключительно вещи вида "вот здесь мы вызываем вон то, вон так"
На самом деле полезность таких проверок ничтожна или даже отрицательна
— вклиниваться в монолитный пайплайн
Решается правильным дизайном

I>>На мой взгляд мокать надо только если не можешь по какой либо причине протестировать иначе, см http://rsdn.org/forum/flame.comp/8218388.1
Автор: Ikemefula
Дата: 03.03.22

·>"Иначе" всегда есть возможность протестировать — на юзерах Цель-то обнаруживать ошибки как можно раньше. Идеал — в процессе набора кода: "не компилится, значит не работает".

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

I>>И валидация это не магия, а обычный кусочек кода. Неожиданные вещи совсем необязательно приведут к падению. Примеры уже приводил.

·>Это верно для всего. В том числе и что юзер вводит в поле ввода. Нажал неожиданно не ту кнопку и всё навернулось в проде. Неясно чем баги в конфиге должны принципиально отличаться от багов в самом приложении.

Вспоминаем ту самую вероятность и разницу между продом и пре-продом.

I>>Код не говорит тебе, сколько причин у бага. И часть этих причин могут быть связаны именно с продом. Более того — далеко не факт, что ты знаешь все это.

·>Если устранение причины X не устраняет данную проблему в проде, значит мы сделали неверный root cause анализ. Нужно идти на второй круг — находим причину Y, репродьюсим в тестовом окружении, правим, прогоняем тесты, релизим

В том то и дело. И это нужно узнать до того, как реальный трафик пойдет на прод.

I>>А что, это принципиальная разница, уронить прод и уронить самолет? Цена ошибки "уронить прод" может исчисляться человеческими жизнями.

·>Я перестал поспевать за твоей мыслью. "начинает резать запросы" — ты же заявил, что это уже в баклоге, т.е. это уже упавший самолёт.

Ну да. А если у тебя неверный root cause analysis, то упадет еще один самолет.

I>>>>Вообще то это называется неявная, т.к. реальная связь следует исключительно из реализации ну или каментов.

I>>·>Что такое "реальная связь", бывают ли нереальные связи и какие комменты?
I>>Реальная, это значит фактическая.
·>А какая ещё связь бывает? Эмоциональная?

Неявная, подразумеваемая, логическая, виртуальная, причинно-следственная, косвенная...

I>>Соответственно, у нас более глубокая изоляция компонентов. Отдельно логика, отдельно взаимодействие, отдельно интеграция.

·>Тебе не удалось это продемонстрировать. Скорее наоборот. Твой код и тесты стали на порядок сложнее.

Если чтото выбросить, то остаётся как правило меньше Вот у тебя мешок камней на шее. Если ты его выбросишь, тебе всплывать легче станет?

I>>·>Уйдёт туда же. Эту фигню притаскивают ui-девелоперы с ихними on_button1_click.

I>>https://en.wikipedia.org/wiki/Async/await
I>>Это все корутины.
·>node/js для бывших VB-разработчиков.

Корутины древние как мир. Их в C# добавили еще когда node и в планах не было. А в modula, smalltalk, lisp это было в начале времён.



I>>>>Очевидно, что есть, в интеграционном коде, там где обрабатывается конкретный юз кейс. Мало ли для чего нотификация используется

I>>·>Я этот код не видел. Код в студию, с тестами.
I>>
I>>   useCase() {  
I>>        ...   
I>>    const [result, event] = this.svc.transfer();
I>>        this.auditQueue.send(event);

I>>    return result; 
I>>   }
I>>

I>>И никаких моков queue нам не надо — в интеграционном тесте мы можем прочесть и убедиться, что все хорошо.
·>У тебя нет тут реализации требования, что MoneyService посылает уведомление. Тут у тебя он только генерирует, а за посылку сообщения должны отвечать консьюмеры сервиса.

Нету такого требования, а потому MoneyService мы можем задизайнить как проще.

I>>сам useCase юнитами покрывать не нужно, он должен быть

·>Зато теперь ещё ты создал необходимость писать и интеграционный тест.

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

·>Верно. Но ты опять доказываешь необходимость запуска тестов в проде необходимостью запусков тестов в проде.

·>Тесты в пре-проде это тоже часть административных мер. И это означает, что вероятность известных багов в проде низка, и риски можно принять.

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

I>>Ок, покажи мне юнит-тест вида "сообщения в налоговую никогда не теряются и накапливаются в очереди если внешняя сеть недоступна, трансферы проходят как положено, аудит это подтверждает, после возобновления работы внешней сети сообщения достигают источника за время x"

·>Элементарно: условно что-то вроде verify(persistentQueue).sendMessage(X). За гарантированную доставку отвечает mq-брокер и у него есть свои тесты.

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

I>>Алё! Еще в 70х стало известно, что для сложного софта количество путей выполнения исчисляется астрономическими числами.

I>>Отсюда ясно, что покрыл тестом, скажем, 1000000 путей. Как быть с остальными 10^14 — 1000000 путями ?
·>И поэтому и придумали разделение на юниты и ю-тесты, чтобы N*M сводить к N+M.

N+M, N*M это ничтожная величина, которая на фоне 10^14 неотличима от нуля. Все остальное работает против тебя.

I>>Стоимость рабочей силы намного больше.

·>Верно. И рабочая сила тратит меньше времени тестируя всё у себя локально, чем ждёт когда оно провалится где-то в проде, куда разрабы ходят только "по праздникам".

Наоборот — рабочая сила тратит больше времени, тестируюя у себя локально, и в проде, сокращая количество итераций багфикса.

I>>Настоящий.

·>А налоговке точно понравится, что вы их спамите их прод каким-то левым трафиком?

Теоретически, может и не понравится. Это решаемо. Без моков.

I>>Это ведь не просто так. Что бы лампочка загорелась, ктото должен скрипт написать "если вот такой запрос то жди +1 в счетчике hmrc иначе запаливай лампочку".

·>Не знаю что за "скрипт" ты имеешь в виду. Простой код и ю-тест к нему.

Нужен интеграционный тест вида "счетчики работают и попадают в мониторинг" + "фейла виден на мониторинге"

I>>Упс, мы выяснили, что hmrc должен не только налоговую уведомлять, но и счетчик мейнтенйнить...

I>>Чуешь, куда все идет?
·>Куда-то в область бурной фантазии. Какой счётчик?!

Обычный. ты то не хочешь рассказывать как L2 суппорт решит задачу "два часа назад должно было быть 1000 запросов к налоговой", я придумал своё решения.
не устраивает — приводи свой вариант.

I>>В том процессе я так понял, ошибки тоже архитектурно невозможны?

·>Архитектурные ошибки процесса эксплуатации?! А что это такое?

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

I>>Отсутствие вызовов hmrc в течение первых часов эксплуатации. собственно, подсказка выше.

·>А почему ты решил что они должны быть? Может все только мелкими переводами балуются?

Мне нужны гарантии, что L2 суппорт сможет обнаружить такую проблему.

I>>поток = thread, т.е. CPU. Попробуй, посчитай. Я вот таким несколько лет занимался, потому и знаю.

·>Какое это отношение имеет к вызовам метода и событиям? Что такое поток отправляющий поток (см. подчёркнутое)? Накой вообще потоки постоянно создавать?! Короче, я нихрена не понял.

CPU тебе тоже нужен? И твоя джава без единого потока работает? Что бы отправить запрос, CPU в конкретном thread должен затратить кучу времени, (подготавливая блок, адрес, записывая в сокет,) на несколько порядков больше, чем прямой/обратный вызов.
Т.е. если прямой/обратный вызов это доли наносекунды, то сетевой запрос займен микросекунды. Реально — в зависимости от протокола еще больше, может даже милисекунды.
Итого — разница в микроскоп не видна. А тебе она мешает
Re[16]: откуда такая любовь к мокам?
От: Codealot Земля  
Дата: 07.03.22 20:03
Оценка:
Здравствуйте, Shtole, Вы писали:

S>Дорогой вы мой, это может быть не проектирование, а требование, прямо вписанное в договор.


Требование, что отчет ни в коем случае нельзя получить вызовом функции, а можно только сохранить в файл?
Ад пуст, все бесы здесь.
Re[56]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 08.03.22 09:35
Оценка: -1
Здравствуйте, Ikemefula, Вы писали:

I>Т.е. когда я показываю пример, что контроллер должен быть, условно, 5 строчек, линейным, тривиальным


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

I>До тебя что, это не доходит, или ты снова поиграть захотел? Играй без меня.


Вот псевдокод типичной зависимости:
class MyController
{
  ISomeService _someService;
  MyController(ISomeService someService) => _someService = someService;
  Task MyAction() => _someService.DoActionAsync();
}

class SomeService : ISomeService
{
  IDependency _dep;
  SomeService(IDependency dep) => _dep = dep;
  Task DoActionAsync()
  {
    _dep.GetDataFromDependency();
    ...
  }
}


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

I>>> то надо или много интеграционных тестов, тогда много времени

НС>>Опять непонятно. Как от размера контроллера зависит количество интеграционных тестов?
I>Мало ли что ты напихаешь в этот контроллер.

Офигеть просто аргумент.

I>Например, ты поместишь туда кучу низкоуровневого кода где читаем из одной бд


Зачем? Чтобы доказать что ты прав?

I>Как я вижу, у многих команд это вариант нормы — всё пихать в контроллер


Ну вот с теми командами ты и общайся на эту тему. Сюда ты зачем про это написал?

I>>>Есть и другой вариант, изменить дизайн, а именно — контроллер сделать коротким, линейным, тривиальным, вынести все или в компоненты, или, что лучше, в метаданные.

I>>>В таком случае нет необходимости гонять все тесты логики/поведения через интеграционные
НС>>Т.е. ты тоже предлагаешь надеятся на авось, что компонентные тесты выловят все проблемы?
I>Я предлагаю вспомнить пирамиду тестов и её смысл:
I>Проблемы в логике надо покрывать юнит-тестами, они дают максимально возможное покрытие и максимальные гарантии. Тестировать интеграцию юнит-тестами смысла нет

Не понял смысла этой фразы. Юнит-тесты по определению не тестируют интеграцию. Если они тестируют интеграцию, то они являются интеграционными тестами.

I>Проблемы в интеграции — интеграционными разных сортов. Логику тестировать интеграциоными смысла никакого нет — гарантии сильнее не станут.


Смелое заявление.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[55]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 08.03.22 12:20
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>·>Тесты нам должны. А если какие-то тесты нам ничего не должны, то мы зря на них тратим время.

I>Вот-вот. Тут главное избавиться от иллюзии про 100% гарантии вида
I>1. нет багов/уязвимостей (зафикшены,необнаруженых итд)
I>2. все причины установлены
Про 100% гарантии ты сам придумал. Мы сравниваем "запускать тесты в прод" vs "не запускать тесты в прод". Ни там, ни там 100% нет. Можно лишь говорить о проценте достаточном, чтобы мы приняли это за неизбежный риск.
Мой тезис в том, что запуск тестов в пре-прод должен уже давать достаточный процент, чтобы заакцептить риски. Следовательно запуск тестов в проде не даст ничего полезного, лишь увеличит риски, что излишняя активность в проде может негативно повлиять на настоящих юзеров, плюс решение дороже, т.к. требует двойное количество прод-ресурсов.
Если вы не способны обеспечить достаточное качество продукта в пре-прод, вы делаете что-то не то.

I>>>Одна проблема — посчитать эту вероятность пока нет матана. Разве что голословно, как у тебя.

I>·>Ок. Но что это меняет?
I>Багфикс и тестирование всего лишь уменьшают вероятность, не могут исключить проблему полностью. Условно — всегда есть другой, неизвестный тебе путь, который приведет к тому же результату.
Верно, это же верно и для прод тестов.

I>>>Наоборот, это именно реальные юзеры на своем обычном окружении. И разница между RC и Release исключительно в версии — 7.0.1943-RC 7.0.1944

I>·>У них обычно, как минимум, другой T&C, они аккцептят больше рисков. Т.е. по сути тестеры. Суть-то одна: бета-тестеры — не реальные пользователи.
I>Да не гони, это именно обычные пользователи.
У меня на компе десятки продуктов. И ни одного из них нет беты. Я не обычный пользователь?

I>Кроме того, кейс с immutable deployment — его специально делают на тот случай, что бы сделать быстрый откат.

Да, верно. Но это иррелевантно к нашему обсуждению.

I>Ты же понимаешь, что никто не будет держать синий прод вечно. А раз так, надо бы побыстрее дать гарантии, что зеленый не хуже.

Давайте эти гарантии в пре-проде. Ничего не мешает.

I>>>Забвно, что релиз-кандидат у тебя бетой стал. Ну-ну.

I>·>Официально зовут "beta-release", т.е. опять терминологическая разница, "beta-release" это то что перед "final release" и по сути "pre-release", что не далеко от "release candidate".
I>В зависимости от стратегии релиза и версионирования, релиз кандидат может сразу превратиться в релиз безо всяких дополнительных сборок. То есть — прошел тесты, значит релиз, не прошел — не релиз.
Причём тут сборки? Опять, это иррелевантно к нашему обсуждению.

I>>>Наоборот — пользуются. Если быстро выявлены проблемы, сразу вместо 7.0.0 будет релизнут какой нибудь 7.0.0.1

I>·>Нет, обычно даже две странички для скачивания.
I>Это ничего не меняет — опубликована и рассылаться юзерам будет только вторая, которая прошла тесты, а первая останется для истории.
Да, т.е. обычные юзеры юзают релиз, а не бету.

I>>>А вообще — смотри на версионирование нынешник вещей навроде вындоуса — просто 10.0.19044

I>·>Последняя циферка это обычно номер билда в CI, и к релизности отношения не имеет.
I>Это снова та самая стратегия версионирования. Совсем необязательно у релиз-кандидата будет тайтл, может быть и просто номер. Прошел тесты — значит релиз, не прошел — релиз-кандидат.
И что? Ты тестируешь сборку, а не деплоишь собранное нечто в прод. Сборка != деплоймет. Только после того сборка прошла все тесты, ты деплоишь официальный релиз. Какой номер присвоен и как оно названо — дело вкуса.

I>·>Ясен пень. Это цель на уровне FRD. Ты же не тест для docx файла пишешь, ты пишешь код, притом тест — это тоже код. Следовательно в каком-то месте у тебя будет некий боевой код который что-то дёргает для обеспечения данной цели.

I>Это неверно. Во первых, код может меняться часто по разными причинам. Теперь, на секундочку, надо все время бегать за твоими моками и патчить их.
Что неверно? Ты тестируешь FRD.docx??!

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

А что ещё-то? Любовь и тепло сердца?

I>>>·>Покажи на уровне кода.

I>>>and notification $налоговая is succeed
I>·>Ок. К чему это привязывается?
I>Да как угодно. Это, к слову, e2e тест, система от прода отличается только конфигом, никаких моков здесь уже нет.
У вас в проде тоже mailtrap стоит?

I>Кстати, забавно, что ты скипнул весь тест и оставил в нем одну строчку.

Потому что разговор идёт об этой строчке. Другие строчки — очевидны, не знаю что там обсуждать.

I>>>Разумеется. Будет еще небольшой wiring код, ровно как у тебя в примере, и вот там будет подкидываться связка.

I>·>Покажи, без зависимости от 3rd party library, как ты требуешь. И покажи как ты это тестируешь
I>Ты нормальный? Этот вайринг код и будет связывать зависимости с тем компонентов. Тест я уже показал — раскрой глаза.
Ты не тест показал, ты сценарий теста показал. Что делается этим сценарием — я это и спрашиваю. Вайринг код ты так и не показал.

I>Цель использования эвента — максимальное развязывание компонентов.

В-нулевых, евент — это лишь средство, эту же цель можно достигнуть другими средствами, _если_ вдруг понадобится. Во-первых, неясно зачем что-то развязывать максимально. Во-вторых, неясно что значит максимально развязывать. В-третьих, связывать развязанное тебе всё равно придётся. И ты упорно не хочешь это признать и кто для связывания затрудняешься написать.

I>>>На самом деле это не повод фейлить трансфер. Это повод повторить уведомление налоговой со временем. А то сервис налоговой может начать блокировать работу твоей системы.

I>·>Это ты сочиняешь требования на ходу. Повод-неповод, это определяется FRD, а не евентами.
I>Просто пример, который под твоё "решение" не подходит
А ещё моё решение кофе не варит!! Всё, я повержен!
Повторяю, повторы, блокировки налоговки — это всё не является частью поведения MoneyService, его дело простое — деньги переводить. А то что ты перечислил — будут требования к Hmrc-компоненту — он ответственен за гарантированную доставку, повторы, фейлы, етс.
Так что моё решение таки подходит, ибо моё решение описывает только работу MoneyService. Непонятно зачем ты своим супер-дизайном всё в кучу мешаешь.

I>·>В любом случае, евенты всё равно не нужны. Реализация trackHim это всё может обеспечивать у себя вунутре

I>Может. А может и нет. Зависит от конкретной архитектуры. Эвенты — это инструмент, который позволяет развязать компоненты, облегчить интеграцию.
А молоток позволяет забивать и шурупы тоже.

I>>>И вот это юнит-тестами не проверяется

I>·>Юнит-тестами самого MoneyService, ясен пень не проверяется. Но проверяется юнит-тестами соответствующего компонента, который заботиться о доставке уведомлений.
I>Снова у тебя юнит-тесты вместо интеграционных
Ты заявил глупость выше, что мол, не проверяется. Я описал как. Что не устраивает-то?

I>>>Зато здесь помогут те самые интеграционные тест — симулируем косяк налоговой, типа "а пусть фарвол блокирует", и тогда "нотификация ушла спустя 10с после возобновления"

I>>>или "пока налоговая недоступна, очередь хранит нотификации"
I>·>Как ты собрался симулировать косяк налоговой в проде?
I>Точно так же, как симулируются фейлы на уровне системы.
И как же?

I>>>Ога. И снова налоговой придется мейнтейнить твой файрвол.

I>·>Мой фаерволл проверяется пингами-хартбитами и прочим мониторингом. Как выяснилось, мониторинг всё равно необходим. И-тесты в проде ничем не помогут, т.к. конфигурация прод сети никак не связана с моими релизами и запуск "run test" никто не обещает.
I>А кто говорит, что мониторинг не нужен? Тесты прода это быстрый тест на то, что в нем выполнимы сценарии юзеров.
Для проверки выполнимости сценариев юэеров нет необходимости тестировать в проде.

I>Мало ли, деплоймент поднялся с какими то мелкими багами. Самое правильно — задетектить по быстрому, откатить деплой, фиксануть, передеплоить.

Какими мелкими багами? Если эти баги ловятся тестами, то какого хера ты задеплоил с багами??! А если не ловятся, то ты их не задетектишь по быстрому.

I>>>Мне поможет например e2e тест, овнершип которых находится у других людей, и там просто так не закоментишь.

I>·>Так оказывается у вас длинный список людей, которые проверяют каждый фикс :facepalm
I>Где ты видишь про длинный список? Я всего то про овнершип. Вот скажем, если овнершип e2e у меня, то тебе придется объяснить мне, на кой ляд ты хочешь закаментить степ в сценарии.
Фиксуны же твои любимые — они же всемогущие.

I>>>Фиксуны они вездесущие. Ну и мержи/ребейзы никто не отменял.

I>·>А как же овнершип?
I>А что овнершип?
Вот и я не понимаю, как так поставлен процесс у вас, что овнершип вроде как есть, но кто угодно всё что угодно втихушку может поменять и уйти в отпуск.

I>>>Процесс воздействия объектов друг на друга. Очевидно, в моем дизайне есть явный интерфейс, который описывает вход, параметры, и выход — возвращаемое значение и событие.

I>·>У меня тоже явный интерфейс. Просто у меня уведомление сокрыто от консьюмеров интерфейса, в соответствии с бизнес-требованиями. У тебя оно торчит наружу, чисто шоб было.
I>Нету такого в бизнес-треботвания,
Есть, конечно. Слыхал need-to-know принцип и information barriers?

I> как "скрывать важные вещи от консумеров интерфейса".

В бизнес-требовании не было требования показывать что попало консумерам. То что вещь важная и её непременно надо кому-то показывать ты сам придумал.

I>·>Напомню, в ООП — вызов метода это единственный способ воздействия объектов друг на друга. И твоё событие — это тоже объект. И подписка на события — это тоже вызов метода.

I>Именно. А воздействовать можно исключительно через интерфейс. Я предпочитаю иметь в интерфейсе явную связь,а у тебя "по бизнес требованиям надо усё упрятать поглубже"
Т.е. ты пишешь код по своим предпочтениям, а не по бизнес-требованиям, типичный over-engineering.

I>>>Еще раз — мок не заменяет ни один интеграционный тест, нисколько.

I>·>Это out-of-scope моего примера. Интеграция с налоговой может быть протестирована в рамках Hmrc класса.
I>В рамках класса ты никакую интеграцию не проверишь. У нас кроме логи куча всего — wiring, di, config, bootstrap, composition root, use case, environment, policies, proxy, firevall, audit, instrumentation и тд
I>Вот это всё надо проверить вместе взятой. Отсюда ясно, что "в рамках класса" этого нет и быть не может.
Вот и ставишь границу что чем проверяется. А ты всё смешал.

I>>>Выбрал конкретный дизайн — провел границы компонентов, выявил точки взаимодействия, описал для этого интерфейс.

I>·>На основании чего конкретно ты выбрал этот конкретный дизайн с pub-sub евентом?
I>Он дает максимальную развязку компонентов, позволяет ключевые вещи покрыть дешевыми и надежными тестами безо всяких моков.
Как выяснилось, не позволяет.
Да, ты покрыл часть более простым тестом, но часть оставил непокрытой, и теперь надо писать ещё дорогой тест с моками.

I>При этом точки интеграции оформлены явно, что облегчает использование, чтение, анализ кода, поиск проблем, инструментирование, итд итд итд

I>Разумеется, взгляд из каменного века даст иную картину — окажется, буквально, что таким методом нам мамонта не убить
Ты просто перепутал средства и цели.

I>>>Буквально — языковая фича event может и не нужна, а вот функциональная возможность уведомлений — нужна. И крайне важно, что бы она явно фигурировала в самом интерфейсе.

I>·>Нужна для чего? Важно для чего?
I>Использование, чтение, анализ кода, поиск проблем, инструментирование, аудит и тд.
Возможно, но это не требуемый публичный интерфейс MoneyService который в требованиях.

I>>>Уже было, много раз

I>>>
I>>>   $thresholdExceeded: Source<ThresholdExceeded>; 
I>>>

I>·>Здесь нет декларации ThresholdExceeded. Выигрыш-то в чём?
I>В том, что ThresholdExceeded объявлен в терминах моего компонента, а не в единицах какой то 3rd party либы.
Зато теперь тебе нужен код связывающий твой компонент с 3rd party либой. Выигрыш-то в чём?

I>Соответственно, нам не надо мастырить игрушечный контекст на моках, что покрыть функционал.

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

I>>>Логическая связь между hmrc и transfer в твоем варианте дизайна находится в самой реализации, больше нигде этого нет, ну еще в каментах, если ты их пишешь.

I>·>Кажется понял. Ты имеешь в виду, что у меня от hmrc зависит класс MoneyService, а не его метод transfer. Правильно? Я не вижу в проблемы.
I>Смотря как ты хочешь использовать. Например, в разных юзкейсах надо уведомлять разное по разному. Соответсвенно, упрятывать такое в конструктор я бы не стал.
Бизнес требования видел? Зачем фантазировать-то?

I>>>API описывается в терминах какого либо фремворка.

I>·>Жуть. API обычно описывается на уровне протокола-транспорта. REST там или FIX или gRPC или ещё чего.
I>Это описание http контроллера. Его задача очистить вход от протокольного мусора. Для graphql есть свое описание, для gRPC — своё. Это уже состоявшаяся реальность.
Так что за описание API в рамках Swing или Hibernate, можно пример?

I>Все это обычно пишется или генерируется по описанию апи.

Ну вот у тебя сгенерировался Result transfer(from, to, amount). Куда ты затолкаешь твои любимые евенты?

I>>>Это заблуждение. Баг описывается в терминах внешнего поведения, а не "вот это значение надо закаментить". А раз так, то на это поведение влияет хрен-знает-скольки-лион факторов.

I>·>Не понимаю почему поведение кода должно принципиально отличаться pre-prod vs prod.
I>
I>отличается конфигурация
Чем отличается? Именем хоста, портом? Вот и тестируйте это.

I>отличается цикл жизни зависимостей

Можно пример?

I>отличается энвайрмент, сам по себе

Енвайрмент вещь эфемерная и его нужно мониторить, а не тестировать во время релиза.

I>>>Ты привел конкретный пример, его и рассматриваем. Ты ведь настаиваешь, что это типичный код. И с ним проблемы. Неужели непонятно?

I>·>Верно, если рассмотреть конкретный пример MoneyService то внезапно выяснится, что совершенно неважно Hmrc — это класс или интерфейс, но ты упорно прикопался к этому, хотя на конкретный пример это вообще никак не влияет. Код и тест MoneyService для ифейса и класса Hmrc будет идентичным.
I>С т.з. мейнтенанса важно. Класс, который непосредственно зависит от другого класса, будет хуже мейнтейниться, и в этом случае зависимость от hmrc может вообще прорасти куда угодно, да так, что сменить дизайн будет невозможно.
Рефакторинг введения или удаления интерфейса — одна минута. Как удобно, так и делай.

I>Соответсвенно, в общем случае тебе нужен интерфейс, + моки, + тесты вида "проверим, что унутре вызвалось вот так"

не надо писать код в общем случае. Делать надо просто, проще как только возможно, но не проще.

I>На эвентах будет иначе- "проверим, что унутре вызвали вон то" у нас не будет, т.к. не будет зависимости, и мокать "htmr.trackHim(321).willReturn" тоже не надо.

willReturn это если метод что-то возвращает (с эвентами ты это вообще вменяемо не сможешь сделать).

I>>>Спека на бизнес-задачу, а не на класс, алё! Все 4 варианта позволяют решить ту же задачу, что и у тебя.

I>·>Ясен пень. И мой 0-й вариант тоже позволяет решить задачу. И кода в моём варианте меньше чем каждом из твоих 4-х.
I>Если закрыть глаза на интерфейсы, моки и тесты "а вот как всё унутре"....
Не закрыть глаза, а отключить бурную фантазию.

I>>>Что в коде — детали, и как я вызову эвент — тоже детали. Снаружи — паблик АПИ, он явно описывает ключевые вещи.

I>·>Ключевой момент transfer — перевод денег. Уведомления в налоговку — детали реализации. Зачем факт того, что евент может посылаться выносить в паблик АПИ MoneyService? Откуда ты это взял? Это вообще может быть секрет, и клиентам это не положено знать, вдруг эти уведомления часть Anti Money Laundry и их разглашать в принципе нельзя?
I>Я же пишу — если консумерам это не надо, можно и упрятать, и снова твой вариант не единственный. Если консумерам это надо — твой вариант крайне сомнительный.
В требованиях ясно, что не надо. Если консумерам что-то таки понадобится, это будет специфицированной частью TransferResult (и пример с someRepId я тебе приводил уже), а не аннотациями-туплами.

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

Т.е. ты отталкиваешься от любимого привычного тебе стиля кодирования, я отталкиваюсь от конкретных требований.

I>·>То что сообщается консумерам должно быть инкапсулировано в Result, "someRepId" какой-нибудь, который transfer возвращает. Зачем события-то? Уведомление в налоговку — обязанность MoneyService, а не его консумеров. Делая [result, event] ты неявно передаёшь ответственность передачи уведомлений консумерам.

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

I>>>Я про пользователей, т.е. консумеров конкретного класса. Мало ли для чего они захотят уведомлемния получать — руководство, бухгалтерию, аудит, логи и тд. Или ты собираешься на каждый кейс создавать свой сервис с отдельным composition root ?

I>·>Не знаю. Требования были вполне конкретными. Не знаю откуда ты придумал про бухгалтерию.
I>Ну так не тебе одному же условия задачи менять.
Дай конкретные условия задачи, я придумаю как отрефактороть.

I>>>Как минимум, мне обязаны сообщить о последствиях, включая уведомления налоговой и тд.

I>·>Не обязаны. В лучшем случае ты об этом узнаешь поставив подпись в договоре с банком.
I> Ну и дикая страна у вас.
Можно скриншотик твоего банка? Где там полный отчёт всего произошедшего выводит при transfer денег между акками?

I>>>Мы снова наблюдаем нежелание посмотреть ну хотя бы в C#

I>·>ThresholdExceeded это часть C#-языка??! Я хочу посмотреть конкретный код.
I>Ну так посмотри про тамошние эвенты,
Я посмотрел и не нашел там ThresholdExceeded.

I>благодаря таким эвентам можно выбросить кучу кода.

А ты не пиши кучу, пиши только то что надо и выбрасывать ничего не надо будет.

I>>>А вот та хрень, которой ты АПИ описываешь, на которой у тебя апликейшн построен, это и есть фремворк.

I>·>За шарп не скажу, то java язык достаточно хороший, чтобы на нём писать без расширений.
I>И потому в джава поголовно используют spring и hybernate?
Чего она только не использует...

I>>>На мой взгляд мокать надо только если не можешь по какой либо причине протестировать иначе, см http://rsdn.org/forum/flame.comp/8218388.1
Автор: Ikemefula
Дата: 03.03.22

I>·>"Иначе" всегда есть возможность протестировать — на юзерах Цель-то обнаруживать ошибки как можно раньше. Идеал — в процессе набора кода: "не компилится, значит не работает".
I>В том то и дело, что "как можно раньше". Я хочу принять решение о том, сохранять ли зеленый и остановить синий, или наоборот, основываясь на жестких данных, а не игрушечном heartbeat
Это уже поздно.

I>>>И валидация это не магия, а обычный кусочек кода. Неожиданные вещи совсем необязательно приведут к падению. Примеры уже приводил.

I>·>Это верно для всего. В том числе и что юзер вводит в поле ввода. Нажал неожиданно не ту кнопку и всё навернулось в проде. Неясно чем баги в конфиге должны принципиально отличаться от багов в самом приложении.
I>Вспоминаем ту самую вероятность и разницу между продом и пре-продом.
Так наймите профессионального архитектора и разница будет меньше допустимых величин риска.

I>>>Код не говорит тебе, сколько причин у бага. И часть этих причин могут быть связаны именно с продом. Более того — далеко не факт, что ты знаешь все это.

I>·>Если устранение причины X не устраняет данную проблему в проде, значит мы сделали неверный root cause анализ. Нужно идти на второй круг — находим причину Y, репродьюсим в тестовом окружении, правим, прогоняем тесты, релизим
I>В том то и дело. И это нужно узнать до того, как реальный трафик пойдет на прод.
Если ты это можешь узнать до трафика, то ты это можешь узнать до прода. По крайней мере с вероятностью достаточной для допустимы величин риска.

I>>>А что, это принципиальная разница, уронить прод и уронить самолет? Цена ошибки "уронить прод" может исчисляться человеческими жизнями.

I>·>Я перестал поспевать за твоей мыслью. "начинает резать запросы" — ты же заявил, что это уже в баклоге, т.е. это уже упавший самолёт.
I>Ну да. А если у тебя неверный root cause analysis, то упадет еще один самолет.
Тут главное избавиться от иллюзии про 100% гарантии. (c)

I>>>·>Что такое "реальная связь", бывают ли нереальные связи и какие комменты?

I>>>Реальная, это значит фактическая.
I>·>А какая ещё связь бывает? Эмоциональная?
I>Неявная, подразумеваемая, логическая, виртуальная, причинно-следственная, косвенная...
У меня связи были явными.

I>>>·>Уйдёт туда же. Эту фигню притаскивают ui-девелоперы с ихними on_button1_click.

I>>>https://en.wikipedia.org/wiki/Async/await
I>>>Это все корутины.
I>·>node/js для бывших VB-разработчиков.
I>Корутины древние как мир. Их в C# добавили еще когда node и в планах не было. А в modula, smalltalk, lisp это было в начале времён.
Причём тут евенты — неясно. Очередная подмена тезиса?

I>>>>>Очевидно, что есть, в интеграционном коде, там где обрабатывается конкретный юз кейс. Мало ли для чего нотификация используется

I>>>·>Я этот код не видел. Код в студию, с тестами.
I>>>
I>>>   useCase() {  
I>>>        ...   
I>>>    const [result, event] = this.svc.transfer();
I>>>        this.auditQueue.send(event);

I>>>    return result; 
I>>>   }
I>>>

I>>>И никаких моков queue нам не надо — в интеграционном тесте мы можем прочесть и убедиться, что все хорошо.
I>·>У тебя нет тут реализации требования, что MoneyService посылает уведомление. Тут у тебя он только генерирует, а за посылку сообщения должны отвечать консьюмеры сервиса.
I>Нету такого требования, а потому MoneyService мы можем задизайнить как проще.
Врёшь, оно было изначально: "должно уведомлять налоговую о всех транзакциях суммой больше ...". Если ты это не будешь делать в MoneyService, то каким-то образом должен обеспечить, что все консумеры таки посылают это уведомление. Это будет очень даже не проще.

I>>>сам useCase юнитами покрывать не нужно, он должен быть

I>·>Зато теперь ещё ты создал необходимость писать и интеграционный тест.
I> интеграционный тест нужен по причине наличия взавимодействия с сервисом налоговой.
I>Независимо от реализации, этот тест необходим.
Это ясно. Тебе потребуется ещё один интеграционный тест, который интегрирует события с налоговой. Т.е. была только интеграция MoneyService с налоговой, а теперь у тебя промежуточный слой появился в виде евентов, с которым тоже надо интегрироваться и тестировать.

I>·>Верно. Но ты опять доказываешь необходимость запуска тестов в проде необходимостью запусков тестов в проде.

I>·>Тесты в пре-проде это тоже часть административных мер. И это означает, что вероятность известных багов в проде низка, и риски можно принять.
I>А вот мой текущий работодатель так не считает, у него все проекты обязаны проходить тесты в проде.
I>И целая куча контор делает так же, кстати говоря.
А некоторые на php пишут... И ничего.

I>>>Ок, покажи мне юнит-тест вида "сообщения в налоговую никогда не теряются и накапливаются в очереди если внешняя сеть недоступна, трансферы проходят как положено, аудит это подтверждает, после возобновления работы внешней сети сообщения достигают источника за время x"

I>·>Элементарно: условно что-то вроде verify(persistentQueue).sendMessage(X). За гарантированную доставку отвечает mq-брокер и у него есть свои тесты.
I>То есть, ни о чем. "никогда не теряются...если сеть недоступно...после возобновления" это проверяется тестом сценария с симуляцией фейла.
Т.е. ты пишешь тесты mq-брокера?

I>>>Алё! Еще в 70х стало известно, что для сложного софта количество путей выполнения исчисляется астрономическими числами.

I>>>Отсюда ясно, что покрыл тестом, скажем, 1000000 путей. Как быть с остальными 10^14 — 1000000 путями ?
I>·>И поэтому и придумали разделение на юниты и ю-тесты, чтобы N*M сводить к N+M.
I>N+M, N*M это ничтожная величина, которая на фоне 10^14 неотличима от нуля. Все остальное работает против тебя.
N*M — это взаимодействие двух слоёв. Если слоёв больше, то и получается N*M*O*P*Q*...*R астрономия. Об этом ты и говорил, что e2e — как решето.

I>>>Стоимость рабочей силы намного больше.

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

I>>>Настоящий.

I>·>А налоговке точно понравится, что вы их спамите их прод каким-то левым трафиком?
I>Теоретически, может и не понравится. Это решаемо. Без моков.
Как?

I>>>Это ведь не просто так. Что бы лампочка загорелась, ктото должен скрипт написать "если вот такой запрос то жди +1 в счетчике hmrc иначе запаливай лампочку".

I>·>Не знаю что за "скрипт" ты имеешь в виду. Простой код и ю-тест к нему.
I>Нужен интеграционный тест вида "счетчики работают и попадают в мониторинг" + "фейла виден на мониторинге"
Это может идти из коробки mq-брокера. Queue Depth называется и не специфично конкретно к сообщениям налоговой, а на всю инфраструктуру гарантированной доставки. Как раз пример сведения N*M к N+M. Т.е. компонент MoneyService просто валит всё в определённое место и это легко тестировать. А это определённое место занимается деталями гарантированной доставки. И это тоже легко тестировать и мониторить.

I>>>Упс, мы выяснили, что hmrc должен не только налоговую уведомлять, но и счетчик мейнтенйнить...

I>>>Чуешь, куда все идет?
I>·>Куда-то в область бурной фантазии. Какой счётчик?!
I>Обычный. ты то не хочешь рассказывать как L2 суппорт решит задачу "два часа назад должно было быть 1000 запросов к налоговой", я придумал своё решения.
I>не устраивает — приводи свой вариант.
Я не понял откуда вообще взялась эта задача. Зачем её вообще решать?

I>>>Отсутствие вызовов hmrc в течение первых часов эксплуатации. собственно, подсказка выше.

I>·>А почему ты решил что они должны быть? Может все только мелкими переводами балуются?
I>Мне нужны гарантии, что L2 суппорт сможет обнаружить такую проблему.
Сможет обнаружить по состоянию очередей доставки.

I>>>поток = thread, т.е. CPU. Попробуй, посчитай. Я вот таким несколько лет занимался, потому и знаю.

I>·>Какое это отношение имеет к вызовам метода и событиям? Что такое поток отправляющий поток (см. подчёркнутое)? Накой вообще потоки постоянно создавать?! Короче, я нихрена не понял.
I>CPU тебе тоже нужен? И твоя джава без единого потока работает?
Одного потока достаточно, созданного при старте приложения. Зачем создавать больше?

I>Что бы отправить запрос, CPU в конкретном thread должен затратить кучу времени, (подготавливая блок, адрес, записывая в сокет,) на несколько порядков больше, чем прямой/обратный вызов.

Зависит от того как ты написал код. При желании оно может читать напрямую из DMA региона сетевой карты и записывать результат туда же.

I>Т.е. если прямой/обратный вызов это доли наносекунды, то сетевой запрос займен микросекунды. Реально — в зависимости от протокола еще больше, может даже милисекунды.

I>Итого — разница в микроскоп не видна. А тебе она мешает
У вас не видна, а у нас была видна.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[56]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 08.03.22 18:48
Оценка:
Здравствуйте, ·, Вы писали:

·>Мой тезис в том, что запуск тестов в пре-прод должен уже давать достаточный процент, чтобы заакцептить риски.


Т.е. все сводится к вере в то, что на проде ничего не может пойти не так.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[57]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 08.03.22 19:23
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>·>Мой тезис в том, что запуск тестов в пре-прод должен уже давать достаточный процент, чтобы заакцептить риски.

НС>Т.е. все сводится к вере в то, что на проде ничего не может пойти не так.
Перечитай. Это всё сводится к тому, что риск того, что в проде что-то может пойти не так — ниже допустимого.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[58]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 09.03.22 07:08
Оценка:
Здравствуйте, ·, Вы писали:

НС>>Т.е. все сводится к вере в то, что на проде ничего не может пойти не так.

·>Перечитай. Это всё сводится к тому, что риск того, что в проде что-то может пойти не так — ниже допустимого.

А полагание что риск ниже допустимого — это разве не вера?
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[59]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 09.03.22 09:31
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>>>Т.е. все сводится к вере в то, что на проде ничего не может пойти не так.

НС>·>Перечитай. Это всё сводится к тому, что риск того, что в проде что-то может пойти не так — ниже допустимого.
НС>А полагание что риск ниже допустимого — это разве не вера?
Эмпирическая оценка.
У тебя есть альтернативы? Хинт: "run test -P e2e" в проде — это тоже вера, или просто религиозный ритуал.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[60]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 09.03.22 10:17
Оценка:
Здравствуйте, ·, Вы писали:

НС>>А полагание что риск ниже допустимого — это разве не вера?

·>Эмпирическая оценка.



·>У тебя есть альтернативы?


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

·>Хинт: "run test -P e2e" в проде — это тоже вера, или просто религиозный ритуал.


Это просто прямая, а не косвенная проверка.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[56]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.03.22 10:57
Оценка:
Здравствуйте, ·, Вы писали:

I>>·>Тесты нам должны. А если какие-то тесты нам ничего не должны, то мы зря на них тратим время.

I>>Вот-вот. Тут главное избавиться от иллюзии про 100% гарантии вида
I>>1. нет багов/уязвимостей (зафикшены,необнаруженых итд)
I>>2. все причины установлены
·>Про 100% гарантии ты сам придумал.

Ты на прошлой неделе заявил, что после твоих фиксов нет ни единого шанса воспроизвести баг на проде.

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


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

I>>Багфикс и тестирование всего лишь уменьшают вероятность, не могут исключить проблему полностью. Условно — всегда есть другой, неизвестный тебе путь, который приведет к тому же результату.

·>Верно, это же верно и для прод тестов.

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

I>>Да не гони, это именно обычные пользователи.

·>У меня на компе десятки продуктов. И ни одного из них нет беты. Я не обычный пользователь?

Обычный.

I>>Кроме того, кейс с immutable deployment — его специально делают на тот случай, что бы сделать быстрый откат.

·>Да, верно. Но это иррелевантно к нашему обсуждению.

Наоборот. В этом случае тебе надо быстренько понять, стоит ли откатывать, или же стоит оставить. Каким же образом выяснить, снова предложиль пинг в качестве проверки?

I>>Ты же понимаешь, что никто не будет держать синий прод вечно. А раз так, надо бы побыстрее дать гарантии, что зеленый не хуже.

·>Давайте эти гарантии в пре-проде. Ничего не мешает.

Ты снова забыл про разницу прода и препрода
— зависимости прода есть только на проде и у них цикл жизни свой собственные
— конфиг
— окружение

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

I>>В зависимости от стратегии релиза и версионирования, релиз кандидат может сразу превратиться в релиз безо всяких дополнительных сборок. То есть — прошел тесты, значит релиз, не прошел — не релиз.

·>Причём тут сборки? Опять, это иррелевантно к нашему обсуждению.

Это именно то и есть — разница между продом и препродом ничтожна.

I>>Это ничего не меняет — опубликована и рассылаться юзерам будет только вторая, которая прошла тесты, а первая останется для истории.

·>Да, т.е. обычные юзеры юзают релиз, а не бету.

Факт в том, что релиз перед раздачей юзерам прошел все нужные тесты, в т.ч. на реальных юзерах.

·>И что? Ты тестируешь сборку, а не деплоишь собранное нечто в прод. Сборка != деплоймет. Только после того сборка прошла все тесты, ты деплоишь официальный релиз. Какой номер присвоен и как оно названо — дело вкуса.


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

I>>Это неверно. Во первых, код может меняться часто по разными причинам. Теперь, на секундочку, надо все время бегать за твоими моками и патчить их.

·>Что неверно? Ты тестируешь FRD.docx??!

Ты как нибудь задавай внятные вопросы или говори, что непонятно. А то выглядит так, как будто ты помнишь максимум последнюю строчку.

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

·>А что ещё-то? Любовь и тепло сердца?

Надо вспомнить, что тест это испытание на предмет выявления соответствия требованиям. А раз так, то ключевое в тестах, это все что относится к требованиям. Код — это всего лишь частный случай, т.к. тесты могут быть не только автоматическими, но и полуавтоматическими и даже ручными.
Требования, кейсы, сценарии, ожидания вызывающей стороны, граничные случаи, т.н. fitness function, и тд и тд.

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

I>>Да как угодно. Это, к слову, e2e тест, система от прода отличается только конфигом, никаких моков здесь уже нет.

·>У вас в проде тоже mailtrap стоит?

тебе повторить содержание беседы про пуск ракеты?

I>>Ты нормальный? Этот вайринг код и будет связывать зависимости с тем компонентов. Тест я уже показал — раскрой глаза.

·>Ты не тест показал, ты сценарий теста показал. Что делается этим сценарием — я это и спрашиваю. Вайринг код ты так и не показал.

Это и есть тест! Про cucumber слышал?

I>>Цель использования эвента — максимальное развязывание компонентов.

·>В-нулевых, евент — это лишь средство, эту же цель можно достигнуть другими средствами, _если_ вдруг понадобится.

можно. эвент — современный метод.

>Во-первых, неясно зачем что-то развязывать максимально.


Затем, что бы мейнтейнить, тестировать было проще.

> Во-вторых, неясно что значит максимально развязывать.


Вполне ясно — наш компонент не имеет зависимости от hmrc.

> В-третьих, связывать развязанное тебе всё равно придётся. И ты упорно не хочешь это признать и кто для связывания затрудняешься написать.


Наоборот — я же тебе показал, и не единожды. В очередной раз:
useCase() {  
       ...   
   const [result, event] = this.svc.transfer();
   this.auditQueue.send(event); // вот твоё связывание

   return result; 
}

если тебе мало, то вот еще пример, если у нас эвент у метода
useCase() {  
       ...   
   const result = this.svc.transfer( {thresholdExceeded: event => this.auditQueue.send(event)}); // вот твоё связывание

   return result; 
}

если мало, то еще вот пример, если у нас эвент у инстанца
useCase() {  
       ...   
   this.svc.thresholdExceeded.use(event => this.auditQueue.send(event));
   const result = this.svc.transfer( ); // вот твоё связывание

   return result; 
}


Теперь,внезапно, что будет, если нам надо ввести какие полиси или счетчики? Вобщем, ничего — добавить функцию вида (event) => event, которая отлично покрывается юнит тестами, тогда все будет вместо this.auditQueue.send(event) будет
policy(event, this.config, x => this.auditQueue.send(x))


То есть, нам не надо лезть в наш компонент, изменится исключительно связывающий код.

·>Повторяю, повторы, блокировки налоговки — это всё не является частью поведения MoneyService, его дело простое — деньги переводить.


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

I>>Может. А может и нет. Зависит от конкретной архитектуры. Эвенты — это инструмент, который позволяет развязать компоненты, облегчить интеграцию.

·>А молоток позволяет забивать и шурупы тоже.

Потому и придумали эвенты, что бы кроме молотка и шурупов было чтото еще.

I>>Снова у тебя юнит-тесты вместо интеграционных

·>Ты заявил глупость выше, что мол, не проверяется. Я описал как. Что не устраивает-то?

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

I>>·>Как ты собрался симулировать косяк налоговой в проде?

I>>Точно так же, как симулируются фейлы на уровне системы.
·>И как же?

есть т.н. failover testing, когда нужны гарантии, что прод не склеится из за тех самых отличий с препродом при fail сценарии.

I>>А кто говорит, что мониторинг не нужен? Тесты прода это быстрый тест на то, что в нем выполнимы сценарии юзеров.

·>Для проверки выполнимости сценариев юэеров нет необходимости тестировать в проде.

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

I>>Мало ли, деплоймент поднялся с какими то мелкими багами. Самое правильно — задетектить по быстрому, откатить деплой, фиксануть, передеплоить.

·>Какими мелкими багами? Если эти баги ловятся тестами, то какого хера ты задеплоил с багами??! А если не ловятся, то ты их не задетектишь по быстрому.

Обычным. На препроде багов не было выявлено, а на проде — снова воспроизвелись. Что делать предложишь?

I>>Где ты видишь про длинный список? Я всего то про овнершип. Вот скажем, если овнершип e2e у меня, то тебе придется объяснить мне, на кой ляд ты хочешь закаментить степ в сценарии.

·>Фиксуны же твои любимые — они же всемогущие.

В данном случае, если овнершип ключевых тестов находится у ответсвенных работников, то это дополнительная степень защиты.

I>>А что овнершип?

·>Вот и я не понимаю, как так поставлен процесс у вас, что овнершип вроде как есть, но кто угодно всё что угодно втихушку может поменять и уйти в отпуск.

У тебя бурная телепатия.

I>>Нету такого в бизнес-треботвания,

·>Есть, конечно. Слыхал need-to-know принцип и information barriers?

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

I>> как "скрывать важные вещи от консумеров интерфейса".

·>В бизнес-требовании не было требования показывать что попало консумерам. То что вещь важная и её непременно надо кому-то показывать ты сам придумал.

Бизнес-требования к конкретному классу имеют сильно слабое отношение. Одно и то же требование можно реализовать как угодно.

I>>Именно. А воздействовать можно исключительно через интерфейс. Я предпочитаю иметь в интерфейсе явную связь,а у тебя "по бизнес требованиям надо усё упрятать поглубже"

·>Т.е. ты пишешь код по своим предпочтениям, а не по бизнес-требованиям, типичный over-engineering.

У меня в бизнес-требованиях только бизнес-специфика а не строчки "в таком то классе вызывайте вот такой то метод"

I>>Вот это всё надо проверить вместе взятой. Отсюда ясно, что "в рамках класса" этого нет и быть не может.

·>Вот и ставишь границу что чем проверяется. А ты всё смешал.

Наоборот.
I>>Он дает максимальную развязку компонентов, позволяет ключевые вещи покрыть дешевыми и надежными тестами безо всяких моков.
·>Как выяснилось, не позволяет.
·>Да, ты покрыл часть более простым тестом, но часть оставил непокрытой, и теперь надо писать ещё дорогой тест с моками.

У меня нет непокрытой части. И тест на моках мне не нужен.
Покажи, что именно мне нужно покрывать "дорогим тестом на моках"

I>>Использование, чтение, анализ кода, поиск проблем, инструментирование, аудит и тд.

·>Возможно, но это не требуемый публичный интерфейс MoneyService который в требованиях.

Нет никакого интерфейса в бизнес-требованиях. Там вообще и кода никакого нет.

I>>В том, что ThresholdExceeded объявлен в терминах моего компонента, а не в единицах какой то 3rd party либы.

·>Зато теперь тебе нужен код связывающий твой компонент с 3rd party либой. Выигрыш-то в чём?

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

I>>Соответственно, нам не надо мастырить игрушечный контекст на моках, что покрыть функционал.

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

Фремворки и у тебя есть, тот самый spring, hibernate и тд. Или ты по старинке, колхозишь склейку строк и работаешь через сокеты?

I>>Смотря как ты хочешь использовать. Например, в разных юзкейсах надо уведомлять разное по разному. Соответсвенно, упрятывать такое в конструктор я бы не стал.

·>Бизнес требования видел? Зачем фантазировать-то?

Видел. За 20 лет мне никто не присылал в бизнес-требованиях "передай вот такую ссылку в конструктор".

I>>Это описание http контроллера. Его задача очистить вход от протокольного мусора. Для graphql есть свое описание, для gRPC — своё. Это уже состоявшаяся реальность.

·>Так что за описание API в рамках Swing или Hibernate, можно пример?

Ты адекватный? читам вместе "Это описание http контроллера. Его задача очистить вход от протокольного мусора. Для graphql есть свое описание, для gRPC — своё."

I>>Все это обычно пишется или генерируется по описанию апи.

·>Ну вот у тебя сгенерировался Result transfer(from, to, amount). Куда ты затолкаешь твои любимые евенты?

Если в АПИ указан эвент, то он и сгенерируется где надо. Нет в АПИ — не сгенерируется.

I>>отличается конфигурация

·>Чем отличается? Именем хоста, портом? Вот и тестируйте это.

Много чем. Ты никогда не знаешь ответ на вопрос "всё ли известно по багу". Например, бывает так:
— юзеры создали 40+ запросов в суппорт
— суппорт "проаггрегировал" запросы и выдал тебе ровно 1 фрагмент
— ты фиксанул фрагмент, и естественно, учел не всё, т.к. суппорт подкинул тебе фрагмент
— упс, на проде все упало
— контора платит конские пенальти, потому, что ты не учел разницы между продом и пре-продом, т.к. суппорт спрятал от тебя разницу прода и пре-прода.
Это история у крупного вендора софта для рынка американского страхования.

А тебя послушать, все как в сказке
— все известно заранее, на любую глубину
— требования пишут в терминах языка программирования "вызови метод по переданной в конструктор ссылке"
— нет ни единого шанса, что баг после фикса воскреснет на проде
— и вообще, все пишут без багов

I>>отличается цикл жизни зависимостей

·>Можно пример?

Например, все шаред зависимости с прошлой версии прода будут работать и в новой версии, что очевидно.

I>>отличается энвайрмент, сам по себе

·>Енвайрмент вещь эфемерная и его нужно мониторить, а не тестировать во время релиза.

Мониторить нужно. А что бы выявить проблемы как можно раньше, стоит протестировать.

I>>С т.з. мейнтенанса важно. Класс, который непосредственно зависит от другого класса, будет хуже мейнтейниться, и в этом случае зависимость от hmrc может вообще прорасти куда угодно, да так, что сменить дизайн будет невозможно.

·>Рефакторинг введения или удаления интерфейса — одна минута. Как удобно, так и делай.

Ога. В твоем случае ты интерфейс проращиваешь куда попало. В моем случае компонент изначально изолирован, потому внутренности я могу менять как попало.

I>>Соответсвенно, в общем случае тебе нужен интерфейс, + моки, + тесты вида "проверим, что унутре вызвалось вот так"

·>не надо писать код в общем случае. Делать надо просто, проще как только возможно, но не проще.

Имено. Потому я решил выбросить все, включая лишние зависимости.

I>>На эвентах будет иначе- "проверим, что унутре вызвали вон то" у нас не будет, т.к. не будет зависимости, и мокать "htmr.trackHim(321).willReturn" тоже не надо.

·> willReturn это если метод что-то возвращает (с эвентами ты это вообще вменяемо не сможешь сделать).

Ты снова прицепился к willReturn, а trackHim похоже тебя не смущает. На самом деле проблему и то, и тд.

I>>Я же пишу — если консумерам это не надо, можно и упрятать, и снова твой вариант не единственный. Если консумерам это надо — твой вариант крайне сомнительный.

·>В требованиях ясно, что не надо. Если консумерам что-то таки понадобится, это будет специфицированной частью TransferResult (и пример с someRepId я тебе приводил уже), а не аннотациями-туплами.

Не ясно, что за требования у тебя.

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

·>Т.е. ты отталкиваешься от любимого привычного тебе стиля кодирования, я отталкиваюсь от конкретных требований.

Мне никто в требованиях не пишет "вызови метод trackHim используя переданную в конструктор ссылку"

I>>Правильно, у одного консумера так, у другого — эдак. Мало ли, юз кейсы какие.

·>Вот когда появятся разные виды консьюмеров, вот тогда и будем усложнять код, есть такая штука интересная, рыбфакторенг или что-то такое... слыхал?. Зачем делать сложно изначально — неясно.

Изначально твоя задача сильно нечеткая, ты же не требования дал, а фрагмент решения. А я должен догадаться, каие требования могли подходить под твое решение

I>>Ну так не тебе одному же условия задачи менять.

·>Дай конкретные условия задачи, я придумаю как отрефактороть.

Начни с себя. Решение задачи ты показал, а требования все никак не родишь.

I>> Ну и дикая страна у вас.

·>Можно скриншотик твоего банка? Где там полный отчёт всего произошедшего выводит при transfer денег между акками?

Про уведомление налоговой меня предупрежают при заключении договора и про (не)уплату налогов. "скриншот банка"

I>>Ну так посмотри про тамошние эвенты,

·>Я посмотрел и не нашел там ThresholdExceeded.

Ты привел описание trackHim, так? У этого метода ты привел параметры? Я сказал тебе, что будет 1 в 1 с той разницей, что
1. не нужен доп интерфейс
2. не нужен мок

I>>благодаря таким эвентам можно выбросить кучу кода.

·>А ты не пиши кучу, пиши только то что надо и выбрасывать ничего не надо будет.

Я и показл, что нужно выбросить относительно твоего варианта

I>>И потому в джава поголовно используют spring и hybernate?

·>Чего она только не использует...

То есть, ты пошел на попятный. У тебя в проекте spring или чтото вместно него? Скажи честно.

I>>В том то и дело, что "как можно раньше". Я хочу принять решение о том, сохранять ли зеленый и остановить синий, или наоборот, основываясь на жестких данных, а не игрушечном heartbeat

·>Это уже поздно.

Наоборот.

I>>Вспоминаем ту самую вероятность и разницу между продом и пре-продом.

·>Так наймите профессионального архитектора и разница будет меньше допустимых величин риска.

Вероятно, ты предлагаешь нам нанять того, кто будет писать требования вида "передайте ссылку в конструктор и потом вызовите у неё метод trackHim"

I>>В том то и дело. И это нужно узнать до того, как реальный трафик пойдет на прод.

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

Покажи методику расчета вероятности.

I>>Ну да. А если у тебя неверный root cause analysis, то упадет еще один самолет.

·>Тут главное избавиться от иллюзии про 100% гарантии. (c)

Именно. Ты все время говоришь что "нет шансов, что баг воспроизведется на проде"

I>>Неявная, подразумеваемая, логическая, виртуальная, причинно-следственная, косвенная...

·>У меня связи были явными.

Явне это через публичное АПИ. Покажи, каким образом, глядя на описание твоего публичного интегрфейса, понять, что есть то самое уведомление.

I>>Корутины древние как мир. Их в C# добавили еще когда node и в планах не было. А в modula, smalltalk, lisp это было в начале времён.

·>Причём тут евенты — неясно. Очередная подмена тезиса?

event это push модель, корутины — pull. И то и другое позволяет реализовать нотификации.


I>>·>У тебя нет тут реализации требования, что MoneyService посылает уведомление. Тут у тебя он только генерирует, а за посылку сообщения должны отвечать консьюмеры сервиса.

I>>Нету такого требования, а потому MoneyService мы можем задизайнить как проще.
·>Врёшь, оно было изначально: "должно уведомлять налоговую о всех транзакциях суммой больше ...". Если ты это не будешь делать в MoneyService, то каким-то образом должен обеспечить, что все консумеры таки посылают это уведомление. Это будет очень даже не проще.

Консумеры будут вызывать или конкретный useCase, или писать кастомный useCase. Сам компонент для трансфера нужно выделить в изолированый компонент, который будет плотно покрыт юнит-тестами.

I>>Независимо от реализации, этот тест необходим.

·>Это ясно. Тебе потребуется ещё один интеграционный тест, который интегрирует события с налоговой. Т.е. была только интеграция MoneyService с налоговой, а теперь у тебя промежуточный слой появился в виде евентов, с которым тоже надо интегрироваться и тестировать.

Этот слой и есть интеграционный, и будет протестирован интеграционными тестами.

I>>И целая куча контор делает так же, кстати говоря.

·>А некоторые на php пишут... И ничего.

Вот именно. И стоит избавляться от видения "только у меня всё правильно, а вы наймите хорошег архитектора"

I>>То есть, ни о чем. "никогда не теряются...если сеть недоступно...после возобновления" это проверяется тестом сценария с симуляцией фейла.

·>Т.е. ты пишешь тесты mq-брокера?

Тесты системы, частью которой является mq-брокер.

I>>·>И поэтому и придумали разделение на юниты и ю-тесты, чтобы N*M сводить к N+M.

I>>N+M, N*M это ничтожная величина, которая на фоне 10^14 неотличима от нуля. Все остальное работает против тебя.
·>N*M — это взаимодействие двух слоёв. Если слоёв больше, то и получается N*M*O*P*Q*...*R астрономия. Об этом ты и говорил, что e2e — как решето.

e2e проверяют интеграцию, а именно — сценарии выполняются на конкретной системе. Они не проверяют валидацию входа/выхода/ и ветвления логики.

I>>Наоборот — рабочая сила тратит больше времени, тестируюя у себя локально, и в проде, сокращая количество итераций багфикса.

·>Протестить локально — время порядка секунд, а дойти до прода может занимать дни и недели.

Дойти до прода — дни и недели. Потому и надо сокращать количество итераций. И тесты на проде именно это и делают.

I>>·>А налоговке точно понравится, что вы их спамите их прод каким-то левым трафиком?

I>>Теоретически, может и не понравится. Это решаемо. Без моков.
·>Как?

См ту часть, что про запуск ракеты.

I>>Нужен интеграционный тест вида "счетчики работают и попадают в мониторинг" + "фейла виден на мониторинге"

·>Это может идти из коробки mq-брокера. Queue Depth называется и не специфично конкретно к сообщениям налоговой, а на всю инфраструктуру гарантированной доставки. Как раз пример сведения N*M к N+M. Т.е. компонент MoneyService просто валит всё в определённое место и это легко тестировать. А это определённое место занимается деталями гарантированной доставки. И это тоже легко тестировать и мониторить.

Твой MoneyService ничего никуда не валит — он вызывает внешний сервис. Или ты снова про то, что налоговая будет часть вашей внутренней инфраструктуры мониторить?

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

I>>Обычный. ты то не хочешь рассказывать как L2 суппорт решит задачу "два часа назад должно было быть 1000 запросов к налоговой", я придумал своё решения.

I>>не устраивает — приводи свой вариант.
·>Я не понял откуда вообще взялась эта задача. Зачем её вообще решать?

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

I>>Мне нужны гарантии, что L2 суппорт сможет обнаружить такую проблему.

·>Сможет обнаружить по состоянию очередей доставки.

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

I>>CPU тебе тоже нужен? И твоя джава без единого потока работает?

·>Одного потока достаточно, созданного при старте приложения. Зачем создавать больше?

Вот и покажи, сколько времени надо на один сетевой запрос.

I>>Что бы отправить запрос, CPU в конкретном thread должен затратить кучу времени, (подготавливая блок, адрес, записывая в сокет,) на несколько порядков больше, чем прямой/обратный вызов.

·>Зависит от того как ты написал код. При желании оно может читать напрямую из DMA региона сетевой карты и записывать результат туда же.

Ну вот сделай замеры end-2-end, да убедись.

I>>Т.е. если прямой/обратный вызов это доли наносекунды, то сетевой запрос займен микросекунды. Реально — в зависимости от протокола еще больше, может даже милисекунды.

I>>Итого — разница в микроскоп не видна. А тебе она мешает
·>У вас не видна, а у нас была видна.

Вероятно, вы так код написали. Причина то в чем была и какой порядок разницы между прямым и обратным вызовом?
Re[57]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.03.22 11:17
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Вот псевдокод типичной зависимости:

НС>
НС>


Ну вот и обрати внимание — тебе надо DI настроить так, что бы хватило на всю глубину вызовов. Контроллер почти ничего не делает, а просто вызвает следующий слой. А тот, очевидно, ровно так же — почти ничего не делая вызывает следующий. Слоёв очевидно будет много, а раз так — изоляция слабая.
И это проблема — придется мокать при тестировании.

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

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


Чем это все отличается от того варианта, что я уже приводил?
Task MyAction () {
   const data = this.dep.GetDataFromDependency(); 
   return this._someService.DoAction(data); 
}


НС>>>Опять непонятно. Как от размера контроллера зависит количество интеграционных тестов?

I>>Мало ли что ты напихаешь в этот контроллер.

НС>Офигеть просто аргумент.


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

I>>Например, ты поместишь туда кучу низкоуровневого кода где читаем из одной бд

НС>Зачем? Чтобы доказать что ты прав?

У меня телепатия не работает, потому объясняю на примере, и говорю об этом прямо "Например"

I>>Как я вижу, у многих команд это вариант нормы — всё пихать в контроллер

НС>Ну вот с теми командами ты и общайся на эту тему. Сюда ты зачем про это написал?

У меня телепатия не работает, потому пишу наиболее вероятные примеры, о чем прямо и говорю "Например"

I>>Я предлагаю вспомнить пирамиду тестов и её смысл:

I>>Проблемы в логике надо покрывать юнит-тестами, они дают максимально возможное покрытие и максимальные гарантии. Тестировать интеграцию юнит-тестами смысла нет
НС>Не понял смысла этой фразы. Юнит-тесты по определению не тестируют интеграцию. Если они тестируют интеграцию, то они являются интеграционными тестами.

Это все тот же пример, ну скажем, сложной валидации. Если ты захочешь валидацию тестировать в АПИ тестах, то долгий старт кролика, или что там у тебя, будет ничтожным на фоне общего прогона.
Re[58]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 09.03.22 11:24
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Ну вот и обрати внимание — тебе надо DI настроить так, что бы хватило на всю глубину вызовов.


Не понимаю о чем ты.

I>Собственно я предлагаю иначе — вместо глубокого дерева вызовов делать максимально плоское, главное что бы контроллер оставался линейным.


Код где?

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

I>Чем это все отличается от того варианта, что я уже приводил?
I>
I>Task MyAction () {
I>   const data = this.dep.GetDataFromDependency(); 
I>   return this._someService.DoAction(data); 
I>}
I>


Покажи аналог всего кода что я привел. Мы же объем оцениваем, не так ли?

НС>>>>Опять непонятно. Как от размера контроллера зависит количество интеграционных тестов?

I>>>Мало ли что ты напихаешь в этот контроллер.
НС>>Офигеть просто аргумент.
I>Я ж не в курсе, что там у тебя

А зачем тебе быть в курсе что там у меня (где именно, кстати?)? Рассуждение, на которое ты отвечал, не предполагали никакой момей персональной специфики. И намеренного написания идиотского кода тоже не предполагало.

I>, потому предполагаю самый типичный вариант, из моего опыта.


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

I>>>Как я вижу, у многих команд это вариант нормы — всё пихать в контроллер

НС>>Ну вот с теми командами ты и общайся на эту тему. Сюда ты зачем про это написал?
I>У меня телепатия не работает, потому пишу наиболее вероятные примеры

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

НС>>Не понял смысла этой фразы. Юнит-тесты по определению не тестируют интеграцию. Если они тестируют интеграцию, то они являются интеграционными тестами.

I>Это все тот же пример, ну скажем, сложной валидации. Если ты захочешь валидацию тестировать в АПИ тестах, то долгий старт кролика, или что там у тебя, будет ничтожным на фоне общего прогона.

Да, и?
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[59]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.03.22 11:55
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

I>>Ну вот и обрати внимание — тебе надо DI настроить так, что бы хватило на всю глубину вызовов.


НС>Не понимаю о чем ты.


Смотри свой код — SomeService принимает зависимость IDependency SomeService(IDependency dep) => _dep = dep;
Конроллер, в свою очередь, принимает ISomeService MyController(ISomeService someService) => _someService = someService;
Т.е. у тебя уже должно быть связывание на всю глубину для всех зависимостей.

НС>Покажи аналог всего кода что я привел. Мы же объем оцениваем, не так ли?


Я привел несколько характеристик, но ты почему то выделил только объём.
Собственно, вот пример, что ты просишь, но вижу, что это пять раз приводилось только в другом виде
Т.е. это всё тот же самый вариант Синклера
class MyController
{
  MyController( private someService: ISomeService, private dep:IDependency) { };
  MyAction(): Task {
     const data = this.dep.GetDataFromDependency();

     return this.someService.doAction(data)
  };
}

class SomeService implements ISomeService
{
  DoAction(data: Data): Task // не ясно, зачем тут Task
  {
    ...
  }
}

В норме, когда выворачиваем код таким образом, то вместо всяких сервисов остаются обычные функции вида вход => выход

НС>>>Офигеть просто аргумент.

I>>Я ж не в курсе, что там у тебя

НС>А зачем тебе быть в курсе что там у меня (где именно, кстати?)?


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

>Рассуждение, на которое ты отвечал, не предполагали никакой момей персональной специфики.


Речь не про персоны, а про типичные задачи, которые у тебя и у меня разные. Очевидно же, дизайн под задачу, а не наоборот.
Тебе вот не нравится, когда я привожу кейс из опыта работы с конкретной командаой, смотри сам "Ну вот с теми командами ты и общайся на эту тему."
Как мне понять, что устроит тебя лично?

> И намеренного написания идиотского кода тоже не предполагало.


Похоже, ты снова начал хамить. Ну-ну.

I>>, потому предполагаю самый типичный вариант, из моего опыта.


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


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

I>>У меня телепатия не работает, потому пишу наиболее вероятные примеры

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

На мой взгляд ничего нового ты не привел — ты задал вопрос, на который уже даден ответ трижды минимум.

I>>Это все тот же пример, ну скажем, сложной валидации. Если ты захочешь валидацию тестировать в АПИ тестах, то долгий старт кролика, или что там у тебя, будет ничтожным на фоне общего прогона.


НС>Да, и?


Ну так если ты это понимаешь, и понимаешь, что именно я предлагаю взамен(см пример про валидацию), то что тебе не ясно и почему ты начал хамить?
Отредактировано 09.03.2022 13:09 Pauel . Предыдущая версия . Еще …
Отредактировано 09.03.2022 12:55 Pauel . Предыдущая версия .
Re[60]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 09.03.22 13:27
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Смотри свой код — SomeService принимает зависимость IDependency SomeService(IDependency dep) => _dep = dep;

I>Конроллер, в свою очередь, принимает ISomeService MyController(ISomeService someService) => _someService = someService;
I>Т.е. у тебя уже должно быть связывание на всю глубину для всех зависимостей.

Это в аспнете искаропки, ничего специально конфигурировать для этого не нужно.

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

I>Т.е. это всё тот же самый вариант Синклера
I>[code]
I>class MyController
I>{
I> MyController( private someService: ISomeService, private dep:IDependency) { };
I> Task MyAction() {
I> const data = this.dep.GetDataFromDependency();

I> return this.someService.doAction(data)

I> };
I>}

Т.е. код контроллера в твоем варианте стал больше. ЧТД.

I> Result DoAction(data: Data) // не ясно, зачем тут Task


Затем что метод асинхронный. Но это так, по привычке.
И еще ты забыл описание класса Data, его тоже придется писать. При сложной модели это очень ощутимая прибавка на каждый чих. Хуже того, на практике народ начинает на моделях экономить (модели то почти всегда в чем то уникальные, и адхок типы тут не используешь потому что контракты наружные), в результате появляются явно избыточные для конкретного кейса модели, что ведет к очень неприятным багам.

I>В норме, когда выворачиваем код таким образом, то вместо всяких сервисов остаются обычные функции вида вход => выход


Функции не особо удобно в DI публиковать.

>> И намеренного написания идиотского кода тоже не предполагало.

I>Похоже, ты снова начал хамить. Ну-ну.

Тебе показалось.

I>Меня на твоей стороне монитора нет, потому я не в курсе


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

I>>>У меня телепатия не работает, потому пишу наиболее вероятные примеры

НС>>Это при том что псевдокод для обсуждения я привел в самом начале сообщения. Ты умудрился его скипнуть, а теперь, якобы, гадаешь что ж там за код такой загадочный может быть.
I>На мой взгляд ничего нового ты не привел — ты задал вопрос, на который уже даден ответ трижды минимум.

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

I>>>Это все тот же пример, ну скажем, сложной валидации. Если ты захочешь валидацию тестировать в АПИ тестах, то долгий старт кролика, или что там у тебя, будет ничтожным на фоне общего прогона.

НС>>Да, и?
I>Ну так если ты это понимаешь, и понимаешь, что именно я предлагаю взамен(см пример про валидацию), то что тебе не ясно и почему ты начал хамить?

Во-первых я не хамил, а во-вторых какое отношение имеет время запуска кролика при разработке конкретного сервиса и время прогона вообще всех тестов? Время же прогона тестов валидации только по конкретному контроллеру да еще и с моками почти наверняка будет существенно быстрее стартапа тяжелых зависимостей (там ведь обычно не только кролик).
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[61]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.03.22 14:23
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

I>>Т.е. у тебя уже должно быть связывание на всю глубину для всех зависимостей.

НС>Это в аспнете искаропки, ничего специально конфигурировать для этого не нужно.

Значит DI будет работать одинаково для обоих вариантов дизайна.

НС>Т.е. код контроллера в твоем варианте стал больше. ЧТД.


Разве я где то говорил, что мой вариант даст самый короткий контроллер?

Мы гонимся не за короткостью контроллера, а устраняем препятствия в тестировании.

I>> Result DoAction(data: Data) // не ясно, зачем тут Task


НС>И еще ты забыл описание класса Data, его тоже придется писать.


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

I>>В норме, когда выворачиваем код таким образом, то вместо всяких сервисов остаются обычные функции вида вход => выход

НС>Функции не особо удобно в DI публиковать.

В DI будут не функции, а контроллер, и все зависимости будут по возможности в нём.

>>> И намеренного написания идиотского кода тоже не предполагало.

I>>Похоже, ты снова начал хамить. Ну-ну.

НС>Тебе показалось.


"намеренного написания идиотского кода" — вот это очевидное хамство

I>>Меня на твоей стороне монитора нет, потому я не в курсе

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

Привычка — ты как правило не отвечаешь на уточняющие вопросы.

I>>На мой взгляд ничего нового ты не привел — ты задал вопрос, на который уже даден ответ трижды минимум.

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

У тебя другой вариант — глубокое и развесистое дерево вызовов твоих депенденсов. Хорошо, если зависимость дергается единожды, легко мокнуть. А если долбится часто или вовсе постоянно — пожелаю тебе удачи в бою

Собственно, твой вариант тоже можно привести к варианту Синклера. Структурировать нужно будет согласно эффектам. 1 эффект это один шаг в контроллере.
У тебя будет примерно N шагов в дереве, у меня — N шагов в линейном контроллере.

I>>Ну так если ты это понимаешь, и понимаешь, что именно я предлагаю взамен(см пример про валидацию), то что тебе не ясно и почему ты начал хамить?


НС>Во-первых я не хамил, а во-вторых какое отношение имеет время запуска кролика при разработке конкретного сервиса и время прогона вообще всех тестов? Время же прогона тестов валидации только по конкретному контроллеру да еще и с моками почти наверняка будет существенно быстрее стартапа тяжелых зависимостей (там ведь обычно не только кролик).


Если ты собираешься валидацию именно на моках тестировать, то конечно будет быстро. Не быстрее, чем на юнит-тестах, и гарантий будет не больше, т.к. валидацию будешь вызывать косвенно.
Re[62]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 09.03.22 16:37
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>Т.е. у тебя уже должно быть связывание на всю глубину для всех зависимостей.

НС>>Это в аспнете искаропки, ничего специально конфигурировать для этого не нужно.
I>Значит DI будет работать одинаково для обоих вариантов дизайна.

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

НС>>Т.е. код контроллера в твоем варианте стал больше. ЧТД.

I>Разве я где то говорил, что мой вариант даст самый короткий контроллер?

Ты одновременно борешься с большими контроллерами и предлагаешь обязательное решение, которое контроллеры раздувает на ровном месте. Даже с одной зависимостью и с тем что ты опустил класс модели разница вполне заметна. А в реальной ситуации с несколькими зависимостями и несколькими развесистыми моделями ты получишь тот самый жирный и конский.
Но это еще не самое страшное. Веселье начинается, когда общение с зависимостью не ограничивается разовым извлечением данных и для того чтобы пообщаться с ней нужны несколько обращений и некая логика между этими обращениями. Внимание вопрос — в каком месте ты разместишь эту логику?

I>Мы гонимся не за короткостью контроллера, а устраняем препятствия в тестировании.


Тогда к чему был пассаж про коней?

I>>> Result DoAction(data: Data) // не ясно, зачем тут Task

НС>>И еще ты забыл описание класса Data, его тоже придется писать.
I>Это возвращаемое значение GetDataFromDependency,

А если оно не подходит, например там несколько методов позвать нужно? А если у него ктор internal и создать экземпляр можно только вызовом родного клиента?

I>>>В норме, когда выворачиваем код таким образом, то вместо всяких сервисов остаются обычные функции вида вход => выход

НС>>Функции не особо удобно в DI публиковать.
I>В DI будут не функции, а контроллер,

Не понял опять.

В норме, когда выворачиваем код таким образом, то вместо всяких сервисов остаются обычные функции вида вход => выход

Т.е. ты вместо IMyService предлагаешь сделать функцию. В DI публикуется именно IMyService, публиковать там контроллер — нафига?
Отдельный вопрос — в чем прелесть набор семантически связанных функций превращать в россыпь? Чтобы получить взрывной рост доли бойлерплейта? Помимо loosely coupling есть еще и hight cohesion, которое ты своей идеей разломаешь нафик. loosely coupling любой ценой никому не нужно.

>>>> И намеренного написания идиотского кода тоже не предполагало.

I>>>Похоже, ты снова начал хамить. Ну-ну.
НС>>Тебе показалось.
I>"намеренного написания идиотского кода" — вот это очевидное хамство

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

I>Привычка — ты как правило не отвечаешь на уточняющие вопросы.


Нет, это привычка пускать в ход подобные аргументы.

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

I>У тебя другой вариант — глубокое и развесистое дерево вызовов твоих депенденсов.

Непонятно. Что за дерево вызовов и почему оно глубокое и развесистое? Пока я вижу что это ты прозрачную передачу зависимостей до любого целевого кода через DI предлагаешь заменить на явное прокидывание данных по всей цепочке зависимостей с самого верха.

I> Хорошо, если зависимость дергается единожды, легко мокнуть. А если долбится часто или вовсе постоянно — пожелаю тебе удачи в бою


Непонятно. Есть что сказать — говори. А мутные намеки лишь свидетельствуют о том, что сказать тебе нечего.

I>Собственно, твой вариант тоже можно привести к варианту Синклера.


Синклер, напомню, так и не ответил на пример с кубом.

I>У тебя будет примерно N шагов в дереве, у меня — N шагов в линейном контроллере.


Не понимаю о чем ты, не будет у меня никаких дополнительных шагов в дереве. В псевдокоде (который, на самом деле, практически рабочий код) все важное есть кроме собственно кода публикации в DI, который в любом из вариантов идентичен.

НС>>Во-первых я не хамил, а во-вторых какое отношение имеет время запуска кролика при разработке конкретного сервиса и время прогона вообще всех тестов? Время же прогона тестов валидации только по конкретному контроллеру да еще и с моками почти наверняка будет существенно быстрее стартапа тяжелых зависимостей (там ведь обычно не только кролик).

I>Если ты собираешься валидацию именно на моках тестировать, то конечно будет быстро.

А если не на моках, тогда вообще непонятно о чем ты. Если уж у нас реальные зависимости, то какая разница сколько времени кролик стартует если его в любом случае поднимать? В том то и проблема интеграционных тестов, что на реальных системах это все равно от десятков минут до десятков часов, даже если там никакая валидация не проверяется. Да и сам поинт отказа от проверки валидации мне, если честно, непонятен. 90% негативных тестов это как раз проверка валидации аргументов того или иного уровня. Если твоя система большую часть негатива не отсекает на этапе проверки — это не очень удачно спроектированная система.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[61]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 09.03.22 21:16
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>·>У тебя есть альтернативы?

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

НС>·>Хинт: "run test -P e2e" в проде — это тоже вера, или просто религиозный ритуал.

НС>Это просто прямая, а не косвенная проверка.
Насколько прямая? Ты измерял? Или просто веришь?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[57]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 10.03.22 00:31
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>1. нет багов/уязвимостей (зафикшены,необнаруженых итд)

I>>>2. все причины установлены
I>·>Про 100% гарантии ты сам придумал.
I>Ты на прошлой неделе заявил, что после твоих фиксов нет ни единого шанса воспроизвести баг на проде.
Я не это заявлял. Я заявлял, что если некий тест не обнаружит баг в пре-проде, то он не обнаружит баг и в проде.

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

I>Покажи методику вычисления этого процента. Если у тебя такой методики нет, то крайне странно заявлять "препрода достаточно"
Эмпирически. Считаем сколько пролезло в прод и их серьёзность.

I>>>Багфикс и тестирование всего лишь уменьшают вероятность, не могут исключить проблему полностью. Условно — всегда есть другой, неизвестный тебе путь, который приведет к тому же результату.

I>·>Верно, это же верно и для прод тестов.
I>Разумеется. При этом проверяя на проде мы получаем максимально возможные гарантии.
Можно получать максимально возможные гарантии и в пре-проде.

I>>>Да не гони, это именно обычные пользователи.

I>·>У меня на компе десятки продуктов. И ни одного из них нет беты. Я не обычный пользователь?
I>Обычный.
С чего ты взял, что бета-тестеры — это обычные пользователи? В чём тогда отличие от таких обычных пользователей как я?

I>>>Кроме того, кейс с immutable deployment — его специально делают на тот случай, что бы сделать быстрый откат.

I>·>Да, верно. Но это иррелевантно к нашему обсуждению.
I>Наоборот. В этом случае тебе надо быстренько понять, стоит ли откатывать, или же стоит оставить.
Откаты у нас для другого. Например, иногда случается, что юзеры внезапно не хотят изменения, которые мы вносим запланированно. Это, конечно, реальный факап, происходит редко, но откаты быть должны как запасной аэродром. Честно говоря, не помню откатывали ли мы вообще что-то за последние пару лет?.. Просто эти скрипты отката используются для пре-прода в основном, чтобы репетировать процесс выкатки в прод: подготовили релиз-скрипт, выкатили, потестили, подебажили, откатили, проверили, что ничего не поломалось.

I>Каким же образом выяснить, снова предложиль пинг в качестве проверки?

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

I>>>Ты же понимаешь, что никто не будет держать синий прод вечно. А раз так, надо бы побыстрее дать гарантии, что зеленый не хуже.

I>·>Давайте эти гарантии в пре-проде. Ничего не мешает.
I>Ты снова забыл про разницу прода и препрода
Я не забыл, мы её просто держим под контролем. Мы знаем что у нас в проде может быть.

I>- зависимости прода есть только на проде и у них цикл жизни свой собственные

В препроде есть пре-прод зависимости, демо какие-нибудь или моки-стабы.

I>- конфиг

Контролируется на раз.

I>- окружение

Мониторится.

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

Не нужен идентичный, нужен с известной разницей.

I>·>Причём тут сборки? Опять, это иррелевантно к нашему обсуждению.

I>Это именно то и есть — разница между продом и препродом ничтожна.
Ну да, значит в проде тестировать нет необходимости.

I>>>Это ничего не меняет — опубликована и рассылаться юзерам будет только вторая, которая прошла тесты, а первая останется для истории.

I>·>Да, т.е. обычные юзеры юзают релиз, а не бету.
I>Факт в том, что релиз перед раздачей юзерам прошел все нужные тесты, в т.ч. на реальных юзерах.
На мне никто хром не тестирует, хоть я и реальный юзер. Не путай юзеров и бета-тестеров.

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

I>·>А что ещё-то? Любовь и тепло сердца?
I>Надо вспомнить, что тест это испытание на предмет выявления соответствия требованиям. А раз так, то ключевое в тестах, это все что относится к требованиям. Код — это всего лишь частный случай, т.к. тесты могут быть не только автоматическими, но и полуавтоматическими и даже ручными.
I>Требования, кейсы, сценарии, ожидания вызывающей стороны, граничные случаи, т.н. fitness function, и тд и тд.
Ты опять куда-то не туда понёсся. Мы обсуждаем конкретное "run test -P e2e". Это ручные тесты или граничные случаи?!

I>>>Да как угодно. Это, к слову, e2e тест, система от прода отличается только конфигом, никаких моков здесь уже нет.

I>·>У вас в проде тоже mailtrap стоит?
I> тебе повторить содержание беседы про пуск ракеты?
Нет, кривые аналогии — не к месту. Просто на вопрос ответь. Как вы проверяете в проде почту?

I>>>Ты нормальный? Этот вайринг код и будет связывать зависимости с тем компонентов. Тест я уже показал — раскрой глаза.

I>·>Ты не тест показал, ты сценарий теста показал. Что делается этим сценарием — я это и спрашиваю. Вайринг код ты так и не показал.
I>Это и есть тест! Про cucumber слышал?
Это просто текстовый сценарий, синтаксис короче, более человекочитаемый для непрограммистов, который потом байндится на соответствующие методы в коде. Вот код меня и интересует.

I>>>Цель использования эвента — максимальное развязывание компонентов.

I>·>В-нулевых, евент — это лишь средство, эту же цель можно достигнуть другими средствами, _если_ вдруг понадобится.
I>можно. эвент — современный метод.
Если "Современный" означает "со времён царя гороха"... то да.

>>Во-первых, неясно зачем что-то развязывать максимально.

I>Затем, что бы мейнтейнить, тестировать было проще.
Пока у тебя получилось всё сложнее, кода больше, потенциальных ошибок больше.

>> Во-вторых, неясно что значит максимально развязывать.

I>Вполне ясно — наш компонент не имеет зависимости от hmrc.
Хотя в требованиях ясно сказано, что зависимость есть: "должно уведомлять налоговую о всех транзакциях суммой больше ...".

>> В-третьих, связывать развязанное тебе всё равно придётся. И ты упорно не хочешь это признать и кто для связывания затрудняешься написать.

I>Наоборот — я же тебе показал, и не единожды. В очередной раз:
I>
I>   const [result, event] = this.svc.transfer();
I>   this.auditQueue.send(event); // вот твоё связывание
I>

Не очень ясно куда ты потерял from, to, amount. Откуда они берутся? И как ты теперь это всё протестируешь?
Ещё ты забыл, что event посылается не всегда и получил NPE на пустом месте.
Как ты обеспечишь, что во всех местах вызова transfer происходит send? По требованиям регуляторов ты не имешь права делать transfer без соответствующих уведомлений в налоговку.
Где у тебя в коде описано, что auditQueue.send собственно должно слать соответствующие уведомление trackHim в налоговку?

I>если тебе мало, то вот еще пример, если у нас эвент у метода

I>
I>   const result = this.svc.transfer( {thresholdExceeded: event => this.auditQueue.send(event)}); // вот твоё связывание
I>

Тест где? Без тестов код — не принимаю.

I>если мало, то еще вот пример, если у нас эвент у инстанца

I>
I>   this.svc.thresholdExceeded.use(event => this.auditQueue.send(event));
I>   const result = this.svc.transfer( ); // вот твоё связывание
I>

А тут ещё и с многопоточностью/атомарностью потенциальные проблемы. Что use делает? Добавляет ещё одного подписчика? Или заменяет предыдущего?

I>Теперь,внезапно, что будет, если нам надо ввести какие полиси или счетчики? Вобщем, ничего — добавить функцию вида (event) => event, которая отлично покрывается юнит тестами, тогда все будет вместо this.auditQueue.send(event) будет

I>
I>policy(event, this.config, x => this.auditQueue.send(x))
I>

И так везде, у каждого консьюмера? А клавиша копипаст выдержит?

I>То есть, нам не надо лезть в наш компонент, изменится исключительно связывающий код.

См. паттерн Decorator, например.

I>·>Повторяю, повторы, блокировки налоговки — это всё не является частью поведения MoneyService, его дело простое — деньги переводить.

I>Странный у тебя подход. Вот тебе перечисляют ЗП. Запрос завершился по таймауту. Как думаешь, кто должен обрабатывать ошибку и каким образом это дело решать?
Эээ... retry, например.

I>>>Снова у тебя юнит-тесты вместо интеграционных

I>·>Ты заявил глупость выше, что мол, не проверяется. Я описал как. Что не устраивает-то?
I>Юнит тесты этот кейс никак не ловят, толко некоторые его пути. Мы можем убедиться, что какой то метод в ответ на таймаут может кинуть результат соответствующий.
I>Но что бы понять, как система на такое среагирует, юнит-теста мало.
В смысле что сдеает обработчик соответстующего результата? Тоже можно протестировать.

I>>>Точно так же, как симулируются фейлы на уровне системы.

I>·>И как же?
I>есть т.н. failover testing, когда нужны гарантии, что прод не склеится из за тех самых отличий с препродом при fail сценарии.
Как симулируется фейл в проде? В пре-проде можно хоть вручную потетстить, выдернув кабель нажать резет, зафигачить "kill -9", искусственно вызвать OOM и т.п. Ты уверен, что готов делать такое в проде?

I>>>А кто говорит, что мониторинг не нужен? Тесты прода это быстрый тест на то, что в нем выполнимы сценарии юзеров.

I>·>Для проверки выполнимости сценариев юэеров нет необходимости тестировать в проде.
I>Выполнимость интересует не абы где, а именно на проде, в силу неустранимой разницы с препродом.
Не надо её устранять, надо её контролировать.

I>>>Мало ли, деплоймент поднялся с какими то мелкими багами. Самое правильно — задетектить по быстрому, откатить деплой, фиксануть, передеплоить.

I>·>Какими мелкими багами? Если эти баги ловятся тестами, то какого хера ты задеплоил с багами??! А если не ловятся, то ты их не задетектишь по быстрому.
I>Обычным. На препроде багов не было выявлено, а на проде — снова воспроизвелись. Что делать предложишь?
На второй круг, я же объяснял где-то. Бага считается всё ещё не пофикшеной, думаем дальше.

I>>>Где ты видишь про длинный список? Я всего то про овнершип. Вот скажем, если овнершип e2e у меня, то тебе придется объяснить мне, на кой ляд ты хочешь закаментить степ в сценарии.

I>·>Фиксуны же твои любимые — они же всемогущие.
I>В данном случае, если овнершип ключевых тестов находится у ответсвенных работников, то это дополнительная степень защиты.
Ну т.е. фикусуны таки не всемогущи, и комментировать случайный код они не могут без аппрувалов у ответственных работников. Об чём спор-то?

I>>>Нету такого в бизнес-треботвания,

I>·>Есть, конечно. Слыхал need-to-know принцип и information barriers?
I>Бизнес-требования пишет обычно бизнес-аналитик, большей частью задолго до появления кода, потому там никак не может появиться вещей "вызовем вот тот метод"
I>Кроме того, требования описываются не в терминах реализации, а в терминах бизнес-специфики.
Если не рассматривать UI, то взаимодействие со внешними системами будет через public api. И очень вероятно в терминах, например, gRPC может звучать именно так.

I>>> как "скрывать важные вещи от консумеров интерфейса".

I>·>В бизнес-требовании не было требования показывать что попало консумерам. То что вещь важная и её непременно надо кому-то показывать ты сам придумал.
I>Бизнес-требования к конкретному классу имеют сильно слабое отношение. Одно и то же требование можно реализовать как угодно.
Консумеры консюмят API, и это именно то, что описывается в бизнес-требованиях.

I>>>Именно. А воздействовать можно исключительно через интерфейс. Я предпочитаю иметь в интерфейсе явную связь,а у тебя "по бизнес требованиям надо усё упрятать поглубже"

I>·>Т.е. ты пишешь код по своим предпочтениям, а не по бизнес-требованиям, типичный over-engineering.
I>У меня в бизнес-требованиях только бизнес-специфика а не строчки "в таком то классе вызывайте вот такой то метод"
Т.е. вместо трёх строчек в твоём коде будет 30 строчек и это лишь потому что "предпочитаю". В бизнес-требованиях не было намёков, что события опциональны или требуется динамический pub-sub... но ты это всё добавил лишь потому что предпочитаешь.

I>>>Он дает максимальную развязку компонентов, позволяет ключевые вещи покрыть дешевыми и надежными тестами безо всяких моков.

I>·>Как выяснилось, не позволяет.
I>·>Да, ты покрыл часть более простым тестом, но часть оставил непокрытой, и теперь надо писать ещё дорогой тест с моками.
I>У меня нет непокрытой части. И тест на моках мне не нужен.
I>Покажи, что именно мне нужно покрывать "дорогим тестом на моках"
Вон у тебя выше было куча кода без тестов.

I>>>Использование, чтение, анализ кода, поиск проблем, инструментирование, аудит и тд.

I>·>Возможно, но это не требуемый публичный интерфейс MoneyService который в требованиях.
I>Нет никакого интерфейса в бизнес-требованиях. Там вообще и кода никакого нет.
Application Programming Interface есть.

I>>>В том, что ThresholdExceeded объявлен в терминах моего компонента, а не в единицах какой то 3rd party либы.

I>·>Зато теперь тебе нужен код связывающий твой компонент с 3rd party либой. Выигрыш-то в чём?
I>Этот код и тебе нужен, ты его показал.
А ты так и не смог показать. И самое главное — покрыть тестом.

I>Выигрыш в том, что мой компонент проще и тест к нему — проще, т.к. зависимостей меньше, а покрытие будет плотнее.

У меня покрытие было 100%. У тебя 146% что-ли?

I>Более того, мелкие изменения, коих тьма, больше не требуют изменения самого компонента.

Величина изменений и необходимость изменения компонента — вещи ортогональные. Какие-то мелкие изменения — таки потребуют.

I>>>Соответственно, нам не надо мастырить игрушечный контекст на моках, что покрыть функционал.

I>·>Надо, федя, надо. То что ты навертел дополнительных слоёв и фреймворков, а всё неудобное замёл под коврик, отказываешься даже показать код, не означает, что этого нет.
I>Фремворки и у тебя есть, тот самый spring, hibernate и тд. Или ты по старинке, колхозишь склейку строк и работаешь через сокеты?
Зависит от.

I>>>Смотря как ты хочешь использовать. Например, в разных юзкейсах надо уведомлять разное по разному. Соответсвенно, упрятывать такое в конструктор я бы не стал.

I>·>Бизнес требования видел? Зачем фантазировать-то?
I>Видел. За 20 лет мне никто не присылал в бизнес-требованиях "передай вот такую ссылку в конструктор".
Напомню: "должно уведомлять налоговую о всех транзакциях суммой больше ...". Не было никаких разных юзкейсов. Это ты нафантазировал.

I>>>Это описание http контроллера. Его задача очистить вход от протокольного мусора. Для graphql есть свое описание, для gRPC — своё. Это уже состоявшаяся реальность.

I>·>Так что за описание API в рамках Swing или Hibernate, можно пример?
I>Ты адекватный? читам вместе "Это описание http контроллера. Его задача очистить вход от протокольного мусора. Для graphql есть свое описание, для gRPC — своё."
Ты заявил "Сейчас все делается фремворками — Swing, Hibernate, и тд. API описывается в терминах какого либо фремворка.". Вот меня и заинтересовало описание API в рамках Swing или Hibernate. Можно пример?
Откуда у тебя взялся http контроллер, я не понял.

I>>>Все это обычно пишется или генерируется по описанию апи.

I>·>Ну вот у тебя сгенерировался Result transfer(from, to, amount). Куда ты затолкаешь твои любимые евенты?
I> Если в АПИ указан эвент, то он и сгенерируется где надо. Нет в АПИ — не сгенерируется.
Напомню: "должно уведомлять налоговую о всех транзакциях суммой больше ...". Там не было, что transfer должен возвращать результат с какими-то евентами.

I>>>отличается конфигурация

I>·>Чем отличается? Именем хоста, портом? Вот и тестируйте это.
I>Много чем. Ты никогда не знаешь ответ на вопрос "всё ли известно по багу". Например, бывает так:
I> — юзеры создали 40+ запросов в суппорт
I> — суппорт "проаггрегировал" запросы и выдал тебе ровно 1 фрагмент
I> — ты фиксанул фрагмент, и естественно, учел не всё, т.к. суппорт подкинул тебе фрагмент
I> — упс, на проде все упало
I> — контора платит конские пенальти, потому, что ты не учел разницы между продом и пре-продом, т.к. суппорт спрятал от тебя разницу прода и пре-прода.
I>Это история у крупного вендора софта для рынка американского страхования.
Не понял какую разницу спрятал.

I>А тебя послушать, все как в сказке

I>- все известно заранее, на любую глубину
I>- требования пишут в терминах языка программирования "вызови метод по переданной в конструктор ссылке"
I>- нет ни единого шанса, что баг после фикса воскреснет на проде
I>- и вообще, все пишут без багов
Это твои фантазии.

I>>>отличается цикл жизни зависимостей

I>·>Можно пример?
I>Например, все шаред зависимости с прошлой версии прода будут работать и в новой версии, что очевидно.
Версии каждого компонента в проде мы знаем точно, задеплоить то же в пре-прод — элементарно. Это вообще никакая не проблема. Причём тут жизненный цикл — я не понял.

I>>>отличается энвайрмент, сам по себе

I>·>Енвайрмент вещь эфемерная и его нужно мониторить, а не тестировать во время релиза.
I>Мониторить нужно. А что бы выявить проблемы как можно раньше, стоит протестировать.
Ага, в пре-проде.

I>>>С т.з. мейнтенанса важно. Класс, который непосредственно зависит от другого класса, будет хуже мейнтейниться, и в этом случае зависимость от hmrc может вообще прорасти куда угодно, да так, что сменить дизайн будет невозможно.

I>·>Рефакторинг введения или удаления интерфейса — одна минута. Как удобно, так и делай.
I>Ога. В твоем случае ты интерфейс проращиваешь куда попало. В моем случае компонент изначально изолирован,
Что такое "проращиваешь"?

I>потому внутренности я могу менять как попало.

И всё нахрен сломать. И теперь тебе нужно всё усердно тестировать на реальных юзерах.
Не надо менять как попало, надо менять как требуется.

I>>>Соответсвенно, в общем случае тебе нужен интерфейс, + моки, + тесты вида "проверим, что унутре вызвалось вот так"

I>·>не надо писать код в общем случае. Делать надо просто, проще как только возможно, но не проще.
I>Имено. Потому я решил выбросить все, включая лишние зависимости.
Но пришлось добавить тучу всего.

I>>>На эвентах будет иначе- "проверим, что унутре вызвали вон то" у нас не будет, т.к. не будет зависимости, и мокать "htmr.trackHim(321).willReturn" тоже не надо.

I>·> willReturn это если метод что-то возвращает (с эвентами ты это вообще вменяемо не сможешь сделать).
I>Ты снова прицепился к willReturn, а trackHim похоже тебя не смущает. На самом деле проблему и то, и тд.
Не распарсил.

I>>>Я же пишу — если консумерам это не надо, можно и упрятать, и снова твой вариант не единственный. Если консумерам это надо — твой вариант крайне сомнительный.

I>·>В требованиях ясно, что не надо. Если консумерам что-то таки понадобится, это будет специфицированной частью TransferResult (и пример с someRepId я тебе приводил уже), а не аннотациями-туплами.
I>Не ясно, что за требования у тебя.
Я эти требования уж раз 20 напоминал.

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

I>·>Т.е. ты отталкиваешься от любимого привычного тебе стиля кодирования, я отталкиваюсь от конкретных требований.
I>Мне никто в требованиях не пишет "вызови метод trackHim используя переданную в конструктор ссылку"
"Обратиться к HMRC API, послать уведомление trackHim(account)" — так и будет.

I>>>Правильно, у одного консумера так, у другого — эдак. Мало ли, юз кейсы какие.

I>·>Вот когда появятся разные виды консьюмеров, вот тогда и будем усложнять код, есть такая штука интересная, рыбфакторенг или что-то такое... слыхал?. Зачем делать сложно изначально — неясно.
I>Изначально твоя задача сильно нечеткая, ты же не требования дал, а фрагмент решения. А я должен догадаться, каие требования могли подходить под твое решение
Что нечётко?

I>>>Ну так не тебе одному же условия задачи менять.

I>·>Дай конкретные условия задачи, я придумаю как отрефактороть.
I>Начни с себя. Решение задачи ты показал, а требования все никак не родишь.
См. выше.

I>>> Ну и дикая страна у вас.

I>·>Можно скриншотик твоего банка? Где там полный отчёт всего произошедшего выводит при transfer денег между акками?
I>Про уведомление налоговой меня предупрежают при заключении договора и про (не)уплату налогов. "скриншот банка"
Это я и сказал, ты на это заявил, что страна дикая. Суть в том, что операция transfer налоговку не упоминает в API. Это внутренние детали реализации MoneyService.

I>>>Ну так посмотри про тамошние эвенты,

I>·>Я посмотрел и не нашел там ThresholdExceeded.
I>Ты привел описание trackHim, так?
Т.е. причём тут азы c#? Я пытаюсь из тебя код выудить решения конкретной задачи, но всё безуспешно.

I> У этого метода ты привел параметры? Я сказал тебе, что будет 1 в 1 с той разницей, что

I>1. не нужен доп интерфейс
Зато нужен тип события. Нужен код привязки события к реальному external API для HMRC.

I>2. не нужен мок

Нужен при тестировании кода привязки.

I>>>благодаря таким эвентам можно выбросить кучу кода.

I>·>А ты не пиши кучу, пиши только то что надо и выбрасывать ничего не надо будет.
I>Я и показл, что нужно выбросить относительно твоего варианта
И умолчал что придётся добавить.

I>>>И потому в джава поголовно используют spring и hybernate?

I>·>Чего она только не использует...
I>То есть, ты пошел на попятный. У тебя в проекте spring или чтото вместно него? Скажи честно.
В разных проектах по-разному.

I>>>Вспоминаем ту самую вероятность и разницу между продом и пре-продом.

I>·>Так наймите профессионального архитектора и разница будет меньше допустимых величин риска.
I>Вероятно, ты предлагаешь нам нанять того, кто будет писать требования вида "передайте ссылку в конструктор и потом вызовите у неё метод trackHim"
Нет. Тот кто объяснит как организовывать архитектуру кода, чтобы он работал как надо, а не как попало.

I>>>В том то и дело. И это нужно узнать до того, как реальный трафик пойдет на прод.

I>·>Если ты это можешь узнать до трафика, то ты это можешь узнать до прода. По крайней мере с вероятностью достаточной для допустимы величин риска.
I>Покажи методику расчета вероятности.
Эмпирически.

I>>>Ну да. А если у тебя неверный root cause analysis, то упадет еще один самолет.

I>·>Тут главное избавиться от иллюзии про 100% гарантии. (c)
I>Именно. Ты все время говоришь что "нет шансов, что баг воспроизведется на проде"
Не баг не воспроизведётся, а тест на препроде будет иметь тот же цвет, что и на проде. Результат работы тестов не зависит от окружения, по дизайну, иначе это плохие, хрупкие, недетерминированные тесты и их надо переписать.

I>>>Неявная, подразумеваемая, логическая, виртуальная, причинно-следственная, косвенная...

I>·>У меня связи были явными.
I>Явне это через публичное АПИ. Покажи, каким образом, глядя на описание твоего публичного интегрфейса, понять, что есть то самое уведомление.
HMRC trackHim — это и есть публичное АПИ которое мы зовём. И MoneyService transfer — тоже публичное API, которое мы предоставляем.

I>>>Корутины древние как мир. Их в C# добавили еще когда node и в планах не было. А в modula, smalltalk, lisp это было в начале времён.

I>·>Причём тут евенты — неясно. Очередная подмена тезиса?
I>event это push модель, корутины — pull. И то и другое позволяет реализовать нотификации.
А евенты, ещё и например, mq-брокер тоже позволяет. Так причём тут твои встроенные в язык евенты?

I>>>Нету такого требования, а потому MoneyService мы можем задизайнить как проще.

I>·>Врёшь, оно было изначально: "должно уведомлять налоговую о всех транзакциях суммой больше ...". Если ты это не будешь делать в MoneyService, то каким-то образом должен обеспечить, что все консумеры таки посылают это уведомление. Это будет очень даже не проще.
I>Консумеры будут вызывать или конкретный useCase, или писать кастомный useCase. Сам компонент для трансфера нужно выделить в изолированый компонент, который будет плотно покрыт юнит-тестами.
Код в студию.

I>>>Независимо от реализации, этот тест необходим.

I>·>Это ясно. Тебе потребуется ещё один интеграционный тест, который интегрирует события с налоговой. Т.е. была только интеграция MoneyService с налоговой, а теперь у тебя промежуточный слой появился в виде евентов, с которым тоже надо интегрироваться и тестировать.
I>Этот слой и есть интеграционный, и будет протестирован интеграционными тестами.
И тут тебе ВНЕЗАПНО потребуется мок налоговки. Как минимум для того, чтобы можно было тестить до выкатки в прод.

I>·>N*M — это взаимодействие двух слоёв. Если слоёв больше, то и получается N*M*O*P*Q*...*R астрономия. Об этом ты и говорил, что e2e — как решето.

I>e2e проверяют интеграцию, а именно — сценарии выполняются на конкретной системе. Они не проверяют валидацию входа/выхода/ и ветвления логики.
Вот и я о том же. Вот у нас есть MoneySerivce, который использует mq, есть ещё 10 других сервисов. Проверять что каждый из этих сервисов умеет "никогда не теряются...если сеть недоступно...после возобновления" — это только тепловую смерть вселенной приближать. Тебе достаточно проверить, что сообщения гарантированно доставлюятся и что каждый из сервисов использует гарантированную доставку где надо.

I>>>Наоборот — рабочая сила тратит больше времени, тестируюя у себя локально, и в проде, сокращая количество итераций багфикса.

I>·>Протестить локально — время порядка секунд, а дойти до прода может занимать дни и недели.
I>Дойти до прода — дни и недели. Потому и надо сокращать количество итераций. И тесты на проде именно это и делают.
Не понял. Вот я поправил строчку в IDE, хочу поглядеть как оно работает, надо бежать тесты на проде делать?!

I>>>Нужен интеграционный тест вида "счетчики работают и попадают в мониторинг" + "фейла виден на мониторинге"

I>·>Это может идти из коробки mq-брокера. Queue Depth называется и не специфично конкретно к сообщениям налоговой, а на всю инфраструктуру гарантированной доставки. Как раз пример сведения N*M к N+M. Т.е. компонент MoneyService просто валит всё в определённое место и это легко тестировать. А это определённое место занимается деталями гарантированной доставки. И это тоже легко тестировать и мониторить.
I>Твой MoneyService ничего никуда не валит — он вызывает внешний сервис. Или ты снова про то, что налоговая будет часть вашей внутренней инфраструктуры мониторить?
Он вызывает external API. Что там делается — вызов внешнего сервиса или идёт всё сразу в /dev/null — его не волнует и волновать не должно. За external API отвечает поставщик.

I>>>Обычный. ты то не хочешь рассказывать как L2 суппорт решит задачу "два часа назад должно было быть 1000 запросов к налоговой", я придумал своё решения.

I>>>не устраивает — приводи свой вариант.
I>·>Я не понял откуда вообще взялась эта задача. Зачем её вообще решать?
I>Эта задача показывает, зачем нужны тесты. Что бы не мониторингом ловить все возможные проблемы, а убедиться, что сценарии выполнимы.
I>Мониторинг на самом деле проверяет только точечно.
Мониторинг показывает, что канал отправки сообщений функционирует, значит отправляемые сообщения отправятся, если они будут. Если не будут, не отправятся. Это и есть выполнимость сценариев.

I>>>Мне нужны гарантии, что L2 суппорт сможет обнаружить такую проблему.

I>·>Сможет обнаружить по состоянию очередей доставки.
I>Покажи пример скрипта, который задетектит любую потенциальную проблему по состоянию этих очередей. Ну мало ли, вдруг ты внёс сто неизвестных багов.
Это из требований определяется. Таймауты на доставки, acks, етс, детали протоколов. Это всё относится к с системе мониторинга. Тестировать её можно отдельно и тоже в пре-прод, с воспроизведением любых хитрых сценариев и отказов.

I>>>CPU тебе тоже нужен? И твоя джава без единого потока работает?

I>·>Одного потока достаточно, созданного при старте приложения. Зачем создавать больше?
I>Вот и покажи, сколько времени надо на один сетевой запрос.
Ты вообще о чём? О потоках или о сетевых запросах?

I>>>Что бы отправить запрос, CPU в конкретном thread должен затратить кучу времени, (подготавливая блок, адрес, записывая в сокет,) на несколько порядков больше, чем прямой/обратный вызов.

I>·>Зависит от того как ты написал код. При желании оно может читать напрямую из DMA региона сетевой карты и записывать результат туда же.
I>Ну вот сделай замеры end-2-end, да убедись.
Убедиться в чём? Я тебе уже неоднократно намекал, что один-к-одному отношения между сетевыми запросами и событиями может и не быть.

I>>>Т.е. если прямой/обратный вызов это доли наносекунды, то сетевой запрос займен микросекунды. Реально — в зависимости от протокола еще больше, может даже милисекунды.

I>>>Итого — разница в микроскоп не видна. А тебе она мешает
I>·>У вас не видна, а у нас была видна.
I>Вероятно, вы так код написали. Причина то в чем была и какой порядок разницы между прямым и обратным вызовом?
Причём тут обратный вызов? И чем он отличается от прямого? Мы вроде сравниваем события vs вызов метода. И события в шарпе, полагаю, в несколько раз медленее и никакого инлайна.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.