Удаление жестко закодированных ценностей и защитного дизайна против YAGNI


10

Сначала немного фона. Я кодирую поиск по возрасту -> Оценить. Есть 7 возрастных скобок, поэтому таблица поиска состоит из 3 столбцов (От | До | Оценить) с 7 строками. Значения редко меняются - это законодательные нормы (первый и третий столбцы), которые остаются неизменными в течение 3 лет. Я подумал, что самый простой способ сохранить эту таблицу без жесткого кодирования - это использовать ее в базе данных в глобальной таблице конфигурации, в виде единого текстового значения, содержащего CSV (так как "65,69,0.05,70,74,0.06" уровни 65-69 и 70-74 будут сохранены). Относительно легко разобрать, затем использовать.

Затем я понял, что для реализации этого мне нужно будет создать новую таблицу, репозиторий для ее обертывания, тесты уровня данных для репозитория, модульные тесты вокруг кода, который раскрывает CSV в таблицу, и тесты вокруг самого поиска. Единственное преимущество всей этой работы - избегание жесткого кодирования таблицы поиска.

Говоря с пользователями (которые в настоящее время используют таблицу поиска напрямую - просматривая печатную копию), в значительной степени складывается мнение, что «ставки никогда не меняются». Очевидно, что это на самом деле не правильно - ставки были созданы только три года назад, и в прошлом вещи, которые «никогда не менялись», имели привычку меняться - поэтому для меня, чтобы защитно программировать это, я определенно не должен хранить таблицу поиска в приложение.

За исключением случаев, когда я думаю, что ЯГНИ . Функция, которую я реализую, не указывает, что ставки будут меняться. Если тарифы меняются, они все равно будут меняться настолько редко, что обслуживание даже не рассматривается, и эта функция на самом деле не настолько критична, чтобы что-то могло повлиять на задержку между изменением тарифа и обновленным приложением.

Я в значительной степени решил, что ничего ценного не будет потеряно, если я жестко закодирую поиск, и я не слишком обеспокоен моим подходом к этой конкретной функции. У меня вопрос, как профессионал, правильно ли я обосновал это решение? Жесткое кодирование значений - это плохой дизайн, но попытка удаления значений из приложения, похоже, нарушает принцип YAGNI.

РЕДАКТИРОВАТЬ Чтобы уточнить вопрос, я не беспокоюсь о фактической реализации. Я обеспокоен тем, что я могу сделать что-то быстрое, плохое и оправдать это, сказав YAGNI, или я могу использовать более оборонительный подход, требующий больших усилий, который даже в лучшем случае в конечном итоге приносит мало пользы. Как профессиональный программист, мое решение реализовать дизайн, который, как я знаю, ошибочно, сводится просто к анализу затрат / выгод?

РЕДАКТИРОВАТЬ Хотя все ответы были очень интересными, так как я думаю, что это сводится к выбору индивидуального дизайна, я думаю, что лучшие ответы были @ Corbin's и @EZ Hart's, поскольку они затрагивают вещи, которые я не учел в вопросе:

  • ложная дихотомия «правильного удаления жестко запрограммированных значений» путем перемещения их в базу данных против «эффективного применения YAGNI» с помощью жесткого кодирования. Существовал третий вариант размещения таблицы соответствия в конфигурации приложения, которая не влечет за собой лишних затрат правильного способа и без эффективности YAGNI. Мы, как правило, не ограничиваемся ни одним из решений, и затем все сводится к решению по соотношению цена / качество.
  • генерация кода может уменьшить накладные расходы на перемещение жестко закодированных значений в базу данных, а также устраняет мое чрезмерно сложное решение обработать CSV в таблице. Потенциально это также добавляет проблему долгосрочного обслуживания сгенерированного кода, если основные требования изменяются для метода поиска. Все это только влияет на анализ затрат / выгод, и, вероятно, если бы у меня была такая автоматизация, я бы даже не подумал о жестком кодировании чего-то подобного.

Я помечаю ответ @ Corbin как правильный, потому что он меняет мои предположения о стоимости разработки, и я, вероятно, добавлю некоторые инструменты генерации кода в свой арсенал в ближайшем будущем.


Не забывайте, что если ставки меняются, и все, что у вас есть, это жестко запрограммированные значения, вы можете испортить расчеты исторических записей при изменении ставок (и они будут изменяться независимо от того, что говорит ваш клиент).
Энди

Ответы:


6

Вы нашли недостаток в своем процессе разработки. Когда будет трудно сделать правильные вещи (создать таблицу, репо, тесты репо, сплющить тесты ...), разработчики найдут способ обойти это. Обычно это связано с неправильным поступком. В этом случае соблазнительно относиться к данным приложения как к логике приложения. Не делай этого. Вместо этого добавьте полезные средства автоматизации в процесс разработки. Мы используем CodeSmith для создания скучного, стандартного кода, который никто не хочет писать. После создания таблицы мы запускаем CodeSmith, и он генерирует DAO, DTO и заглушки для каждого из них.

