Re[62]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 10.03.22 08:39
Оценка:
Здравствуйте, ·, Вы писали:

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

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

Есть, проверять прод.

НС>>Это просто прямая, а не косвенная проверка.

·>Насколько прямая?

Насколько возможно. Тестируем ровно те машины ровно в той конфигурации, которые пойдут на прод.

·> Ты измерял? Или просто веришь?


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

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


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


Правильно — явно контролируем поток данных, явно контролируем эффекты.

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

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

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


Я борюсь за легко поддерживаемый, тестопригодный код. Контроллеры на ровном месте раздувает in-place логика, а вот если там оставить только пайплайн, то контроллер будет компактным, хоть и не однострочником.

>А в реальной ситуации с несколькими зависимостями и несколькими развесистыми моделями ты получишь тот самый жирный и конский.


Покажи пример.

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


Пример нужен.

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


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


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

I>>Это возвращаемое значение GetDataFromDependency


НС>А если оно не подходит, например там несколько методов позвать нужно? А если у него ктор internal и создать экземпляр можно только вызовом родного клиента?


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

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

I>>В DI будут не функции, а контроллер,

НС>Не понял опять.

НС>

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


Смотри внимательно — в моем варианте дизайна у сервиса SomeService нет зависимости от IDependency, а раз так, то DI ему для этой цели не нужен.

НС>Т.е. ты вместо IMyService предлагаешь сделать функцию. В DI публикуется именно IMyService, публиковать там контроллер — нафига?


Контроллер получает зависимости через DI, ровно как и у тебя. Надо ли публиковать сам контролер или нет — полагаю, всё как и у тебя.

НС>Отдельный вопрос — в чем прелесть набор семантически связанных функций превращать в россыпь? Чтобы получить взрывной рост доли бойлерплейта? Помимо loosely coupling есть еще и hight cohesion, которое ты своей идеей разломаешь нафик. loosely coupling любой ценой никому не нужно.


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

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

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

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

I>>У тебя другой вариант — глубокое и развесистое дерево вызовов твоих депенденсов.


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


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

I>>Собственно, твой вариант тоже можно привести к варианту Синклера.

НС>Синклер, напомню, так и не ответил на пример с кубом.

Нету наилучшего дизайна на все случаи жизни.

I>>У тебя будет примерно N шагов в дереве, у меня — N шагов в линейном контроллере.


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


Обычные шаги, ты их сам же и показал — GetDataFromDependency и DoAction. Два штуки в глубину. У меня — два штуки один за одним в контроллере.

> Да и сам поинт отказа от проверки валидации мне, если честно, непонятен.


Правильно понимаю, тестирование юнит-тесты + интеграционный wiring тест это, по твоему, отказ от проверки?
Похоже, всё что не по-твоему, это неправильно.
Re[64]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 10.03.22 10:11
Оценка:
Здравствуйте, Ikemefula, Вы писали:

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

I>Правильно — явно контролируем поток данных, явно контролируем эффекты.

Ага, даже если ничего контролировать не надо. Обезьянья работа.

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

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

Нет, ты борешься с моками. Потому что с моками прекрасно все тестируется и без искусственного вытаскивания всех зависимостей в контроллер.
А знаешь что самое смешное? Когда мы возьмем весь код, включая код тестов, то окажется что тот код, который эту самую Data подготавливает окажется практически 1 в 1 с тем кодом, что будет внутри мока. Т.е., при отказе от моков ты ничего не выиграл и проиграл в объеме обвязочного кода.

I> Контроллеры на ровном месте раздувает in-place логика


Где в моем примере in place логика? Что ты опять сражаешься с чучелками?

НС>>А если оно не подходит, например там несколько методов позвать нужно? А если у него ктор internal и создать экземпляр можно только вызовом родного клиента?

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

У меня вся логика нетривиального общения останется внутри компонента, использующего зависимости. А где она будет у тебя?
Давай опять пример, чтобы избежать трактовок
async Task DoActionAsync()
{
  var data = await _dep.GetDataFromDependency();
  var secondRequest = CreateRequest(data);
  await _dep.PerformSecondAction(secondRequest);
}

Контроллер остается идентичным исходному примеру.
Перепиши пример с учетом выноса зависимостей в контроллер.

НС>>Не понял опять.

НС>>

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

I>Смотри внимательно — в моем варианте дизайна у сервиса SomeService нет зависимости от IDependency, а раз так, то DI ему для этой цели не нужен.

Логгер, трейсер, метрики, конфиги, соседние сервисы — будешь тоже через параметры передавать явно?

НС>>Т.е. ты вместо IMyService предлагаешь сделать функцию. В DI публикуется именно IMyService, публиковать там контроллер — нафига?

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

Для получения зависимостей не нужно себя публиковать, о чем ты?

I> Надо ли публиковать сам контролер или нет — полагаю, всё как и у тебя.


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

I>Где ты видишь взрывной рост бойлерплейта?


НС>>DI то будет. А вот протаскивать данные через колстек тебе придется руками, без DI.
I>Правильно — явно контролируем поток данных, явно контролируем эффекты.

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

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

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

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

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

НС>·>У тебя есть альтернативы?
НС>Есть, проверять прод.
Т.е. ты веришь, что прогон тестов в проде непременно должен от чего страховать и защищать от того, что "что может пойти не так".

НС>>>Это просто прямая, а не косвенная проверка.

НС>·>Насколько прямая?
НС>Насколько возможно. Тестируем ровно те машины ровно в той конфигурации, которые пойдут на прод.
Это лишь говорит о том, что у вас плохо поставлен процесс деплоймента. В эпоху контейнеров воспроизвести точную конфигурацию машины с точностью до бита — вещь тривиальная. В итоге это переносится с уровня деплоймента новой версии на уровень мониторинга и эксплуатации.
Все эти "ровно в той конфигурации" — яйца выеденного не стоят, ибо конфигурация окружения меняется со временем вскоре после "успешно протестированного" деплоймента.
Например, когда нода кластера вышла из строя в проде после успешного и давно забытого релиза, воспроизвести конфигурацию на новой ноде надо за минуты, в автоматическом режиме, а не ждать когда кто-то что-то заметит, передеплоит и запустит "run test -P e2e". И вся эта автоматика прекрасно тестируется в пре-проде.

НС>·> Ты измерял? Или просто веришь?

НС>Верю во что? В то что тесты прода тестируют прод?
Да. Ибо на самом деле тесты в лучшем случае тестируют тестовые аккаунты/етс, а не реальные живые сценарии реальных живых пользователей.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[58]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.03.22 11:39
Оценка:
Здравствуйте, ·, Вы писали:

I>>·>Про 100% гарантии ты сам придумал.

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

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

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

·>Эмпирически. Считаем сколько пролезло в прод и их серьёзность.

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

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

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

А если этого недостаточно?

I>>Обычный.

·>С чего ты взял, что бета-тестеры — это обычные пользователи? В чём тогда отличие от таких обычных пользователей как я?

А я и не говорю про бета-тестеров. Сидит себе Вася и пользуется софтом. Ему админы подкидывают релиз-кандидат, Вася продолжает работать как работал.


I>>- зависимости прода есть только на проде и у них цикл жизни свой собственные

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

Вот это и есть основа проблем — чем больше такого, тем больше шансов напороться на баг в проде.

I>>- конфиг

·>Контролируется на раз.

Особенно, когда ты доступа не имеешь Ты точно уверен, что валидатор сможет проверить любые комбинации любых ключей?

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

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

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

I>>Требования, кейсы, сценарии, ожидания вызывающей стороны, граничные случаи, т.н. fitness function, и тд и тд.

·>Ты опять куда-то не туда понёсся. Мы обсуждаем конкретное "run test -P e2e". Это ручные тесты или граничные случаи?!

Если именно e2e, то это кейсы, сценарии, пишутся по требованиям. Все это проверка именно интеграции — проверять логику при помощи e2e в своём уме мало кто станет.

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

·>Нет, кривые аналогии — не к месту. Просто на вопрос ответь. Как вы проверяете в проде почту?

Никак, у нас её нет.

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

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

Есть просто либа, которая умеет стандартные действия. Действие это или клив в UI + ожидаемый результат, или вызов некоторого API + результат. Ничего особенного.

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

·>Пока у тебя получилось всё сложнее, кода больше, потенциальных ошибок больше.

Похоже, что любая новая вещь для тебя невероятно сложная.

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


Именно. И здесь ничего про детали реализации.

·>Не очень ясно куда ты потерял from, to, amount. Откуда они берутся? И как ты теперь это всё протестируешь?


В твоём случае был абстрактный trackHim с единственным целочисленным параметром

·>Ещё ты забыл, что event посылается не всегда и получил NPE на пустом месте.


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

·>Как ты обеспечишь, что во всех местах вызова transfer происходит send? По требованиям регуляторов ты не имешь права делать transfer без соответствующих уведомлений в налоговку.


Вызываешь, где надо, конкретный use case.

·>Где у тебя в коде описано, что auditQueue.send собственно должно слать соответствующие уведомление trackHim в налоговку?


У тебя ведь тоже нигде ничего не указано.

·>Тест где? Без тестов код — не принимаю.




I>>если мало, то еще вот пример, если у нас эвент у инстанца

I>>
I>>   this.svc.thresholdExceeded.use(event => this.auditQueue.send(event));
I>>   const result = this.svc.transfer( ); // вот твоё связывание
I>>

·>А тут ещё и с многопоточностью/атомарностью потенциальные проблемы. Что use делает? Добавляет ещё одного подписчика? Или заменяет предыдущего?

Никаких проблем. У тебя у самого нет подробностей про многопоточность, атомарность, т.е. мой код не хуже

I>>
I>>policy(event, this.config, x => this.auditQueue.send(x))
I>>

·>И так везде, у каждого консьюмера? А клавиша копипаст выдержит?

У каждого юз кейса очевидно своя полиси — кода нотифицировать, кого натофицировать.

I>>Но что бы понять, как система на такое среагирует, юнит-теста мало.

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

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

·>На второй круг, я же объяснял где-то. Бага считается всё ещё не пофикшеной, думаем дальше.

Вот-вот. И выявить это надо до того, как напорется юзер, упадет прод/самолёт/итд.

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

·>Ну т.е. фикусуны таки не всемогущи, и комментировать случайный код они не могут без аппрувалов у ответственных работников. Об чём спор-то?

У нас получается контроль качества не юни-тестами и моками, а правильными административными мерами.

I>>Кроме того, требования описываются не в терминах реализации, а в терминах бизнес-специфики.

·>Если не рассматривать UI, то взаимодействие со внешними системами будет через public api. И очень вероятно в терминах, например, gRPC может звучать именно так.

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

·>Консумеры консюмят API, и это именно то, что описывается в бизнес-требованиях.

Именно что АПИ, а не внутренности реализации, как ты это интерпретируешь

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

·>Т.е. вместо трёх строчек в твоём коде будет 30 строчек и это лишь потому что "предпочитаю". В бизнес-требованиях не было намёков, что события опциональны или требуется динамический pub-sub... но ты это всё добавил лишь потому что предпочитаешь.

Покажи, какие именно 30 строчек. Связывающий код будет примерно 1 к 1.

I>>Покажи, что именно мне нужно покрывать "дорогим тестом на моках"

·>Вон у тебя выше было куча кода без тестов.

Интеграционный код тестируется интеграционными тестами, а не моками.

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

·>Application Programming Interface есть.

Внешний АПИ у меня и у тебя будут идентичными.

I>>Этот код и тебе нужен, ты его показал.

·>А ты так и не смог показать. И самое главное — покрыть тестом.

Т.е. надо показать, как тестировать y = sin(x) ? Я думал это тривиально.

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

·>У меня покрытие было 100%. У тебя 146% что-ли?

Смешно. В строчках кода считал?

I>>Более того, мелкие изменения, коих тьма, больше не требуют изменения самого компонента.

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

В моем случае основной компонент придется менять реже.

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

·>Зависит от.

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

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

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

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

·>Ты заявил "Сейчас все делается фремворками — Swing, Hibernate, и тд. API описывается в терминах какого либо фремворка.". Вот меня и заинтересовало описание API в рамках Swing или Hibernate. Можно пример?


Ты адекватен? Я тебе привел пример, а ты его скипнул дважды
В конкретном сервисе у меня будет задан АПИ, который будет соответствовать описанию в доках, сгенерится тулом или будет написан руками — непринципиально:
@Get('transfer/{from}/{to}')
@Scheme(Scheme.Controller.Transfer.In, Scheme.Controller.Transfer.Out)
@ReturnValue(Return.Body)
@event(Controller.Evetns.thresholdExceeded)
transfer(@Path() from: Id, @Path() to:Id, @Query() async: bool, @Header() options: RequestOptions, @Body() details:Transfer) {
}


·>Откуда у тебя взялся http контроллер, я не понял.


Ты же говоришь про АПИ, вот я тебе его и показл. Есть сервис — его АПИ должно быть описано хоть как угодно — в единицах фремворка, на сокетах, grpc, схемой в graphql или odata

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


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

·>Не понял какую разницу спрятал.

40+ подробностей.

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

·>Я эти требования уж раз 20 напоминал.

У тебя каким то чудом из бизнес-требований следует один единственный вариант класса

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

·>"Обратиться к HMRC API, послать уведомление trackHim(account)" — так и будет.

Не разу не было.

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

·>Что нечётко?

Всё нечетко. Ты выдал решение, а не бизнес-требования.

·>Это я и сказал, ты на это заявил, что страна дикая. Суть в том, что операция transfer налоговку не упоминает в API. Это внутренние детали реализации MoneyService.


Т.е. твой сервис это какой то публичный АПИ?

·>Т.е. причём тут азы c#? Я пытаюсь из тебя код выудить решения конкретной задачи, но всё безуспешно.

Ты лучше условие сформулируй.

I>>1. не нужен доп интерфейс

·>Зато нужен тип события. Нужен код привязки события к реальному external API для HMRC.

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

I>>2. не нужен мок

·>Нужен при тестировании кода привязки.

Тебе повторить про отличия твоего варианта от моего? Эвент описан в терминах моего компонента. А у тебя — привязка к 3rd party

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

·>В разных проектах по-разному.

То есть, те самые фремворка. Бу-га-га

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

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

То есть, голословно

·>HMRC trackHim — это и есть публичное АПИ которое мы зовём. И MoneyService transfer — тоже публичное API, которое мы предоставляем.


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

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

·>А евенты, ещё и например, mq-брокер тоже позволяет. Так причём тут твои встроенные в язык евенты?

Я же тебе показал пример кода.

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

·>Код в студию.

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

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

I>>Этот слой и есть интеграционный, и будет протестирован интеграционными тестами.
·>И тут тебе ВНЕЗАПНО потребуется мок налоговки. Как минимум для того, чтобы можно было тестить до выкатки в прод.

Але — это всего лишь одно из возможных решений, а не единственное.

·>Вот и я о том же. Вот у нас есть MoneySerivce, который использует mq, есть ещё 10 других сервисов. Проверять что каждый из этих сервисов умеет "никогда не теряются...если сеть недоступно...после возобновления" — это только тепловую смерть вселенной приближать. Тебе достаточно проверить, что сообщения гарантированно доставлюятся и что каждый из сервисов использует гарантированную доставку где надо.


Недостаточно.

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

·>Не понял. Вот я поправил строчку в IDE, хочу поглядеть как оно работает, надо бежать тесты на проде делать?!

Это смотря как у вас релизная стратегия работает. Бывает и каждый фикс по одному на прод выкатывают. В любом случае проде после деплоя тестируют, а не после фикса в ИДЕ.

I>>Мониторинг на самом деле проверяет только точечно.

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

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

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

·>Ты вообще о чём? О потоках или о сетевых запросах?

В данном случае ты предлагаешь экономить доли наносекунд при выполнении сетевого запроса hmrc.trackHim
Вот и сравни одно с другим

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

I>>Ну вот сделай замеры end-2-end, да убедись.
·>Убедиться в чём? Я тебе уже неоднократно намекал, что один-к-одному отношения между сетевыми запросами и событиями может и не быть.

Это ничего не меняет.

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

·>Причём тут обратный вызов? И чем он отличается от прямого? Мы вроде сравниваем события vs вызов метода. И события в шарпе, полагаю, в несколько раз медленее и никакого инлайна.

Конкретно в C# будет в несколько раз медленее, то есть, наносекунда. А запрос твой hmrc.trackHim сколько процессора съест?
Re[64]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 10.03.22 12:08
Оценка:
Здравствуйте, ·, Вы писали:

НС>>Есть, проверять прод.

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

Это не вопрос веры, это факт. Прямая проверка надежнее косвенной.

·>Это лишь говорит о том, что у вас плохо поставлен процесс деплоймента.


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

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


Ага, что может пойти не так.

·>Все эти "ровно в той конфигурации" — яйца выеденного не стоят


Безумству храбрых ..
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[59]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 10.03.22 12:08
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Каким же образом вы считаете сколько чего пролезло в прод, если прод вы не трогаете? Магия?


Да чего тут непонятного? Реальные пользователи выступают в роли бета-тестеров. Пока у пользователей или в мониторинге не бомбанет проблем нет.
На самом деле, думаю, у него либо очень слабенький SLA, либо вообще отсутствует. Поэтому он может расслабится и позволять всякие фокусы вроде если на проде вылезла бага — ждем пока юзеры напишут о проблеме и потом берем ее в штатном режиме в спринт. Проблема только в том, что он пытается эту расслабуху напялить на любые проекты.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[65]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.03.22 12:18
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

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

I>>Правильно — явно контролируем поток данных, явно контролируем эффекты.

НС>Ага, даже если ничего контролировать не надо. Обезьянья работа.


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

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

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

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


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

НС>А знаешь что самое смешное? Когда мы возьмем весь код, включая код тестов, то окажется что тот код, который эту самую Data подготавливает окажется практически 1 в 1 с тем кодом, что будет внутри мока. Т.е., при отказе от моков ты ничего не выиграл и проиграл в объеме обвязочного кода.


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

I>> Контроллеры на ровном месте раздувает in-place логика

НС>Где в моем примере in place логика? Что ты опять сражаешься с чучелками?

Ты пишешь, что у меня будет откуда то раздувание. А я тебе объясняю, что именно раздувает контролер — in-place логика.
Если in-place логику помещать в функции, то не будет никакого раздувания — в контроллере остаётся только сам пайплан, количество степов будет = количеству эффектов.

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


НС>У меня вся логика нетривиального общения останется внутри компонента, использующего зависимости. А где она будет у тебя?

НС>Давай опять пример, чтобы избежать трактовок
НС>
НС>async Task DoActionAsync()
НС>{
НС>  var data = await _dep.GetDataFromDependency();
НС>  var secondRequest = CreateRequest(data);
НС>  await _dep.PerformSecondAction(secondRequest);
НС>}
НС>

НС>Контроллер остается идентичным исходному примеру.

Какой смысл рассматривать эти синтетические примеры?

НС>Перепиши пример с учетом выноса зависимостей в контроллер.

MyAction(): Task {
     const data = this.dep.GetDataFromDependency();
     const secondRequest = this.someService.CreateRequest(data); // не знаю, что это такое. Выглядит, как неявная зависимость от чего то. 

     return this.dep.PerformSecondAction(secondRequest);
  }


I>>Смотри внимательно — в моем варианте дизайна у сервиса SomeService нет зависимости от IDependency, а раз так, то DI ему для этой цели не нужен.

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

Логгер, трейсер, конфиги — вот такое может протаскиваться через DI или же вовсе остаётся в контроллере. C соседними сервисами поступаем как я уже сказал — избавляемся от тяжелых зависимостей и превращаем по возможности в функции.

НС>>>Т.е. ты вместо IMyService предлагаешь сделать функцию. В DI публикуется именно IMyService, публиковать там контроллер — нафига?

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

НС>Для получения зависимостей не нужно себя публиковать, о чем ты?

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

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

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


Смотри свой пример — где там тот самый ужос в бойлерплейте?

I>>Жирный контроллер это далеко не всегда плохой вариант.


НС>Приплыли.


Именно. Его пишут не просто так — на старте нарезать компоненты, не видя полной картины, сильно преждевременно. Зато этот жирный контроллер довольно легко трансформировать во чтото удобоваримое.
Точно так же и твой вариант не всегда самый лучший, если нарезку делать не видя полной картины, получится ригидная структура.
Какой именно вариант будет оптимиальным — зависит от задачи, а не твоих синтетических примеров.
Re[66]: откуда такая любовь к мокам?
От: Ночной Смотрящий Россия  
Дата: 10.03.22 12:44
Оценка: +1
Здравствуйте, Ikemefula, Вы писали:

НС>>Ага, даже если ничего контролировать не надо. Обезьянья работа.

I>Это важная работа.

Или нет.

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


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

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

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

А для другого — обязательны. И?

НС>>А знаешь что самое смешное? Когда мы возьмем весь код, включая код тестов, то окажется что тот код, который эту самую Data подготавливает окажется практически 1 в 1 с тем кодом, что будет внутри мока. Т.е., при отказе от моков ты ничего не выиграл и проиграл в объеме обвязочного кода.

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

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

I>>> Контроллеры на ровном месте раздувает in-place логика

НС>>Где в моем примере in place логика? Что ты опять сражаешься с чучелками?
I>Ты пишешь, что у меня будет откуда то раздувание.

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

I> А я тебе объясняю, что именно раздувает контролер — in-place логика.


А зачем ты это обясняешь, если я ни разу не намекнул на то что собираюсь в контроллере делать in place логику, а с точностью до наоборот, я оттуда убираю логику общения с зависимостями. Что это как не чучелко?

I>Если in-place логику помещать в функции,


Угу, у рыбы нет шерсти, а вот если бы была ...

НС>>Давай опять пример, чтобы избежать трактовок

НС>>
НС>>async Task DoActionAsync()
НС>>{
НС>>  var data = await _dep.GetDataFromDependency();
НС>>  var secondRequest = CreateRequest(data);
НС>>  await _dep.PerformSecondAction(secondRequest);
НС>>}
НС>>

НС>>Контроллер остается идентичным исходному примеру.

I>Какой смысл рассматривать эти синтетические примеры?


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

НС>>Перепиши пример с учетом выноса зависимостей в контроллер.

I>
I>MyAction(): Task {
I>     const data = this.dep.GetDataFromDependency();
I>     const secondRequest = this.someService.CreateRequest(data); // не знаю, что это такое. Выглядит, как неявная зависимость от чего то. 

I>     return this.dep.PerformSecondAction(secondRequest);
I>  }
I>


Т.е. сервис знает про конкретный реквест к конкретной зависимости, но при этом зависимость из него мы выдрали. А заодно натащили в контроллер еще логики (что ты там говорил про нераздувание оного?). Ну чего, все фееричнее и фееричнее.

I>>>Смотри внимательно — в моем варианте дизайна у сервиса SomeService нет зависимости от IDependency, а раз так, то DI ему для этой цели не нужен.

НС>>Логгер, трейсер, метрики, конфиги, соседние сервисы — будешь тоже через параметры передавать явно?
I>Логгер, трейсер, конфиги — вот такое может протаскиваться через DI

Ну то есть идея с функциями вместо сервисов уже не выглядит так удачно?

I> или же вовсе остаётся в контроллере. C соседними сервисами поступаем как я уже сказал — избавляемся от тяжелых зависимостей и превращаем по возможности в функции.


Как можно превратить в функцию сервис со стейтом?

I>Я про твой DI ничего не знаю.


Так спроси. Иначе тебя крайне тяжело понимать.

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


А зачем искать контроллер?

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

I>Смотри свой пример — где там тот самый ужос в бойлерплейте?

 MyController( private someService: ISomeService, private dep:IDependency) { };


Совершенно бесполезная с точки зрения семантики строка.

I>>>Жирный контроллер это далеко не всегда плохой вариант.

НС>>Приплыли.
I>Именно. Его пишут не просто так

Да пофигу. Просто ты сперва рассказывал про зло в больших контроллерах, а в конце внезапно оказалось что это не всегда плохой вариант.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[67]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.03.22 13:32
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

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


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

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

НС>А для другого — обязательны. И?

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

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

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

Может. Только сами моки необязательные.

I>>Ты пишешь, что у меня будет откуда то раздувание.


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


Приведи пример.

I>> А я тебе объясняю, что именно раздувает контролер — in-place логика.


НС>А зачем ты это обясняешь, если я ни разу не намекнул на то что собираюсь в контроллере делать in place логику, а с точностью до наоборот, я оттуда убираю логику общения с зависимостями. Что это как не чучелко?


Ты сам пишешь про распухание. Больше всего контроллер пухнет именно от in-place логики. Нет in-place логики — не нужно бояться за распухание.

I>>Какой смысл рассматривать эти синтетические примеры?

НС>Чтобы ты не прятался за абстрактными рассуждениями. В несинтетических будет все еще смешнее, но это объемно.

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

НС>>>Перепиши пример с учетом выноса зависимостей в контроллер.

I>>
I>>MyAction(): Task {
I>>     const data = this.dep.GetDataFromDependency();
I>>     const secondRequest = this.someService.CreateRequest(data); // не знаю, что это такое. Выглядит, как неявная зависимость от чего то. 

I>>     return this.dep.PerformSecondAction(secondRequest);
I>>  }
I>>


НС>Т.е. сервис знает про конкретный реквест к конкретной зависимости, но при этом зависимость из него мы выдрали. А заодно натащили в контроллер еще логики (что ты там говорил про нераздувание оного?). Ну чего, все фееричнее и фееричнее.


Где ты видишь "натащили логики"? Три строки у тебя, три строки у меня.

I>>>>Смотри внимательно — в моем варианте дизайна у сервиса SomeService нет зависимости от IDependency, а раз так, то DI ему для этой цели не нужен.

НС>>>Логгер, трейсер, метрики, конфиги, соседние сервисы — будешь тоже через параметры передавать явно?
I>>Логгер, трейсер, конфиги — вот такое может протаскиваться через DI

НС>Ну то есть идея с функциями вместо сервисов уже не выглядит так удачно?


Наоборот. Сервис будет стейтлесс, т.е. мало чем от функции отличаться будет.

НС>Как можно превратить в функцию сервис со стейтом?


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

I>>Я про твой DI ничего не знаю.


НС>Так спроси. Иначе тебя крайне тяжело понимать.


С тобой как правило смысла нет вопросы задавать — сужу по предыдущим беседам.

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


НС>А зачем искать контроллер?


Ктото же должен связать входящие реквест и обработчики для них. В зависимости от фремворка это делается самыми разными способами. Например — сходу задаём роутинг, стартуя от рутового app. Или инстанцируем сам контроллер и возвращаем в каком метода. Иногда это декоратор @Controller. Иногда — строчка в конфиге.

I>>Смотри свой пример — где там тот самый ужос в бойлерплейте?

НС>
НС> MyController( private someService: ISomeService, private dep:IDependency) { };
НС>

НС>Совершенно бесполезная с точки зрения семантики строка.

У тебя ровно такая же, только зависимость 1шт, а здесь — две.

I>>Именно. Его пишут не просто так


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


Ну и логика. Это самый частый кейс, но из этого не следует, что это всегда плохо. В жирном контроллере границы размыты. В твоем варианте, как ты показал, границы установлены жестко. В зависимости от цели нам нужно искать баланс между двумя крайностями, т.к. у обоих вариантов есть недостатки
1 жирный со временем все труднее тестировать и мейнтейнить, т.к. структура неясная, размытая. Рефакторинг затруднен, т.к. все завязано на всё.
2 твой вариант со временем все труднее читать, изменять и рефакторить, т.к. "самое главное где то там". Вместо рефакторинга будет редизайн с забегом на месяцы. Структура ригидная.
Вариант со стейтлесс компонентами это баланс между 1 и 2, при чем ты сам выбираешь, куда ближе, к 1, или к 2.
Отредактировано 11.03.2022 7:35 Pauel . Предыдущая версия .
Re[59]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 14.03.22 18:03
Оценка: :)
Здравствуйте, Ikemefula, Вы писали:

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

I>·>Я не это заявлял. Я заявлял, что если некий тест не обнаружит баг в пре-проде, то он не обнаружит баг и в проде.
I>Ну и логика На самом деле это не так по ряду причин — например, ты не в курсе, чтоу тебя фрагментарные сведения по багу, или есть разнциа с продом и тд и тд.
Как ты по таким фрагментарным знаниям напишешь тест, который _гарантированно_ (как ты от меня требуешь) будет зелёным в пре-проде, но красным в проде?

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

I>·>Эмпирически. Считаем сколько пролезло в прод и их серьёзность.
I>Каким же образом вы считаете сколько чего пролезло в прод, если прод вы не трогаете? Магия?
По feedback, очевидно. А вы как считаете?

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

I>·>Можно получать максимально возможные гарантии и в пре-проде.
I>А если этого недостаточно?
Недостаточно максимально возможного? Ну это где-то из мира 146%.

I>>>Обычный.

I>·>С чего ты взял, что бета-тестеры — это обычные пользователи? В чём тогда отличие от таких обычных пользователей как я?
I>А я и не говорю про бета-тестеров. Сидит себе Вася и пользуется софтом. Ему админы подкидывают релиз-кандидат, Вася продолжает работать как работал.
Прям релиз-кандидат?! Бедный Вася. Это может только для пользователей какого-нибудь копроративного софта сгодится, т.к выбора нет. А так юзеры разбегутся. Мне никто rc-версию chrome подсунуть не может.

I>>>- зависимости прода есть только на проде и у них цикл жизни свой собственные

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

I>>>- конфиг

I>·>Контролируется на раз.
I>Особенно, когда ты доступа не имеешь Ты точно уверен, что валидатор сможет проверить любые комбинации любых ключей?
Ох... Ну давай попробую зайти с другой стороны. Вот ты имеешь доступ к тому что видит реальный юзер в твоём приложении? Ну там формочка, странички, контролы. Нажимать юзер может чего угодно как угодно, в в любом порядке. И твоя роль, как разработчика, — чтоб всё работало.
А теперь подумай, чем комбинации ключей хуже? Если подумать, то прод-конфигурация типичного приложения на порядки проще самого приложения. Раз уж вы способны (?) обеспечить работоспособность самого приложения для юзера, который обычно не особо в теме, да ещё и бывает, что враждебно настроенный, то почему вызывает проблемы обеспечить достаточное качество для пачки примитивных ключей, которыми управляют специально нанятые профессионалы в prod-support команде?
Единственное объяснение — контролю качества самого приложения вы уделяете больше внимания, чем какому-то "никому неинтересному" конфигурированию, т.е. тупо забиваете, набивая технический долг. Ну и итог немного предсказуем — проблемы с выкатыванием релизов и эксплуатацией.

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

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

I>>>Требования, кейсы, сценарии, ожидания вызывающей стороны, граничные случаи, т.н. fitness function, и тд и тд.

I>·>Ты опять куда-то не туда понёсся. Мы обсуждаем конкретное "run test -P e2e". Это ручные тесты или граничные случаи?!
I>Если именно e2e, то это кейсы, сценарии, пишутся по требованиям. Все это проверка именно интеграции — проверять логику при помощи e2e в своём уме мало кто станет.
Теперь вернёмся к контексту:

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

В чём было возражение, неясно. Таки "run test -P e2e" — это всего лишь код.

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

I>·>Нет, кривые аналогии — не к месту. Просто на вопрос ответь. Как вы проверяете в проде почту?
I>Никак, у нас её нет.
Да не важно... Если бы была, то как бы проверяли?

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

I>·>Это просто текстовый сценарий, синтаксис короче, более человекочитаемый для непрограммистов, который потом байндится на соответствующие методы в коде. Вот код меня и интересует.
I>Есть просто либа, которая умеет стандартные действия. Действие это или клив в UI + ожидаемый результат, или вызов некоторого API + результат. Ничего особенного.
Вот это я и пытаюсь выяснить собственно. Получается, что я написал некий код, а ты его раскритиковал, лишь за то, что у меня был слишком простой код, без cucumber, без фреймворков, без либ и прочих mailtraps. А что твоё решение — это по сути тоже самое, ты просто не видишь за деревьями леса.

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

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

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

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

I>·>Не очень ясно куда ты потерял from, to, amount. Откуда они берутся? И как ты теперь это всё протестируешь?

I>В твоём случае был абстрактный trackHim с единственным целочисленным параметром
Откуда куда и сколько у тебя this.svc.transfer(); переводит?

I>·>Ещё ты забыл, что event посылается не всегда и получил NPE на пустом месте.

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

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

I>Вызываешь, где надо, конкретный use case.
Протестировать-то как, что вызывается именно только конкретный юзкейс?

I>·>Где у тебя в коде описано, что auditQueue.send собственно должно слать соответствующие уведомление trackHim в налоговку?

I>У тебя ведь тоже нигде ничего не указано.
У меня стоит вызов прямой trackHim. Который собственно и делает что надо. У тебя где-то тоже дожен быть такой вызов. Но код ты стесняешься показать.

I>·>Тест где? Без тестов код — не принимаю.

I>
Если бы ты писал код с тестами, то не было бы этих неработающих идей.

I>>>если мало, то еще вот пример, если у нас эвент у инстанца

I>>>
I>>>   this.svc.thresholdExceeded.use(event => this.auditQueue.send(event));
I>>>   const result = this.svc.transfer( ); // вот твоё связывание
I>>>

I>·>А тут ещё и с многопоточностью/атомарностью потенциальные проблемы. Что use делает? Добавляет ещё одного подписчика? Или заменяет предыдущего?
I>Никаких проблем. У тебя у самого нет подробностей про многопоточность, атомарность, т.е. мой код не хуже
Проблемы ты сам создал тем, что у твоего объекта есть дополнительные состояния. А значит появились вопросы про атомарность и т.п. и как теперь это всё тестировать...

I>>>
I>>>policy(event, this.config, x => this.auditQueue.send(x))
I>>>

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

I>>>Но что бы понять, как система на такое среагирует, юнит-теста мало.

I>·>В смысле что сделает обработчик соответстующего результата? Тоже можно протестировать.
I>>>Обычным. На препроде багов не было выявлено, а на проде — снова воспроизвелись. Что делать предложишь?
I>·>На второй круг, я же объяснял где-то. Бага считается всё ещё не пофикшеной, думаем дальше.
I>Вот-вот. И выявить это надо до того, как напорется юзер, упадет прод/самолёт/итд.
Не понял какой конкретно случай ты имеешь в виду. Мы рассматриваем ситуацию, когда ошибка уже есть в баклоге и самолёт уже таки упал.

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

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

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

I>·>Консумеры консюмят API, и это именно то, что описывается в бизнес-требованиях.
I>Именно что АПИ, а не внутренности реализации, как ты это интерпретируешь
Я это так не интерпретирую, ты сочиняешь.

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

I>·>Т.е. вместо трёх строчек в твоём коде будет 30 строчек и это лишь потому что "предпочитаю". В бизнес-требованиях не было намёков, что события опциональны или требуется динамический pub-sub... но ты это всё добавил лишь потому что предпочитаешь.
I>Покажи, какие именно 30 строчек. Связывающий код будет примерно 1 к 1.
Нарисуй полный код с тестами и убедись.

I>>>Покажи, что именно мне нужно покрывать "дорогим тестом на моках"

I>·>Вон у тебя выше было куча кода без тестов.
I>Интеграционный код тестируется интеграционными тестами, а не моками.
Ну да, куча кода.

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

