Здравствуйте, Sinclair, Вы писали:
S>·>Да, кстати, у его решения ещё один огромный недостаток. Его реализация неявно подразумевает, что передаваемый "DateTime dt" это DateTime.Now, т.е. плавно изменяющийся параметр, только тогда кеш будет пересчитываться раз в неделю. Кто-то видя сигнатуру nextFriday(DateTime dt) — запросто может позвать её с чем попало, выкашивая кеш в самые неожиданные моменты времени. Отличная такая грабля будущим поколениям, happy debugging. Более того, чтобы даже просто начать такую оптимизацию метода — надо будет исследовать все call sites и удостовериться что туда передаётся именно текущее время, иначе кеш может быть бессмысленным, а в большом проекте эта штука может жить в шаред либе и задача вообще практически неразрешимой становится. S>Это работает не совсем так. S>Смотрите, любая оптимизация начинается с профилирования и им же заканчивается. S>То есть перед тем, как что-то на что-то менять, мы берём и снимаем профиль. S>И вот когда мы по профилю видим, что эта функция становится bottleneck, тогда мы и начинаем её оптимизировать. S>Когда мы её оптимизируем, мы, конечно же, смотрим на характер нагрузки. Если у нас там приходит небольшое количество одинаковых значений — мы оборачиваем функцию в memoize, проверяем результат, и едем разгребать следующую таску из джиры.
У меня будет изначально nextFriday() — с которой всё просто, характер "главного" параметра ЧПФ известен. Поэтому такой проблемы не будет в принципе, функция в местах использования одна — вариант использования один, параметров нет.
Конечно, если в моём случае вдруг возникнет необходимость посчитать nextFriday(platezhka.date) — тогда мне придётся ввести новую функцию (новую, т.е. менять ничего не приходится, от чего так страдает Pauel с его постоянными изменениями дизайна) и она будет отдельной и там уже будем посмотреть где что как анализировать и оптимизировать, нужно ли кешировать, если нужно то как.
В твоём случае же решение хоть более универсальное, но за универсальность нужно платить. Ты исходишь из изначально неудачно задизайненного случая. У тебя есть некая универсальная nextFriday(someDay) хотя она везде по факту (вроде бы... надо тщательно проверять по всему коду!), используется только как nextFriday(now), ну значит давайте просто сунем в wrapAndCacheMonotonous, да закроем джиру. Ура. Но знание о том, что этот кеш требует определённый характер значений параметра — нигде в коде не зафиксировано; и когда в следующей джире через год потребуется nextFriday(platezhka.date) — просто так и напишут, проблему обнаружат только потом, когда заметят что кеш теряется в неожиданные моменты времени, придётся искать в мониторинге и метриках корреляцию между внезапными провалами в производительности и запросами, когда клиент приходит со слишком старой платёжкой, что случается только после дождичка в четверг в полнолуние. Happy debugging.
S>Сам подход работает совершенно независимо от выбранной архитектуры — ФП, ПП, или ООП. Но у вас, похоже, возникает иллюзия, что вы можете написать реализацию, которая будет не просто оптимальна, но и устойчива ко всем будущим изменениям характера нагрузки.
Нет, я просто не стараюсь писать универсальные всемогутеры, а ровно то, что требуется для решения конкретной задачи, ну может ещё немного в соответствии с достаточно очевидными прогнозами на будущее. Ясновидец из меня никудышный, поэтому приходится выдавать решение из того что известно сейчас, а не для того, что случиться в будущем, я лучше потом порефакторю.
S>Нет, так не получится. Потому, к примеру, что у вас нет гарантий на монотонность применяемого источника времени. Если она есть у вас — то она есть и у вашего оппонента, и оптимизация сработает.
Я не про монотонность, а про то, что в nextFriday(x) — есть степень свободы что передавать в качестве x — и приходится делать предположения и анализ что может быть этим x во всём коде. В моём случае у меня явное ЧПФ nextFriday = () => nextFriday(timeSource.now()), зафиксированно знание о том, что же может быть этим самым x есть более широкий простор для оптимизаций.
S>·>В моём же случае, nextFriday() явно запрещает туда передать что-то не то. S>Это иллюзия. Вот у нас есть "фактическое время" клиента, "фактическое время" сервера. А есть ещё "время по документу клиента". Который в понедельник принёс платёжку за прошлый четверг. S>Ну и всё — вы в свой алгоритм nextFriday вынуждены воткнуть зависимость от источника времени, который просто парсит переданный с клиента JSON и возвращает то, что там нашлось. S>Отличная такая грабля будущим поколениям, happy debugging.
Вот когда появится бизнес-требование обработки старых платёжек, тогда можно будет отрефакторить, добавив новую функцию nextFriday(someDay) или даже вообще сразу ЧПФ nextFriday(platezhka).
S>·>Знание об источнике времени тут есть явно. И такие оптимизации делать становится гораздо проще, с более предсказуемым импактом. Иными словами, мы знаем конкретный применённый аргумент ЧПФ и эту информацию фиксируем явно и можем использовать. S>Ну так и мы знаем конкретный применённый аргумент, и явно фиксируем эту информацию. Только она не спрятана внутрь вашего класса с методом nextFriday, а применена по месту использования. S>Поэтому в одном месте будет прямой вызов nextFriday, а в другом — вызов функции, полученной при помощи wrapAndCacheMonotonous(nextFriday). S>При этом поведение wrapAndCacheMonotonous(nextFriday) мы тестируем тем же набором тестов, что и саму nextFriday (т.к. у них одинаковый контракт). И нам не нужны никакие моки, которые изображают поведение часов.
Ну как выяснили, немного меняется синтаксис в коде теста, больше разницы никакой. Т.е. первый параметр ЧПФ идёт "особым" образом, остальное всё то же самое.
P>>>·>"Снаружи" это откуда? А проблема в том, что множество мест связки nextFriday с Time.now ты протестировать никикак не можешь. S>Положа руку на сердце: сколько таких мест вы ожидаете в крупном проекте? Три, пять?
Не очень понял что ты именно спрашиваешь, ясен пень, что nextFriday я вообще считаю такого не будет нигде. Аналогом могу придумать например бизнес-понятие tradeDate() — текущий торговый день биржи. Который обычно переключается раз в сутки, зависит от системный часов, таймзоны биржи, официального времени работы с учётом праздников, т.е. вычисление не очень тривиально, но значение используется очень часто и из разных мест, в т.ч. и latency sensitive.
Иметь синглтон static-кеш как у тебя — просто недопустимо, т.к. торговая система может работать с толпой разных бирж.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай