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

P>>·>Не понял, чем отличается 1 от 2? "все виды" это разве не "удалить"+"выгрузить"?

P>>Разница в слове "отложенные". У вас недавно была проблема с этим словом. Решилась?
·>У нас такой проблемы не было. Т.е. разницы нет. ЧТД.

Забавный аргумент — у вас чего то там не было Мощный заход, внушает!

> Причём тут обсуждаемый "инлайн nextFriday"? У тебя там Time.now будет константным, да?


Вы зачем то полезли в инлайн строк

P>>Джава компилятор на основании иммутабельности умеет вводить кое какие оптимизации. Строки — одна из таких вещей.

·>Допустим, и причём тут инлайн?

Это вы мне объясните, для чего вам понадобилось инлайнить строки. Это ж ваш аргумент был.
Я вам показал, что с str.length() у нас всё близко к идеалу — компилятор и джит без вас умеют инлайнить не абы как, а практически в константу.

P>>·>Можно, конечно. Но это не происходит непрерывно сто раз на дню как ты тут заявлял выше. Да, возможно раз в месяц надо поискать боттл-нек и как-то порефакторить.

P>>"как то" Не как то, а вручную вместо работы компилятором и ИДЕ.
·>Это твои фантазии, или кривая IDE, или неумение ею пользоваться.

Вы пока так и не показали, как будете свой nextFriday инлайнить. Ваш последний аргумент — сбежать в сторону "заинлайни str.length()"

P>>>>Не любое. Изменение конфига сюда не подходит.

P>>·>Конфиг это не код. Выделил жирным.
P>>А протаскивание такого конфига — тот еще код. Особенно когда это все инжектится
·>"изменение конфига" != "протаскивание конфига".

Весело у вас — изменение конфига не является кодом, изменение дерева депенденсов не является кодом, добавление параметра в конструктор не является кодом...
Что еще у вас кодом не является?
Зато интерфейс с аннотациями без реализации у вас почему то "ужос-ужос это код!!!!111111"

·>Он _вам_ ответил. Его ответ — другое решение, которое и в моём коде тоже реализуется тривиально. Его решение иногда не подойдёт в том, что у него будет latency spike на cache miss. А моё решение с таймером в твоём коде не реализуется, придётся всё везде перелопачивать. ЧТД — мой код универсальнее, не требует изменения дизайна на каждый чих.


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

P>>Нет, не нужно — функция где БЛ никак не изменилась, ни внутри, ни снаружи. Изменилась исключительно интеграция.

·>Ага, но у тебя интеграции — на каждый вызов nextFriday из множества методов контроллеров. У меня интеграция wiring — ровно одна строчка.

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

P>>В вашем случае вы перепахали внутрянку той самой функции

·>Ну вы тоже.

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

·>"Снаружи" это откуда? А проблема в том, что множество мест связки nextFriday с Time.now ты протестировать никикак не можешь. Ещё раз повторюсь: ЧПФ. У тебя его нет.


Буквально "вызываем метод с параметром x" — такого не будет. И не нужно. А все, что дает конкретные результаты — будет ровно как у вас.

P>>·>Почему он проще? Мне показалось ровно наоборот. А моки можно прикручивать без фреймворков в любом случае. Правда количество кода увеличивается.

P>>С каких пор низкоуровневые приседания стали проще?
·>Я не знаю что называешь низкоуровневыми приседаниями.

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

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

·>
·>const dependenciesStub = mock<AnInterface>().whenCalledWith('getTopRestaurants', 'ляляля').returns(restaurants);
·>const ratingsHandler: Handler = controller.createTopRatedHandler(dependenciesStub);
·>

·>Я правильно понял?

Чтото навроде, примерно так же и у вас.

P>>Вот вам типы в TypeScript:

P>>
P>>mock<AnInterface>().whenCalledWith('getTopRestaurants', 'ляляля').returns(restaurants)[/tt] 
P>>

P>>Что теперь, попросите показать как это всё типизуется?
·>Да, серьёзно, Интересно. Ведь в коде теста никакого AnInterface даже и нет

Есть, глаза разуйте. Фаулер конструирует этот самый интерфейс. А раз он есть, то можно и тип оформить.

> , фаулер за типы топит, которые не export. Автодополнятор вставит строчку 'getTopRestaurants' сам? Найдёт|отрефакторит имя функции и определит типы ляляля параметров?


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

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

·>Именно. Вот это всё и ещё маленько — оно может давать гарантию. Тесты же гарантию давать не могут, или ты так своё умение варить кашу из топора демонстрируешь?

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

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


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

P>>Нет такого "проверка работоспособности" — это менеджерский сленг. Есть выполнение сценариев А...Z, тесты для всевозможных ...ility, итд итд

P>>То есть, находим конкретные свойства, которые покрываем тестами на том или ином уровне, в зависимости от вашего инструментария
·>Реальным клиентам пофиг что у вас за такие сценарии A...Z и когда они у вас гоняются. Им надо их сценарии.

Забавно — это вы всерьёз покрываете тестами левые сценарии? Или это вам видится, что все вокруг вас дураки?

P>>Зачем?

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

Я так понимаю, хорошего примера у вас нет.

P>>Голословно. Любой большой кусок кода нужно в первую очередь тестировать непосредственно.

·>Зачем?

1. чем больше кода между замерами, тем хуже детализация ошибок
2. чем больше косвенность, тем вам труднее покрыть основные пути хоть с какой нибудь детализацией
Это особенности тестов вообще. Потому и убирают лишнее из тестового кода, и тут два основных подхода, оба основаны на отделении эффектов и зависимостей:
1. моки — тот подход, который вам кажется единственно верным, т.е. обрезание, подмена зависимостей и эффектов
Пример — обмазали моками и написали тест "таймер вызывается дважды с такими вот аргументами"
2. классический — вытеснение зависимостей и эффектов в код верхнего уровня
Пример "sin(x) = y"

P>>А вы предлагаете всё делать наоборот.

·>Конечно. Т.к. надо тестировать поведение, а не детали реализацию.

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