I>·>Application Programming Interface есть.
I>Внешний АПИ у меня и у тебя будут идентичными.
Я до сих пор не видел.

I>>>Этот код и тебе нужен, ты его показал.

I>·>А ты так и не смог показать. И самое главное — покрыть тестом.
I>Т.е. надо показать, как тестировать y = sin(x) ? Я думал это тривиально.
sin мы не обсуждаем. Мы обсуждаем вполне конкретную задачу. Я, видимо, забыл написать условие задачи. Извиняюсь, условие вот: "должно уведомлять налоговую о всех транзакциях суммой больше ...".

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

I>·>У меня покрытие было 100%. У тебя 146% что-ли?
I>Смешно. В строчках кода считал?
Тогда я не знаю, что значит "покрытие" в твоей терминологии и как рассчитать его плотность.

I>>>Более того, мелкие изменения, коих тьма, больше не требуют изменения самого компонента.

I>·>Величина изменений и необходимость изменения компонента — вещи ортогональные. Какие-то мелкие изменения — таки потребуют.
I>В моем случае основной компонент придется менять реже.
С чего ты взял?

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

I>·>Зависит от.
I>Похоже, ты сам сидишь на фремворках, только стесняешься сказать об этом прямо.
Я участвовал в разных проектах и где-то был spring, где-то hibernate, где-то даже свои библиотеки для коллекций и сети.

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

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

I>·>Ты заявил "Сейчас все делается фремворками — Swing, Hibernate, и тд. API описывается в терминах какого либо фремворка.". Вот меня и заинтересовало описание API в рамках Swing или Hibernate. Можно пример?

I>Ты адекватен? Я тебе привел пример, а ты его скипнул дважды
Я задаю конкретный вопрос по твоему высказыванию, что "Сейчас все делается фремворками — Swing, Hibernate, и тд. API описывается в терминах какого либо фремворка.". Я не понимаю как можно описывать API в терминах Swing, вот и спрашиваю. Ты отвечаешь на вопрос, который я не задавал.

I>·>Откуда у тебя взялся http контроллер, я не понял.

I>Ты же говоришь про АПИ, вот я тебе его и показл. Есть сервис — его АПИ должно быть описано хоть как угодно — в единицах фремворка, на сокетах, grpc, схемой в graphql или odata
Либо тупо в виде типов — классов-интерфейсов. Какая разница-то? Почему сервис обязан быть сетевым и со слоями фреймворков, неясно.

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

I>·>Я эти требования уж раз 20 напоминал.
I>У тебя каким то чудом из бизнес-требований следует один единственный вариант класса
Это просто минимальный код для данных требований. Мой пример был изначально для демонстрации как тестировать сайд-эффект. Зачем в рамках примера использовать фреймворки и прочее — мне неясно.

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

I>·>"Обратиться к HMRC API, послать уведомление trackHim(account)" — так и будет.
I>Не разу не было.
А что было? Вон дают какой-нибудь FIX Rules of Engagement — там описано какие сообщения, какие поля, в какой последовательности етс. должны быть посланы в каких сценариях.

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

I>·>Что нечётко?
I>Всё нечетко. Ты выдал решение, а не бизнес-требования.
У меня было и то, и то.

I>·>Это я и сказал, ты на это заявил, что страна дикая. Суть в том, что операция transfer налоговку не упоминает в API. Это внутренние детали реализации MoneyService.

I>Т.е. твой сервис это какой то публичный АПИ?
Неясно, почему это должно быть каким-то решающим фактором? Если MoneyService не вызывается извне, то его публичные методы нужно усложнять? Зачем?

I>·>Т.е. причём тут азы c#? Я пытаюсь из тебя код выудить решения конкретной задачи, но всё безуспешно.

I>Ты лучше условие сформулируй.
"при вызове перевода денег надо настучать в налоговку если сумма больше $1k".
"Настучать в налоговку" == вызвать метод void trackHim(int account), что делает этот метод — не твоя ответственность, этим занимаются другие люди, они тебе дают тип Hmrc в виде либы.

I>>>1. не нужен доп интерфейс

I>·>Зато нужен тип события. Нужен код привязки события к реальному external API для HMRC.
I>Это все уже было показано. Если ты не понимаешь, что такое эвент, то очевидно и примеры не понял.
Ты утверждаешь, что евент каким-то образом спасает от определения интерфейса. Нет, не спасает. Просто вместо определение ифейса у тебя появляется определение евента.

I>>>2. не нужен мок

I>·>Нужен при тестировании кода привязки.
I>Тебе повторить про отличия твоего варианта от моего? Эвент описан в терминах моего компонента. А у тебя — привязка к 3rd party
У тебя тоже будет привязка к 3rd party. Где-то точно будет. _Если_ мне надо будет отвязаться от 3rd party, я могу это легко сделать добавив интерфейс. Ты же добавил евент просто так, без всякой необходимости, по привычке что-ли.

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

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

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

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

I>·>HMRC trackHim — это и есть публичное АПИ которое мы зовём. И MoneyService transfer — тоже публичное API, которое мы предоставляем.

I>Вот, подробности всплывают задним числом Я вообще думал что MoneyService это просто класс, который мы у себя внутри вызываем где нужно.
Ну допустим... Объясни почему это должно что-то менять.

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

I>·>А евенты, ещё и например, mq-брокер тоже позволяет. Так причём тут твои встроенные в язык евенты?
I>Я же тебе показал пример кода.
Я знаю что ты показал, я не понимаю — зачем.

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

I>·>Код в студию.
I>Уже показал, смотри внимательно.
Код тестов не я видел. Приведи весь код целиком, с тестами.

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

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

I>·>Вот и я о том же. Вот у нас есть MoneySerivce, который использует mq, есть ещё 10 других сервисов. Проверять что каждый из этих сервисов умеет "никогда не теряются...если сеть недоступно...после возобновления" — это только тепловую смерть вселенной приближать. Тебе достаточно проверить, что сообщения гарантированно доставлюятся и что каждый из сервисов использует гарантированную доставку где надо.

I>Недостаточно.
Почему?

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

I>·>Не понял. Вот я поправил строчку в IDE, хочу поглядеть как оно работает, надо бежать тесты на проде делать?!
I>Это смотря как у вас релизная стратегия работает. Бывает и каждый фикс по одному на прод выкатывают. В любом случае проде после деплоя тестируют, а не после фикса в ИДЕ.
Мы в проде не тестируем. Мы тестируем в пре-проде и потом выкатываем в прод.

I>>>Мониторинг на самом деле проверяет только точечно.

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

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

I>·>Ты вообще о чём? О потоках или о сетевых запросах?
I>В данном случае ты предлагаешь экономить доли наносекунд при выполнении сетевого запроса hmrc.trackHim
I>Вот и сравни одно с другим
Ты почему-то решил, что trackHim непременно должен делать сетевой запрос. Может там буфер какой и пакеты UDP шлются изредка.

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

I>>>Ну вот сделай замеры end-2-end, да убедись.
I>·>Убедиться в чём? Я тебе уже неоднократно намекал, что один-к-одному отношения между сетевыми запросами и событиями может и не быть.
I>Это ничего не меняет.
Как это не меняет? Тысяча наносекундных евентов — уже ощутимая микросекунда и плюс мусор, для gc работа.

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

I>·>Причём тут обратный вызов? И чем он отличается от прямого? Мы вроде сравниваем события vs вызов метода. И события в шарпе, полагаю, в несколько раз медленее и никакого инлайна.
I>Конкретно в C# будет в несколько раз медленее, то есть, наносекунда. А запрос твой hmrc.trackHim сколько процессора съест?
Зависит от. Например, оно может что-нибудь в буфер класть какой-нибудь, доли наносекунды.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[60]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 15.03.22 09:27
Оценка:
Здравствуйте, ·, Вы писали:

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

·>Как ты по таким фрагментарным знаниям напишешь тест, который _гарантированно_ (как ты от меня требуешь) будет зелёным в пре-проде, но красным в проде?

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

I>>Каким же образом вы считаете сколько чего пролезло в прод, если прод вы не трогаете? Магия?

·>По feedback, очевидно. А вы как считаете?

Это называется "тестировать пользователем". Недостаток такой методики в том, что ты не знаешь состояние дел, пока не пройдет достаточное время.

Мы считаем выявленые проблемы при тестах проде
1 регрессионные тесты
2 эксплорейтори
И бОльшая часть проблем выявляется именно тестами.

I>>А если этого недостаточно?

·>Недостаточно максимально возможного? Ну это где-то из мира 146%.

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

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

·>Прям релиз-кандидат?! Бедный Вася. Это может только для пользователей какого-нибудь копроративного софта сгодится, т.к выбора нет. А так юзеры разбегутся. Мне никто rc-версию chrome подсунуть не может.

Естественно, контора подписывает соглашение, что будет учавствовать в таких активностях.
Ты похоже не в курсе, чем релиз-кандидат отличается от беты.
Сейчас, вообще говоря, используется немного другая стратегия — юзеров кормят короткими апдейтами, будь то браузер, ос, или офис, или вообще любой софт.
Бенефит в том, что это намного дешевле. Недостаток — отсутствие внятного тестирования, т.к. софт превращается в вечную бету.
Т.е. никто тебе не будет делать адский забег в тестах ради одного фикса. Предположение — "у нас только один фикс, там ничо не поломается". Запускаешь — поломалось то и это.
Т.е. в данном случае остаются регрешн тесты, и почти полностью исключаются эксплорейтори. А раз так — то ты точно не знаешь, а какое же состояние дел на проде.

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

·>Обычно эти баги не страшны и исправляются prod-support командой.

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

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

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

Нету такой задачи у разработчика как "чтоб всё работало" Есть конкретный перечень задач в баклоге. Все что туда не попало или зависло работает а хрен его знает как. По моему это очевидно.

·>А теперь подумай, чем комбинации ключей хуже?


Конфиг определяет работу всего приложения, насквозь.

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


Ну и дичь — у тебя технический долг почему то пропорционален времени на контроль качеству Больше тестируешь — больше проблем

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

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

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

·>Ты уверен, что это образцово-показательное устройство процесса? Или всё-таки это образец как делать не надо?

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

·>В чём было возражение, неясно. Таки "run test -P e2e" — это всего лишь код.


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

I>>Никак, у нас её нет.

·>Да не важно... Если бы была, то как бы проверяли?

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

I>>Есть просто либа, которая умеет стандартные действия. Действие это или клив в UI + ожидаемый результат, или вызов некоторого API + результат. Ничего особенного.

·>Вот это я и пытаюсь выяснить собственно. Получается, что я написал некий код, а ты его раскритиковал, лишь за то, что у меня был слишком простой код, без cucumber, без фреймворков, без либ и прочих mailtraps. А что твоё решение — это по сути тоже самое, ты просто не видишь за деревьями леса.

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

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

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

А на самом деле разница исключительно в языковых фичах и стоимости разработки.

I>>В твоём случае был абстрактный trackHim с единственным целочисленным параметром

·> Откуда куда и сколько у тебя this.svc.transfer(); переводит?

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

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

·>Непонятно зачем показывать идеи, которые тупо не работают для данных условий. Условие было дано изначально: "должно уведомлять налоговую о всех транзакциях суммой больше ...". Опять игноришь?

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

I>>Вызываешь, где надо, конкретный use case.

·>Протестировать-то как, что вызывается именно только конкретный юзкейс?

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

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

I>>У тебя ведь тоже нигде ничего не указано.

·>У меня стоит вызов прямой trackHim. Который собственно и делает что надо. У тебя где-то тоже дожен быть такой вызов. Но код ты стесняешься показать.

Похоже, до тебя эвенты не доходят
Показал еще 23го февраля http://rsdn.org/forum/flame.comp/8204375.1
Автор: Ikemefula
Дата: 23.02.22