В зависимости от технологий, которые вы используете, у вас должны быть похожие опции. Многие инструменты ORM будут генерировать модели из существующей схемы. Миграции Rails работают в обратном направлении - таблицы из моделей. Мета-программирование в динамических языках особенно эффективно при устранении стандартного кода. Вам придется работать немного усерднее, чтобы сгенерировать все, что вам нужно, если у вас есть сложное многоуровневое приложение, но оно того стоит. Не позволяйте чувству «вау, это боль в шее» помешать вам поступить правильно.

Да, и не храните ваши данные в формате, который требует дополнительной обработки (CSV). Это просто добавляет дополнительные шаги, которые требуют вашего внимания и тестирования.


Я бы не сказал, что миграция Rails создает таблицы из моделей ... Миграции Rails описывают изменения в таблицах. Выполнение миграции изменяет базу данных. Свойства модели, соответствующие структуре таблицы, создаются во время выполнения.
Кевин Клайн

Меня это интересует, я не рассматривал автоматизацию части первоначальных усилий до этого уровня. И эта автоматизация означала бы, что я мог бы создать полную таблицу, а не использовать CSV, чтобы сэкономить время. Меня беспокоит долгосрочное обслуживание сгенерированного кода. Создавая его заранее, я сделал предположение, что метод поиска никогда не изменится. Я полагаю, если это возможно, я должен просто принять это во внимание как часть затрат / выгод, учитывая сниженную стоимость шаблона. +1
Ребекка Скотт

Вопрос был таков: «Стоит ли мне жестко кодировать значения, когда мой клиент говорит, что они не изменятся?» и ваш ответ «нет, и на самом деле вы должны бросить ORM на проблему». Я не согласен. Существуют более простые варианты, которые позволят OP избежать жесткого кодирования. Внесение больших дополнений в архитектуру для поддержки вещей, явно обозначенных как ненужные, неэтично. К сожалению, многие разработчики предрасположены к таким вещам. И я должен сказать, что я не согласен на 100% с вашим предложением не «позволять чувству,« вау, это боль в шее », мешать вам делать правильные вещи». Эти чувства имеют значение!
user1172763

10

Отключить и расширить ответ @ Thorbjørn Ravn Andersen: Хорошее начало - держать расчет / поиск в одном месте.

Ваш мыслительный процесс защиты против ЯГНИ является распространенной проблемой. В этом случае я бы посоветовал ему сообщить еще две вещи.

Во-первых, как были представлены требования пользователя? Они указали возможность редактирования ставок? Если нет, то является ли дополнительная сложность частью того, за что вы можете выставить счет или нет? (или если вы работаете в штате, что вы можете вместо этого тратить время на другую работу?)

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

Короче говоря, я отмечаю, что фактическое редактируемое требование вполне может быть довольно сложным, поэтому, если оно не будет уточнено, простое, вероятно, лучше.

Удачи


1
+1 за ваше второе очко. Я не пытаюсь перехитрить то, что законодательные органы могут сделать в будущем.
Дэвид Торнли

Сделайте это в функции библиотеки. Можно иметь только одного пользователя. Когда и если требования изменятся, у вас есть одно место, чтобы измениться. (Возможно, вам потребуется добавить функцию для поиска значения на определенную дату.)
BillThor

Лучший и самый полный ответ, +1
Энди

7

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


Поиск будет реализован только в одном месте (что-то вроде PensionRateLookupкласса), который затем используется глобально. Я хотел бы сделать это независимо от того, хранится ли он вне приложения или жестко закодирован, таким образом PensionRateLookupнеобходимо поддерживать только реализацию класса. Моя проблема в том, как я использовал YAGNI, чтобы прийти к выводу, что жесткое кодирование таблицы поиска приемлемо.
Ребекка Скотт

Спасибо за ваш ответ, хотя. Хранение реализации поиска в одном месте, безусловно, хороший дизайн.
Ребекка Скотт

YAGNI действителен только если вы можете отправлять новые двоичные файлы при изменении тарифов. Если вы не можете, но можете изменить конфигурацию, сделайте для нее значение конфигурации, прочитанное при запуске, с текущим текстовым представлением по умолчанию.

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

Тогда в чем проблема? Когда цены меняются, вы обновляете код и отправляете всем клиентам?

2

Дай мне посмотреть, правильно ли я понял твой вопрос. У вас есть 2 варианта реализации функции: либо вы жестко кодируете значение, и ваша функция проста в реализации (хотя вам не нравится часть с жестким кодом), либо у вас есть очень большие усилия, чтобы «повторить» много дел, которые сделаны Таким образом, вы можете развивать свои функции в чистом виде. Это верно?

