Здравствуйте, Sinclair, Вы писали:
S>Кроме Delivered у нас ещё много промежуточных типов.
И что? Это этого количество путей не становится экспотенциальным. Каждый тип выражает некую бизнес-сущеность. Ее можно выразить через типы, можно спагетти-кодом, можно классами но как-то это сделать придеться.
PJ>>Что значит склеил? ShippableOrder их ко-произведение. Я использую логику процесса, как я его понимаю. На мой взгляд готовность к отправке не зависит от статуса оплаты, по твоим объяснениям.
S>Да, не зависит. Но мне непонятно, как вы собираетесь получать из ShippableOrder при помощи одной операции два разных типа — UnpaidShippedOrder и PaidShippedOrder.
Никак это один тип: UnpaidShippedOrder | PaidShippedOrder, или OneOf<UnpaidShippedOrder, PaidShippedOrder>
PJ>>Зачем нужен второй prepareToShip я не представляю, но вполне допускаю, что смысл в этом может быть. Но, в этом случае, хоть с типами, хоть без, у тебя ровно два решения: две функции или две ветки if-else. А как еще?
S>Ну, очень просто. В плюсах это была бы частичная специализация; в C#/Java у нас была бы простая проверка предусловия.
Ну т.е. две функции и if-else. Я ровно это и сказал.
S> Причём, возможно, вообще не выраженного в коде приложения — была бы конфигурация предиката, которую может править администратор вообще без единого запуска компилятора. Кто ж может себе позволить ре-компиляцию и ре-деплоймент каждый раз, как надо изменить одно из правил
Т.е. администратор может изменить правила и отправить себе бесплатно посылку, без постоплаты? Тогда мы о разном говорим.
S>S>public static void ShipOrder(Order o)
S>{
S> Assert(ShippingManager.IsShippingAddressValid(o.ShipmentMethod, o.ShippingAddress);
S> Assert(BillingManager.IsOrderOkForDelivery(o.BillingMethod, o.Customer);
S> Assert(o.ProcessingStage == ProcessingStage.ReadyForPickup);
S> var pickupSchedule = ShippingManager.SchedulePickup(o);
S> OrderManager.SetStage(ProcessingStage.PickupScheduled, pickupSchedule);
S>}
S>
В случае администратора, который поменял правила не запуская компилятора, этот код может просто грохнуться.
Если у тебя поменяется любое из правил, тебе придется руками найти все места где это надо исправить, делать так каждый раз и компилятор тебе ничем не поможет.
PJ>>Реально заначимый код это sunny day path. Все остальное это бойлерплейт. Удачи с таким кодом.
S>По моему опыту, sunny day path — это 7% кода. Как раз он и есть boilerplate. Всё остальное — это детальные политики того, что делать, когда всё пойдёт не так.
В примере выше у тебя как раз sunny day и есть, с крэшем во всех остальных случаях.
S>Фрод скрининг, пересортица, обработка отказов сети, обработка отказов от партнёров, вот это вот всё. Потому что happy path — в основном один, или два, а способов сломаться — много.
Именно поэтому поддерживать все это в виде "политик" ага спагетти кода — крайне трудоемко и с большим количеством вероятных ошибок. Типы позволяют не пропустить не один из сценариев, сделать правильную декомпозицию и сосредоточится именно на бизнес-процессе.
Все это делается гораздо проще и надежнее. Вот почитай
https://fsharpforfunandprofit.com/rop/
Хотя сам термин и как он используется в F# мне, лично, не нравится. Это просто паттерн и не обязательно про ошибки. Ну хоть так...
S> и C# всё отлично откомпилирует, а F# бы дал по рукам?
Единственное место где F# дает по рукам это неявное приведение типов. int и unit это разные типы. В остальном C# позволяет выражать все то же самое, но большим количеством кода.
Если сравнивать типичный C# код, с "правильным" F# кодом, то таки да. Руки отобьет.
PJ>>Смысл моей фразы в том, что все описанное на f# можно сделать и на c#. Я вовсе не призываю тебя писать на c#, если есть возможность писать на f#, это было бы слабоумно. Но такая возможность не всегда доступна.
S>А этот смысл — он чем-то другой, чем "все тьюринг-полные языки функционально эквивалентны"? Ну, т.е. следует ли из того, что всё, описанное на F#, можно сделать и на IL, оправданность применения IL для описания вот этих вот систем зависимых типов?
Писать на IL необходимости нет, писать на C# у многих вынужденная. Зачем сравнивать какие-то нелепости? На RSDN F# считается мертвым языком, а c# вполне себе популярен. Я не уговариваю писать на C#, но пишут.
PJ>>То же самое и в C# или любом другом языке. Либо ты больше используешь компилятор, либо дебаггер. Как-то так...
S>Не вполне понимаю всё же как именно выносить сайд-эффекты на "границы домена".
Как именно, это не про DDD, это просто паттерн IO/Actions.