Классика коммунистического подхода: подменять политическое решение интересами выгодоприобретателей, незаметно выставляя всё так, будто бы они являются причиной. Когда они уже поймут, что принцип "ищи кому выгодно" так не работает. Фрезеровщик, получивший деньги за детальку для ядерной боеголовки, не является причиной и не несёт никакой ответственности за потенциальную ядерную войну.
Но Маркс ведь учил, что надо искать проблемы в капитализме, а значит, надо притянуть за уши таких вот фрезеровщиков, и сказать: вот, из-за них всё. Как им самим-то не смешно - не понимаю...
Я, честно говоря, удивлён, что никто не понял, что это сарказм. То, что для людей это оказалось неочевидным, - само по себе уже печальный признак... Даже предложение про перекладывание ответственности не помогло...
Скорей бы коммунизм, и как следствие, интранет как в КНДР. И доступа к этим вашим капиталистическим ютубам не будет ни у кого, кроме ЦК. Ура, товарищи! Статья - прекрасный пример того, как комми умело (нет) перекладывают ответственность.
Хороший простой ответ. Автору следовало это расписать, а не писать "Т.е. мы установили, что ... он максимум состоит из 6 цифр." мелким шрифтом, как что-то само собой разумеющееся. Я тоже при прочтении завис на этом моменте: "Когда это мы установили?"
Я C#-backender, которому приходится быть fullstacker'ом, и эта статья для меня - то, что нужно. Респкт автору. Отличное понятное изложение, грамотный язык. А это редкость...
Отлично, рад что мы поняли друг друга ;) Просто, глядя на этот конкретный пример, у меня зародились подозрения о слепом использовании каких-то подходов (о чём я писал). Но если это делается с умом, то это конечно другое дело. Будем ждать апдейта и новых статей, и успехов Вам в разработке!
Помимо пользы, от паттернов проектирования может быть и вред. Бездумное и неразумное использование любого даже самого полезного инструмента или технологии приведет к «абсурду и коррупции». Сколько раз вы сталкивались с проблемой “overengineering-а”, когда для реализации простой концепции использовался десяток паттернов проектирования? В общем, это очередной пример того, что прагматизм и здравый смысл, как всегда является лучшим выбором, и паттерны проектирования – не исключение.
Да восторжествует здравый смысл, и всем нам будет счастье! :)
потому что есть другая система, которая принимает всё в копейках.
Надо было так и написать. Предложение «В ПО, которое разрабатывает наша команда используются денежные значения в рублях и копейках.» не говорит об этом.
Лично я бы преобразовывал суммы сразу при общении с этой другой системой в decimal, только и всего. И удалил бы напрочь «long kopeks» из проекта, как кошмарный сон, чтобы вот вообще никаких следов это безобразия не осталось :)
Мне жаль, что у меня не получается донести до вас мысль о том, что концепцию нельзя представить примитивом.
Эмм… А «концепция»-то в чём заключается? Чем вот по сути эта структура отличается от long? Умножением и делением на 100? Это и есть та «концепция», которую непременно надо куда-то инкапсулировать?
Эта проблема решается не усложнением кода всего проекта, а правильным написанием кода, который отвечает за взаимодействие с этой другой системой, который должен быть обособлен и полностью абстрагирован от всего остального. Чтобы основной проект вот даже слыхом не слыхивал о том, что суммы где-то хранятся в копейках ))
Не объектов, как объектов, которые имеют поведение, а объектов, которые являются структурами данных
Ну, лично в моём проекте там полно поведения :) Некоторые вещи прекрасно решаются интерфейсами и методами расширения. Я не идеализирую EF, ни в коем случае. Там огромная куча недоработок…
Может быть я не прав, но я воспринял эту статью. как воспитание ненависти к примитивам ради неких призрачных и неописываемых словами мистических концепций. А это, по моему глубокому убеждению, путь исключительно ложный и вредный, особенно для незрелых умов, которые, не научившись пользоваться и примитивами, стремятся наплодить как можно больше структур и классов невнятного назначения, потому что так написано в умной книжке. Это я не о Вас, о многих из тех, кто это прочтёт.
Подчёркиваю, любой паттерн создан для решения каких-то проблем. Если этих проблем нет и не предвидится, любое их использование — это дорога в ад. А если проблема есть, то надо сначала подумать, какими способами можно её решить, собственной головой. Умный не тот, кто прочитал много книг. А то, кто умеет перерабатывать информацию и генерировать новую (если она конечно полезна). Тот, у кого развита интуиция за базе собственного опыта. Какие-либо авторитеты и совершенно ненужные знания обычно не помогают, а вредят интеллектуальному развитию и личному росту. Вот ей Богу, если бы тот разработчик, которого я упоминал, не прочитал ни одной книги, он бы написал намного более качественный и понятный код, а главное — научился бы думать.
На самом деле, даже обёртка над decimal может пригодиться, если понадобится унифицировать обработку разных по смыслу данных. Самый простой пример — ToString():
var items = new object [ ] { someMoney, someOtherValue };
foreach (var item in items) Show(item.ToString());
Если бы в Вашем примере был реализован ToString(), в нём был бы хоть какой-то смысл. Хотя, и то этот смысл сомнителен, т.к. необходимость ради одного ToString реализовывать кучу операторов (для превращения Money в полноценный decimal) — это большой вопрос, и зависит опять-таки от контекста, в роли которого выступает проект.
Money.FromRubles(10) гораздо лучше чем decimal a = 10m;
Есть структура, которая делает код более читабельным
Да Вы, верно, шутите? По-Вашему это более читабельно? Дело не в согласии несогласии, а в фактах. Сколько человек на Земле знают про Вашу структуру Money? И сколько человек на Земле знают про тип decimal? Глядя на запись «Money.FromRubles(10)» у меня сразу же возникает куча вопросов: а как эта структура будет хранить данные — с какой точностью? А не конвертирует ли она, случайно, рубли во что-то ещё в этой ф-ции? А смогу ли я использовать её в мат. выражениях? А насколько она производительна? И т.д. Вы сами посмотрите на этот код через полгодика и будете судорожно пытаться вспомнить, зачем Вы этот Money вообще ввели.
Представьте, что Вы открыли чужой код. Что для Вас будет более читабельно — вот это: «new DateTime(2015, 4, 5)», или вот это: «5.April(2015)»?
Ну, так тот разработчик сделал глупости, вероятно
Самая главная его глупость — это то, что он слепо применял всё подряд о чём прочёл. И здесь я вижу ровно то же самое. Меж тем,, как надо совершенно ясно понимать, для чего создавались те или иные решения, и всегда думать, прежде чем применять что-то, проходя самостоятельно тот путь, который прошли до Вас, но уже гораздо быстрее, т.к. на пути есть указатели. А если Вы сразу переноситесь в конечную точку рассуждений, Вы с очень большой вероятностью оказываетесь не там.
и расширяема, если потребуется введение валют.
А если потребуется учесть нашествие инопланетян? Предусматривать какие-то абстракции нужно только в том случае, когда вероятность их применения достаточно высока. Иначе от них никакой пользы, кроме вреда.
И даже в случае проверки корректности данных (что совершенно не относится к Вашему примеру)… Предположим, что Вам нужно принимать от пользователя, сохранять и отображать Zip-Code, а вы, скажем, работаете с EntityFramework, в котором корректность обеспечивается атрибутами на свойствах модели. Нужна ли в этом случае обёртка над string? Нет. Всё зависит от ситуации, и универсальных на все 100% решений не существует. Никто и никогда не избавит Вас от необходимости думать, когда Вы принимаете решение использовать какой-либо готовый подход.
Ну, или же, оборачивайте в структуры все подряд: string'и, int'ы, float'ы. Оберните заодно и все объекты Framework'а. А что, вдруг пригодится? ;)
Если вы напишите класс ZipCode, то он станет оболочкой над string и что дальше?
Я уже цитировал, и процитирую ещё раз:
Инкапсулируем примитивное значение в объект-значение, который содержит соответствующие защитные выражения и т.д., для того, чтобы гарантировать, что возможно создать только корректные экземпляры.
Где у Вас проверки на корректность как в случае в ZipCode?
Фаулер однажды сказал, что люди его ненавидят, но рано или поздно приходят к его же мнению, только через набитие шишек.
Помнится, я работал с одним молодым разработчиком, который слишком любил читать «умные книжки». И однажды, когда мне пришлось, работать с его кодом, я пришёл в тихий ужас, который у меня не проходил несколько дней. Грубо говоря, у него для деления на 100 использовалась даже не одна структура, а целая иерархия из шаблонных классов. И практически каждый паттерн, который он применил, был применён совершенно не по делу, что сделало его код нечитаемым даже для него самого. И весь код был выброшен в помойку.
Хорошие решения призваны бороться со сложностью, а не создавать её на пустом месте.
Можете начать бросать в меня помидоры, потому что я не осилил это гору комментов, но я скажу вот что…
В той статье про «одержимость примитивами» сказано:
«Инкапсулируем примитивное значение в объект-значение, который содержит соответствующие защитные выражения и т.д., для того, чтобы гарантировать, что возможно создать только корректные экземпляры.»
Уже на этом этапе имела место ошибка в понимании этого текста, т.к. decimal уже гарантирует только корректные экземпляры.
Я сам разрабатываю довольно сложное финансовое приложение, которое давно крутится в продакшене, и мне даже в кошмарном сне не мог присниться подобный класс. Я бегло пробежался по тексту и комментам, но не увидел ответа на простой вопрос: зачем хранить сумму в копейках?
За мой немалый опыт разработчика я усвоил одну истину: самый большой вред — это одержимость не примитивами, а паттернами и «советами умных людей», не понимая их суть. И использование сложных подходов там, где они не нужны по определению.
Если Вы решите хранить и оперировать деньгами в decimal и перепишете этот класс соответствующим образом, чем он станет? Оболочкой над decimal.
И поверьте, если у Вас в системе фигурируют суммы в «long kopecs» (что изначально являлось недоработкой проектирования), то запись «decimal money = kopecs/100» будет гораздо очевиднее незнакомому с вашим кодом человеку, чем «var money = new Money(kopecs)», т.к. с Вашим Money он вообще не знаком, и ему придётся заглянуть в него и ужаснуться.
Ваш класс только тогда начнёт иметь смысл, когда не будет являться оболочкой над decimal (который и так уже всё гарантирует), а будет содержать в себе ещё что-то. Например, код валюты.
А до тех пор лучше заняться избавлением проекта от «long kopecs», а не потворствовать этому. А эта абстракция, раз уж она уже есть, пусть существует в виде оболочки над decimal, может, когда-нибудь и пригодится…
Да по сути, в любом случае на общую производительность, судя по тестам, 4-канальность не влияет… Поэтому и в DDR4 я особого смысла не вижу, если latency будет той же…
Сейчас пошукал в инете и выяснил, что всё-таки не будет он на Z87 работать… Получается, что выбора только два: покупать сейчас LGA2011 или ждать год. Иначе не будет никакой возможности для роста.
В том-то и дело, что к сожалению, Z97 выйдет только во второй половине 2014-го, насколько я читал… Надеюсь, Broadwell хотя бы не откажется работать на Z87…
А мне вот интересно, что будет лучше 4-канальная DDR3 на LGA2011 или 2-канальная DDR4? Мне сейчас как раз апгрейд светит, и получается, что если это будет равносильно, то можно преспокойно продолжать сидеть на DDR3 ещё ооочень долго…
Ютуб не из-за антимонопольного законодательства блочат
Классика коммунистического подхода: подменять политическое решение интересами выгодоприобретателей, незаметно выставляя всё так, будто бы они являются причиной. Когда они уже поймут, что принцип "ищи кому выгодно" так не работает. Фрезеровщик, получивший деньги за детальку для ядерной боеголовки, не является причиной и не несёт никакой ответственности за потенциальную ядерную войну.
Но Маркс ведь учил, что надо искать проблемы в капитализме, а значит, надо притянуть за уши таких вот фрезеровщиков, и сказать: вот, из-за них всё. Как им самим-то не смешно - не понимаю...
Я, честно говоря, удивлён, что никто не понял, что это сарказм. То, что для людей это оказалось неочевидным, - само по себе уже печальный признак... Даже предложение про перекладывание ответственности не помогло...
Скорей бы коммунизм, и как следствие, интранет как в КНДР. И доступа к этим вашим капиталистическим ютубам не будет ни у кого, кроме ЦК. Ура, товарищи!
Статья - прекрасный пример того, как комми умело (нет) перекладывают ответственность.
Я не понял, а как повторы-то исключается, если нигде не фигурирует ID участника?
Хороший простой ответ. Автору следовало это расписать, а не писать "Т.е. мы установили, что ... он максимум состоит из 6 цифр." мелким шрифтом, как что-то само собой разумеющееся. Я тоже при прочтении завис на этом моменте: "Когда это мы установили?"
Я C#-backender, которому приходится быть fullstacker'ом, и эта статья для меня - то, что нужно. Респкт автору. Отличное понятное изложение, грамотный язык. А это редкость...
В общем, как писал SergeyT:
Да восторжествует здравый смысл, и всем нам будет счастье! :)
Надо было так и написать. Предложение «В ПО, которое разрабатывает наша команда используются денежные значения в рублях и копейках.» не говорит об этом.
Лично я бы преобразовывал суммы сразу при общении с этой другой системой в decimal, только и всего. И удалил бы напрочь «long kopeks» из проекта, как кошмарный сон, чтобы вот вообще никаких следов это безобразия не осталось :)
Эмм… А «концепция»-то в чём заключается? Чем вот по сути эта структура отличается от long? Умножением и делением на 100? Это и есть та «концепция», которую непременно надо куда-то инкапсулировать?
Эта проблема решается не усложнением кода всего проекта, а правильным написанием кода, который отвечает за взаимодействие с этой другой системой, который должен быть обособлен и полностью абстрагирован от всего остального. Чтобы основной проект вот даже слыхом не слыхивал о том, что суммы где-то хранятся в копейках ))
Ну, лично в моём проекте там полно поведения :) Некоторые вещи прекрасно решаются интерфейсами и методами расширения. Я не идеализирую EF, ни в коем случае. Там огромная куча недоработок…
Может быть я не прав, но я воспринял эту статью. как воспитание ненависти к примитивам ради неких призрачных и неописываемых словами мистических концепций. А это, по моему глубокому убеждению, путь исключительно ложный и вредный, особенно для незрелых умов, которые, не научившись пользоваться и примитивами, стремятся наплодить как можно больше структур и классов невнятного назначения, потому что так написано в умной книжке. Это я не о Вас, о многих из тех, кто это прочтёт.
Подчёркиваю, любой паттерн создан для решения каких-то проблем. Если этих проблем нет и не предвидится, любое их использование — это дорога в ад. А если проблема есть, то надо сначала подумать, какими способами можно её решить, собственной головой. Умный не тот, кто прочитал много книг. А то, кто умеет перерабатывать информацию и генерировать новую (если она конечно полезна). Тот, у кого развита интуиция за базе собственного опыта. Какие-либо авторитеты и совершенно ненужные знания обычно не помогают, а вредят интеллектуальному развитию и личному росту. Вот ей Богу, если бы тот разработчик, которого я упоминал, не прочитал ни одной книги, он бы написал намного более качественный и понятный код, а главное — научился бы думать.
var items = new object [ ] { someMoney, someOtherValue };
foreach (var item in items) Show(item.ToString());
Если бы в Вашем примере был реализован ToString(), в нём был бы хоть какой-то смысл. Хотя, и то этот смысл сомнителен, т.к. необходимость ради одного ToString реализовывать кучу операторов (для превращения Money в полноценный decimal) — это большой вопрос, и зависит опять-таки от контекста, в роли которого выступает проект.
Да Вы, верно, шутите? По-Вашему это более читабельно? Дело не в согласии несогласии, а в фактах. Сколько человек на Земле знают про Вашу структуру Money? И сколько человек на Земле знают про тип decimal? Глядя на запись «Money.FromRubles(10)» у меня сразу же возникает куча вопросов: а как эта структура будет хранить данные — с какой точностью? А не конвертирует ли она, случайно, рубли во что-то ещё в этой ф-ции? А смогу ли я использовать её в мат. выражениях? А насколько она производительна? И т.д. Вы сами посмотрите на этот код через полгодика и будете судорожно пытаться вспомнить, зачем Вы этот Money вообще ввели.
Представьте, что Вы открыли чужой код. Что для Вас будет более читабельно — вот это: «new DateTime(2015, 4, 5)», или вот это: «5.April(2015)»?
Самая главная его глупость — это то, что он слепо применял всё подряд о чём прочёл. И здесь я вижу ровно то же самое. Меж тем,, как надо совершенно ясно понимать, для чего создавались те или иные решения, и всегда думать, прежде чем применять что-то, проходя самостоятельно тот путь, который прошли до Вас, но уже гораздо быстрее, т.к. на пути есть указатели. А если Вы сразу переноситесь в конечную точку рассуждений, Вы с очень большой вероятностью оказываетесь не там.
А если потребуется учесть нашествие инопланетян? Предусматривать какие-то абстракции нужно только в том случае, когда вероятность их применения достаточно высока. Иначе от них никакой пользы, кроме вреда.
И даже в случае проверки корректности данных (что совершенно не относится к Вашему примеру)… Предположим, что Вам нужно принимать от пользователя, сохранять и отображать Zip-Code, а вы, скажем, работаете с EntityFramework, в котором корректность обеспечивается атрибутами на свойствах модели. Нужна ли в этом случае обёртка над string? Нет. Всё зависит от ситуации, и универсальных на все 100% решений не существует. Никто и никогда не избавит Вас от необходимости думать, когда Вы принимаете решение использовать какой-либо готовый подход.
Ну, или же, оборачивайте в структуры все подряд: string'и, int'ы, float'ы. Оберните заодно и все объекты Framework'а. А что, вдруг пригодится? ;)
Без разницы. Money.FromKopecs — ничем не лучше.
Я уже цитировал, и процитирую ещё раз:
Где у Вас проверки на корректность как в случае в ZipCode?
Помнится, я работал с одним молодым разработчиком, который слишком любил читать «умные книжки». И однажды, когда мне пришлось, работать с его кодом, я пришёл в тихий ужас, который у меня не проходил несколько дней. Грубо говоря, у него для деления на 100 использовалась даже не одна структура, а целая иерархия из шаблонных классов. И практически каждый паттерн, который он применил, был применён совершенно не по делу, что сделало его код нечитаемым даже для него самого. И весь код был выброшен в помойку.
Хорошие решения призваны бороться со сложностью, а не создавать её на пустом месте.
В той статье про «одержимость примитивами» сказано:
Уже на этом этапе имела место ошибка в понимании этого текста, т.к. decimal уже гарантирует только корректные экземпляры.
Я сам разрабатываю довольно сложное финансовое приложение, которое давно крутится в продакшене, и мне даже в кошмарном сне не мог присниться подобный класс. Я бегло пробежался по тексту и комментам, но не увидел ответа на простой вопрос: зачем хранить сумму в копейках?
За мой немалый опыт разработчика я усвоил одну истину: самый большой вред — это одержимость не примитивами, а паттернами и «советами умных людей», не понимая их суть. И использование сложных подходов там, где они не нужны по определению.
Если Вы решите хранить и оперировать деньгами в decimal и перепишете этот класс соответствующим образом, чем он станет? Оболочкой над decimal.
И поверьте, если у Вас в системе фигурируют суммы в «long kopecs» (что изначально являлось недоработкой проектирования), то запись «decimal money = kopecs/100» будет гораздо очевиднее незнакомому с вашим кодом человеку, чем «var money = new Money(kopecs)», т.к. с Вашим Money он вообще не знаком, и ему придётся заглянуть в него и ужаснуться.
Ваш класс только тогда начнёт иметь смысл, когда не будет являться оболочкой над decimal (который и так уже всё гарантирует), а будет содержать в себе ещё что-то. Например, код валюты.
А до тех пор лучше заняться избавлением проекта от «long kopecs», а не потворствовать этому. А эта абстракция, раз уж она уже есть, пусть существует в виде оболочки над decimal, может, когда-нибудь и пригодится…