public MoneyService 
{
  private Hmrc hmrc;
  public TranferReceipt transfer(int accountFrom, int accountTo, long amount)
  {
...
    if(amount > 1000) this.raiseEvent('trackHim', hmrc, accountTo); 
...
    return [ new TranfserReceipt("Thank you, come again!");
  }
}

new MoneyService { events { trackHim: (hmrc, accountTo) => hmrc.trackHim(accountTo); } } // вот и вся разница


А потом еще раз, 5го марта, там где useCase.

А потом еще раз.

И похоже, что дело именно в твоем понимании того, что же такое эвент.

·>Если бы ты писал код с тестами, то не было бы этих неработающих идей.


Похоже, кому то стоит разобраться с тем, что такое эвенты.

I>>·>А тут ещё и с многопоточностью/атомарностью потенциальные проблемы. Что use делает? Добавляет ещё одного подписчика? Или заменяет предыдущего?

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

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

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

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

Элементарно — логику в контроллер помещать не надо. Для этого у нас useCase, который обеспечивает интеграцию под конкретный случай.

I>>Вот-вот. И выявить это надо до того, как напорется юзер, упадет прод/самолёт/итд.

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

Разумеется. Упал один — есть шанс, что упадёт и другой, по той же причине, т.к. ты решил что "разница с продом не имеет значения"

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

·>Одно другому не мешает. Однако, если у вас администратинвые меры — замена тестам, то ничего в этом хорошего нет.

У вас, как выяснилось, ровно так же, например — куча людей которые по цепочке проверяют изменения, целая команда prod-support которая чтото там фиксает и тд.

I>>·>Консумеры консюмят API, и это именно то, что описывается в бизнес-требованиях.

I>>Именно что АПИ, а не внутренности реализации, как ты это интерпретируешь
·>Я это так не интерпретирую, ты сочиняешь.

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

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

I>>Покажи, какие именно 30 строчек. Связывающий код будет примерно 1 к 1.

·>Нарисуй полный код с тестами и убедись.

см тот пример, про эвенты и spy, который ты путаешь с моками.

I>>·>Вон у тебя выше было куча кода без тестов.

I>>Интеграционный код тестируется интеграционными тестами, а не моками.
·>Ну да, куча кода.

Именно — раз фигурирует налоговая, то нужны именно интеграционные тесты, а не моки.

I>>Внешний АПИ у меня и у тебя будут идентичными.

·>Я до сих пор не видел.

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

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


Именно. См, например, ссылку выше на сообщение от 23го февраля

I>>Смешно. В строчках кода считал?

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

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

I>>В моем случае основной компонент придется менять реже.

·>С чего ты взял?

Например, если тебе надо добавить policy, внезапно, нужно исправить тот самый if в твоем коде, где захардкожена проверка на тот самый уровен
if(amount > 1000) hmrc.trackHim(accountTo);

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

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

Все что нам надо проверить от компонента — что у него есть реакция на событие.

I>>Похоже, ты сам сидишь на фремворках, только стесняешься сказать об этом прямо.

·>Я участвовал в разных проектах и где-то был spring, где-то hibernate, где-то даже свои библиотеки для коллекций и сети.

Вот-вот.

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

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

Меньще — выбрасываем моки и доп-интерфейсы благодаря языковым или библиотечным фичам

> требуют дополнительные фреймворки и усложняют тестирование.


Жиденько. Именно у тебя дополнительный фремворк — мокито.

I>>Ты адекватен? Я тебе привел пример, а ты его скипнул дважды

·>Я задаю конкретный вопрос по твоему высказыванию, что "Сейчас все делается фремворками — Swing, Hibernate, и тд. API описывается в терминах какого либо фремворка.". Я не понимаю как можно описывать API в терминах Swing, вот и спрашиваю. Ты отвечаешь на вопрос, который я не задавал.

Ты перевираешь. Ну описал ты API ну пусть OpenAPI. Дальше то что? Всё эти вещи ты должен повторить в коде своего приложения
— вручную
— генератором
Используешь фремворк А — ищи генератор OpenAPI->A, или делай вручную.

I>>Ты же говоришь про АПИ, вот я тебе его и показл. Есть сервис — его АПИ должно быть описано хоть как угодно — в единицах фремворка, на сокетах, grpc, схемой в graphql или odata

·>Либо тупо в виде типов — классов-интерфейсов. Какая разница-то? Почему сервис обязан быть сетевым и со слоями фреймворков, неясно.

Вот и я говорю — ты задание сформулировать не можешь. Очевидно, что архитектура сервиса будет отличаться в зависимости от того, как мы его используем.
Если мы его будем вызывать исключительно через http, то бОльшая часть кода уйдет в контроллер и сам класс сервиса может и не понадобится.
А если мы его можем вызывать и через http, и grpc, и grapql, и локально, да еще передавать куда попало — всё это накладывает требования и ограничения.


I>>У тебя каким то чудом из бизнес-требований следует один единственный вариант класса

·>Это просто минимальный код для данных требований.

Из твоего минимального кода можно выбросить любое упоминание hmrc и trackHim. То есть, твой "минимальный" на самом деле ни разу не минимальный.

> Мой пример был изначально для демонстрации как тестировать сайд-эффект. Зачем в рамках примера использовать фреймворки и прочее — мне неясно.


Ну ты же используешь мокито, и почему то удивляешься про фремворки Тебе можно, а мне нельзя?

I>>Не разу не было.

·>А что было? Вон дают какой-нибудь FIX Rules of Engagement — там описано какие сообщения, какие поля, в какой последовательности етс. должны быть посланы в каких сценариях.

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

I>>Т.е. твой сервис это какой то публичный АПИ?

·>Неясно, почему это должно быть каким-то решающим фактором? Если MoneyService не вызывается извне, то его публичные методы нужно усложнять? Зачем?

А потому, что мы дизайн делаем ради конкретной цели, а не один раз на все времена. Вот ты захардкодил условие (x > 1000) а лично мое мнение, что так ты хардкодишь важную вещь — теперь надо тестами покрыть именно этот порог 1000, само условие.
А тут прийдет фиксун, добавит && x < 2000 и вся твоя красивая история закончится.

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

·>"при вызове перевода денег надо настучать в налоговку если сумма больше $1k".

·>"Настучать в налоговку" == вызвать метод void trackHim(int account), что делает этот метод — не твоя ответственность, этим занимаются другие люди, они тебе дают тип Hmrc в виде либы.

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

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

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

Именно. В этом и бенефит — всё объявляется по месту и видно снаружи. А у тебя замаскировано в конструкторе.

Откуда мне знать, кто и как захочет использовать сервис? С эвентом все очень гибко
— хочешь, что бы уведомление уходило как деталь реализации — пожалуйста
— хочешь, что бы это было явной частью контракта — пожалуйста

·>У тебя тоже будет привязка к 3rd party. Где-то точно будет.


Будет. В интеграционном коде, где будем собирать конкретный use case

>_Если_ мне надо будет отвязаться от 3rd party, я могу это легко сделать добавив интерфейс. Ты же добавил евент просто так, без всякой необходимости, по привычке что-ли.


Потому, что это минимальный вариант — отсутствует любая привязка к 3rd party.

I>>То есть, те самые фремворка. Бу-га-га

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

Ты же используешь мокито, spring, hibernate... Как ты себя раскрыл то

I>>·>HMRC trackHim — это и есть публичное АПИ которое мы зовём. И MoneyService transfer — тоже публичное API, которое мы предоставляем.

I>>Вот, подробности всплывают задним числом Я вообще думал что MoneyService это просто класс, который мы у себя внутри вызываем где нужно.
·>Ну допустим... Объясни почему это должно что-то менять.

Мы делаем дизайн компонентов:
1 ради конкреной цели, а не в ваккууме
2 используя конкретные инструменты


I>>Уже показал, смотри внимательно.

·>Код тестов не я видел. Приведи весь код целиком, с тестами.

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

I>>·>И тут тебе ВНЕЗАПНО потребуется мок налоговки. Как минимум для того, чтобы можно было тестить до выкатки в прод.

I>>Але — это всего лишь одно из возможных решений, а не единственное.
·>А какие ещё варианты?

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

I>>·>Вот и я о том же. Вот у нас есть MoneySerivce, который использует mq, есть ещё 10 других сервисов. Проверять что каждый из этих сервисов умеет "никогда не теряются...если сеть недоступно...после возобновления" — это только тепловую смерть вселенной приближать. Тебе достаточно проверить, что сообщения гарантированно доставлюятся и что каждый из сервисов использует гарантированную доставку где надо.

I>>Недостаточно.
·>Почему?

У тебя тест на способность к интеграции, а не на саму интеграцию. Ничего другого твои моки тестировать не могут.
Гарантированая доставка это провека состояния очереди, т.е. чтение условно на другом конце, или же симуляция сетевых проблем и отслеживание реакции всей системы.
Например — выключили сеть, обнаружили накопление сообщений в очереди, включили сеть, через 10с все сообщения ушли.
Здесь нужно вкинуть минимум три компонента — трансфер, очередь, и процессинг для этой очереди.

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

·>Это — наивная вера. Нет, не гарантируется, ясен пень. Выполнением тестового набора сценариев можно лишь гарантировать, что тестовый набор сценариев был выполним в момент их выполнения.

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

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


Ну так посчитай издержки суммарно на весь пайплайн, получишь разницу примерно в 3-4 порядка. Буфер, скажем, должен быть закрыт или lock-free, или блокирующей очередью. Упс — уже потери много бОльшие, нежели доли наносекунд.

I>>Это ничего не меняет.

·>Как это не меняет? Тысяча наносекундных евентов — уже ощутимая микросекунда и плюс мусор, для gc работа

Во первых — gc отдыхает, здесь всё ровно. Это у вас в джаве всё пихается в хип. Можно и иначе.
Во вторых — тысяча записей в буфер и в конце один udp пакет — даст намного бОльше той самой микросекунды, и много бОльше работы для gc.

I>>Конкретно в C# будет в несколько раз медленее, то есть, наносекунда. А запрос твой hmrc.trackHim сколько процессора съест?

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

Не будет там долей наносекунд хотя бы из за write barrier, т.к. этот буфер долгоживущий а ссылаться будет на свежесозданный объект
А если еще и многопоточность решишь оформить, то издержки на lock-free или блокирующую очередь перекроют с огромным перевесом
Отредактировано 15.03.2022 10:52 Pauel . Предыдущая версия .
Re[61]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 15.03.22 17:52
Оценка:
Здравствуйте, Ikemefula, Вы писали:

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

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

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

Это вера. Ответь на вопрос: Каким образом ты добьёшься, что тест будет красным в проде, но зелёным в препроде?

I>>>Каким же образом вы считаете сколько чего пролезло в прод, если прод вы не трогаете? Магия?

I>·>По feedback, очевидно. А вы как считаете?
I>Это называется "тестировать пользователем". Недостаток такой методики в том, что ты не знаешь состояние дел, пока не пройдет достаточное время.
Другой методики просто нет, если исключить веру в тесты в проде.

I>Мы считаем выявленые проблемы при тестах проде

I>1 регрессионные тесты
I>2 эксплорейтори
I>И бОльшая часть проблем выявляется именно тестами.
То что у вас эти проблемы выявляются только в проде — это беда. Всё это прекрасно можно выявлять в препроде с таким же успехом.

I>>>А если этого недостаточно?

I>·>Недостаточно максимально возможного? Ну это где-то из мира 146%.
I>У тебя снова "пишем без багов". Например, если запускать тесты на проде, то оказывается, что часть проблем выявляются до того, как пользователи получат версию.
Того же можно добиться запуская тесты и в пре-проде.

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

I>·>Прям релиз-кандидат?! Бедный Вася. Это может только для пользователей какого-нибудь копроративного софта сгодится, т.к выбора нет. А так юзеры разбегутся. Мне никто rc-версию chrome подсунуть не может.
I>Естественно, контора подписывает соглашение, что будет учавствовать в таких активностях.
Что я сразу заявил ранее: У них обычно, как минимум, другой T&C, они аккцептят больше рисков. Т.е. по сути тестеры. Суть-то одна: бета-тестеры — не реальные пользователи., но ты не согласился, мол пользователи, самые обыкновенные. Или ты не понял что такое Terms&Conditions?

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

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

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

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

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

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

I>·>А теперь подумай, чем комбинации ключей хуже?

I>Конфиг определяет работу всего приложения, насквозь.
И что? Чем он принципиально отличается от формочек/кнопочек?

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

I>Ну и дичь — у тебя технический долг почему то пропорционален времени на контроль качеству Больше тестируешь — больше проблем
Ты причину со следствием перепутал. Много т-долга нафигачили — сложнее тестировать до достижения приемлемого качества.

I>Технический долг проявляется в следующих вещах:

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

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

Контроль качества сам по себе не уменьшает т-долг. В то же время, т-долг усложняет процесс контроля качества.

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

I>·>Ты уверен, что это образцово-показательное устройство процесса? Или всё-таки это образец как делать не надо?
I>Ты рассказываешь сказки "никто на проде не тестирует". А я привожу примеры того, что
I>- тестириют на проде сейчас
I>- делали это и раньше
Я имел в виду, не то что "никто не делает", а то что это не является общепринятой good practice. Как если бы я заявил "никто zip-файлы в качестве vcs не использует", а ты бы мне привёл пример проекта где так делается. Ну да пусть где-то делается. Но это не доказывает, что так надо делать. Просто они не смогли нанять профессионального архитектора/техлида, вот и мучаются.

I>·>В чём было возражение, неясно. Таки "run test -P e2e" — это всего лишь код.

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

I>>>Никак, у нас её нет.

I>·>Да не важно... Если бы была, то как бы проверяли?
I>Подозреваю, я бы сделал так, что отсылка емейла делается специализированым компонентом, чья работа исключительно отсылать емейлы. Этот компонент вешается на эвенты в интеграционном слое.
I>Соответственно, нам нужен специализированый транспорт-сторадж для тестирования самого компонента и интеграции низкого уровня.
I>Для более высокого уровня интеграции нужно тестировать используя вещи типа Mailtrap.
I>Если еще более высокий уровень интеграции — честный аккаунт, емейл-рассылка, куда приходят все письма.
I>Соответсвенно, что бы проверить, ушли ли письма и тд, нужно просто зайти в этот тестовый аккаунт да посмотреть.
И потом выяснится, что в прод-серваке кто-то фиксун smtp relay и ходят письма только на тестовые аккаунты, а настоящие юзеры письма не видят. В итоге — накрутили кучу слоёв, лишних сервисов, а результат тот же как и банальный "verify(smtpClient).sendMail(xxx)". Вот и спрашивается, накой приближать тепловую смерть вселенной mailtrap-ом...

I>>>Есть просто либа, которая умеет стандартные действия. Действие это или клив в UI + ожидаемый результат, или вызов некоторого API + результат. Ничего особенного.

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

I>>>Именно. И здесь ничего про детали реализации.

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

I>>>В твоём случае был абстрактный trackHim с единственным целочисленным параметром

I>·> Откуда куда и сколько у тебя this.svc.transfer(); переводит?
I>Так же, как и у тебя. Зачем мне повторять все детали? Код 1 в 1, кроме реализации обратного вызова.
У тебя было самое интересное пропущено — тесты.

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

I>·>Непонятно зачем показывать идеи, которые тупо не работают для данных условий. Условие было дано изначально: "должно уведомлять налоговую о всех транзакциях суммой больше ...". Опять игноришь?
I>похоже, здесь снова твои проблемы с эвентами. Еще раз — у тебя один вариант обратного вызова, неочевидный, и плохо поддерживаемый, а у меня другой вариант обратного вызова, более гибкий — можно сделать и так, и так.
Я повторяю. Нахрена мне "и так, и так"? Накой мне эта гибкость?! Мне самое главное надо, чтобы было так как в надо требованиях: "должно уведомлять". У тебя этого не было. Т.е. за погоней за "красотой" ты забыл о деле.
То что мой вариант для тебя неочевидный и плохо поддерживаемый, лишь показывает твои проблемы с ООП.

I>>>Вызываешь, где надо, конкретный use case.

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

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

Ну так как проверить-то?

I>>>У тебя ведь тоже нигде ничего не указано.

I>·>У меня стоит вызов прямой trackHim. Который собственно и делает что надо. У тебя где-то тоже дожен быть такой вызов. Но код ты стесняешься показать.
I> Похоже, до тебя эвенты не доходят
I>Показал еще 23го февраля http://rsdn.org/forum/flame.comp/8204375.1
Автор: Ikemefula
Дата: 23.02.22

I>
I>new MoneyService { events { trackHim: (hmrc, accountTo) => hmrc.trackHim(accountTo); } } // вот и вся разница
I>

ТЕСТ ГДЕ?! Говорю же, без тестов — не принимаю. "and notification $налоговая is succeed" — это тоже не тест, ибо пропущено несколько важных слоёв, которые тебе тоже придётся писать. Мне нужно цельный код.

I>И похоже, что дело именно в твоем понимании того, что же такое эвент.

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

I>>>·>А тут ещё и с многопоточностью/атомарностью потенциальные проблемы. Что use делает? Добавляет ещё одного подписчика? Или заменяет предыдущего?

I>>>Никаких проблем. У тебя у самого нет подробностей про многопоточность, атомарность, т.е. мой код не хуже
I>·>Проблемы ты сам создал тем, что у твоего объекта есть дополнительные состояния. А значит появились вопросы про атомарность и т.п. и как теперь это всё тестировать...
I>Похоже, ты вообще недогоняешь, что такое обратный вызов и как его можно делать.
I>В моем коде еще меньше дополнительных состояний по сравнению с твоим вариантом. И та самая атомарность гарантируется ровно так же, как и у тебя.
Я здесь конкретно писал про этот код:
 this.svc.thresholdExceeded.use(event => this.auditQueue.send(event));
 const result = this.svc.transfer( ); // вот твоё связывание


Его по ошибке можно написать так:
 const result = this.svc.transfer( ); // вот твоё связывание
 this.svc.thresholdExceeded.use(event => this.auditQueue.send(event));


И обнаружить проблему только на более тяжелых тестах. У меня такое невозможно, тупо не скомпилится.
Ещё неясно что тут у тебя делает use. Код в студию. В зависимости от того, что там происходит, можно напороться ещё на кучу интересных багов, которые могут быть даже intermittent, что тестами даже никак нормально не выявить.

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

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

I>>>Вот-вот. И выявить это надо до того, как напорется юзер, упадет прод/самолёт/итд.

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

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

I>·>Одно другому не мешает. Однако, если у вас администратинвые меры — замена тестам, то ничего в этом хорошего нет.
I>У вас, как выяснилось, ровно так же, например — куча людей которые по цепочке проверяют изменения, целая команда prod-support которая чтото там фиксает и тд.
Как будто я это скрывал; это ты хвастался, что у тебя некие фиксуны могут менять втихушку что угодно где угодно и убегать в отпуск.
А куда деваться? Изменение может быть просто не так понято разработчиком. Все тесты зелёные, и в проде сверакет зеленью, т.к. works as coded, а юзеры жалуются. Поэтому изменения должны быть просмотрены и sign-off by PO. Команда prod-support это про другое, она отвечает за эксплуатацию.

I>>>·>Консумеры консюмят API, и это именно то, что описывается в бизнес-требованиях.

I>>>Именно что АПИ, а не внутренности реализации, как ты это интерпретируешь
I>·>Я это так не интерпретирую, ты сочиняешь.
I>А тебя послушать, так должен быть особая ссылка непременно в конструкторе
Нет, должен быть указан некий HMRC API. Иначе вообще неясно как же реализовывать собственно нотификацию. Если бы это не было явно указано в бизнес-требованиях, то попробуй докажи, что просто в /dev/null писать нельзя.

I>>>Покажи, какие именно 30 строчек. Связывающий код будет примерно 1 к 1.

I>·>Нарисуй полный код с тестами и убедись.
I>см тот пример, про эвенты и spy, который ты путаешь с моками.
У тебя не было _полного_ кода. У тебя была проверка, что MoneyService посылает событие. Но не было проверки, что это событие таки уходит в HMRC API.
И даже из того, что ты показал — кода было уже больше, чем у меня.

I>Единственная разница в том, как именно связывается отсылка уведомления.

I>У тебя она прибита гвоздями к коду и ты проверяешь, цитирую тебя "что вызывается"
I>А у меня здесь эвент и я проверяю поведение "есть реакция на такой запрос"
Вызов метода и есть частный случай евента. У тебя просто используется ещё один (ненужный, пока не доказано обратное) слой абстракции.

I>>>Смешно. В строчках кода считал?

I>·>Тогда я не знаю, что значит "покрытие" в твоей терминологии и как рассчитать его плотность.
I>Элементарно — строчки кода слабо коррелируют с количеством всех возможных путей учитывая скрытое ветвление, граничные условия и тд и тд и тд.
I>Всех путей — астрономическое число.
I>Строчек кода — на десять порядков меньше.
I>Идея понятна?
Мне не нужна идея. Мне нужны ответы на вопросы. Что такое "покрытие"? Как померить его плотность? Какие единицы измерения у плотности покрытия? На основании чего ты утверждаешь, что "покрытие будет плотнее"?

I>>>В моем случае основной компонент придется менять реже.

I>·>С чего ты взял?
I>Например, если тебе надо добавить policy, внезапно, нужно исправить тот самый if в твоем коде, где захардкожена проверка на тот самый уровен
I>
I>if(amount > 1000) hmrc.trackHim(accountTo);
I>

Исправить if на что и зачем?

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

Я тебе уже рассказал о паттерне decorator, например.

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


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

Т.е. типичный over-engineering.

I>А дальше всё интересное в интеграционном коде

Это всё легко делается если использовать интерфейс. Можно ввести свой интерфейс или банально шаблонный Consumer (тип лямбды с одним аргументом) из стандартной библиотеки.

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

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

>> требуют дополнительные фреймворки и усложняют тестирование.

I>Жиденько. Именно у тебя дополнительный фремворк — мокито.

Во-первых, этот фреймворк только для тестов и на боевой код никак не влияет (в отличие от всяких спрингов и ).
Во-вторых, у тебя был такой же "дополнительный" фреймворк откуда ты взял spy, т.е. ты заменил шило на мыло.
Во-третьих, если Hmrc — это интерфейс, то и мокито не нужен просто пишешь лямбдой new MoneyService((account) -> assert (... account ...)). Мокито просто позволяет мокать не только интерфейсы, но и классы.

I>>>Ты адекватен? Я тебе привел пример, а ты его скипнул дважды

I>·>Я задаю конкретный вопрос по твоему высказыванию, что "Сейчас все делается фремворками — Swing, Hibernate, и тд. API описывается в терминах какого либо фремворка.". Я не понимаю как можно описывать API в терминах Swing, вот и спрашиваю. Ты отвечаешь на вопрос, который я не задавал.
I>Ты перевираешь.
Перевираю что? Это твоя цитата. Мой вопрос — причём тут вообще Swing или Hibernate?

I>>>Ты же говоришь про АПИ, вот я тебе его и показл. Есть сервис — его АПИ должно быть описано хоть как угодно — в единицах фремворка, на сокетах, grpc, схемой в graphql или odata

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

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

Тогда будет сложнее тестировать.

I>А если мы его можем вызывать и через http, и grpc, и grapql, и локально, да еще передавать куда попало — всё это накладывает требования и ограничения.

В худшем случае разница будет в случае async. Что немного другая история.

I>>>У тебя каким то чудом из бизнес-требований следует один единственный вариант класса

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

I>>>Не разу не было.

I>·>А что было? Вон дают какой-нибудь FIX Rules of Engagement — там описано какие сообщения, какие поля, в какой последовательности етс. должны быть посланы в каких сценариях.
I>Это уже совсем другие требования, которых в общем случае может и не быть, а мне самому надо будет решать, что именно куда слать.
Лёгкая жизнь у тебя. Решай слать всё в /dev/null и пусть другие доказывают, что так нельзя.

I>>>Т.е. твой сервис это какой то публичный АПИ?

I>·>Неясно, почему это должно быть каким-то решающим фактором? Если MoneyService не вызывается извне, то его публичные методы нужно усложнять? Зачем?
I>А потому, что мы дизайн делаем ради конкретной цели, а не один раз на все времена. Вот ты захардкодил условие (x > 1000) а лично мое мнение, что так ты хардкодишь важную вещь — теперь надо тестами покрыть именно этот порог 1000, само условие.
I>А тут прийдет фиксун, добавит && x < 2000 и вся твоя красивая история закончится.
I>Сдержать такого фиксуна может только тест более высокого уровня с овнершипом у другого разработчика или даже команды.
ты видимо уроки Computer Science прогуливал? Такое даже теоретически никак не сдерживается. Намёк. Попробуй сдержать код && x != 1234.45, когда никто кроме фиксуна не знает эту магическую константу.

I>·>"при вызове перевода денег надо настучать в налоговку если сумма больше $1k".

I>·>"Настучать в налоговку" == вызвать метод void trackHim(int account), что делает этот метод — не твоя ответственность, этим занимаются другие люди, они тебе дают тип Hmrc в виде либы.
I>Ты путаешь требование и реализацию. Очевидно, что вариантов реализации может быть сколько угодно.
Тут ведь как... может быть сколько угодно, а ведь может и не быть!

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

I>·>Ты утверждаешь, что евент каким-то образом спасает от определения интерфейса. Нет, не спасает. Просто вместо определение ифейса у тебя появляется определение евента.
I>Именно. В этом и бенефит — всё объявляется по месту и видно снаружи. А у тебя замаскировано в конструкторе.
"замаскировано" — это твой ярлык, неясно с чем тут можно спорить. Можно сказать и так: у меня всё объявляется в конструкторе и видно снаружи, а у тебя замаскировано в евенте — шо за thresholdExceeded и шо с этим делать — неясно, придётся читать комменты.

I>Откуда мне знать, кто и как захочет использовать сервис?

Действительно, бином ньютона. А может просто поглядеть на бизнес-требования?

I>·>У тебя тоже будет привязка к 3rd party. Где-то точно будет.

I>Будет. В интеграционном коде, где будем собирать конкретный use case
Ок... Хорошо, но уже лучше. Далее. Как этот код собирания будем тестировать?

>>_Если_ мне надо будет отвязаться от 3rd party, я могу это легко сделать добавив интерфейс. Ты же добавил евент просто так, без всякой необходимости, по привычке что-ли.

I>Потому, что это минимальный вариант — отсутствует любая привязка к 3rd party.
Это не минимальный вариант, а вариант где ты спрятал интеграционный код. Полный код, включая интеграционный внезапно станет не минимальным.

I>>>То есть, те самые фремворка. Бу-га-га

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

I> Как ты себя раскрыл то

Как будто я как-то скрывался.

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

I>·>Ну допустим... Объясни почему это должно что-то менять.
I>Мы делаем дизайн компонентов:
I>1 ради конкреной цели, а не в ваккууме
I>2 используя конкретные инструменты
Круто, молодцы, поздравляю. Но вопрос остался: почему это должно что-то менять? Экспозится MoneyService через какой-нибудь там http или это внутренний класс — какая разница-то?

I>>>Уже показал, смотри внимательно.

I>·>Код тестов не я видел. Приведи весь код целиком, с тестами.
I>Во первых, было
Ты ни разу не написал что такое use. Не было декларации ThresholdExceeded, не рассказал откуда берётся слово spy, как обрабатывается and notification $налоговая is succeed. И т.п. интересные подробности.

I>Во вторых, на кой ляд мне стараться еще раз, если ты отказываешься разобраться с эвентами?

Я с евентами много лет назад разобрался.

I>>>·>И тут тебе ВНЕЗАПНО потребуется мок налоговки. Как минимум для того, чтобы можно было тестить до выкатки в прод.

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

I>А раз так, то у нас будет та самая очередь, где будет запись "уведомить налоговую"

I>Соответсвенно вместо мока просто прочитаем запись в очереди.
Из _мока_ очереди. И, в твоей терминологии, завяжемся на реализацию, что "уведомить налоговую" это на самом деле запись в определённую очередь определённого mq-брокера. Т.е. по сути ты заменил шило на мыло, но только теперь протестить без запуска mq-брокера не получится.
А на проде вдруг внезапно окажется, что тесты читают из очереди "hmrc.queue", а фиксун нафиксил, что прод-налоговка читает из очереди "hrmc.queue". И вся твоя вера в тесты на проде идёт бьётся о суровую реальность.

I>·>Почему?

I>У тебя тест на способность к интеграции, а не на саму интеграцию. Ничего другого твои моки тестировать не могут.
I>Гарантированая доставка это провека состояния очереди, т.е. чтение условно на другом конце, или же симуляция сетевых проблем и отслеживание реакции всей системы.
I>Например — выключили сеть, обнаружили накопление сообщений в очереди, включили сеть, через 10с все сообщения ушли.
I>Здесь нужно вкинуть минимум три компонента — трансфер, очередь, и процессинг для этой очереди.
Ну смотри. Протестировать что очередь таки доставляет сообщения — это, допустим десяток сценариев, ну там разные варианты обрыва связи, разные таймауты, ретраи етс. Далее, у тебя есть десяток сервисов, ну там MoneyService, BillingService, BookingService, етс. Ты утверждаешь, что нам надо написать сто тестов? Или двадцати хватит?

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

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

I>·>Ты почему-то решил, что trackHim непременно должен делать сетевой запрос. Может там буфер какой и пакеты UDP шлются изредка.

I> Ну так посчитай издержки суммарно на весь пайплайн, получишь разницу примерно в 3-4 порядка. Буфер, скажем, должен быть закрыт или lock-free, или блокирующей очередью. Упс — уже потери много бОльшие, нежели доли наносекунд.
Пусть disruptor какой-нибудь с batching, запись нескольких байтов в память — именно что наносекунды.

I>>>Это ничего не меняет.

I>·>Как это не меняет? Тысяча наносекундных евентов — уже ощутимая микросекунда и плюс мусор, для gc работа
I>Во первых — gc отдыхает, здесь всё ровно. Это у вас в джаве всё пихается в хип. Можно и иначе.
Как иначе? Что такое ThresholdExceeded? Код в студию.

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

Есть такая штука — zero gc.

I>>>Конкретно в C# будет в несколько раз медленее, то есть, наносекунда. А запрос твой hmrc.trackHim сколько процессора съест?

I>·>Зависит от. Например, оно может что-нибудь в буфер класть какой-нибудь, доли наносекунды.
I>Не будет там долей наносекунд хотя бы из за write barrier, т.к. этот буфер долгоживущий а ссылаться будет на свежесозданный объект
I>А если еще и многопоточность решишь оформить, то издержки на lock-free или блокирующую очередь перекроют с огромным перевесом
https://lmax-exchange.github.io/disruptor/
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[62]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 17.03.22 09:47
Оценка:
Здравствуйте, ·, Вы писали:

I>>·>Как ты по таким фрагментарным знаниям напишешь тест, который _гарантированно_ (как ты от меня требуешь) будет зелёным в пре-проде, но красным в проде?

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

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

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

·>Это вера. Ответь на вопрос: Каким образом ты добьёшься, что тест будет красным в проде, но зелёным в препроде?

Тест нужно изначально писать против прода и в тесте должны быть указаны все наблюдаемые симптомы. Где зафиксировали — там и покрыли тестом.
Не надо делать преположений "должно хватить и пре-прода". Меньше предположений — проще разработка.

I>>Это называется "тестировать пользователем". Недостаток такой методики в том, что ты не знаешь состояние дел, пока не пройдет достаточное время.

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



I>>И бОльшая часть проблем выявляется именно тестами.

·>То что у вас эти проблемы выявляются только в проде — это беда. Всё это прекрасно можно выявлять в препроде с таким же успехом.

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

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

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

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

I>>Естественно, контора подписывает соглашение, что будет учавствовать в таких активностях.

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

По сути — тестеры, только обычные, с их естественными задачами и окружением, без каких либо приседаний "а давайте сделаем тысячу кликов в кнопку и посмотрим, ляжет ли сервер"

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

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

Релиз-кандидат это когда бета давно уже пройдена.

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

·>А кто ещё может? У других просто доступа нет фиксить. Ну нельзя, например, девам видеть пароли прод-коннектов.

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

I>>Нету такой задачи у разработчика как "чтоб всё работало" Есть конкретный перечень задач в баклоге. Все что туда не попало или зависло работает а хрен его знает как. По моему это очевидно.

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

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

I>>Конфиг определяет работу всего приложения, насквозь.

·>И что? Чем он принципиально отличается от формочек/кнопочек?

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

I>>Технический долг проявляется в следующих вещах:

·>Это в чём он проявляется, а не как он создаётся. Вот забили вы на хороший дизайн конфига

Смотри пример выше про 100 строчек.

·>Я имел в виду, не то что "никто не делает", а то что это не является общепринятой good practice.


Ровно как и отказ от тестирования в проде не является общепринятой практикой. Последний раз я где то в нулевых слышал вопли "ой-ой-ой, не трогайте прод а то ужос-ужос"

I>>Подход "e2e это всего лишь код" плодит исключительно проблемы.

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

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

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

·>И потом выяснится, что в прод-серваке кто-то фиксун smtp relay и ходят письма только на тестовые аккаунты, а настоящие юзеры письма не видят.

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

I>>тесты, которые я показал, это не просто интеграционные, а системные.

·>Системные тесты немного про другое. Например, тест, что "если систему забэкапить, а потом восстановить в DR-сайте, то данные не теряются". И такое не надо (да и не невозможно) тестить в проде.

Ты путаешь уровень и вид тестов. e2e запускаются на системном уровне. Очевидно, "забекапить-восстановить-итд" это не сценарий юзера.

I>>А на самом деле разница исключительно в языковых фичах и стоимости разработки.

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

Смотрим вместе:
Один из вариантов:
new MoneyService { events { trackHim: (hmrc, accountTo) => hmrc.trackHim(accountTo); } } // вот и вся разница

Кроме него я привел еще несколько штук.

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

·>У тебя было самое интересное пропущено — тесты.

Наоборот — ты сам неделю кряду называл spy из моего теста моком. Забыл?

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

·>Я повторяю. Нахрена мне "и так, и так"? Накой мне эта гибкость?! Мне самое главное надо, чтобы было так как в надо требованиях: "должно уведомлять". У тебя этого не было. Т.е. за погоней за "красотой" ты забыл о деле.

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

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

·>Круто, но я с этим и не спорил.

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

Вызов налоговой проверяется пересечением границы нашего энвайрмента, а не моком конркретного класса. И это делается очевидно интеграционными тестами.

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

·>Ну так как проверить-то?

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

·>ТЕСТ ГДЕ?! Говорю же, без тестов — не принимаю. "and notification $налоговая is succeed" — это тоже не тест, ибо пропущено несколько важных слоёв, которые тебе тоже придётся писать. Мне нужно цельный код.


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

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


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

·>Его по ошибке можно написать так:

·>
·> const result = this.svc.transfer( ); // вот твоё связывание
·> this.svc.thresholdExceeded.use(event => this.auditQueue.send(event));
·>


Можно. И юнит-тестами вида "а вот оно вызывается" смысла не сильно много тестировать. Это интеграционный код, а значит и проверять нужно интеграционным тестом.

Например, вызываем АПИ приложения(sic!) и проверяем, соответствует или состояние известных точек нашим ожиданиям или нет.

·>И обнаружить проблему только на более тяжелых тестах. У меня такое невозможно, тупо не скомпилится.


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

·>Ещё неясно что тут у тебя делает use. Код в студию. В зависимости от того, что там происходит, можно напороться ещё на кучу интересных багов, которые могут быть даже intermittent, что тестами даже никак нормально не выявить.


Ты собрался покрывать тестами 3rd party либу? use в данном случе берем забесплатно, если есть такой. Если нет — есть и другие варианты дизайна, см варианты с возвращаемым значением итд.

I>>Элементарно — логику в контроллер помещать не надо. Для этого у нас useCase, который обеспечивает интеграцию под конкретный случай.

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

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

I>>Разумеется. Упал один — есть шанс, что упадёт и другой, по той же причине, т.к. ты решил что "разница с продом не имеет значения"

·>Я это не решил.

Именно ты. Баги в софте имеют обыкновение воскрешаться и время от времени такое происходит в самый неприятный момент.

I>>У вас, как выяснилось, ровно так же, например — куча людей которые по цепочке проверяют изменения, целая команда prod-support которая чтото там фиксает и тд.

·>Как будто я это скрывал; это ты хвастался, что у тебя некие фиксуны могут менять втихушку что угодно где угодно и убегать в отпуск.
·>А куда деваться? Изменение может быть просто не так понято разработчиком. Все тесты зелёные, и в проде сверакет зеленью, т.к. works as coded, а юзеры жалуются. Поэтому изменения должны быть просмотрены и sign-off by PO.

Что за PO такой, что в курсе всех тонкостей кода реализации? У вас там CEO случаем не занимается багфиксом по ночам/выходным?

I>>А тебя послушать, так должен быть особая ссылка непременно в конструкторе

·>Нет, должен быть указан некий HMRC API. Иначе вообще неясно как же реализовывать собственно нотификацию. Если бы это не было явно указано в бизнес-требованиях, то попробуй докажи, что просто в /dev/null писать нельзя.

АПИ это дело десятое. Важнее описать ожидания налоговой — например "обязательно на каждый трансфер который удовлетворяет условиям <перечень> отсылать то и это, в противном случае отзовем лицуху и дадим штраф по самые небалуй"

I>>см тот пример, про эвенты и spy, который ты путаешь с моками.

·>У тебя не было _полного_ кода. У тебя была проверка, что MoneyService посылает событие. Но не было проверки, что это событие таки уходит в HMRC API.

"событие таки уходит в hmrc API" и у тебя не было. У тебя было
1. способность вызова точки интеграции с hmrc API — тот самый тест на моках
2. три раза п1.

Что бы проверить, что событие таких уходит в тот API, нужен интеграционный тест. А именно — запрос пересекает границу нашего энвайрмента.

·>И даже из того, что ты показал — кода было уже больше, чем у меня.


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

I>>А у меня здесь эвент и я проверяю поведение "есть реакция на такой запрос"

·>Вызов метода и есть частный случай евента. У тебя просто используется ещё один (ненужный, пока не доказано обратное) слой абстракции.

Наконец то! Только это не слой абстракции — это языковая фича или библиотечная, цель которой избавить от написания того кода который ты пишешь.

I>>Идея понятна?

·>Мне не нужна идея. Мне нужны ответы на вопросы. Что такое "покрытие"? Как померить его плотность? Какие единицы измерения у плотности покрытия? На основании чего ты утверждаешь, что "покрытие будет плотнее"?

У меня будут прямые проверки всех компонентов вида "expect(sin(x)).to.eq(y)" вместо твоих косвенных,
ключевые вещи типа "if(x > 1000)" будт тестироваться специальными юнит-тестами так же напрямую безо всяких моков
И код самого сервиса, очевидно, становится проще — лишние ветвления убираются.
+ проверки пересекает ли физический запрос границы энвайрмента.
В сумме это значит, что я могу написать намного бОльше дешевых юнит-тестов.

I>>>>В моем случае основной компонент придется менять реже.

I>>·>С чего ты взял?
I>>Например, если тебе надо добавить policy, внезапно, нужно исправить тот самый if в твоем коде, где захардкожена проверка на тот самый уровен
I>>
I>>if(amount > 1000) hmrc.trackHim(accountTo);
I>>

·>Исправить if на что и зачем?

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

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

·>Я тебе уже рассказал о паттерне decorator, например.

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


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

·>Т.е. типичный over-engineering.

Наоборот, делаем самый минимум предположений.

I>>А дальше всё интересное в интеграционном коде

·>Это всё легко делается если использовать интерфейс. Можно ввести свой интерфейс или банально шаблонный Consumer (тип лямбды с одним аргументом) из стандартной библиотеки.

Вот его и стоило использовать, и до кучи вынести if(x < 1000) наружу. В сервисе остаётся линейная логика безо всяких приседаний.

I>>Меньще — выбрасываем моки и доп-интерфейсы благодаря языковым или библиотечным фичам

·>Нет, выбросить не удастся. Удастся лишь задвинуть это в какое-то другое место. Ещё раз повторяю — мой код — минимальный, там ничего принципиально не выбрасывается.

Ты сам только что сказал, что можно взять generic интерфейс, т.е. принципиально выбрасываем зависимость от hmrc.
А еще можно выбросить if(x > 1000), т.к. такие вещи имеют обыкновение меняться гораздо чаще, чем основной пайплайн.
Мало ли — все это будет приходить из конфига, или определяться каждым кейсом использования
Например, для физиков одни условия, для юриков другие, а для каких то случаев и вовсе отключить уведомление.

I>>Жиденько. Именно у тебя дополнительный фремворк — мокито.

·>
·>Во-первых, этот фреймворк только для тестов и на боевой код никак не влияет (в отличие от всяких спрингов и ).

Спринг и Хибернейт как мы выяснили, и у тебя есть.

·>Во-вторых, у тебя был такой же "дополнительный"фреймворк откуда ты взял spy, т.е. ты заменил шило на мыло.


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

·>Во-третьих, если Hmrc — это интерфейс, то и мокито не нужен просто пишешь лямбдой new MoneyService((account) -> assert (... account ...)). Мокито просто позволяет мокать не только интерфейсы, но и классы.


Ты никак определиться не можешь, то у тебя hmrc интерфейс, то класс

I>>Ты перевираешь.

·>Перевираю что? Это твоя цитата. Мой вопрос — причём тут вообще Swing или Hibernate?

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

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

·>Мне неочевидно. Почему она должна обязательно отличаться?

Необязательно, но архитектура/дизайн выбирается с учетом целей, задач и инструментов.
Например, если я читаю-пишу в бд, то код будет писаться с учетом возможностей какого нибудь Hybernate,а если та же задача, но читать-писать нужно в REST сервис, то здесь все будет чуточку иначе. А если нужно читать-писать в разные сервисы, то все будет гораздо сложнее.
В одном случае transaction management будет бесплатным, а в другом его нужно будет обеспепечить конкретными действиями.

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

·>Тогда будет сложнее тестировать.

Совсем необязательно.

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

·>Как же код будет уведомлять hmrc?

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

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

·> ты видимо уроки Computer Science прогуливал? Такое даже теоретически никак не сдерживается. Намёк. Попробуй сдержать код && x != 1234.45, когда никто кроме фиксуна не знает эту магическую константу.

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

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

·>Тут ведь как... может быть сколько угодно, а ведь может и не быть!

"может и не быть" это частный случай от "может быть сколько угодно". Ты ничего не сказал.

·>"замаскировано" — это твой ярлык, неясно с чем тут можно спорить. Можно сказать и так: у меня всё объявляется в конструкторе и видно снаружи, а у тебя замаскировано в евенте — шо за thresholdExceeded и шо с этим делать — неясно, придётся читать комменты.


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

I>>Откуда мне знать, кто и как захочет использовать сервис?

·>Действительно, бином ньютона. А может просто поглядеть на бизнес-требования?

Бизнес-требования пишутся на приложение или систему, а не конкретный класс.

I>>Будет. В интеграционном коде, где будем собирать конкретный use case

·>Ок... Хорошо, но уже лучше. Далее. Как этот код собирания будем тестировать?

Все, что вызывается из интеграционного кода дожно быть
1. или 3rd party, библиотечные, и тд
2. или компонент/функция, который покрыт тестами

Потому для интеграционного кода пишем
1. wiring тест, например "фабрика такая то возвращает объет такой структуры, привязывает конфиг, метаданные, параметры, итд"
2. интеграционный "вызываем трансфер с таким то конфигом и получам запись в очереди вида xxx-yyy"
3. все пути активации компонента помещаем в e2e сценарии

>>>_Если_ мне надо будет отвязаться от 3rd party, я могу это легко сделать добавив интерфейс. Ты же добавил евент просто так, без всякой необходимости, по привычке что-ли.

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

Минимальный вариант это значит минимально возможное количество предположений. О том, что надо зиповать код речи не было. Достаточно только избавиться от лишних зависимостей.

I>> Ты же используешь мокито, spring, hibernate...

·>Неясно как ты в один ряд ставишь мелкую либу для тестов с монстрами spring/hibernate.

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

I>>Мы делаем дизайн компонентов:

I>>1 ради конкреной цели, а не в ваккууме
I>>2 используя конкретные инструменты
·>Круто, молодцы, поздравляю. Но вопрос остался: почему это должно что-то менять? Экспозится MoneyService через какой-нибудь там http или это внутренний класс — какая разница-то?

Я ж пишу
1 важна цель нашего использования. Не бывает "уведомлять" да захардкоженое условие. Как правило полиси имеют обыкновение меняться часто. А еще бывает так, что правила меняются или физлиц, для юрлиц, и тд и тд. А раз так, то надо изначально закладывать в дизайн такие вещи.
2 конкретные инструменты. Например, если экспозится только через http, то здесь куча вещей переложится на фремворк и метаданные и будет влегкую покрыто всякими pre, post, условиями и тд. Соответсвенно, интеграционные станут проще, а юнит-тесто станет бОльше.

I>>Во первых, было

·>Ты ни разу не написал что такое use. Не было декларации ThresholdExceeded, не рассказал откуда берётся слово spy, как обрабатывается and notification $налоговая is succeed. И т.п. интересные подробности.

У меня нет желания рассказывать тебе, как в разных ЯП и библиотеках устроены события, сигналы, уведомления и тд. Важно что use просто связывает эвент с колбеком, делает это надежно и это не надо тестировать. Тестировать нужно наличие реакции. Каждое событие имеет тип аргумента. Что именно помещать туда — зависит от цели. Хочешь закладыватся на полиси, тогда это будет не ThresholdExceeded, а TransferDone, и тип события это подробности трансфера — кто, кому, сумма, итд.

I>>Во вторых, на кой ляд мне стараться еще раз, если ты отказываешься разобраться с эвентами?

·>Я с евентами много лет назад разобрался.

Тогда нужно просто вспомнить

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

·>Это не ответственность MoneyService который мы обсуждаем.

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

·>А на проде вдруг внезапно окажется, что тесты читают из очереди "hmrc.queue", а фиксун нафиксил, что прод-налоговка читает из очереди "hrmc.queue". И вся твоя вера в тесты на проде идёт бьётся о суровую реальность.


Тесты на проде никакие очереди не читают. Из очереди могут читать тесты уровнем пониже, простые интеграционные.

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

·>Ну смотри. Протестировать что очередь таки доставляет сообщения — это, допустим десяток сценариев, ну там разные варианты обрыва связи, разные таймауты, ретраи етс. Далее, у тебя есть десяток сервисов, ну там MoneyService, BillingService, BookingService, етс. Ты утверждаешь, что нам надо написать сто тестов? Или двадцати хватит?

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

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

·>И? Что этим гарантируется-то? Что алармы не сработали?

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

·>Пусть disruptor какой-нибудь с batching, запись нескольких байтов в память — именно что наносекунды.


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

I>>Во первых — gc отдыхает, здесь всё ровно. Это у вас в джаве всё пихается в хип. Можно и иначе.

·>Как иначе? Что такое ThresholdExceeded? Код в студию.

Иначе — alloc free или zero gc. Это достигается за счет фич конкретной платформы, например — можно передавать параметры в регистрах процессора, а не совать в хип, как это делает джава. Но вобщем и в джаве можно добиться похожих вещей, только придется встать раком.

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

·>Есть такая штука — zero gc.

чудо — а тут ты сам знаеш, что такое zero gc

I>>А если еще и многопоточность решишь оформить, то издержки на lock-free или блокирующую очередь перекроют с огромным перевесом

·>https://lmax-exchange.github.io/disruptor/

Вижу — минимальная задержка согласно их собственным замерам ажно 29 наносекунд. Это целый алгоритм в такое время влезет, а не просто обратный вызов.
Отредактировано 18.03.2022 9:28 Pauel . Предыдущая версия .
Re[63]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 18.03.22 10:32
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>·>Как ты по таким фрагментарным знаниям напишешь тест, который _гарантированно_ (как ты от меня требуешь) будет зелёным в пре-проде, но красным в проде?

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

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

I>·>Это вера. Ответь на вопрос: Каким образом ты добьёшься, что тест будет красным в проде, но зелёным в препроде?
I>Тест нужно изначально писать против прода и в тесте должны быть указаны все наблюдаемые симптомы. Где зафиксировали — там и покрыли тестом.
Вопрос остаётся. Каким образом ты добьёшься гарантии, что покрыл тестом именно ту проблему, что возникла у пользователя?

I>Не надо делать преположений "должно хватить и пре-прода". Меньше предположений — проще разработка.

Т.е. у вас с reproducibility проблема. Воспроизвести проблему в немного другом окружении вы толком не можете. Скорее всего это и есть корень проблемы. Наймите нормального архитектора.

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

I>·>Того же можно добиться запуская тесты и в пре-проде.
I>Смотря какие риски. Если риски исчисляются количеством трупов в самолете, то надо бы подстраховаться.
Ясно... Прод это то, с чем работают пользователи, по определению. Вы же тесты запускаете до того, как пользователи получат версию. Вы продом называете пре-прод что-ли? Или под продом подразумеваете определённый набор оборудования куда всё деплоится?

I>>>Естественно, контора подписывает соглашение, что будет учавствовать в таких активностях.

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

I>без каких либо приседаний "а давайте сделаем тысячу кликов в кнопку и посмотрим, ляжет ли сервер"

Т.е. если я, как разработчик аппликухи, нажму кнопки в том же порядке как типичный юзер, то внезапно стану "обычным юзером"?! Нетушки. Какие конкретно сценарии тестирует некая группа тестеров — другой вопрос, и совершенно неинтересный.

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

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

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

I>·>А кто ещё может? У других просто доступа нет фиксить. Ну нельзя, например, девам видеть пароли прод-коннектов.
I>А еще бывает так, что тестами на проде выявляют некоторые проблемы, быстренько документируют, спускают разработчикам, те выкатывают фикс и происходит откат деплоймента и деплой новой версии.
I>Или же просто через неделю-две выкатывается обновление, а а до того юзерам отключают проблемные кейсы.
Какое обновление?! Обновление чего? Пароль правильно забить всё равно придётся прод-команде, никто кроме них ничего сделать не может в принципе.

I>>>Нету такой задачи у разработчика как "чтоб всё работало" Есть конкретный перечень задач в баклоге. Все что туда не попало или зависло работает а хрен его знает как. По моему это очевидно.

I>·>Так вот заведите аналогичный перечень задач для комбинации ключей.
I>Ну вот у тебя коротенький простенький конфиг на сто строчек — каждая строка это флажок.
I>Сколько времени будут идти твои тесты, что бы прогнать все комбинации?
I>Управшишься до тепловой смерти вселенной или надо времени добавить?
Про N*M->N+M я тебе уже неоднократно рассказывал.

I>>>Конфиг определяет работу всего приложения, насквозь.

I>·>И что? Чем он принципиально отличается от формочек/кнопочек?
I>Очевидно. Кнопочка обычно влияет исключительно локально — по месту вызова. Формочка ровно так же.
Кнопочка-формочка генерит соответствующие команды внутре. Что потом ниже по курсу превращается в развесистые документы-данные и кучей комбинаций. Как вы управляетесь — неясно.

I>Конфигом может подкидывать вещи, которые, например, меняют поведение всех формочек, всех кнопочек.

Мы тут говорим конкретно о енв-специфичных вещах, которые вы способны только в проде проверить. Вот и интересно откуда у вас сто таких штук набиратся.

I>>>Технический долг проявляется в следующих вещах:

I>·>Это в чём он проявляется, а не как он создаётся. Вот забили вы на хороший дизайн конфига
I>Смотри пример выше про 100 строчек.
Вот зайди на about:config — и погляди сколько там строчек. Но тесты браузера у меня никто не гоняет. Чудеса, да и только.

I>·>Я имел в виду, не то что "никто не делает", а то что это не является общепринятой good practice.

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

I>>>Подход "e2e это всего лишь код" плодит исключительно проблемы.

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

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

I>·>И потом выяснится, что в прод-серваке кто-то фиксун smtp relay и ходят письма только на тестовые аккаунты, а настоящие юзеры письма не видят.
I>Вот-вот. Ты сам привел пример того, почему надо тестировать на проде в т.ч. у реальных юзеров об чем я тебе и говорю..
Можно попросить пользователя при выкатке каких-то конкретных изменений поглядеть, что письма ходят. Но причём тут "run test -P e2e"? После десятка таких писем любой вменяемый юзер вас лесом пошлёт или зарплату потребует.

I>>>тесты, которые я показал, это не просто интеграционные, а системные.

I>·>Системные тесты немного про другое. Например, тест, что "если систему забэкапить, а потом восстановить в DR-сайте, то данные не теряются". И такое не надо (да и не невозможно) тестить в проде.
I>Ты путаешь уровень и вид тестов. e2e запускаются на системном уровне. Очевидно, "забекапить-восстановить-итд" это не сценарий юзера.
И какой же по-твоему это вид тестов?

I>>>А на самом деле разница исключительно в языковых фичах и стоимости разработки.

I>·>Нет, я не увидел, где у тебя было обеспечено требование, что "должно уведомлять".
I>Смотрим вместе:
I>Один из вариантов:
I>
I>new MoneyService { events { trackHim: (hmrc, accountTo) => hmrc.trackHim(accountTo); } } // вот и вся разница
I>

Ты тесты не привёл. Так что не засчитывается, требование ничем не обеспечено.

I>Кроме него я привел еще несколько штук.

И они тоже были без тестов, и с багами.

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

I>·>У тебя было самое интересное пропущено — тесты.
I>Наоборот — ты сам неделю кряду называл spy из моего теста моком. Забыл?
Теста "должно уведомлять hmrc" у тебя не было. Был тест — "создаётся какой-то там евент".

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

I>·>Я повторяю. Нахрена мне "и так, и так"? Накой мне эта гибкость?! Мне самое главное надо, чтобы было так как в надо требованиях: "должно уведомлять". У тебя этого не было. Т.е. за погоней за "красотой" ты забыл о деле.
I>Для того, что бы
I>- упростить тестирование
I>- упростить использование
I>- мейнтенанс.
I>Например, для моих вариантов не нужны ни моки, ни мокито. В принципе даже spy не нужен при желании.
Это всё красиво, но бессмысленно. Пока нет бизнес-требования не удовлетворены, твоё упрощение нафиг никому не впёрлось.

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

I>·>Круто, но я с этим и не спорил.
I>Ога — ты только и повторяешь, что надо тестировать "что вызывается". Именно это есть та самая причина, ради которой моки тащут в тесты.
I>На самом деле это крайне хилая гарантия "что вызывается"
I>Вызов налоговой проверяется пересечением границы нашего энвайрмента, а не моком конркретного класса. И это делается очевидно интеграционными тестами.
И что должно являться этой границей?

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

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

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

Я давно объяснил, что в нашем демонстрационном примере, происходящее внутри метода trackHim — это 3rd party система, которая не является частью нашей системы за работоспособность которой мы отвечаем. Почему для тебя единственный способ взаимодействия систем это непосредственно обязательно должен быть какой-то HTTP?

I>·>ТЕСТ ГДЕ?! Говорю же, без тестов — не принимаю. "and notification $налоговая is succeed" — это тоже не тест, ибо пропущено несколько важных слоёв, которые тебе тоже придётся писать. Мне нужно цельный код.

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

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

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

I>·>Его по ошибке можно написать так:

I>·>
I>·> const result = this.svc.transfer( ); // вот твоё связывание
I>·> this.svc.thresholdExceeded.use(event => this.auditQueue.send(event));
I>·>

I>Можно. И юнит-тестами вида "а вот оно вызывается" смысла не сильно много тестировать. Это интеграционный код, а значит и проверять нужно интеграционным тестом.
I>Например, вызываем АПИ приложения(sic!) и проверяем, соответствует или состояние известных точек нашим ожиданиям или нет.
Код в студию.

I>·>И обнаружить проблему только на более тяжелых тестах. У меня такое невозможно, тупо не скомпилится.

I>Эти более тяжелые тесты нужны в любом случае. Гарантия вызова налоговой это не зеленый тест на моках, а сообщение о том, что вызов пересек границу энвайрмента.
В рамках моего примера я очень чётко очертил границу — вызов метода trackHim.

I>·>Ещё неясно что тут у тебя делает use. Код в студию. В зависимости от того, что там происходит, можно напороться ещё на кучу интересных багов, которые могут быть даже intermittent, что тестами даже никак нормально не выявить.

I>Ты собрался покрывать тестами 3rd party либу? use в данном случе берем забесплатно, если есть такой.
Я пытаюсь из тебя выудить что значит написанный тобою код. Опиши контракт use, или ссылку на доку раз либа.

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

И в них были другие проблемы.

I>>>Элементарно — логику в контроллер помещать не надо. Для этого у нас useCase, который обеспечивает интеграцию под конкретный случай.

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

I>>>Разумеется. Упал один — есть шанс, что упадёт и другой, по той же причине, т.к. ты решил что "разница с продом не имеет значения"

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

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

I>·>А куда деваться? Изменение может быть просто не так понято разработчиком. Все тесты зелёные, и в проде сверакет зеленью, т.к. works as coded, а юзеры жалуются. Поэтому изменения должны быть просмотрены и sign-off by PO.
I>Что за PO такой, что в курсе всех тонкостей кода реализации? У вас там CEO случаем не занимается багфиксом по ночам/выходным?
Причём тут тонкости реализации? Изменение как-то влияет на функционирование продукта? Влияет. PO должен об этом знать и проверить, что функционирует как надо, а не as coded.

I>>>А тебя послушать, так должен быть особая ссылка непременно в конструкторе

I>·>Нет, должен быть указан некий HMRC API. Иначе вообще неясно как же реализовывать собственно нотификацию. Если бы это не было явно указано в бизнес-требованиях, то попробуй докажи, что просто в /dev/null писать нельзя.
I>АПИ это дело десятое. Важнее описать ожидания налоговой — например "обязательно на каждый трансфер который удовлетворяет условиям <перечень> отсылать то и это, в противном случае отзовем лицуху и дадим штраф по самые небалуй"
Куда отсылать-то? На деревню дедушке?

I>>>см тот пример, про эвенты и spy, который ты путаешь с моками.

I>·>У тебя не было _полного_ кода. У тебя была проверка, что MoneyService посылает событие. Но не было проверки, что это событие таки уходит в HMRC API.
I>"событие таки уходит в hmrc API" и у тебя не было.
Было. Hmrc — это 3rd party. и метод trackHim — это api.

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

Допустим. И? Где тест? Вот тебе hmrc прислала бинарник jar|dll, в нём лежит класс Hmrc. Что делать будешь?

I>·>И даже из того, что ты показал — кода было уже больше, чем у меня.

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

I>>>А у меня здесь эвент и я проверяю поведение "есть реакция на такой запрос"

I>·>Вызов метода и есть частный случай евента. У тебя просто используется ещё один (ненужный, пока не доказано обратное) слой абстракции.
I>Наконец то! Только это не слой абстракции — это языковая фича или библиотечная, цель которой избавить от написания того кода который ты пишешь.
Что наконец-то? Нет, это именно слой абстракции. Вместо вызова метода ты используешь промежуточный механизм евентов для вызова того же метода.

I>>>Идея понятна?

I>·>Мне не нужна идея. Мне нужны ответы на вопросы. Что такое "покрытие"? Как померить его плотность? Какие единицы измерения у плотности покрытия? На основании чего ты утверждаешь, что "покрытие будет плотнее"?
I>У меня будут прямые проверки всех компонентов вида
[поток слов поскипан]
Ответь на конкретные вопросы:
Что такое "покрытие"?
Как померить его плотность?
Какие единицы измерения у плотности покрытия?
На основании чего ты утверждаешь, что "покрытие будет плотнее"?

I>·>Исправить if на что и зачем?

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

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

I>·>Т.е. типичный over-engineering.
I>Наоборот, делаем самый минимум предположений.
У тебя миниум какой-то неминимальный.

I>>>А дальше всё интересное в интеграционном коде

I>·>Это всё легко делается если использовать интерфейс. Можно ввести свой интерфейс или банально шаблонный Consumer (тип лямбды с одним аргументом) из стандартной библиотеки.
I>Вот его и стоило использовать, и до кучи вынести if(x < 1000) наружу. В сервисе остаётся линейная логика безо всяких приседаний.
Нет, не стоило. Демонстрационный пример бы не получился.

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

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

I>А еще можно выбросить if(x > 1000), т.к. такие вещи имеют обыкновение меняться гораздо чаще, чем основной пайплайн.

Не выбрасываем, а переносим в другое место.

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

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

I>>>Жиденько. Именно у тебя дополнительный фремворк — мокито.

I>·>
I>·>Во-первых, этот фреймворк только для тестов и на боевой код никак не влияет (в отличие от всяких спрингов и ).
I>Спринг и Хибернейт как мы выяснили, и у тебя есть.
Немного Спринга в некоторых местах есть, легаси от "виликих" архитекторов, давно бы пора выпилить. Хибернейт лет 10+ назад использовал.

I>·>Во-вторых, у тебя был такой же "дополнительный"фреймворк откуда ты взял spy, т.е. ты заменил шило на мыло.

I>Такой spy, как я показал, не требует фремворка.
Это как? spy в твоём коде это ключевое слово языка что-ли?

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

Ты, видимо, код не понял. Перечитай что-ли.

I>·>Во-третьих, если Hmrc — это интерфейс, то и мокито не нужен просто пишешь лямбдой new MoneyService((account) -> assert (... account ...)). Мокито просто позволяет мокать не только интерфейсы, но и классы.

I>Ты никак определиться не можешь, то у тебя hmrc интерфейс, то класс
Да потому что нет принципиальной разницы. Хоть так, хоть эдак. Незначительное техническое отличие. Тебя это почему так беспокоит?

I>>>Ты перевираешь.

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

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

I>·>Мне неочевидно. Почему она должна обязательно отличаться?
I>Необязательно, но архитектура/дизайн выбирается с учетом целей, задач и инструментов.
I>Например, если я читаю-пишу в бд, то код будет писаться с учетом возможностей какого нибудь Hybernate,а если та же задача, но читать-писать нужно в REST сервис, то здесь все будет чуточку иначе. А если нужно читать-писать в разные сервисы, то все будет гораздо сложнее.
I>В одном случае transaction management будет бесплатным, а в другом его нужно будет обеспепечить конкретными действиями.
Т.е., теоретически может отличаться, и, как выяснилось, может и не отличаться. Но ты без задавания вопросов выдал какое-то конкретное решение конкретной архитектуры, т.е. ты сделал какие-то предположения. Зачем, неясно.

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

I>·>Тогда будет сложнее тестировать.
I>Совсем необязательно.
Обязательно. Т.к. уменьшить простоту _полного_ тестирования моего кода принципиально невозможно.

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

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

I>Ты сам говоришь, что в некоторых случаях может быть noop

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

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

I>·> ты видимо уроки Computer Science прогуливал? Такое даже теоретически никак не сдерживается. Намёк. Попробуй сдержать код && x != 1234.45, когда никто кроме фиксуна не знает эту магическую константу.
I>Вот-вот. И это проблема твоего дизайна где все ключевое спрятано Стоит вынести условие во внешнее полиси, как все становится максимально видимым, прозрачным, и тогда все сразу обнаруживается разными методам — код ревью, тесты и тд.
Опять словоблудие. Почему некое внешнее полиси вдруг ревьювится, а MoneyService нет?

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

I>·>Тут ведь как... может быть сколько угодно, а ведь может и не быть!
I>"может и не быть" это частный случай от "может быть сколько угодно". Ты ничего не сказал.
Хотя бы я сказал больше, чем ты. Я сказал, хотя бы намёком, что ты ничего не сказал.

I>·>"замаскировано" — это твой ярлык, неясно с чем тут можно спорить. Можно сказать и так: у меня всё объявляется в конструкторе и видно снаружи, а у тебя замаскировано в евенте — шо за thresholdExceeded и шо с этим делать — неясно, придётся читать комменты.

I>Ни разу не видел скажем C# разработчика, который не в курсе тамошних эвентов.
Нету в c# никакого thresholdExceeded, или давай ссылку на language spec. Это не тамошний евент, а некий пользовательский тип, определение которого ты стесняешься показать.

I>И если есть задача "уведомлять" то первым делом приходит в голову именно событие.

Это проблема конкретной головы, а не c#.

I>А если сделать через возвращаемое значение, то игнорировать становится и вовсе затруднительно.

Возвращаемое значение игнорировать как раз запросто.

I>>>Откуда мне знать, кто и как захочет использовать сервис?

I>·>Действительно, бином ньютона. А может просто поглядеть на бизнес-требования?
I>Бизнес-требования пишутся на приложение или систему, а не конкретный класс.
В требованиях описан нужный public API. Какой именно протокол — неважно _в рамках нашего примера_, поэтому для простоты я и говорю, пусть этот API будет в виде сигнатуры метода transfer.

I>>>Будет. В интеграционном коде, где будем собирать конкретный use case

I>·>Ок... Хорошо, но уже лучше. Далее. Как этот код собирания будем тестировать?
I>Все, что вызывается из интеграционного кода дожно быть
I>1. или 3rd party, библиотечные, и тд
Наш случай.

I>Потому для интеграционного кода пишем

I>1. wiring тест, например "фабрика такая то возвращает объет такой структуры, привязывает конфиг, метаданные, параметры, итд"
I>2. интеграционный "вызываем трансфер с таким то конфигом и получам запись в очереди вида xxx-yyy"
I>3. все пути активации компонента помещаем в e2e сценарии
Вот наша ситуация. Нам дан 3rd party библиотека с классом Hmrc, конструктор — адрес соединения, метод trackHim. Напиши интеграционный тест.

>>>>_Если_ мне надо будет отвязаться от 3rd party, я могу это легко сделать добавив интерфейс. Ты же добавил евент просто так, без всякой необходимости, по привычке что-ли.

I>>>Потому, что это минимальный вариант — отсутствует любая привязка к 3rd party.
I>·>Это не минимальный вариант, а вариант где ты спрятал интеграционный код. Полный код, включая интеграционный внезапно станет не минимальным.
I>Минимальный вариант это значит минимально возможное количество предположений. О том, что надо зиповать код речи не было. Достаточно только избавиться от лишних зависимостей.
У тебя предположений гораздо больше. Вот явный пример: " Как правило полиси имеют обыкновение меняться часто. А еще бывает так, что правила меняются или физлиц, для юрлиц, и тд и тд.". Откуда это всё? И главное зачем?

I>>> Ты же используешь мокито, spring, hibernate...

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

I>·>Круто, молодцы, поздравляю. Но вопрос остался: почему это должно что-то менять? Экспозится MoneyService через какой-нибудь там http или это внутренний класс — какая разница-то?

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

I>2 конкретные инструменты. Например, если экспозится только через http, то здесь куча вещей переложится на фремворк и метаданные и будет влегкую покрыто всякими pre, post, условиями и тд. Соответсвенно, интеграционные станут проще, а юнит-тесто станет бОльше.

Ну добавишь implements FrameworkGeneratedHttpInterface, делов-то. Менять-то что надо?

I>>>Во первых, было

I>·>Ты ни разу не написал что такое use. Не было декларации ThresholdExceeded, не рассказал откуда берётся слово spy, как обрабатывается and notification $налоговая is succeed. И т.п. интересные подробности.
I>У меня нет желания рассказывать тебе, как в разных ЯП и библиотеках устроены события, сигналы, уведомления и тд.
Я не прошу ничего рассказывать. Я прошу привести цельный код, а не бессмысленные фрагменты. Рассказываешь всякую чушь ты по собственному желанию, я же, наоборот, тебя уже в сотый раз прошу — не нужны мне твои рассказы. Мне нужен код.

I>Важно что use просто связывает эвент с колбеком, делает это надежно и это не надо тестировать.

Важно, например, понимать, что произойдёт если use выполнится дважды.

I>Тестировать нужно наличие реакции. Каждое событие имеет тип аргумента. Что именно помещать туда — зависит от цели. Хочешь закладыватся на полиси, тогда это будет не ThresholdExceeded, а TransferDone, и тип события это подробности трансфера — кто, кому, сумма, итд.

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

I>>>Во вторых, на кой ляд мне стараться еще раз, если ты отказываешься разобраться с эвентами?

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

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

I>·>Это не ответственность MoneyService который мы обсуждаем.
I>О том и речь — с тз приложения нам твоих моков не хватит, и все равно нужны внятные интеграционные тесты.
I>А когда они появятся, то надобность в твоих моках сразу отпадает.
Не отпадёт. Ибо твои "внятные" интеграционные тесты потребуют полной сборки и запуска нетривиального окружения.
Мой тест с моками отрабатывает за миллисекунду сразу в IDE.

I>·>А на проде вдруг внезапно окажется, что тесты читают из очереди "hmrc.queue", а фиксун нафиксил, что прод-налоговка читает из очереди "hrmc.queue". И вся твоя вера в тесты на проде идёт бьётся о суровую реальность.

I>Тесты на проде никакие очереди не читают. Из очереди могут читать тесты уровнем пониже, простые интеграционные.
Вот я из тебя всё пытаюсь выудить что же скрывается за "and notification $налоговая is succeed", но ты упорно скрываешь.

I>·>Ну смотри. Протестировать что очередь таки доставляет сообщения — это, допустим десяток сценариев, ну там разные варианты обрыва связи, разные таймауты, ретраи етс. Далее, у тебя есть десяток сервисов, ну там MoneyService, BillingService, BookingService, етс. Ты утверждаешь, что нам надо написать сто тестов? Или двадцати хватит?

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

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

I>·>И? Что этим гарантируется-то? Что алармы не сработали?
I>Гарантируется выполнимость сценариев на проде. + мы видим все это в мониторинге и сразу получам сигналы о проблемах. Т.е. в короткий срок собираем сведения о том, какие есть проблемы.
_Тестовых_ сценариев. И зачем это гарантировать?

I>·>Пусть disruptor какой-нибудь с batching, запись нескольких байтов в память — именно что наносекунды.

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

I>>>Во первых — gc отдыхает, здесь всё ровно. Это у вас в джаве всё пихается в хип. Можно и иначе.

I>·>Как иначе? Что такое ThresholdExceeded? Код в студию.
I>Иначе — alloc free или zero gc.
Код в студию.

I>>>А если еще и многопоточность решишь оформить, то издержки на lock-free или блокирующую очередь перекроют с огромным перевесом

I>·>https://lmax-exchange.github.io/disruptor/
I>Вижу — минимальная задержка согласно их собственным замерам ажно 29 наносекунд. Это целый алгоритм в такое время влезет, а не просто обратный вызов.
Вот тут вижу, что посылка одного жалкого евента, даже без парама, уже 1.6 наносекунд. Вот и считай сколько влезет.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[64]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 18.03.22 13:51
Оценка:
Здравствуйте, ·, Вы писали:

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

Про coverage — гугли "Test Coverage & Requirement Traceability". Т.е. покрываем требования-кейсы-сценарии, а не строчки-конструкторы-используется-вызывается

I>>Тогда нужно просто вспомнить

·>Почему ты решил, что я что-то не знаю об евентах?

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

I>>А когда они появятся, то надобность в твоих моках сразу отпадает.

·>Не отпадёт. Ибо твои "внятные" интеграционные тесты потребуют полной сборки и запуска нетривиального окружения.
·>Мой тест с моками отрабатывает за миллисекунду сразу в IDE.

Ну ок — ты написал тесты на моках.
И как же мы узнаем, что живая система таки шлёт запросы куда положено?
Пришел реквест с того конца "мы не видим от вас никаких запросов, готовьтесь платить штрафы"
Как быть?

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

Что делать будешь? Начнешь переписываться неделями-месяцами, что у тебя де тесты на моках, и там всё хорошо?

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

·>Вот я из тебя всё пытаюсь выудить что же скрывается за "and notification $налоговая is succeed", но ты упорно скрываешь.

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

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

·>Серьёзно? А как же тепловая смерть вселенной? На любом сколько-нибудь нетривиальном проекте этих тестов будет не сотня, а на несколько порядков больше. Да даже таймауты порядка 10 секунд повторённые сотню раз уже делают неадекватным время работы тестов.

Серьёзно. Ты забыл про вализацию конфига из 2^100 комбинаций? Здесь ровно так же — выделяем на тесты некоторый бюджет времени и распределяем в соответствии с ценой ошибки.

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

·>_Тестовых_ сценариев. И зачем это гарантировать?

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

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

·>Что такое прямой вызов и чем он отличается от обратного? И причём тут евенты?

Или ничем, или почти ничем. Эвенты — это правильный способ обратных вызовов, наименьшее количество синтаксиса при максимальных гарантиях работоспособности.

I>>·>Как иначе? Что такое ThresholdExceeded? Код в студию.

I>>Иначе — alloc free или zero gc.
·>Код в студию.

Код чего? Внутренностей GIT, который короткие структуры укладывет в регистры?

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

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


10 лет назад
на старом железе
на старом компилере
на старом рантайме
было в 20-30 раз быстрее
чем нынешний вариант дизруптора на новой платформе на новом железе на новом компилере.

Ты адекватен?
Отредактировано 18.03.2022 14:06 Pauel . Предыдущая версия .
Re[65]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 18.03.22 16:52
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Про coverage — гугли "Test Coverage & Requirement Traceability". Т.е. покрываем требования-кейсы-сценарии, а не строчки-конструкторы-используется-вызывается

Т.е. ты вбросил враньё, а мне бежать в гугл это доказывать?.. Ты адекватен?
Если считать по сценариям, то мой код был покрыт на 100% — два сценария (больше 1000 и меньше), покрыты оба. У тебя сколько? 146%, да?
Или ты наверное считаешь, что раз кукумбера нет, то значит покрываются не сценарии, а строчки? или что?

I>>>Тогда нужно просто вспомнить

I>·>Почему ты решил, что я что-то не знаю об евентах?
I>Потому, что ты задаешь вопросы, ответы на которых следуют буквально из определений. Минимального опыта достаточно, что бы понять о чем речь.
Я такие вопросы не задавал. Цитаты в студию, или не было.

I>>>А когда они появятся, то надобность в твоих моках сразу отпадает.

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

I>Пришел реквест с того конца "мы не видим от вас никаких запросов, готовьтесь платить штрафы"

I>Как быть?
Это совсем другой вопрос, и никакого отношения к "run -P e2e" не имеет.

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

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

I>Что делать будешь? Начнешь переписываться неделями-месяцами, что у тебя де тесты на моках, и там всё хорошо?

Ловить траблы в пре-проде.

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

I>·>Вот я из тебя всё пытаюсь выудить что же скрывается за "and notification $налоговая is succeed", но ты упорно скрываешь.
I>Мы же каким образом должны иметь возможность проверить, что наши запросы в живой системе реально добираются до налоговой и что штрафы нам не светят.
Это тоже никакого отношения к "run -P e2e" не имеет. Это должно обеспечиваться на уровне архитектуры всего программно-аппаратного комплекса. Например, у нас в одном месте использовался network tap. Т.е. условно говоря, записывался проходящий сетевой трафик по конкретному волокну, призмочка такая специальная, делит луч пополам. Плюс системы мониторинга, что id-шники сущностей которые мы у себя отметили как отправленные появляются в исходящем сетевом трафике. И т.п. трюки. Т.е. если к нам кто-то через неделю выкатит предъяву, что "мы X не видели", у нас были полные логи каждого сетевого пакета и даются гарантии на основании законов физики лазерного луча. А вы это тестами гарантируете?!

I>Этот же способ используется и для этого степа.

I>Подробностей, как все это устроено, ты не показал, так что извини — только общее описание.
Чем вам помогают "run -P e2e" — неясно. Ну пришли к вам из налоговкой, говорят "мы X не видели", а вы: "А мы тесты прогнали, вроде, ничё не знаем"?.
Т.е. ничего принципиально нового тесты в проде не гарантируют, всё то же можно обеспечивать в пре-проде.

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

I>·>Серьёзно? А как же тепловая смерть вселенной? На любом сколько-нибудь нетривиальном проекте этих тестов будет не сотня, а на несколько порядков больше. Да даже таймауты порядка 10 секунд повторённые сотню раз уже делают неадекватным время работы тестов.
I>Серьёзно. Ты забыл про вализацию конфига из 2^100 комбинаций? Здесь ровно так же — выделяем на тесты некоторый бюджет времени и распределяем в соответствии с ценой ошибки.
А толку-то. Даже если цена одной ошибки один наноцент, то из 2^100 комбинаций вы не покроете тестами и квинтилионную часть, даже имея на руках бюджет всей планеты.
Поэтому, сам подход покрывать все комбинации — не работает. Вообще никак. Надо делить на слои и сводить 2^100 комбинаций к 2*100 комбинаций, которые уже элементарно тестируются, но с моками.

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

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

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

I>·>Что такое прямой вызов и чем он отличается от обратного? И причём тут евенты?
I>Или ничем, или почти ничем. Эвенты — это правильный способ обратных вызовов, наименьшее количество синтаксиса при максимальных гарантиях работоспособности.
Я похоже перестал поспевать за твоей мыслью. Ответь на два вопроса:
"Прямой вызов это... . Пример кода: ..."
"Обратный вызов это... . Пример кода: ..."

I>>>·>Как иначе? Что такое ThresholdExceeded? Код в студию.

I>>>Иначе — alloc free или zero gc.
I>·>Код в студию.
I>Код чего? Внутренностей GIT, который короткие структуры укладывет в регистры?
Как ты в твоём примере с евентами сделаешь zero gc.

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

I>·>Вот тут вижу, что посылка одного жалкого евента, даже без парама, уже 1.6 наносекунд. Вот и считай сколько влезет.
I>было в 20-30 раз быстрее
I>чем нынешний вариант дизруптора на новой платформе на новом железе на новом компилере.
Дирзаптор между тредами передаёт (то что ты утверждал непременно должно быть на порядки медленнее). И блин, евенты, работают почти так же медленно как передача между тредами. Заметь, в том же бенчмарке вызов метода, который я предложил в ~50 раз быстрее.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[66]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 21.03.22 09:48
Оценка:
Здравствуйте, ·, Вы писали:

I>>Про coverage — гугли "Test Coverage & Requirement Traceability". Т.е. покрываем требования-кейсы-сценарии, а не строчки-конструкторы-используется-вызывается

·>Т.е. ты вбросил враньё, а мне бежать в гугл это доказывать?.. Ты адекватен?
·>Если считать по сценариям, то мой код был покрыт на 100% — два сценария (больше 1000 и меньше), покрыты оба. У тебя сколько? 146%, да?
·>Или ты наверное считаешь, что раз кукумбера нет, то значит покрываются не сценарии, а строчки? или что?

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

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

·>Я такие вопросы не задавал. Цитаты в студию, или не было.

Посмотри что ты сам пишешь про эвенты.

I>>И как же мы узнаем, что живая система таки шлёт запросы куда положено?

·>По мониторингу.

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

I>>Пришел реквест с того конца "мы не видим от вас никаких запросов, готовьтесь платить штрафы"

I>>Как быть?
·>Это совсем другой вопрос, и никакого отношения к "run -P e2e" не имеет.

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

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

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

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

I>>Что делать будешь? Начнешь переписываться неделями-месяцами, что у тебя де тесты на моках, и там всё хорошо?

·>Ловить траблы в пре-проде.

Бинго! Ты скромно намекаешь, что и у тебя будет тот механизм, который позволит установить факт нотификации или её отсутствия.
Раз он есть, то его и стоит использовать в интеграционных тестах.
Вобщем, тебе бы прекратить рассказывать сказки про моки ?

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

·>Это тоже никакого отношения к "run -P e2e" не имеет. Это должно обеспечиваться на уровне архитектуры всего программно-аппаратного комплекса.

именно.

> Например, у нас в одном месте использовался network tap. Т.е. условно говоря, записывался проходящий сетевой трафик по конкретному волокну, призмочка такая специальная, делит луч пополам. Плюс системы мониторинга, что id-шники сущностей которые мы у себя отметили как отправленные появляются в исходящем сетевом трафике. И т.п. трюки. Т.е. если к нам кто-то через неделю выкатит предъяву, что "мы X не видели", у нас были полные логи каждого сетевого пакета и даются гарантии на основании законов физики лазерного луча. А вы это тестами гарантируете?!


Логи, тапы, и тд — это конкретные инструменты. Важно узнать о проблеме на ранних этапах. Для этого нужно автоматизировать проверку и гонять при каждом билде-деплое.

·>Чем вам помогают "run -P e2e" — неясно. Ну пришли к вам из налоговкой, говорят "мы X не видели", а вы: "А мы тесты прогнали, вроде, ничё не знаем"?.

·>Т.е. ничего принципиально нового тесты в проде не гарантируют, всё то же можно обеспечивать в пре-проде.

Тесты препрода это косвенная проверка. Она заведомо слабее прямой.

I>>Серьёзно. Ты забыл про вализацию конфига из 2^100 комбинаций? Здесь ровно так же — выделяем на тесты некоторый бюджет времени и распределяем в соответствии с ценой ошибки.

·>А толку-то. Даже если цена одной ошибки один наноцент, то из 2^100 комбинаций вы не покроете тестами и квинтилионную часть, даже имея на руках бюджет всей планеты.

Именно! А раз так, то хватит рассказывать сказки про валидацию конфига.

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

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

Разумеется. Один же ты тут умный. Сколько ни повторяй — никак не запомнишь.

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

·>Я похоже перестал поспевать за твоей мыслью. Ответь на два вопроса:
·>"Прямой вызов это... . Пример кода: ..."
·>"Обратный вызов это... . Пример кода: ..."

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

I>>Код чего? Внутренностей GIT, который короткие структуры укладывет в регистры?

·>Как ты в твоём примере с евентами сделаешь zero gc.

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

I>>было в 20-30 раз быстрее

I>>чем нынешний вариант дизруптора на новой платформе на новом железе на новом компилере.
·>Дирзаптор между тредами передаёт (то что ты утверждал непременно должно быть на порядки медленнее). И блин, евенты, работают почти так же медленно как передача между тредами. Заметь, в том же бенчмарке вызов метода, который я предложил в ~50 раз быстрее.

И ты реально недогоняешь, что и эвент можно сделать таким же?
Re[67]: откуда такая любовь к мокам?
От: · Великобритания  
Дата: 21.03.22 12:26
Оценка: -1
Здравствуйте, Ikemefula, Вы писали:

I>>>Про coverage — гугли "Test Coverage & Requirement Traceability". Т.е. покрываем требования-кейсы-сценарии, а не строчки-конструкторы-используется-вызывается

I>·>Т.е. ты вбросил враньё, а мне бежать в гугл это доказывать?.. Ты адекватен?
I>·>Если считать по сценариям, то мой код был покрыт на 100% — два сценария (больше 1000 и меньше), покрыты оба. У тебя сколько? 146%, да?
I>·>Или ты наверное считаешь, что раз кукумбера нет, то значит покрываются не сценарии, а строчки? или что?
I>Я могу закоментить половину тестов у себя и все равно покрытие, если считать строчкаи, ниже 90 не опустится. Идея понятна?
Мне не нужна идея. Мне нужен конкретный код и ответы на конкретные вопросы.

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

I>·>Я такие вопросы не задавал. Цитаты в студию, или не было.
I>Посмотри что ты сам пишешь про эвенты.
Т.е. цитаты нет, значит не было.

I>>>И как же мы узнаем, что живая система таки шлёт запросы куда положено?

I>·>По мониторингу.
I>Вот чудо — а мониторинг как об этом узнает? Магией?
Конечно, магией. Не запуском тестов же.

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

Рассказал, там про призмочку. Ещё как вариант — отмечать что пакет у нас считается ушедшим и что мы видели ack от налоговки.

I>>>Пришел реквест с того конца "мы не видим от вас никаких запросов, готовьтесь платить штрафы"

I>>>Как быть?
I>·>Это совсем другой вопрос, и никакого отношения к "run -P e2e" не имеет.
I> Если у нас есть возможность проверить, дошел ли запрос в налоговую или нет, если ты конечно не про магию, то ровно так же будет выполнен и шаг в e2e.
Круто, но что e2e гарантирует-то? Ситуация "никаких запросов" вообще — это не проблема с которой мы можем столкнуться. Не очень понимаю какой пяткой надо писать код, чтобы такое случилось. Интереснее будет если заявят "мы не получили запрос X, готовьтесь платить штрафы" — но тут ваши e2e пойдут лесом.

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

I>·>Всё что ты перечислил — относится к релизному артефакту и никакого отношения к прод-енву не имеет. А значит это всё можно тестировать до выкатки в прод, хоть даже на машине разработчика. Или у вас при выкатке в прод выбираются случайные http-агенты случайных версий?!
I>Во первых, ты стесняешься прямо сказать, что твоих моков недостаточно При этом, если есть такие тесты, то не совсем понятно, то что сверх этого дают моки? :xz
Я не говорил, что моками можно протестировать всё и их для всего достаточно, я говорю, что всё что тестируется, протестировать можно в пре-прод и этого достаточно. Моки ускрояют фидбек.

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

Всё что ты перечислил — относится к релизному артефакту и никакого отношения к прод-енву не имеет.

I>>>Что делать будешь? Начнешь переписываться неделями-месяцами, что у тебя де тесты на моках, и там всё хорошо?

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

I>Раз он есть, то его и стоит использовать в интеграционных тестах.

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

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

I>·>Это тоже никакого отношения к "run -P e2e" не имеет. Это должно обеспечиваться на уровне архитектуры всего программно-аппаратного комплекса.
I>именно.
Угу. И зачем ты это всё рассказывал в контексте доказательства необходимости тестов в проде?

>> Например, у нас в одном месте использовался network tap. Т.е. условно говоря, записывался проходящий сетевой трафик по конкретному волокну, призмочка такая специальная, делит луч пополам. Плюс системы мониторинга, что id-шники сущностей которые мы у себя отметили как отправленные появляются в исходящем сетевом трафике. И т.п. трюки. Т.е. если к нам кто-то через неделю выкатит предъяву, что "мы X не видели", у нас были полные логи каждого сетевого пакета и даются гарантии на основании законов физики лазерного луча. А вы это тестами гарантируете?!

I>Логи, тапы, и тд — это конкретные инструменты. Важно узнать о проблеме на ранних этапах. Для этого нужно автоматизировать проверку и гонять при каждом билде-деплое.
Моки же.

I>·>Чем вам помогают "run -P e2e" — неясно. Ну пришли к вам из налоговкой, говорят "мы X не видели", а вы: "А мы тесты прогнали, вроде, ничё не знаем"?.

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

I>>>Серьёзно. Ты забыл про вализацию конфига из 2^100 комбинаций? Здесь ровно так же — выделяем на тесты некоторый бюджет времени и распределяем в соответствии с ценой ошибки.

I>·>А толку-то. Даже если цена одной ошибки один наноцент, то из 2^100 комбинаций вы не покроете тестами и квинтилионную часть, даже имея на руках бюджет всей планеты.
I>Именно! А раз так, то хватит рассказывать сказки про валидацию конфига.
Это не сказки, конфиг (и не только) валидировать можно сводя N*M -> N+M, чтобы не было необходимости перебирать 2^100 комбинаций. Вариативности юзерских действий в реальном приложении на порядки порядков больше, чем в каком-то конфиге.

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

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

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

I>·>Я похоже перестал поспевать за твоей мыслью. Ответь на два вопроса:
I>·>"Прямой вызов это... . Пример кода: ..."
I>·>"Обратный вызов это... . Пример кода: ..."
I>Это снова твои познания про эвенты. Извини, у меня нет задачи учить тебя таким вещам.
Меня не надо учить, я пытаюсь понять что ты имеешь в виду. Но видимо, у тебя нет задачи чтобы собеседник тебя понимал...

I>>>Код чего? Внутренностей GIT, который короткие структуры укладывет в регистры?

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

I>>>было в 20-30 раз быстрее

I>>>чем нынешний вариант дизруптора на новой платформе на новом железе на новом компилере.
I>·>Дирзаптор между тредами передаёт (то что ты утверждал непременно должно быть на порядки медленнее). И блин, евенты, работают почти так же медленно как передача между тредами. Заметь, в том же бенчмарке вызов метода, который я предложил в ~50 раз быстрее.
I>И ты реально недогоняешь, что и эвент можно сделать таким же?
Можно и зайца научить курить, но это явно будет не проще банального вызова метода.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[68]: откуда такая любовь к мокам?
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 21.03.22 13:50
Оценка:
Здравствуйте, ·, Вы писали:

I>>·>Или ты наверное считаешь, что раз кукумбера нет, то значит покрываются не сценарии, а строчки? или что?

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

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

I>>Вот чудо — а мониторинг как об этом узнает? Магией?

·>Конечно, магией. Не запуском тестов же.

Непонятно, что за магия такая. Как она работает и кто эту магию коммитает в репозиторий?

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

·>Рассказал, там про призмочку. Ещё как вариант — отмечать что пакет у нас считается ушедшим и что мы видели ack от налоговки.

В чем это проявляется "видели ack от налоговой" ?

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

·>Круто, но что e2e гарантирует-то? Ситуация "никаких запросов" вообще — это не проблема с которой мы можем столкнуться.

Элементарно. Конфиг не тот. Некто для прода вписал noop. А e2e проверяет наличие запроса, видит отсутствие наличия и зажигает красную лампочку.

I>>Во первых, ты стесняешься прямо сказать, что твоих моков недостаточно При этом, если есть такие тесты, то не совсем понятно, то что сверх этого дают моки? :xz

·>Я не говорил, что моками можно протестировать всё и их для всего достаточно, я говорю, что всё что тестируется, протестировать можно в пре-прод и этого достаточно. Моки ускрояют фидбек.

Ускорение фидбека дают обычные юнит-тесты. А моки это способ тестирования "как унутре вызывается". Ну вызвали как то иначе, результат тот же. Моки поломались. Где тут "ускорение фидбека"?

Каким образом моки помогут ускорить фидбек про кривой конфиг, депенденсы, энвайрмент и тд?

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

·>Всё что ты перечислил — относится к релизному артефакту и никакого отношения к прод-енву не имеет.



I>>Раз он есть, то его и стоит использовать в интеграционных тестах.

I>>Вобщем, тебе бы прекратить рассказывать сказки про моки ?
·>Интеграционные тесты могут работать с моками, если вендор не имеет тестовых endpoints (или имеет, но недостаточно для наших тестовых енвов).

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

I>>·>Это тоже никакого отношения к "run -P e2e" не имеет. Это должно обеспечиваться на уровне архитектуры всего программно-аппаратного комплекса.

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

Смотри сюда:

I>Пришел реквест с того конца "мы не видим от вас никаких запросов, готовьтесь платить штрафы"
I>Как быть?
Это совсем другой вопрос, и никакого отношения к "run -P e2e" не имеет.

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

>>> Например, у нас в одном месте использовался network tap. Т.е. условно говоря, записывался проходящий сетевой трафик по конкретному волокну, призмочка такая специальная, делит луч пополам. Плюс системы мониторинга, что id-шники сущностей которые мы у себя отметили как отправленные появляются в исходящем сетевом трафике. И т.п. трюки. Т.е. если к нам кто-то через неделю выкатит предъяву, что "мы X не видели", у нас были полные логи каждого сетевого пакета и даются гарантии на основании законов физики лазерного луча. А вы это тестами гарантируете?!

I>>Логи, тапы, и тд — это конкретные инструменты. Важно узнать о проблеме на ранних этапах. Для этого нужно автоматизировать проверку и гонять при каждом билде-деплое.
·>Моки же.

I>>·>Чем вам помогают "run -P e2e" — неясно. Ну пришли к вам из налоговкой, говорят "мы X не видели", а вы: "А мы тесты прогнали, вроде, ничё не знаем"?.

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

I>>>>Серьёзно. Ты забыл про вализацию конфига из 2^100 комбинаций? Здесь ровно так же — выделяем на тесты некоторый бюджет времени и распределяем в соответствии с ценой ошибки.

I>>·>А толку-то. Даже если цена одной ошибки один наноцент, то из 2^100 комбинаций вы не покроете тестами и квинтилионную часть, даже имея на руках бюджет всей планеты.
I>>Именно! А раз так, то хватит рассказывать сказки про валидацию конфига.
·>Это не сказки, конфиг (и не только) валидировать можно сводя N*M -> N+M, чтобы не было необходимости перебирать 2^100 комбинаций. Вариативности юзерских действий в реальном приложении на порядки порядков больше, чем в каком-то конфиге.

Это как раз сказки N+M это не чудо, а минимально необходимая граница, которая хоть что либо гарантирует.

I>>Это снова твои познания про эвенты. Извини, у меня нет задачи учить тебя таким вещам.

·>Меня не надо учить, я пытаюсь понять что ты имеешь в виду. Но видимо, у тебя нет задачи чтобы собеседник тебя понимал...

Ты продолжаешь думать в терминах своей jvm. Каким чудом я тебе могу что либо объяснить, если ты код не понимаешь?

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

I>>И здесь не нужно писать какого то особенного кода, это дефолтная фича рантайма, т.е. JIT.
·>А ещё у рантайма есть такая фича — боксинг.

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

>Но кода, как я понял, я не увижу... Поэтому придётся оставить твои высказывания как недоказанными.


Это у вас в джаве zero gc это ужос-ужос. А в дотнет, например, достаточно class поменять на struct и весь zero gc достанется забесплатно.
struct X { Id from; Id to; decimal amount;  }

void f(X a) {
}

f(new X() {from = f, to = t, amout = a}) // zero gc, никакого боксинга, памяти прямо на стеке или даже прямое использование регистра


I>>И ты реально недогоняешь, что и эвент можно сделать таким же?

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

Мы уже вроде говорили, что эвент можно банальным вызовом метода сделать. Что тебя не устраивает?
f(x) // прямой вызов
f(x) // обратный вызов

Видишь разницу?
Отредактировано 21.03.2022 14:39 Pauel . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.