Здравствуйте, vaa, Вы писали:
vaa>Здравствуйте, gandjustas, Вы писали:
G>>Стоит ли в данном случае изнутри БЛ кидать ArgumentException? Нужно ли в таком случае выдавать 400 клиенту? Или это уже 500 ошибка?
vaa>Это общая проблема, если ловим конкретное исключение, то можно 400, если другое 500.
Про 400 и 500 это был провокационный вопрос.
Ответ в стандарте — если клиент получает 400, то он не должен пытаться повторить запрос с теми же параметрами.
Это означает, что 400 нельзя кидать для ситуаций, которые могут меняться со временем и для любых rntime эксепшенов.
точно! по моему лучший вариант. вместо исключения возвращать Result, аля ФП F# подход с Result<'ok, 'err> , я ведь даже его знал.. но не сразу вспомнил
и волки сыты и овцы целы!
и ещё немаловажный бонус — в сценриаях когда ошибка ожидаемое поведение (а это как раз для рест-апи), возврат кода ошибки по перфомансу более выигрышно чем исключение и его кэтч.
type ErrorKind = InvalidArg of string * string
type Result = Ok | Error of ErrorKind
let getThing arg1 =
//bla blaif not (some condition) then
Error("arg1", "arg1 invalid")
else//do ok work
Ok
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, MadHuman, Вы писали:
MH>>и волки сыты и овцы целы!
НС>Ага, только куча логики по прокидыванию этого резалта через весь коллстек
в исходном примере, речь про один уровень.
НС>, и возвращаемые типы все в стиле maybe монады.
да, невижу в этом неудобств или недостатков.
ну и если быть точным не maybe (она про Some | None), а про Result ( Ok | Error ), где Error может включать доп информацию, а None из maybe нет
Здравствуйте, MadHuman, Вы писали:
НС>>Ага, только куча логики по прокидыванию этого резалта через весь коллстек MH>в исходном примере, речь про один уровень.
Исключения как раз придумали чтобы уйти от лапши, которую порождают коды возврата. А тут какой то back to the future.
НС>>, и возвращаемые типы все в стиле maybe монады. MH>да, невижу в этом неудобств или недостатков.
Это в шарпе то?
MH>ну и если быть точным не maybe (она про Some | None), а про Result ( Ok | Error ), где Error может включать доп информацию, а None из maybe нет
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, gandjustas, Вы писали:
G>>Что мешает просто в отдельный метод вынести? Или даже в отдельный класс?
НС>К примеру, для проверки могут потребоваться промежуточные данные, которые затем используются для собственно вычислений.
сразу виден обширный практический опыт) согласен с аргументацией
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Исключения как раз придумали чтобы уйти от лапши, которую порождают коды возврата. А тут какой то back to the future.
Исключения не предназначены, чтобы на них строить логику. Если приложение слоистое, то лучше использовать алгебраические типы.
НС>Это в шарпе то?
Есть либы для этого. Гораздо удобнее и нагляднее, в отличие от стандартных исключений.
Здравствуйте, IncremenTop, Вы писали:
НС>>Исключения как раз придумали чтобы уйти от лапши, которую порождают коды возврата. А тут какой то back to the future. IT>Исключения не предназначены, чтобы на них строить логику.
А кто предлагает на них строить логику? Речь про возврат ошибки. Это именно то для чего придуманы исключения.
IT> Если приложение слоистое, то лучше использовать алгебраические типы.
В шарпе нет алгебраических типов.
НС>>Это в шарпе то? IT>Есть либы для этого. Гораздо удобнее и нагляднее, в отличие от стандартных исключений.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здесь должен быть пример.
Result result = new Result.Ok("OK");
WriteLine(result switch
{
Result.Ok x => "200 " + x.Result,
Result.Error e => "400 " + e.Err
});
public record Result()
{
public record Ok(string Result) : Result();
public record Error(string Err) : Result();
}
vaa>Result result = new Result.Ok("OK");
vaa>WriteLine(result switch
vaa>{
vaa> Result.Ok x => "200 " + x.Result,
vaa> Result.Error e => "400 " + e.Err
vaa>});
vaa>public record Result()
vaa>{
vaa> public record Ok(string Result) : Result();
vaa> public record Error(string Err) : Result();
vaa>}
vaa>
ЧТД. Ровно 100% этого кода при использовании исключений можно выкинуть.
vaa>>Result result = new Result.Ok("OK");
vaa>>WriteLine(result switch
vaa>>{
vaa>> Result.Ok x => "200 " + x.Result,
vaa>> Result.Error e => "400 " + e.Err
vaa>>});
vaa>>public record Result()
vaa>>{
vaa>> public record Ok(string Result) : Result();
vaa>> public record Error(string Err) : Result();
vaa>>}
vaa>>
НС>ЧТД. Ровно 100% этого кода при использовании исключений можно выкинуть.
не совсем. Result — может быть библиотечным/инфраструктурным.
вместо свитча — будет try/catch. я бы сказал примерно одно и тоже.
в общем случае исключения конечно удобнее (когда не надо каждый вызов функции хэндлить и обрабатывать ошибку), за счет меньшего шума и доп бойлерплейта.
паттерн Result лучше, когда ошибочная ситуация ожидаема и часть штатного поведения, в этом случае лучше и перф (иногда это важно).
и мы точно знаем все ожидаемые исходы из самого типа результата.
решается и исходная проблема топика — неоднозначность места исключения (возникло ли оно внутри самой функции и то что мы и хотим словить либо из более глубоких недр).
ввод нового класса исключения по бойлерплейту будет примерно тоже что ввод нового класса Result для конкретного случая.
Здравствуйте, MadHuman, Вы писали:
MH>вместо свитча — будет try/catch. я бы сказал примерно одно и тоже.
Не будет там никакого try..catch, в этом суть. Просто вешается единожды написанная простенькая мидлвера. А вот твой Result придется явно протаскивать по всему коллстеку, загаживая код.
Еще раз — единственная фича исключений, ради которой их придумали — возможность абсолютно независимо от любого коллстека прервать выполнение и вернуть ошибку. И все это происходит абсолютно прозрачно для любого кода между источником и конечным обработчиком. А вот вариант с возвращаемыми кодами ошибок откатывает нас во времена до исключений, когда любой код приходилось специально под обработку ошибок затачивать. Особенно эротично это было в случае наличия колбеков. Вот есть некий библиотечный код, не твой. Ему на вход идет твой собственный колбек, в котором, внезапно, возникает ошибка. В случае с исключениями все работает, а вот что делать с кодами ошибок?
Здравствуйте, gandjustas, Вы писали:
G>Это означает, что 400 нельзя кидать для ситуаций, которые могут меняться со временем и для любых rntime эксепшенов.
Все равно это должна быть какая-то ошибка 4xx, а не 5xx
MH>>вместо свитча — будет try/catch. я бы сказал примерно одно и тоже. НС>Не будет там никакого try..catch, в этом суть. Просто вешается единожды написанная простенькая мидлвера. А вот твой Result придется явно протаскивать по всему коллстеку, загаживая код.
тогда мы вернёмся к исходной проблеме. вот мидлвара словила исключение (даже наше спец исключение типа WrongAccountException), если под мидлварей вызов функции вида Transfer (из которой напрямую это исключение и возвращается),
то да — всё хорошо, возвращаем 400, т.к. номер счета передан снаружи неверно. но исключение может подняться по колстэку и из глубин бизнес-логики, и на вызывающей стороне (хандлере под мидлаварей) и не было речи ни о каком счете.
а когда у нас в частном случае появится новое исключение — снова идти править общую мидлвару?
НС>Еще раз — единственная фича исключений, ради которой их придумали — возможность абсолютно независимо от любого коллстека прервать выполнение и вернуть ошибку. И все это происходит абсолютно прозрачно для любого кода между источником и конечным обработчиком.
да, всё так.
НС>А вот вариант с возвращаемыми кодами ошибок откатывает нас во времена до исключений, когда любой код приходилось специально под обработку ошибок затачивать.
этот вариант надо использовать когда в конкретном случае он имеет преимущества перед кэтчем исключения. если его всегда использовать/злоупотреблять, то конечно мы получим как в Go и всё то о чем ты говориш (не надо так).
Здравствуйте, MadHuman, Вы писали:
MH>то да — всё хорошо, возвращаем 400, т.к. номер счета передан снаружи неверно. но исключение может подняться по колстэку и из глубин бизнес-логики, и на вызывающей стороне (хандлере под мидлаварей) и не было речи ни о каком счете.
Вот поэтому и вводится специальный класс бизнес-исключений.
НС>>А вот вариант с возвращаемыми кодами ошибок откатывает нас во времена до исключений, когда любой код приходилось специально под обработку ошибок затачивать. MH>этот вариант надо использовать когда в конкретном случае он имеет преимущества перед кэтчем исключения.
И что это за преимущества?
MH> если его всегда использовать/злоупотреблять, то конечно мы получим как в Go
В Go ситуация существенно лучше, потому что там весь код под такое заточен. А в дотнете это полный ахтунг.
Здравствуйте, Буравчик, Вы писали:
Б>Здравствуйте, gandjustas, Вы писали:
G>>Это означает, что 400 нельзя кидать для ситуаций, которые могут меняться со временем и для любых rntime эксепшенов.
Б>Все равно это должна быть какая-то ошибка 4xx, а не 5xx
G>Ответ в стандарте — если клиент получает 400, то он не должен пытаться повторить запрос с теми же параметрами. G>Это означает, что 400 нельзя кидать для ситуаций, которые могут меняться со временем и для любых rntime эксепшенов.
Здесь возврат 400 для запроса, некорректного с точки зрения бизнес-логики. Запрос, который некорректен сегодня, может стать корректным завтра. И тогда его можно смело повторить и он вернёт 200.