Re[51]: Что такое Dependency Rejection
От: Pauel Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.01.24 20:01
Оценка:
Здравствуйте, ·, Вы писали:

P>>Вы притягивает юзера к вашим тестам. Юзера можно притянуть только к функциональным тестам. Во всех остальных он не фигурирует.

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

Вы лучше сами отмотайте, да посмотрите. Я вам про функции приложения, а вы мне про функции в джаве.

P>>Я вам подсветил, что бы полегче прочесть было

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

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

P>>1 получению размера внутреннего массива символов что есть неизменная величина

P>>2 гарантии иммутабельности соответсвующей ссылки. Т.е. никакой modify(str) не сможет легально изменить длину строки str
P>>3 джит компилятор в курсе 1 и 2 и инлайнит метод length минуя все слои абстракции, включая сам массив и его свойство

Похоже, тут вы торопились, и прочитать не успели

P>>Если вы запилите свой класс строк, нарушив или 1, или 2, компилятор ничего вам не сможет заинлайнить.

·>Бред, джит великолепно инлайнит length(), например, и у StringBuffer или даже LinkedList, и практически каждый getter/setter. И даже умеет инлайнить виртуальные функции.

Если вы вызовете str.length() сотню раз, джит сделает обращение к памяти ровно единожды — а дальше просто будет использовать значение как константу.
С мутабельной ссылкй или внутренним контейнером переменной длины так поступать нельзя
Похоже, что вы слишком торопитесь чего то настрочить

·>У тебя опять каша в голове. Напомню конткест: не провайдер времени, а nextFriday() вроде как ты собирался инлайнить.

·>Но вряд ли это всё заинлайнится, т.к. friday и работа с календарём — довольно сложный код, использующий таймзоны и календари, относительно.

У меня много чего инлайнится, и это даёт ощутимые бенефиты.

P>>Я вижу здесь другой кейс — вы так торопитесь, что обгоняете сами себя. Инлайнить методы нужно для оптимизации или изменения дизайна. В случае c Length инлайн в целях оптимизации выполнит компилятор.

·>Для оптимизации инлайнят только в в случаях если компилятор слишком тупой (что практически никогда) или случай ужасно нетривиальный (тогда и IDE не справится).

Конечная цель — оптимизация. Её можно достигнуть через изменение дизайна, например — нужные данные расположить рядом, убрать лишнее из hot path итд.

P>>Ну да — добавить компонент с конфигом и сайд-эффектом это стало вдруг нулевым изменением дизайна

·>Ну да. И? Как nextFriday() был, так и остался. Зачем менять дизайн?

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

P>>Т.е. вы не в курсе, что значение функции закешировать гораздо проще, чем мастырить LRU кеш? Более того — такую кеширующую функцию еще и протестировать проще.

·>Ты издеваешься что-ли? Мы тут конкретный пример рассматриваем. Давай расскажи, как ты nextFriday(now) закешируешь "гораздо проще", где now — это текущее время.

Вы что, не в курсе мемоизации? Разница только в том, где связывание — или "где то там" или "прямо здесь".

P>>Вот-вот. Отдельный компонент. В том то и проблема. И вам все это придется мастырить и протаскивать. Только всегда "где то там"

·>Что всё? _Добавить_ новую логику в CalendarLogic, внутри него использовать этот кеш, и собственно всё. В чём _изменение_ дизайна-то? Можно обойтись одним новым приватным полем.

Вы описали это изменение дизайна. у вас с вашим кешем как минимум новые свойства у решения появились.

т проталкивать этот кеш и его настройки.
P>>Ровно так же как и у вас, только дизайн не надо перелопачивать.
·>У меня как-то так. Было
>
·>class CalendarLogic {
·>   private volatile LocalDate currentFriday;//вот наш кеш
·>   constructor... {
·>      var updater = () => currentFriday = doSomeComputations(instantSource.now());
·>      timer.schedule(updater, ... weekly);
·>      updater.run();
·>   }
·>   ...
·>   LocalDate nextFriday() {
·>      return currentFriday;
·>   }
·>}
·>

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

