Re[80]: Haskell нужен! (в Standard Chartered Bank)
От: genre Россия  
Дата: 12.03.15 10:42
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Но в функции pay_order вы вряд ли найдёте развесистую логику, в которой из разных веток вызываются методы, к которым можно придумать нетривиальные предусловия.

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

Все верно. Задача системы типов в данном случае заставить программиста написать эти банальные проверки.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[81]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.03.15 18:01
Оценка:
Здравствуйте, genre, Вы писали:
S>>Поэтому банальные проверки бизнес-правил в начале функции, и выброс исключения в случае их нарушения прекрасно сработают и без ввода сложной системы типов.
G>Все верно. Задача системы типов в данном случае заставить программиста написать эти банальные проверки.
Не получится. В данном случае — это как порошок от блох, который нужно сыпать в глаза каждой блохе.
Т.е. сначала программист должен не забыть написать "типы", которые заставят его сделать проверку, а потом должен сделать эту проверку.
Ему куда проще написать сразу сами проверки.
Вы попробуйте в качестве упражнения написать мало-мальски реалистичную функцию pay_order(Order o, Payment p). Вы устанете выносить из неё подфункции, которые можно было бы типизировать так, чтобы "заставить программиста написать эти банальные проверки".
Вот, скажем, близкий к рабочему пример:
void pay_order(Order o, Payment p)
{
   
    Assert(o.PaymentStatus != PaymentStatus.Paid, "An order cannot be paid twice. Detach an existing payment from order prior to attaching another payment");
    Assert(p.UsedFor == null, "This payment is already used to pay another order");
    Assert(o.Amount == p.Amount, "Payment amount must exactly match the order amount");
    Assert(p.Status >= Verified, "Only verified payments can be used to pay the orders");
    
    p.UsedFor = o;
    o.Payment = p;
    o.PaymentStatus = PaymentStatus.Paid;
}

Покажите, как система типов поможет "заставить программиста написать эти банальные проверки".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[82]: Haskell нужен! (в Standard Chartered Bank)
От: AlexRK  
Дата: 12.03.15 18:37
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Т.е. сначала программист должен не забыть написать "типы", которые заставят его сделать проверку, а потом должен сделать эту проверку.

S>Ему куда проще написать сразу сами проверки.

Здесь уже несколько раз говорилось — если проверки присутствуют в программе в единственном экземпляре каждая, то, конечно же, писать для них типы бессмысленно.
А если у вас N проверок и M их комбинаций в разных функциях (которые могут еще и вызывать друг друга) — это совершенно другая ситуация.
Как часто встречаются подобные ситуации на практике — не знаю. Когда нет удобного инструмента для работы со всем этим (а его нет), то эти ситуации проходят мимо незамеченными.
Re[83]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.03.15 19:06
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здесь уже несколько раз говорилось — если проверки присутствуют в программе в единственном экземпляре каждая, то, конечно же, писать для них типы бессмысленно.

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

ARK>А если у вас N проверок и M их комбинаций в разных функциях (которые могут еще и вызывать друг друга) — это совершенно другая ситуация.

ARK>Как часто встречаются подобные ситуации на практике — не знаю. Когда нет удобного инструмента для работы со всем этим (а его нет), то эти ситуации проходят мимо незамеченными.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[84]: Haskell нужен! (в Standard Chartered Bank)
От: AlexRK  
Дата: 12.03.15 20:03
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Я ещё раз намекну про то, что ошибку попытки двойного взятия платежа хотелось предотвратить статически.

S>Дупа — в том, что "в программе" переходы состояний размазаны по нескольким функциям, которые общаются через нетипизированную базу.
S>На первый взгляд я не вижу способа системой типов предотвратить то, что ордер попадает в состояние awaiting_for_payment дважды в разных местах программы.

