Здравствуйте, Pauel, Вы писали:
P>>>·>Не понял, чем отличается 1 от 2? "все виды" это разве не "удалить"+"выгрузить"?
P>>>Разница в слове "отложенные". У вас недавно была проблема с этим словом. Решилась?
P>·>У нас такой проблемы не было.
Т.е. разницы нет. ЧТД.
P>Забавный аргумент — у вас чего то там не было
Мощный заход, внушает!
Ты нафантазировал, что у нас есть проблемы с отложенными вычислениями. Какой ты аргумент ожидаешь на такие фантазии?
>> Причём тут обсуждаемый "инлайн nextFriday"? У тебя там Time.now будет константным, да?
P>Вы зачем то полезли в инлайн строк 
Я пример привёл, что инлайн сам по себе ни о чём не говорит. Ладно, если тебе строки не устраивают, пусть будет list.length() — с инлайном тоже ничего не выйдет.
P>>>Джава компилятор на основании иммутабельности умеет вводить кое какие оптимизации. Строки — одна из таких вещей.
P>·>Допустим, и причём тут инлайн?
P>Это вы мне объясните, для чего вам понадобилось инлайнить строки. Это ж ваш аргумент был.
Я объяснил, что метод length инлайнить не выйдет, но это вовсе не оозначает, что это какое-то плохой дизайн и код куда-то как-то прибит.
P>Я вам показал, что с str.length() у нас всё близко к идеалу — компилятор и джит без вас умеют инлайнить не абы как, а практически в константу.
Пусть будет list.length(). Дались тебе эти константы, вообще к теме не относится.
P>>>"как то"
Не как то, а вручную вместо работы компилятором и ИДЕ.
P>·>Это твои фантазии, или кривая IDE, или неумение ею пользоваться.
P>Вы пока так и не показали, как будете свой nextFriday инлайнить. Ваш последний аргумент — сбежать в сторону "заинлайни str.length()"
Ты так и не рассказал с какой целью инлайнить.
P>>>А протаскивание такого конфига — тот еще код. Особенно когда это все инжектится
P>·>"изменение конфига" != "протаскивание конфига".
P>Весело у вас — изменение конфига не является кодом,
Конфиг это какой-нибудь тупой key=value файлик или около того, или файл с сертом например. Это ты правда это считаешь кодом?
P>изменение дерева депенденсов не является кодом, добавление параметра в конструктор не является кодом...
Является, конечно. И ты это называешь изменением дизайна.
P>Что еще у вас кодом не является?
А что у вас не является изменением дизайна?
P>Зато интерфейс с аннотациями без реализации у вас почему то "ужос-ужос это код!!!!111111"
Опять какая-то твоя больная фантазия. Цитаты ведь не будет как всегда.
P>·>Он _вам_ ответил. Его ответ — другое решение, которое и в моём коде тоже реализуется тривиально. Его решение иногда не подойдёт в том, что у него будет latency spike на cache miss. А моё решение с таймером в твоём коде не реализуется, придётся всё везде перелопачивать. ЧТД — мой код универсальнее, не требует изменения дизайна на каждый чих.
P>Не нужно ничего перелопачивать — будет ровно такая же функция как у Синклера, только кеширование будет иначе сделано.
А ты вот потрудись код написать, и опять увидишь что погорячился.
P>В этом случае мы основную бл тестируем без изменений — эта функция вообще не изменится. Для неё как были тесты по таблице истинности, так и остались.
Ну да, у меня тоже. В чём у тебя возникли сложности-то?
P>>>Нет, не нужно — функция где БЛ никак не изменилась, ни внутри, ни снаружи. Изменилась исключительно интеграция.
P>·>Ага, но у тебя интеграции — на каждый вызов nextFriday из множества методов контроллеров. У меня интеграция wiring — ровно одна строчка.
P>Вам нужно в каждый компонент явно вписывать это как зависимость, и не ошибаться — где клиентское, где серверное, где текущее, где предзаписаное время.
И? Это всё покрыто легковесными тестами, с проверками ожиданий правильности источника времени.
P>>>В вашем случае вы перепахали внутрянку той самой функции
P>·>Ну вы тоже.
P>Нисколько. Сама функция осталась без изменений. Смотрите пример Синклера внимательно — он вызывает основную функцию, а не модифицирует её.
Ты либо его код не понял, либо мой. Основная функция расчётов у него "SlowlyCalculatePrevAndNextFridays", у меня "doSomeComputations".
Да, кстати, у его решения ещё один огромный недостаток. Его реализация
неявно подразумевает, что передаваемый "DateTime dt" это DateTime.Now, т.е. плавно изменяющийся параметр, только тогда кеш будет пересчитываться раз в неделю. Кто-то видя сигнатуру
nextFriday(DateTime dt) — запросто может позвать её с чем попало, выкашивая кеш в самые неожиданные моменты времени. Отличная такая грабля будущим поколениям, happy debugging. Более того, чтобы даже просто начать такую оптимизацию метода — надо будет исследовать все call sites и удостовериться что туда передаётся именно текущее время, иначе кеш может быть бессмысленным, а в большом проекте эта штука может жить в шаред либе и задача вообще практически неразрешимой становится.
В моём же случае, nextFriday() явно запрещает туда передать что-то не то. Знание об источнике времени тут есть явно. И такие оптимизации делать становится гораздо проще, с более предсказуемым импактом. Иными словами, мы знаем конкретный применённый аргумент ЧПФ и эту информацию фиксируем явно и можем использовать.
P>·>"Снаружи" это откуда? А проблема в том, что множество мест связки nextFriday с Time.now ты протестировать никикак не можешь. Ещё раз повторюсь: ЧПФ. У тебя его нет.
P>Буквально "вызываем метод с параметром x" — такого не будет. И не нужно. А все, что дает конкретные результаты — будет ровно как у вас.
Я это и не спрашивал. Я спрашивал "результат зависит от Time.now", а не от чего-то ещё. C Time.now ты не можешь получить "
конкретный результат", по определению.
P>>>С каких пор низкоуровневые приседания стали проще?
P>·>Я не знаю что называешь низкоуровневыми приседаниями.
P>Посмотрите внимательно — Фаулер для компонента протаскивает не абы что, репозитории-кеши-итд, а интерфейс взаимодействия
Просто выражено в терминах явы-шарпов "интерфейс с одним методом". getTopRestaurants — это и есть репозиторий по сути. Для ts оно ок наверное, но в яву-шарп такое лучше не тащить.
P>·>Я правильно понял?
P>Чтото навроде, примерно так же и у вас.
Ок. Круто, договорились, наконец-то. Теперь расскажи, как в твоей голове согласуется "код
без использования
моков" и "
mock<AnInterface>"?
P>>>P>>>mock<AnInterface>().whenCalledWith('getTopRestaurants', 'ляляля').returns(restaurants)[/tt]
P>>>
P>>>Что теперь, попросите показать как это всё типизуется?
P>·>Да, серьёзно, Интересно. Ведь в коде теста никакого AnInterface даже и нет
P>Есть, глаза разуйте. Фаулер конструирует этот самый интерфейс. А раз он есть, то можно и тип оформить.
Я не вижу, ткни в строчку кода. Откуда ты возьмёшь AnInterface
тут?
>> , фаулер за типы топит, которые не export. Автодополнятор вставит строчку 'getTopRestaurants' сам? Найдёт|отрефакторит имя функции и определит типы ляляля параметров?
P>Найдет. Отрефакторит. Определит. В тайпскрипте есть внятный вывод типа, и вы можете вывести тип тупла аргументов метода по его имени, тип возвращаемого значения, итд и тд. А раз есть тип, то у нас будет статический контроль и whenCalledWith, и returns, и много чего другого.
Круто, если так. Но ни шарп, ни ява так не умеет. Там такое просто не прокатит.
P>>>Смотря что вам надо. Серебряную пулю — такого нет. Составить список требований, сделать ревью, предложить дизайн, сделать ревью, написать тесты, сделать ревью, написать код, сделать ревью, пофиксить баги, сделать ревью — по моему так всё и делается.
P>·>Именно. Вот это всё и ещё маленько — оно может давать гарантию. Тесты же гарантию давать не могут, или ты так своё умение варить кашу из топора демонстрируешь?
P>Без тестов гарантий никаких не будет.
Да и в той притче каши без топора таки не было.
P>Нужно всё вместе:
P>1 Код ревью не работает в том случае, когда его можно скипнуть
P>2 Тесты не работают, когда их можно обойти
P>Что бы добиваться качества, вам нужно решить обе этих проблемы.
Угу. И?
P>·>Опять у тебя какая-то особая терминология. Под запросом я имею в виду данные приходящие от клиентов через внешний апи. Вот то что условный curl посылает — это запрос.
P>А я вам про принимающую сторону. Серверное и текущее время вы получаете забесплатно.
Допустим. Вопрос-то как проверить, что именно нужный источник времени используется где-то там для расчёта каких-то результатов?
P>А клиентское и так придет в виде значения, если у вас в апи так прописано.
curl генерит клиентское время сам где-то там внутре.
P>·>Реальным клиентам пофиг что у вас за такие сценарии A...Z и когда они у вас гоняются. Им надо их сценарии.
P>Забавно — это вы всерьёз покрываете тестами левые сценарии? Или это вам видится, что все вокруг вас дураки?
Тестовые сценарии != реальные сценарии.
P>>>Зачем?
P>·>Чтобы можно было пальчиком тыкнуть где конкретно ты заблуждаешься.
P>Я так понимаю, хорошего примера у вас нет.
Примера чего?
P>>>Голословно. Любой большой кусок кода нужно в первую очередь тестировать непосредственно.
P>·>Зачем?
P>1. чем больше кода между замерами, тем хуже детализация ошибок
P>2. чем больше косвенность, тем вам труднее покрыть основные пути хоть с какой нибудь детализацией
Для этого и используют разделение на юниты и юнит-тестирование. А моками отрезаются комбинации деталей.
P>Это особенности тестов вообще. Потому и убирают лишнее из тестового кода, и тут два основных подхода, оба основаны на отделении эффектов и зависимостей:
P>1. моки — тот подход, который вам кажется единственно верным, т.е. обрезание, подмена зависимостей и эффектов
Не то, что единственно верный, но практически неизбежный в достаточно сложной программе.
P>Пример — обмазали моками и написали тест "таймер вызывается дважды с такими вот аргументами"
Тебе уже двое раз 30 раз повторили — что так делать не надо.
P>2. классический — вытеснение зависимостей и эффектов в код верхнего уровня
P>Пример "sin(x) = y"
Это работает только на хоумпейджах. Чуть сложнее и внезапно выяснится что там этих самых верхних уровней штук пять.
А 3. где? В Ложную Дилемму поиграть решил?
P>>>А вы предлагаете всё делать наоборот.
P>·>Конечно. Т.к. надо тестировать поведение, а не детали реализацию.
P>Тестируется как раз наблюдаемое поведение вычислителя фильтров. Вычислитель фильтров обычная чистая функция, в ней ничего военного нет — тестируем как любую чистую функцию.
Проблема в том, что ты её адекватно протетсировать не можешь. Ассертить имена приватных функций и буквальные тексты запроса — такие тесты — бессмысленные и беспощадные.