Первое, что приходит мне в голову: «Самое важное в знании хороших практик - это знать, когда тебе лучше без них».

В этом случае усилия очень высоки, так что вы можете сделать это аккуратно, шансы побочного эффекта этого изменения велики, а отдача, которую вы получите, мала (как вы объяснили, похоже, что это не так). изменение).

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

Это был бы мой подход :)


Спасибо @Оскар. Техническая часть этого - def. правильный. И я согласен с тем, как бы вы подошли к проблеме, проводя рефакторинг только тогда, когда это необходимо. Итак, вы говорите, что как профессионал мы можем и должны выбирать наши принципы проектирования, основанные исключительно на соотношении цена / качество? Имеет смысл.
Ребекка Скотт

@ Бен Скотт: Добро пожаловать :). Да, на мой взгляд, принципы проектирования были созданы / каталогизированы не потому, что они выглядят красиво, а потому, что они приносят такие преимущества, как «чистота» кода, гибкость, надежность и т. Д. Но всегда есть 2 вопроса: 1- Нужно ли мне это ? 2- Позволяют ли мои ограничения (временные, технические и т. Д.) Реализовать это? Обычно это то, что заставляет меня выбирать принцип дизайна. Чрезмерная инженерия тоже плоха;) ps: если вы думаете, что это интересный ответ, пожалуйста, проголосуйте, чтобы другие люди также читали его с большей вероятностью. Спасибо! :)
JSBach


2

Это элемент, который «не изменится», пока не изменится. Это неизбежно, что это изменится, но это время может быть немного далеко.

Ваше обоснование верно. В это время клиент не просил о возможности легко изменить эти тарифы. Как таковой, ЯГНИ.

Однако вам не нужен код, который получает доступ к вашим ставкам и интерпретирует результаты, разбросанные по всей базе кода. Хороший ОО-проект позволил бы вам инкапсулировать внутреннее представление ваших ставок в классе и раскрыть только один или два метода, необходимых для использования данных.

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

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


Спасибо @berin, я не упомянул SRP в вопросе, но это было в плане. Хороший вопрос - вернуть право собственности на проблему клиенту.
Ребекка Скотт

Признание вины за то, что в будущем что-то пойдет не так, мне не кажется профессиональным.
Энди

@ Энди, какая часть в этом виновата? Представление клиенту ограничений дизайна дает им возможность либо расставить приоритеты в сложной работе сейчас, а также убрать другие вещи со стола, отодвинуть сроки или принять ограниченный дизайн сейчас, поскольку другие вещи на столе для них более важны. Вы расширяете возможности своего клиента по выбору продукта. Информирование вашего клиента о риске / вознаграждении за выбор, который вы хотите сделать в его интересах, сделает проект более плавным.
Берин Лорич

@BerinLoritsch Но это конкретное дизайнерское решение похоже на использование некачественных деталей, говорящих: «Я могу использовать шпаклевку для сантехники, чтобы закрыть эту протекающую трубу, это ваш самый дешевый вариант!» Цены будут меняться. Это само собой разумеющееся, и для профессионала безответственно строить систему, которая этого не позволяет. И экономия, вероятно, незначительна в грандиозной схеме стоимости проекта. Поместите данные в таблицу; код, который получает данные поиска, немного отличается, логика, определяющая, какую скорость использовать, одинакова в любом случае. Единственное другое решение заключается в том, как обрабатывать исторические данные после ...
Энди

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

2

Разделите разницу и поместите данные о скорости в настройку конфигурации. Вы можете использовать формат CSV, который у вас уже есть, избегая ненужных накладных расходов на базу данных, и если изменение когда-либо понадобится, это будет изменение, которое клиент сможет внести без перекомпиляции / переустановки и без ошибок. вокруг в базе данных - они могут просто редактировать файл конфигурации.

Обычно, когда вы смотрите на выбор между двумя крайностями (нарушение YAGNI или жесткое кодирование динамических данных), лучший ответ - где-то посередине. Остерегайтесь ложных дихотомий.

Это предполагает, что вся ваша конфигурация находится в файлах; если это где-то сложно, как в реестре, вы, вероятно, должны игнорировать этот совет :)


Я подумал о том, чтобы включить его в настройку конфигурации, но отложил его в сторону, потому что пользователи не очень техничны в том, что касается редактирования строки CSV, поэтому я был бы единственным, кто обновляет конфигурацию для N пользователей (поскольку я делаю всю поддержку также с точки зрения усилий) было бы проще выполнить предварительную работу, чтобы поместить ее в базу данных, которой я могу управлять из одного места. Я полагаю, что если бы это не учитывалось (если бы пользователи могли управлять своей индивидуальной конфигурацией), у меня не было бы этой проблемы. Так что очень хороший момент, спасибо.
Ребекка Скотт