Итого
1 — меняется внутренний дизайн компонента
2 — инжектится таймер
3 — теперь вам надо пройти по всем тестам где это аффектается и всунуть все что надо ради timer.schedule

В моем случае тесты nextFriday остаются неизменными, потому, что нет причины для изменения — кеш будет добавлен снаружи

P>>И где ваш код nextFriday и всех вариантов инжекции для разных кейсов — клиенское время, серверное, текущие, такое, сякое ?

·>А что там показывать? Вроде всё очевидно:
·>
·>var clientCalendarLogic = new CalendarLogic(timeProviders.clientClock());
·>var serverCalendarLogic = new CalendarLogic(timeProviders.systemClock());
·>var eventCalendarLogic = new CalendarLogic(timeProviders.eventTimestampClock());
·>


Вот видите — у вас ровно та же проблема, можно слегка ошибиться и clientClock уйдет в serverLogic.

P>>wiring и есть связывание. Код связывания в dependency injection, который вы называете wiring, и код связывания в контроллере — выполняют одно и то же — интеграцию. Разница отражает подходы к дизайну. И то и другое wiring, и то и другое связывание. И задача решается одна и та же. Только свойства решения разные.

·>Интересная терминология. Покажи хоть одну статью, где код в методах контроллеров называется wiring.

Если вы вызываете какую то функцию, это уже есть интеграция — то самое связывание. В моем случае я помещаю связывания в контроллер, часть — в юз кейс, см у фаулера 'src/restaurantRatings/topRated.ts'

P>>Похоже, что пример для Буравчика вы не поняли

·>Код я понял. Я не понял зачем такой код и что именно он улучшил, я предполагаю этого никто тут не понял. А про ЧПФ и классы было в обсуждаемой тут в начале топика статье.

Вводится изоляция — вместо низкоуровневой зависимости на репозиторий появляется абстракция. Ровно то же делает фаулер, 'src/restaurantRatings/topRated.ts'

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

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

Если зафейлить можно в юнит-тестах, то это всё равно быстрее вашего случая.

·>У меня аналогом будет

·>
·>var repo = mock(Repo.class);
·>var vancouverRestaurants = List.of(
·>  new Restaurant("cafegloucesterid", "Cafe Gloucester"),
·>  new Restaurant("baravignonid", "Bar Avignon"),
·>);
·>when(repo.getTopRestaurants("vancouverbc")).thenReturn(vancouverRestaurants);
·>var ratingsHandler new TopRatedHandler(repo);
·>

·>Теперь чуешь о чём я говорю что кода меньше?

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

·>
·>    const vancouverRestaurants = [
·>      new Restaurant( "cafegloucesterid", "Cafe Gloucester"),
·>      new Restaurant( "baravignonid", "Bar Avignon")
·>    ];
·>    const dependenciesStub = mock({}).whenCalledWith('getTopRestaurants', 'ляляля').returns(restaurants)
·>    const ratingsHandler: Handler =
·>      controller.createTopRatedHandler(dependenciesStub);
·>


Похоже, вы не вдупляете ни пример Фаулера, ни мой пример для Буравчика.

·>И не можете проверить что зависимости — operational? Пинг послать?

·>А для проверок consistency — нужно версирование и проверка совместимости версий. Гонять тесты — не _нужно_. Хотя, конечно, в случае хоумпейджей — можно.

Ну вот сценарий
— юзер залогинился
— добавил платежную карту
— набрал покупок
— нажал кнопку оплатить

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

P>>Смотрите пример про Колю Петрова, там ответ на этот вопрос

·>Смотрю, там нет ответа на этот вопрос. Код покажи.

Вы не знаете, что такое кукумбер? Забавно

P>>Я ж говорю — смотрите, как это у QA делается.

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

traceability matrix

P>>Примером по Колю Петрова вам показываю, что такое интеграционные тесты. Вы же в них хотите проверять "а должно вот там вызываться!"