Ну да, если между изменениями состояния находится нетипизированная база, то — в случае задания предусловий на типах — компилятор вынудит ставить проверки везде после "выхода" из этой базы.
То есть статически предотвратить двойной платеж можно, но компилятор заставит писать рантайм-проверку перед каждым вызовом pay_order.
Но не везде ведь есть нетипизированная база. Топик вроде бы носит более общий характер.
Re[85]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.03.15 04:29
Оценка:
Здравствуйте, AlexRK, Вы писали:
ARK>Ну да, если между изменениями состояния находится нетипизированная база, то — в случае задания предусловий на типах — компилятор вынудит ставить проверки везде после "выхода" из этой базы.
Это в обсуждаемом конкретном подходе. Им типизация не исчерпывается.
ARK>То есть статически предотвратить двойной платеж можно, но компилятор заставит писать рантайм-проверку перед каждым вызовом pay_order.
ARK>Но не везде ведь есть нетипизированная база. Топик вроде бы носит более общий характер.
Ну, я очень удивлюсь, когда увижу типизированную базу с поддержкой хотя бы дженериков .Net, не говоря уже о шаблонах С++. И с поддержкой смены типа персистед объекта.
А до тех пор всё, что у нас есть для persistence в бизнес-приложениях — это нетипизированные базы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[86]: Haskell нужен! (в Standard Chartered Bank)
От: AlexRK  
Дата: 13.03.15 06:32
Оценка:
Здравствуйте, Sinclair, Вы писали:

ARK>>Но не везде ведь есть нетипизированная база. Топик вроде бы носит более общий характер.

S>Ну, я очень удивлюсь, когда увижу типизированную базу с поддержкой хотя бы дженериков .Net, не говоря уже о шаблонах С++. И с поддержкой смены типа персистед объекта.
S>А до тех пор всё, что у нас есть для persistence в бизнес-приложениях — это нетипизированные базы.

Я имел в виду, что базы вообще может не быть, программы же разные бывают. Например, в коде современной компьютерной игры много сложной логики.
Re[87]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.03.15 07:21
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Я имел в виду, что базы вообще может не быть, программы же разные бывают. Например, в коде современной компьютерной игры много сложной логики.

Это да. Но в ответ на вопрос "как применить развитую типизацию в системах автоматизации бизнеса" примеры из компьютерных игр не вполне подходят.
А про устройство игр я, скажем, рассуждать уже совсем неспособен — слишком я далёк от понимания того, как они внутри устроены.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[80]: Haskell нужен! (в Standard Chartered Bank)
От: jazzer Россия Skype: enerjazzer
Дата: 13.03.15 07:35
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>>Как вам удаётся написать "развесистую логику" в обработке одного шага workflow? Или вам удалось одной функцией с развесистой логикой описать workflow, который исполняется несколько недель?


J>>Ну как-то так:

J>>
J>>void next_step(Order& o)
J>>

S>Очень странно. Кто вызывает этот "next_step"? По какому событию?

По таймеру, по изменению окружения (пришла новая market data, случился (возможно) меняющий общий риск трейд, пересчиталась модель и т.п.).
По свистку, наконец (EOD jobs).

J>> Где тут место исключениям? Где тут место рантайм-ошибкам, кроме ошибок программиста?

S>Например, попытка сделать pay_order повторно на уже оплаченный ордер. Если это внешняя система — то байт им судья, могли что угодно накосячить. Но ведь может так оказаться, что мы сами накосячили. У нас в workflow попало два шага request_payment. А из-за асинхронности они попали в разные обработчики событий. То есть эта "рантайм-ошибка" статически неизбежна.
S>Именно такие вещи мы и хотим ловить при помощи системы типов.

Можешь разъяснить суть вашего бага? Я пока не очень понял, чтобы предлагать какое-то решение на типах.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[81]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.03.15 07:49
Оценка:
Здравствуйте, jazzer, Вы писали:

J>По таймеру, по изменению окружения (пришла новая market data, случился (возможно) меняющий общий риск трейд, пересчиталась модель и т.п.).

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

S>>Например, попытка сделать pay_order повторно на уже оплаченный ордер. Если это внешняя система — то байт им судья, могли что угодно накосячить. Но ведь может так оказаться, что мы сами накосячили. У нас в workflow попало два шага request_payment. А из-за асинхронности они попали в разные обработчики событий. То есть эта "рантайм-ошибка" статически неизбежна.

S>>Именно такие вещи мы и хотим ловить при помощи системы типов.

J>Можешь разъяснить суть вашего бага? Я пока не очень понял, чтобы предлагать какое-то решение на типах.

Суть простая — был заказ, его оплатили. Из-за ошибки в логике на одном из шагов (например, обработка оповещения от склада о приходе недостающего товара) запрашивается новый платёж.
Мы хотим гарантировать простую вещь — чтобы нельзя было оплатить один и тот же заказ дважды.
При этом мы хотим предотвратить ошибку в логике workflow, а не просто выкинуть messagebox со словами "ой, ваш платёж сюда не засунешь".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[82]: Haskell нужен! (в Standard Chartered Bank)
От: jazzer Россия Skype: enerjazzer
Дата: 13.03.15 08:58
Оценка: 75 (2)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, jazzer, Вы писали:


J>>По таймеру, по изменению окружения (пришла новая market data, случился (возможно) меняющий общий риск трейд, пересчиталась модель и т.п.).

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

S>В жизни не поверю, что все эти случаи обрабатывает одна и та же процедура.

Как ты там говорил: "Вооот"
В то, что ты не веришь, я готов поверить, но циферках на своем зарплатном счете я все равно верю больше

S>Сейчас даже wndproc так никто не делает — события диспетчеризуются в специфичные обработчики.

Ты не на том уровне мыслишь.
Ты хотя бы примерно представляешь себе, как работает автоматический трейдинг?
Если тебе нужна виндовая аналогия — представь обработку события "юзер захотел минимизировать все окна разом". Очевидно, это событие не должно прийти в окна, которые уже минимизированы, и соответствующая логика внутри винды должна это учитывать. Это не событие для конкретного окна, это общее событие, и винда должна решить, каким окнам его в очередь сообщений засунуть, а каким — нет.

S>>>Например, попытка сделать pay_order повторно на уже оплаченный ордер. Если это внешняя система — то байт им судья, могли что угодно накосячить. Но ведь может так оказаться, что мы сами накосячили. У нас в workflow попало два шага request_payment. А из-за асинхронности они попали в разные обработчики событий. То есть эта "рантайм-ошибка" статически неизбежна.

S>>>Именно такие вещи мы и хотим ловить при помощи системы типов.

J>>Можешь разъяснить суть вашего бага? Я пока не очень понял, чтобы предлагать какое-то решение на типах.

S>Суть простая — был заказ, его оплатили.
То есть в БД у ордера взведен флажок "оплачено", так?

S>Из-за ошибки в логике на одном из шагов (например, обработка оповещения от склада о приходе недостающего товара) запрашивается новый платёж.

Вот, кстати, отличный пример разветвленной логики, не относящейся к конкретному ордеру. При приходе недостающего товара надо обойти ВСЕ ордера и посмотреть, нет ли в них этого товара, и если есть, то что-то сделать (в т.ч. запросить платеж). Типа
void goods_arrived(Goods g) {
  for( Order& o: orders_in_db() ) {
    if ( o.contains(g) ) {
      // do lots of stuff: mark arrived goods as available etc...
      request_payment(o);
    }
  }
}

S>Мы хотим гарантировать простую вещь — чтобы нельзя было оплатить один и тот же заказ дважды.
Т.е. предусловие у request_payment — что флажок "оплачено" не должен быть взведен, так?

S>При этом мы хотим предотвратить ошибку в логике workflow, а не просто выкинуть messagebox со словами "ой, ваш платёж сюда не засунешь".

Т.е. ошибка (программиста) в том, что он просто вызвал request_payment(o), в то время как надо было сунуть этот вызов под условие if(unpayed(o)) request_payment(o)?
Т.е. правильный код goods_arrived должен быть таким?
O request_payment(O o) { ... }

void goods_arrived(Goods g) {
  for( Order& o: orders_in_db() ) {
    if ( o.contains(g) ) {
      // do lots of stuff: mark arrived goods as available etc...
      if ( !payed(o) ) { // <<< вот этот вот if программер забыл
        request_payment(o);
      }
    }
  }
}


Если все так, то это один-в-один то, что я описал в своей статье: http://rsdn.ru/forum/philosophy/5949645.1
Автор: jazzer
Дата: 10.02.15
, самый первый пример, только вместо increase_amount будет request_payment, вместо try_to_change_amount будет goods_arrived, ну и свойство будет Payed вместо HasRisk:
struct Payed;

template<class O>
typename boost::enable_if< CheckExact< O, Payed, bm::false_ >, O >::type
request_payment(O o) { ... }

void goods_arrived(Goods g) {
  for( Order& o: orders_in_db() ) {
    if ( o.contains(g) ) {
      // do lots of stuff: mark arrived goods as available etc...
      PROP_IF_NOT( unpayed_o, payed(o), Payed ) { // <<< без вот этого if
        request_payment(unpayed_o);               // <<< эта строчка не скомпилируется
        // (я тут даже переименовал o в unpayed_o для наглядности, хотя можно было и о оставить)
      }
    }
  }
}

ну и предыдуший if(o.contains(g)) тоже можно в соответствующий PROP_IF превратить, если под этим if вызывается код, который нельзя звать за его пределами.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[88]: Haskell нужен! (в Standard Chartered Bank)
От: jazzer Россия Skype: enerjazzer
Дата: 13.03.15 09:22
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, AlexRK, Вы писали:


ARK>>Я имел в виду, что базы вообще может не быть, программы же разные бывают. Например, в коде современной компьютерной игры много сложной логики.

S>Это да. Но в ответ на вопрос "как применить развитую типизацию в системах автоматизации бизнеса" примеры из компьютерных игр не вполне подходят.
S>А про устройство игр я, скажем, рассуждать уже совсем неспособен — слишком я далёк от понимания того, как они внутри устроены.

Если честно, не вижу разницы между "сделать что-то со всеми живыми объектами в игре" (скажем, подвинуть их в соответствии с их скоростями) и "сделать что-то со всеми неоплаченными ордерами" (скажем, послать юзерам напоминания, чтоб оплатили)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[82]: Haskell нужен! (в Standard Chartered Bank)
От: genre Россия  
Дата: 13.03.15 10:33
Оценка:
Здравствуйте, Sinclair, Вы писали:

G>>Все верно. Задача системы типов в данном случае заставить программиста написать эти банальные проверки.

S>Не получится. В данном случае — это как порошок от блох, который нужно сыпать в глаза каждой блохе.
S>Т.е. сначала программист должен не забыть написать "типы", которые заставят его сделать проверку, а потом должен сделать эту проверку.
S>Ему куда проще написать сразу сами проверки.

Ну все-таки в большинстве систем существует некое ядро вокруг которого пишется функционал, например в торговых системах ордер это базовая сущность, которая пишется один раз, а потом много лет пишутся функции обработки этого самого ордера.


S>Вы попробуйте в качестве упражнения написать мало-мальски реалистичную функцию pay_order(Order o, Payment p). Вы устанете выносить из неё подфункции, которые можно было бы типизировать так, чтобы "заставить программиста написать эти банальные проверки".



S>Вот, скажем, близкий к рабочему пример:

S>
S>void pay_order(Order o, Payment p)
S>{
   
S>    Assert(o.PaymentStatus != PaymentStatus.Paid, "An order cannot be paid twice. Detach an existing payment from order prior to attaching another payment");
S>    Assert(p.UsedFor == null, "This payment is already used to pay another order");
S>    Assert(o.Amount == p.Amount, "Payment amount must exactly match the order amount");
S>    Assert(p.Status >= Verified, "Only verified payments can be used to pay the orders");
    
S>    p.UsedFor = o;
S>    o.Payment = p;
S>    o.PaymentStatus = PaymentStatus.Paid;
S>}
S>

S>Покажите, как система типов поможет "заставить программиста написать эти банальные проверки".