Если вы объединили это с другими предложениями централизованной логики, то это отличный ответ. Это чистое зло, чтобы действительно хардкор поиск, а не в способе, который позволяет изменить его через конфигурацию. Всякий раз, когда любой другой разработчик сталкивается с этим, они будут ненавидеть вас за это. Даже один разработчик должен подумать о том, что произойдет, если их сбьет шина, и позволить следующему разработчику легко изменить значения без полной версии программного обеспечения. Только если вы ненавидите клиента и ненавидите всех других разработчиков, вы должны делать это жестко. Так что в принципе никогда.
simbo1905

2

Я подумал, что самый простой способ сохранить эту таблицу без жесткого кодирования - это использовать ее в базе данных в глобальной таблице конфигурации, в виде единого текстового значения, содержащего CSV (так как "65,69,0.05,70,74,0.06" уровни 65-69 и 70-74 будут сохранены.

Только что создал таблицу БД. (Вы думали о том, чтобы хранить всю таблицу в одном файле, вы сошли с ума?)

В таблице нужно 2 поля НЕ 3. Возраст и рейтинг. Следующая строка содержит верхнее значение! Вы нормализуетесь, даже не подозревая об этом!

Вот Sql, чтобы получить тариф для человека в возрасте 67 лет.

Select * from RateTable where Age in (Select max(age) from RateTable where age <=67) 

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

РЕДАКТИРОВАТЬ: Как уже говорили другие, сохранить код централизованно получает ставку, в случае если вся структура ставки меняется.


Привет @ Morons, спасибо за ваш ответ. Таблице фактически потребуется 3 столбца. Это единая ставка для диапазона возрастов, минимальный возраст до максимального возраста (от 65 до 69 лет на 5%). И я храню только небольшое количество данных для ограниченной цели, так что плохого в том, чтобы сделать предположение о структуре и перейти к CSV вместо целой выделенной таблицы? Я бы, вероятно, добавил разделитель строк, и разделить на строку, а затем столбец и перетащить столбцы в необходимые поля. Это всегда будет читаться гораздо больше, чем записано, поэтому я не слишком беспокоюсь о полной таблице.
Ребекка Скотт

Следующая строка содержит верхнее значение диапазона ... Это дублирование данных. Сказать <69 и> 7 - это одно и то же. Единственная причина иметь оба значения, если диапазон может иметь отверстия. ... Я говорю об использовании таблицы, потому что это проще (и лучший дизайн). Я не понимаю, почему вы думаете, что сохранение CSV в таблице сэкономит вам время и усилия. Вам все еще нужен вызов БД, чтобы получить эту строку, а затем вам нужно ее проанализировать. Как я уже говорил выше, вы можете получить тариф за один вызов БД.
дебилы

Ах, правда. Я держал саму таблицу, похожую на исходный материал ... и я упустил, что возраст - это верхний предел в вашем ответе, потому что у меня были пены, которые я дал вам пены.
Ребекка Скотт

1
«Вы деморализуете, даже не подозревая об этом!» - сначала я подумал, что это опечатка, а вы имели в виду «денормализацию», но чем больше я думал об этом, тем больше казалось, что вы в любом случае правы :)
EZ Hart

@ez Харт LOL правда.
Ребекка Скотт

1

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

У меня есть далекие воспоминания о том, что я читал известного парня из Agile / OOP (например, Дейва Томаса, Кента Бека или кого-то другого), который говорил, что их практическое правило для дублирования кода было два и только два: не реорганизуйте первый раз, когда вы что-то дублируете, так как Вы можете написать это только дважды в своей жизни. Но в третий раз ...

Это не совсем решает вопрос, так как вы спрашиваете YAGNI, но я думаю, что это говорит об общей гибкости гибких правил. Смысл гибкого подхода заключается в том, чтобы адаптироваться к ситуации и двигаться вперед.


Спасибо @Dave, это полезно. Я единственный сопровождающий с самого начала, но это большая, относительно стабильная база кода (тысячи файлов, более 100 таблиц и т. Д.), И я до сих пор постоянно удивлен (и встревожен). Последовательность определенно является одной из моих целей в будущем.
Ребекка Скотт

0

Жесткий код в функции.

  • Когда значения меняются, вы можете выставить счет клиенту снова
  • Когда значения изменятся, скорее всего, придется изменить формат таблицы, выполнение CSV приведет к потере времени
  • Проще реализовать, больше шансов быть в бюджете с текущим контрактом
  • Можно легко найти, когда его нужно будет обновить

Позвольте мне установить это некачественное значение, чтобы, когда оно наверняка перестанет работать через год, я получил повторный заказ. Это звучит сомнительно, потому что это так.
Энди
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.