В этой статье Алекса Пападимулиса вы можете увидеть этот фрагмент:
private void attachSupplementalDocuments()
{
if (stateCode == "AZ" || stateCode == "TX") {
//SR008-04X/I are always required in these states
attachDocument("SR008-04X");
attachDocument("SR008-04XI");
}
if (ledgerAmnt >= 500000) {
//Ledger of 500K or more requires AUTHLDG-1A
attachDocument("AUTHLDG-1A");
}
if (coInsuredCount >= 5 && orgStatusCode != "CORP") {
//Non-CORP orgs with 5 or more co-ins require AUTHCNS-1A
attachDocument("AUTHCNS-1A");
}
}
Я действительно не понимаю эту статью.
Я цитирую:
Если бы каждая константа бизнес-правила была сохранена в каком-то файле конфигурации, жизнь была бы намного [более ( sic )] трудной для всех, кто обслуживает программное обеспечение: было бы много файлов кода, которые совместно использовали один, большой файл (или, наоборот, куча крошечных конфигурационных файлов); развертывание изменений в бизнес-правилах требует не нового кода, а изменения файлов конфигурации вручную; и отладка намного сложнее.
Это аргумент против наличия целого числа «500000» в файле конфигурации или «AUTHCNS-1A» и других строковых констант.
Как это может быть плохой практикой?
В этом фрагменте «500000» не является числом. Это не, например, то же самое, что:
int doubleMe(int a) { return a * 2;}
где 2 - число, которое не нужно абстрагировать. Его использование очевидно, и оно не представляет собой то, что может быть использовано позже.
Наоборот, «500000» - это не просто число. Это значительная ценность, представляющая идею точки останова в функциональности. Этот номер можно использовать более чем в одном месте, но это не тот номер, который вы используете; это идея предела / границы, ниже которой применяется одно правило, а выше которого другое.
Как обращение к нему из файла конфигурации, или даже из того #define
, const
что предоставляет ваш язык, хуже, чем включение его значения? Если впоследствии программе или другому программисту также потребуется эта граница, чтобы программное обеспечение сделало другой выбор, вы облажались (потому что при его изменении ничто не гарантирует, что оно изменится в обоих файлах). Это явно хуже для отладки.
Кроме того, если завтра правительство потребует «Начиная с 5/3/2050, вам нужно добавить AUTHLDG-122B вместо AUTHLDG-1A», эта строковая константа не является простой строковой константой. Это тот, который представляет идею; это просто текущая стоимость этой идеи (то есть «вещь, которую вы добавляете, если регистр превышает 500 КБ»).
Позвольте мне уточнить. Я не говорю, что статья неверна; Я просто не понимаю этого; возможно это не слишком хорошо объяснено (по крайней мере для моего размышления).
Я понимаю, что замена любого возможного строкового литерала или числового значения на постоянную, определяемую или конфигурационную переменную не только не нужна, но и усложняет вещи, но этот конкретный пример, кажется, не подпадает под эту категорию. Откуда ты знаешь, что тебе это не понадобится позже? Или кто-то еще в этом отношении?
Ответы:
Автор предостерегает от преждевременной абстракции.
Линия
if (ledgerAmt > 500000)
выглядит как бизнес-правило, которое вы ожидаете увидеть для больших сложных бизнес-систем, требования которых невероятно сложны, но точны и хорошо документированы.Обычно такие требования являются исключительными / крайними случаями, а не полезной многократно используемой логикой. Эти требования, как правило, принадлежат и поддерживаются бизнес-аналитиками и отраслевыми экспертами, а не инженерами
(Обратите внимание, что «владение» требованиями бизнес-аналитиками / экспертами в этих случаях обычно происходит, когда разработчики, работающие в специализированных областях, не обладают достаточным опытом в предметной области; хотя я все же ожидаю полной коммуникации / сотрудничества между разработчиками и экспертами в предметной области для защиты от двусмысленные или плохо написанные требования.)
При обслуживании систем, требования которых заполнены крайними случаями и очень сложной логикой, обычно нет способа бесполезно абстрагировать эту логику или сделать ее более обслуживаемой; Попытки создания абстракций могут легко привести к обратным последствиям - не только приводить к потере времени, но и к уменьшению объема поддерживаемого кода.
Этот вид кода имеет тенденцию быть защищенным фактом, что у самого кода, вероятно, есть непосредственное соответствие требованиям; то есть, когда разработчик знает, что в требованиях
500000
фигура встречается дважды, этот разработчик также знает, что она фигурирует дважды в коде.Рассмотрим другой (в равной степени вероятный) сценарий, когда
500000
в документе с требованиями встречается несколько мест, но эксперты по предмету решают изменить только один из них; там у вас есть еще худший риск того, что кто-то, изменяющийconst
значение, может не осознавать, что500000
используется для обозначения разных вещей - поэтому разработчик меняет его в одном-единственном месте, которое он находит в коде, и заканчивает тем, что что-то нарушает не понимал, что они изменились.Этот сценарий часто встречается в специальном юридическом / финансовом программном обеспечении (например, в логике страховых котировок) - люди, которые пишут такие документы, не являются инженерами, и у них нет проблем с копированием + вставкой целых кусков спецификации, изменением нескольких слов / цифр, но оставляя большую часть этого же.
В этих сценариях лучший способ справиться с требованиями копирования-вставки - это написать код копирования-вставки и сделать код максимально похожим на требования (включая жесткое кодирование всех данных).
Реальность таких требований заключается в том, что они обычно не остаются копировать + вставлять долго, а значения иногда меняются на регулярной основе, но они часто не меняются в тандеме, поэтому стараются рационализировать или абстрагировать эти требования или упростить в любом случае они создают больше головной боли при обслуживании, чем просто дословный перевод требований в код.
источник
Those requirements are typically owned and maintained by business analysts and subject matter experts, rather than by engineers
что не всегда хорошая идея. Иногда процесс превращения этих требований в код выявляет крайние случаи, когда требования либо недостаточно четко определены, либо определены таким образом, что это противоречит интересам бизнеса. Если бизнес-аналитики и разработчики могут сотрудничать для достижения общей цели, то можно избежать множества проблем.У статьи есть хороший момент. Как может быть плохой практикой извлекать константы в файл конфигурации? Это может быть плохой практикой, если это усложняет код без необходимости. Наличие значения непосредственно в коде намного проще, чем чтение его из файла конфигурации, и за написанным кодом легко следовать.
Да, тогда вы меняете код. Смысл статьи в том, что изменить код не сложнее, чем изменить файл конфигурации.
Подход, описанный в статье, не масштабируется, если вы получаете более сложную логику, но дело в том, что вы должны сделать суждение, и иногда простое решение просто является лучшим.
В этом смысл принципа ЯГНИ. Не проектируйте для неизвестного будущего, которое может оказаться совершенно другим, дизайн для настоящего. Вы правы, что, если значение 500000 используется в нескольких местах в программе, оно, конечно, должно быть извлечено в константу. Но это не тот случай в рассматриваемом коде.
Мягкое кодирование - это действительно вопрос разделения проблем . Информация о программном коде, которую вы знаете, может изменяться независимо от логики основного приложения. Вы никогда не будете жестко кодировать строку подключения к базе данных, потому что вы знаете, что она может измениться независимо от логики приложения, и вам нужно будет дифференцировать ее для разных сред. В веб-приложении нам нравится отделять бизнес-логику от HTML-шаблонов и таблиц стилей, поскольку они могут изменяться независимо и даже изменяться разными людьми.
Но в случае с примером кода жестко закодированные строки и числа являются неотъемлемой частью логики приложения. Возможно, что один файл может изменить свое имя из-за какого-то изменения политики вне вашего контроля, но также возможно, что нам нужно добавить новую проверку if-ветки для другого условия. Извлечение имен файлов и номеров фактически нарушает сплоченность в этом случае.
источник
if
основан на другой переменной! Если нужная переменная недоступна из конфигурации, вам все равно нужно изменить программное обеспечение.Далее в статье говорится о движке Enterprise Rule Engine, который, вероятно, является лучшим примером того, против чего он спорит.
Логика в том, что вы можете обобщать до такой степени, что ваша конфигурация становится настолько сложной, что она содержит свой собственный язык программирования.
Например, код состояния для сопоставления документа в примере может быть перемещен в файл конфигурации. Но тогда вам нужно будет выразить сложные отношения.
Может быть, вы также добавили бы сумму бухгалтерской книги?
Вскоре вы обнаруживаете, что программируете на новом изобретенном вами языке и сохраняете этот код в конфигурационных файлах, которые не имеют источника или контроля изменений.
Следует отметить, что эта статья была написана в 2007 году, когда подобные вещи были обычным подходом.
В настоящее время мы, вероятно, решили бы проблему с помощью внедрения зависимостей (DI). Т.е. у вас был бы «жесткий код»
который вы бы заменили на жестко закодированный или более настраиваемый
когда закон или бизнес-требования изменились.
источник
if
операторов для разных значений для каждого клиента? Это звучит как то, что должно быть в файле конфигурации. Нахождение в том или ином виде файла, при прочих равных условиях, не является причиной для того, чтобы не контролировать / отслеживать / резервировать файл. @ewan , кажется, говорит , что файл DSL - не может быть сохранен как часть проекта по какой - то причине, когда даже без кода активы , такие как изображения и звуковые файлы и документы , конечно , есть .И это выражается в наличии (и я могу утверждать, что даже комментарий является излишним):
Это просто повторение того, что делает код:
Обратите внимание, что автор предполагает, что значение 500000 связано с этим правилом; это не значение, которое может или может быть повторно использовано в другом месте:
На мой взгляд, основной смысл статьи заключается в том, что иногда число - это просто число: оно не имеет никакого дополнительного значения, кроме того, что передается в коде, и его вряд ли можно использовать в другом месте. Следовательно, неуклюжее обобщение того, что код делает (сейчас) в имени переменной только для того, чтобы избежать жестко закодированных значений, в лучшем случае является ненужным повторением.
источник
LEDGER_AMOUNT_REQUIRING_AUTHLDG1A
, вы бы больше не писали комментарий в коде. Комментарии плохо поддерживаются программистами. Если сумма когда-либо изменилась,if
условие и комментарий вышли бы из синхронизации. Напротив, константаLEDGER_AMOUNT_REQUIRING_AUTHLDG1A
никогда не синхронизируется сама с собой и объясняет свое назначение без лишних комментариев.attachDocument("AUTHLDG-2B");
строку, не сможет обновить имя константы одновременно. В этом случае, я думаю, код достаточно ясен, без комментариев и переменных-объяснений. (Хотя это может иметь смысл иметь условность с указанием соответствующего раздела документа бизнес - требований через комментарии кода При такой конвенции, кода комментария , что делает. , Что было бы уместно.)LEDGER_AMOUNT_REQUIRING_ADDITIONAL_DOCUMENTS
(что я, вероятно, должен был сделать в первую очередь). У меня также есть привычка вставлять идентификаторы бизнес-требований в сообщения коммитов Git, а не в исходный код.attachIfNecessary()
методом и просто перебрал бы все из них.Другие ответы правильные и вдумчивые. Но вот мой короткий и сладкий ответ.
Если правила и специальные значения появляются в одном месте в коде и не изменяются во время выполнения, то используйте жесткий код, как показано в вопросе.
Если правила или специальные значения появляются в нескольких местах кода и не изменяются во время выполнения, то программный код. Мягкое программирование для правила может определять определенный класс / метод или использовать шаблон Builder . Для значений мягкое кодирование может означать определение одной константы или перечисления для значения, которое будет использоваться в вашем коде.
Если правила или специальные значения могут измениться во время выполнения, вы должны их экстернализовать. Обычно это делается путем обновления значений в базе данных. Или обновите значения в памяти вручную пользователем, вводящим данные. Это также делается путем сохранения значений в текстовом файле (XML, JSON, обычный текст и т. Д.), Который многократно сканируется для изменения даты и времени изменения файла.
источник
Это ловушка, в которую мы попадаем, когда используем игрушечную задачу, а затем ставим только соломенные решения, когда пытаемся проиллюстрировать реальную проблему.
В приведенном примере не имеет значения, являются ли приведенные значения жестко закодированными как встроенные значения или определены как константы.
Именно окружающий код сделает пример ужасом обслуживания и кодирования. Если нет нет окружающих код, то фрагмент отлично, по крайней мере , в условиях постоянного рефакторинга. В среде, где рефакторинг, как правило, не происходит, разработчики этого кода уже мертвы по причинам, которые вскоре станут очевидными.
Видите ли, если есть код, окружающий его, тогда явно происходят плохие вещи.
Первое, что плохо, это то, что значение 50000 используется для другого значения где-нибудь, скажем, суммы бухгалтерской книги, в которой изменяется налоговая ставка в некоторых штатах ... затем, когда происходит изменение, сопровождающий не может узнать, когда он находит те два экземпляра 50000 в коде, означают ли они те же самые 50 Кб, или совершенно не связанные 50 Кб. И стоит ли вам искать 49999 и 50001, если кто-то тоже использовал их в качестве констант? Это не вызов для добавления этих переменных в файл конфигурации отдельного сервиса: но жесткое их кодирование в строке явно также неверно. Вместо этого они должны быть константами, определенными и определенными в пределах класса или файла, в котором они используются. Если два экземпляра 50k используют одну и ту же константу, то они, вероятно, представляют одно и то же законодательное ограничение; если нет, то, вероятно, нет; и так или иначе, у них будет имя,
Имена файлов передаются в функцию - attachDocument (), которая принимает базовые имена файлов в виде строки без пути или расширения. Имена файлов, по сути, являются внешними ключами для некоторой файловой системы, базы данных или везде, где attachDocument () получает файлы. Но строки ничего не говорят об этом - сколько там файлов? Какие типы файлов они? Как узнать, нужно ли обновлять эту функцию при открытии нового рынка? К каким типам вещей они могут быть прикреплены? Сопровождающий полностью оставлен в неведении, и все, что у него есть, - это строка, которая может появляться в коде несколько раз и означать разные вещи при каждом его появлении. В одном месте «SR008-04X» - чит-код. В другом это команда заказать четыре ракеты-носителя SR008. Здесь это имя файла? Это связано? Кто-то просто изменил эту функцию, упомянув другой файл, «КЛИЕНТ». Тогда вам, плохому сопровождающему, сказали, что файл «КЛИЕНТ» необходимо переименовать в «ЗАКАЗЧИК». Но строка «КЛИЕНТ» появляется 937 раз в коде ... где вы вообще начали искать?
Проблема игрушка является то , что значения все необычное и может быть разумно гарантированно быть уникальным кодом. Не «1» или «10», а «50 000». Не "клиент" или "отчет", а "SR008-04X".
По сути , единственный способ решить проблему непроницаемых непрозрачных констант состоит в том, чтобы поместить их в файл конфигурации какого-либо несвязанного сервиса.
Вместе вы можете использовать эти две ошибки, чтобы доказать любой аргумент.
источник
if (...) { attachDocument(...); }
.В этом есть несколько вопросов.
Одна проблема заключается в том, что должен быть собран механизм правил, чтобы все правила легко конфигурировались вне самой программы. Ответ в случаях, подобных этому, чаще всего - нет. Правила будут изменяться странными способами, которые трудно предсказать, что означает, что механизм правил должен быть расширен, когда есть изменение.
Другая проблема заключается в том, как обрабатывать эти правила и их изменения в вашем контроле версий. Лучшее решение здесь - разделить правила на класс для каждого правила.
Это позволяет каждому правилу иметь собственную действительность, некоторые правила меняются каждый год, некоторые изменяются в зависимости от того, было ли выдано разрешение или выставлен счет-фактура. Само правило, содержащее проверку, для какой версии оно должно применяться.
Кроме того, поскольку константа является закрытой, ее нельзя использовать где-либо еще в коде.
Затем составьте список всех правил и примените этот список.
Еще одна проблема заключается в том, как обрабатывать константы. 500000 может показаться неприметным, но нужно быть очень осторожным, чтобы убедиться, что он конвертируется правильно. Если применяется какая-либо арифметика с плавающей запятой, она может быть преобразована в 500 000,00001, поэтому сравнение с 500 000,00000 может быть неудачным. Или, что еще хуже, 500000 всегда работает как задумано, но 565000 почему-то дает сбой при конвертации. Убедитесь, что преобразование явное и сделано вами, а не угадыванием компилятором. Часто это делается путем преобразования его в какой-то BigInteger или BigDecimal перед его использованием.
источник
Хотя это прямо не упоминается в этом вопросе, я хотел бы отметить, что важно не скрывать бизнес-логику в коде.
Код, как и в приведенном выше примере, который кодирует заданные извне бизнес-требования, должен действительно
businesslogic
находиться в отдельной части дерева исходных текстов, возможно, названной или что-то в этом роде, и следует позаботиться о том, чтобы он кодировал только бизнес-требования просто, легко и наглядно. кратко, насколько это возможно, с минимумом шаблонного и с четкими и информативными комментариями.Его не следует смешивать с «инфраструктурным» кодом, который реализует функциональные возможности, необходимые для реализации бизнес-логики, такие как, например, реализация
attachDocument()
метода в примере или, например, пользовательский интерфейс, протоколирование или код базы данных в целом. В то время как один способов обеспечения такого разделения является «программный код» всей бизнес-логики в файле конфигурации, это далеко не единственный (или лучший) метод.Такой код бизнес-логики также должен быть написан достаточно четко, чтобы, если бы вы показали его эксперту по бизнес-области, не обладающему навыками кодирования, он смог бы разобраться в этом. По крайней мере, если и когда изменятся бизнес-требования, код, который их кодирует, должен быть достаточно ясным, чтобы даже новый программист, не имеющий предшествующего семейства с базой кода, мог легко находить, просматривать и обновлять бизнес-логику, предполагая, что качественно новый функционал не требуется.
В идеале такой код также должен быть написан на предметно-ориентированном языке, чтобы обеспечить разделение между бизнес-логикой и базовой инфраструктурой, но это может быть излишне сложно для базового внутреннего приложения. Тем не менее, если вы, например, продаете программное обеспечение нескольким клиентам, каждый из которых нуждается в своем собственном настраиваемом наборе бизнес-правил, простой язык сценариев для конкретного домена (возможно, например, основанный на песочнице Lua ) может быть просто идеальным.
источник