Сложно обсуждать такой пример в отрыве от полных требований к системе. Первый вариант которых приходит в голову это вынести все что описано в ассертах на уровень выше и с помощью PROP_IF заставить программиста сделать проверки до вызова pay_order.

Вообще, подобные проверки будут иметь смысл в системе в которой есть некая базовая сущность и базовые операции над ней из которых потом складывается бизнес-логика. Тогда эти базовые вещи реализуются с подобными проверками и в дальнейшем программисты не забудут написать проверки, если же базовых операций нет (ну или они выглядят как order.amount+=10) то конечно это все не имеет смысла.

Вот еще пара примеров когда система типов помогает жить.

1. Я уже приводил этот пример. Борьба с NPE:
До:
public void process(Order o){
// программисты любят забыть эту проверку
//  if (o == null) throw ...
o.amount += 10; .. //ой

После:
public void process(Optiona<Order> o){
o.amount += 10; .. //не скомпилировалось


2. Типы в чистом виде, без извратов:
order.amount = 10.usd + 10.eur  // не скомпилировалось
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[91]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 16.03.15 12:34
Оценка:
J>Давай так, просто ради смеха ... ты возьмешь и добавишь

Давай так. Просто ради смеха. Ты возьмешь и решишь эту задачу с начала и до конца?


dmitriid.comGitHubLinkedIn
Re[81]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 16.03.15 12:34
Оценка:
M>>У меня есть действие increase_amount, у которого есть конкретные предусловия
S>По такому описанию реально ничего не напишешь.
S>В том смысле, что хотелось бы понять — а что предшествует этому increase_amount?

А, собственно, зачем?

S>Это есть такой API, который выставлен наружу, и внешняя система может в произвольный момент времени запросить увеличение amount?

S>Или есть какой-то (какие-то) сценарий типа "объединить два ордера", в рамках которого происходит косвенное увеличение amount?
S>Или есть workflow для ордеров, который реализован внутри вашей системы, и в рамках этого workflow есть какие-то действия, когда можно увеличить amount?


А зачем это знать для данной конкретной задачи?


dmitriid.comGitHubLinkedIn
Re[83]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 16.03.15 12:39
Оценка: -1 :))
G>1. Я уже приводил этот пример. Борьба с NPE:
G>До:
G>
G>public void process(Order o){
G>// программисты любят забыть эту проверку
G>//  if (o == null) throw ...
G>o.amount += 10; .. //ой
G>

G>После:
G>
G>public void process(Optiona<Order> o){
G>o.amount += 10; .. //не скомпилировалось
G>



И все просто бегают как огня ответа на вопрос, что будет, когда там будет не просто Optional, не скомпилировалось, а два-три-пять-да хоть пятндацать условий. Код так никто и не осилил, щато внезапно примеры оказываются неправильными, или просто на словах рассказывается, как все будет легко и прекрасно


dmitriid.comGitHubLinkedIn
Re[82]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.03.15 05:34
Оценка:
Здравствуйте, Mamut, Вы писали:
M>А, собственно, зачем?

M>А зачем это знать для данной конкретной задачи?

Потому, что без этого невозможно понять, что можно повторно использовать, и где можно получить выигрыш на однократной проверке вместо многократных.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[83]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 17.03.15 09:44
Оценка: :)
M>>А, собственно, зачем?

M>>А зачем это знать для данной конкретной задачи?

S>Потому, что без этого невозможно понять, что можно повторно использовать, и где можно получить выигрыш на однократной проверке вместо многократных.


Так как задача достаточно изолированна, то можно придумать себе какие угодно условия. Попробовать и так и так Как видим, пока проблема в том, что ни у кого не получается ничего придумать


dmitriid.comGitHubLinkedIn
Re[84]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.03.15 08:38
Оценка:
Здравствуйте, Mamut, Вы писали:
M>Так как задача достаточно изолированна, то можно придумать себе какие угодно условия. Попробовать и так и так Как видим, пока проблема в том, что ни у кого не получается ничего придумать
Ну, это уже выходит игра в одни ворота. Загадывающий всегда выигрывает, т.к. может додумать доп.условия, конфликтующие с любым предложенным решением.
А если от этого произвола отказаться, то задача уже решена:
1. Вводим два типа ордеров: OrderThatAllowsIncreasingAmount и Order
2. Реализуем EnsureOrderAllowsIncreasingAmount() — оператор конверсии из второго в первый, который делает 18 проверок и выкидывает исключение, если что-то пошло не так.
3. Придумываем себе условия, при которых increase_amount вызывается 500 раз из различных мест. Например, из метода MergeNewOrderIntoAPreviousOrder.
Убеждаемся, что компилятор обязывает нас либо вставить оператор конверсии прямо в этот метод, либо заменить тип аргумента с Order на OrderThatAllowsIncreasingAmount, подчёркивая тот факт, что в "залоченный" ордер мы ничего добавить не можем.
Убеждаемся, что теперь компилятор не пропускает код вида:
public void HandleDelivery(Order newOrder)
{
   var previousOrder = GetExistingCustomerOrders(newOrder.Customer).FirstOrDefault();
   if (previousOrder != null)
   {
     MergeNewOrderIntoAPreviousOrder(previousOrder, newOrder); // ARRGH! there is no implicit conversion from Order to OrderThatAllowsIncreasingAmount
     SubmitforDelivery(previousOrder);
   }
   else
     SubmitForDelivery(newOrder);
   
}

Это сразу подсказывает нам переписать код вот так:
public void HandleDelivery(Order newOrder)
{
   var previousOrder = GetExistingCustomerOrdersAllowedForAmountIncrease(newOrder.Customer).FirstOrDefault();
   if (previousOrder != null)
   {
     MergeNewOrderIntoAPreviousOrder(previousOrder, newOrder); // Compiler's happy
     SubmitforDelivery(previousOrder);
   }
   else
     SubmitForDelivery(newOrder);
   
}

В бестиповом аналоге первый вариант HandleDelivery мог бы успешно уехать в продакшн — потому что вылет исключения случается не каждый раз, а только тогда, когда у кастомера есть предыдущие ордера, и наугад выбранный один из них подпал под одно из 18 условий.
То, что программист может на всё наплевать, и исправить код вот так, выходит за рамки технических решений:
public void HandleDelivery(Order newOrder)
{
   var previousOrder = GetExistingCustomerOrders(newOrder.Customer).FirstOrDefault();
   if (previousOrder != null)
   {
     MergeNewOrderIntoAPreviousOrder(EnsureOrderAllowsIncreasingAmount(previousOrder), newOrder); // ARRGH! Runtime exception.
     SubmitforDelivery(previousOrder);
   }
   else
     SubmitForDelivery(newOrder);
   
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[85]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 18.03.15 17:55
Оценка:
M>>Так как задача достаточно изолированна, то можно придумать себе какие угодно условия. Попробовать и так и так Как видим, пока проблема в том, что ни у кого не получается ничего придумать
S>Ну, это уже выходит игра в одни ворота. Загадывающий всегда выигрывает, т.к. может додумать доп.условия, конфликтующие с любым предложенным решением.

Да, безусловно. Но от этого становится только интереснее — можно протестировать границы применимости предлагаемых подходов

S>А если от этого произвола отказаться, то задача уже решена:

S>1. Вводим два типа ордеров: OrderThatAllowsIncreasingAmount и Order
S>2. Реализуем EnsureOrderAllowsIncreasingAmount() — оператор конверсии из второго в первый, который делает 18 проверок и выкидывает исключение, если что-то пошло не так.

Можно, пожалуйста, дать мне ссылку, где эта задача решена на этом форуме А то все говорят про «OrderThatAllowsIncreasingAmount» и про «ну там же очевидно как реализовать 18 проверок», но так никто не показал ни одного куска законченного кода


Все остальное скипнуто, потому что оно ничем не отличается от пафосных заявлений в сотне сообщений


dmitriid.comGitHubLinkedIn
Отредактировано 18.03.2015 17:56 Mamut [ищите в других сетях] . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.