·>В том примере неясно как отличить откуда берётся информация. Что тест проходит и работает не означает, что функциональность работает правильно.

Вот-вот.

P>>Тесты где сравнивается выхлоп из базы не решают проблемы data complexity.

·>А я где-то заявлял обратное? И расскажи заодно какие же _тесты_ _решают_ проблемы data complexity [willy-wonka-meme.gif].

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

P>>Отсюда ясно — что нужно добавлять нечто большее.

·>Причём тут тесты-то?

Вы же который раз ссылаетесь на ваши примитивные тесты именно в контексте data complexity

P>>Зато сразу ясно, где именно хоум пейдж, и почему ваши тесты работают ажно 20 минут.

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

А посоны то и не знают... @

P>>В вашем случае вы ничего не гарантируете на тех данных, что у вас нет.

·>Причём тут _мои_ тесты??! Твои _тесты_ могут гарантировать что-то большее? С какого такого бодуна?

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

P>>Примерно так же, как assert.notnull(parameter) в начале метода или return assert.notEmpty(value) в конце

·>Не понял. Откуда у тебя возьмутся все данные всех юзеров на будущее тысячелетие из assert.notnull?

Этот assert сработает для всех вызовов функции, сколько бы вы туда ни пихали, хоть тысячу лет кряду, хоть миллион.
Вы, похоже, не в курсе, как инварианты, пред-, и пост-условия используются.

P>>·>В каком месте тут телепатия? Билд занимающий часы — это твои слова. И тесты в проде — тоже.

P>>Вы всё знаете — и сложность проекта, и объемы кода, и начинку тестов, и частоту тех или иных тестов. Просто удивительно, как тонкая телепатия.
·>Так ты собственно всё рассказал. Перечитай что ты писал.

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

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

·>А где у вас основное? И почему _основное_ не покрыто тестами??!

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

P>>Почему ж не код? Это в кукумбер переводит ися практически один к одному.

·>Ну вот давай значит клей показывай.

Какой еще клей?

P>>·>Я это и сказал. Если тут всё равно серверное время, то да, не функциональное, и тесты не пострадают. Тесты сломаются и должны сломаться если ты заменишь источник серверного времени на источник клиентского времени.

P>>А вы точно интеграционные пишите? Чтото мне кажется, вы пишете высокоуровневые юнит-тесты.
·>Не буду о терминологии спорить. Не так уж важно как какие тесты классифицируются.

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

P>>Такое же, как ваши классы, методы, dependency injection итд.

·>Всё смешалось, люди, кони.

Что вам непонятно? Одна техника в программировании и другоя техника в программировании, обеими можно решить задачу.

P>>·>Тесты не могут давать гарантию.

P>> Тесты именно ради гарантий и пишутся. Только чудес от них ждать не надо.
·>Гарантий чего? Они могут лишь проверить, что тестируемый сценарий работает. Что как где устроено — никаких гарантий.

Вы сейчас плавно отказываетесь от своих слов "Тесты не могут давать гарантию"

P>>Это слишком долго. Фейлы перформанса в большинстве случаев можно обнаруживать прямо во время юнит-тестирования.

·>Наивный юноша.

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

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

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

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

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

·>Мде.

Именно. Вопрос в том, умеете ли вы сделать это дешовым в тестах или нет.

P>>Они показывают, выполнимы ли сценарии под нагрузкой(при изменениях сети, топологии, итд) или нет.

·>Для этого есть более адекватные подходы.

Вы пока ни одного ни привели.

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

·>А ты опять контекст потерял? Напомню: "Сертификат может обновиться не у вашего приложения, а у какого нибудь из внешних сервисов". Причём тут нагрузки? Причём тут Коля?

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

P>>И ежу понятно — вам максимум с собой легко интегрироваться

·>Ну других по себе не судите, а мне вот сегодня опять приходится ворошить FIX спеку от Bloomberg, 891 страниц в PDF. Не, я работаю не там.

Как думаете, сколько % от общей массы программистов заняты тем же?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.