All streams
Search
Write a publication
Pull to refresh
29
0
Фофанов Илья @EngineerSpock

Ответственный программист

Send message
1. Согласен.
2. Согласен. Мы его не обрабатываем. Это исключение входит в список фатальных. Если мы встречаем такое, то падаем.
3. Согласен. Срочно убираю этот бред. Доверившись, скопировал у кого-то индуса.
4. Верно. Мы фильтруем внутри на список фатальных исключений для конкретного приложения. Т.е., мы ловим все исключения, кроме списка фатальных, плюс логирование встроенное. В блоке Exceptions в Enterprise Library делается нечто похожее, только в более ООП стиле со всякими рюшками. Для нас подходит описанное решение в статье. C# 6.0 мы использовать не можем. И не нравится мне его система фильтрования, да ещё с какими-то подводными камнями.
Конкретные претензии в личку, если вас не затруднит. Оригинал всегда читать лучше.
Однако, повторюсь.
У меня есть подозрение, что decimal для выражения денежных величин может использовать на проекте год и даже два. Ровно до тех пор, пока кто-то не перепутает копейки с рублями и сравнение не отработает так, как ожидалось. С decimal перепутать инициализацию копейками и рублями гораздо проще. Останусь при своём мнении.
Может быть я не прав, но я воспринял эту статью. как воспитание ненависти к примитивам ради неких призрачных и неописываемых словами мистических концепций.

Конечно же, цель была не в этом.

Да, то, что люди забывают думать своей головой это проблема. Но это другая проблема и ей нужно посвящать отдельную статью. В инженерии нет универсальных ответов на все вопросы.

Нам подходит наша реализация Money, её кто-то сможет адаптировать под свои нужды, особенно если появятся методы распределения в процентном соотношении для перевода по разным банковским счетам. И да, надо будет не забыть убрать long изнутрей структуры, а то мало ли что :) Как сделаю, так и статью проапдейчу.
Что для Вас будет более читабельно — вот это: «new DateTime(2015, 4, 5)», или вот это: «5.April(2015)»?

Для меня будет более читабельно Money.FromRubles(10).

И здесь я вижу ровно то же самое. Меж тем,, как надо совершенно ясно понимать, для чего создавались те или иные решения, и всегда думать, прежде чем применять что-то, проходя самостоятельно тот путь, который прошли до Вас, но уже гораздо быстрее, т.к. на пути есть указатели. А если Вы сразу переноситесь в конечную точку рассуждений, Вы с очень большой вероятностью оказываетесь не там.

Если вы внимательно прочитаете статью, то увидите, что мы изначально использовали, где могли decimal и приходилось заниматься конвертацией, потому что есть другая система, которая принимает всё в копейках. Мы пришли к заключению, что нам нужен Value-Object. Мы не применяли его сразу, несмотря на то, что знали о существовании этого подхода. Некоторые люди упорно не читают статьи и комментарии, пускаясь в рассуждения, основанные на собственных домыслах.

Что касается EntityFramework. Это вообще отдельная история. Такие фрэймворки проталкивают насильно использование DTO. Не объектов, как объектов, которые имеют поведение, а объектов, которые являются структурами данных. На все 100% решений нет, а кто об этом говорил? Никто не собирается всё оборачивать. Мне жаль, что у меня не получается донести до вас мысль о том, что концепцию нельзя представить примитивом.
Money.FromRubles(10) гораздо лучше чем decimal a = 10m; Если вы не согласны, это ваше мнение. Ну, так тот разработчик сделал глупости, вероятно. В статье всё нормально. Здесь нет десяти шаблонов и иерархии классов. Есть структура, которая делает код более читабельным, более простым для интероперабельности с системами, которые требуют всё только в копейках и расширяема, если потребуется введение валют.
Если вы напишите класс ZipCode, то он станет оболочкой над string и что дальше?
Читайте комменты. Обратите внимание, что конструкторы закрыты. Не делайте поспешных выводов. Фаулер однажды сказал, что люди его ненавидят, но рано или поздно приходят к его же мнению, только через набитие шишек.
Вам просто необходимо научиться хорошим манерам. В первую очередь понять, что вы не самый умный. И прочитать хорошую статью о том, как правильно себя вести в цивилизованном обществе, а не в обществе дикарей.
И каким образом накопятся ошибки округления? Money — неизменяемый тип. В данном случае работает строго с двумя знаками после запятой. Хотя в целом, да, с тем, что внутри надо сделать decimal — согласен. Это правильно.
но зачем использовать long для хранения суммы в копейках внутри класса?

Согласен, внутри лучше сделать decimal. Только насколько я понял, другой хабравчанин имел ввиду, что Money это плохо и надо тупо использовать decimal.
для отображения в интерфейсе суммы в копейках или рублях с копейками используется концепция Value Formatter

Если планируется поддерживать такие валюты, то да, тогда какой-нибудь форматтер надо будет использовать. Я про это даже не думаю, в любом случае это ляжет на ООП спокойно. Посыл статьи — не использовать decimal для представления денег.
Вещи разные, но концепция decimal у них одинаковая, и придумана она специально для денежных целей, чтобы не использовать float, который не гарантирует точности, и не городить велосипеды с int/long.

Она не придумана для денежных целей, она придумана для десятичных значений. SQL не умеет классы, поэтому концепцию Money вы в нём не выразите. Придётся использовать decimal.
Ещё вдогонку.

10m*100 = одна тысяча десятичных слонов

Надеюсь так понятнее :)
1. Money(10), а здесь сколько? В вашем случае с 2мя конструкторами это будет 0.1 рубля как я понимаю

Конструкторы закрыты. Сделаны специальные фабрики.
2. А если вам будет нужно общаться с системами которым нужна точность до 3 знака? Конечно конвертацию, только почему городим — если система принимает значение умноженное на 100, так с ней и общайтесь — 10m * 100

Нам это не нужно, но если бы было нужно, то сделали бы всё равно Money. Такая бизнес-логика должна быть инкапсулирована в объекте. Не надо повсюду делать умножения на 100. То, что вы предлагает 10m*100 — плохо.
Я попробую выразить мысль и скорее всего не только мою — наличествование класса Money это не плохо, но реализация с «копексами» это плохо,

Это решается текущими потребностями, а не понятиями типа "...Money должен быть". Money, как и его имплементация никому ничего не должны :-D Шучу, конечно, но в каждой шутке есть доля шутки. Всё дело в домене. Нужна валюта — ок. Не нужна — значит ок, не нужна.

Подытоживая — объект Money стоит завести, чтобы конвертации были проще, чтобы бизнес-логика в будущем могла быть накручена, проверки различные. Для этого и используются объекты в ООП. То, что в C# есть decimal — это прекрасно. Это великолепный тип, но он слабый для того, чтобы представлять концепцию. Чтобы представлять именно деньги он должен быть инкапсулирован в объект денег. То же самое относится к таким понятиям как IPAddress и ZipCode. Их нельзя представлять строками или другими любыми примитивами.

decimal предназначен для работы со значениями десятичными, типа денег, но это не сама концепция денег. Нельзя путать одно с другим.
Что касается ответов на ваши вопросы.
Да, валюты всё усложняют, согласен.
А если все-таки когда-нибудь понадобится конвертировать в другую валюту — будете использовать копейки или рубли?
А конвертировать будете в центы или в доллары?

Для конвертации будет метод конвертации, который будет учитывать полную сумму, выраженную в обеих частях. Плюс нужен будет доступ к сервису курсов валют. А как вы собираетесь это делать без типа Money? Прикручивать методы-расширители?
А для каждой валюты будете писать свой класс, где kopeks в названии функции будет заменять на cents/penny/sen и т.п.?

Нет, поменяют имена двух методов на подходящие для всех валют, например HigherUnit и LowerUnit. Менее понятно, чем Kopecs и Rubles, но программисту работающему с классом нужно понять, что это такое — ровно один раз. Это всё равно будет более эксплицитно, чем записывать decimal a = 10m — что это?
А еще в мире до сих пор не вымерли валюты-динозавры, где бывают 1/1000 части основной единицы, 1/5, 1/12, 1/20 и даже 1/240, и несколько разных могут совместно сосуществовать в одной валюте.

Совершенно верно. Это легко решается объектно-ориентированным программированием, которое и демонстрируется паттерном Value-Object вместо одержимости примитивами. В случае использования decimal вы эту задачу никак не решите.

P.S. Stackoverflow тоже советует использовать decimal для хранения денежных значений (там опять же про sql, но не думаю, что decimal в C# сильно отличается в этом плане).

Сравнивать SQL с C# я бы вообще не стал. Разные это вещи.
Если согласны, то вам пара вопросов из моего комментария. Начинайте с раздела «по существу» :) Нет, структура будет работать катастрофически быстро. С трудом представляю сценарий с продолбами в производительности со структурой.
Вот мой ответ, только другому хабравчанину. Вам там в раздел «по существу» :)
Ну, значит Фаулер и Марк Симан тоже не умеют программировать? Они-то рекомендуют использовать ValueObject. Что вы скажете по этому поводу? Пуститесь в рассуждения о том, что они вам не кумиры?

По существу:
1. С точки зрения читабельности: объясните что написано здесь: decimal a = 10m; Сколько это? Без учёта валюты.
2. Нужна интероперабельность с легаси-системой, которая в нашем случае есть. Она принимает всё только в копейках. Городим конвертацию?
3. Что если нужно нужно сделать перераспределение по разным счетам? Стандартная банковская фича. Разделить в некотором процентном соотношении сумму денег и перевести на разные счета. Городим ещё метод-расширение?
Да, однажды всё начнёт расползаться. Ваш пример тому доказательство. Не надо городить огороды там, где нужен тип.
О том и речь, возникает необходимость конвертации так и так. Нет смысла выдумывать конвертеры, нужно просто сделать нормальный тип, который представляет концепцию. Использование примитивов в таком случае будет означать отсутствие концепции.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity