Являются ли когда-либо жесткие литералы приемлемыми?

Кодовая база, над которой я сейчас работаю, усеяна жестко закодированными значениями.

Я рассматриваю все жестко закодированные значения как запах кода и пытаюсь по возможности устранить их... однако есть некоторые случаи, в которых я не уверен.

Вот два примера, которые я могу придумать, которые заставляют меня задуматься о том, что является лучшим опытом:

1. MyTextBox.Text = someCondition ? "Yes" : "No"
2. double myPercentage = myValue / 100;

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

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

Кто-нибудь может предложить подходящий способ справиться с таким жестким кодированием? And can anyone think of any places where hard coding is an acceptable practice?

21 ответ

Решение

И может ли кто-нибудь придумать, где жесткое кодирование является приемлемой практикой?

  • Небольшие приложения
  • Одиночные проекты
  • Выбросить
  • Недолговечные проекты

Для краткости все, что не будет поддерживаться другими.

Ну и дела, я только что понял, как быть программистом-разработчиком больно мне в прошлом:)

Настоящий вопрос не в жестком кодировании, а в повторении. Если вы воспользуетесь отличным советом из "Прагматичного программиста", просто не повторяйте себя (СУХОЙ).

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

Конечно, жесткое кодирование иногда приемлемо. Следование догме редко бывает так полезно, как использование вашего мозга.

(Для примера этого, возможно, интересно вернуться к войнам goto. Сколько программистов, как вы знаете, поклялись всем святым, что goto является злом? Почему тогда Стив Макконнелл посвящает дюжину страниц взвешенному обсуждению тема в коде завершена?)

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

Это не значит, что "самая простая вещь" не должна быть читабельным кодом. Это может иметь смысл, даже в броске, чтобы написать:

const MAX_CACHE_RECORDS = 50
foo = GetNewCache(MAX_CACHE_RECORDS)

Это не зависит от того факта, что за три итерации кто-то может попросить настроить количество записей в кеше, и вы можете в конечном итоге выполнить рефакторинг константы.

Просто помните, если вы идете в крайности такие вещи, как

const ONE_HUNDRED = 100
const ONE_HUNDRED_AND_ONE = 101

мы все придем на The Daily WTF и посмеемся над тобой.:-)

Считать! Это все.

Это никогда не хорошо, и ты только что доказал это...

double myPercentage = myValue / 100;

Это НЕ процент. То, что вы хотели написать:

double myPercentage = (myValue / 100) * 100;

Или правильнее:

double myPercentage = (myValue / myMaxValue) * 100;

Но эти жестко запрограммированные 100 запутались в твоих мыслях... Так что воспользуйся методом getPercentage, который предложил Колен:)

double getpercentage(double myValue, double maxValue)
{
   return (myValue / maxValue) * 100;
}

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

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

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

Случай 2: для случая 2 вы правы: законы "процента" не изменятся (здесь разумно), поэтому вы можете жестко встроить код.

Случай 3: третий случай, когда вы думаете, что ситуация может измениться, но вы не хотите / не имеете времени загружать ResourceBundles или XML или что-то еще. В этом случае вы используете любой возможный механизм централизации - ненавистный класс Singleton - хороший - и продолжайте в том же духе, пока вам действительно не понадобится решать проблему.

Третий случай сложен: чрезвычайно сложно интернационализировать приложение, не выполняя его на самом деле... так что вам захочется что-то запрограммировать и просто надеяться, что, когда парни из i18n постучат, ваш код не самый плохой. дегустация кода вокруг:)

Изменить: позвольте мне упомянуть, что я только что закончил проект рефакторинга, в котором предыдущий разработчик поместил строки подключения MySql в более чем 100 мест в коде (PHP). Иногда они были прописными, иногда строчными и т. Д., Поэтому их было трудно найти и заменить (хотя Netbeans и PDT очень помогли). Есть причины, по которым он / она сделал это (проект под названием POG в основном вызывает эту глупость), но нет ничего, что кажется менее хорошим кодом, чем повторять то же самое в миллионах мест.

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

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

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

Я использую константы для таких вещей, как имена тестовых файлов для сравнения.

Лучший способ для вашего второго примера - определить встроенную функцию:

double getpercentage(double myValue)
{
   return(myValue / 100);
}

...

double myPercentage = getpercentage(myValue);

Таким образом, гораздо более очевидно, что вы делаете.

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

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

Следует избегать жесткого кодирования, так как Дракула избегает солнца. Это вернется, чтобы укусить тебя в задницу в конце концов.

"жесткое кодирование" - это не та вещь, о которой стоит беспокоиться Дело не в том, есть ли специальные значения в коде или в конфигурационных файлах, дело в том:

  • Если ценность может когда-либо измениться, сколько работы это и как трудно найти? Поместить его в одном месте и сослаться на это место в другом месте - это не большая работа и, следовательно, способ обезопасить себя.
  • Будут ли программисты сопровождения точно понимать, почему ценность такая, какая она есть? Если есть какие-либо сомнения, используйте именованную константу, которая объясняет значение.

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

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

Нет.

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

Текст для условий должен быть в файле ресурсов; вот для чего это.

Не обычно (допустимы литералы с жестким кодированием)

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

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

ИМХО, облегчение чтения программ должно быть второй натурой опытного профессионала в области программного обеспечения. Сырые числа редко общаются осмысленно.

Дополнительное время, затрачиваемое на использование именованной константы, сделает код читабельным (легко запоминающимся) и полезным для дальнейшего повторного анализа (повторное использование кода).

Помните, что вы забудете значение любого неочевидного жестко закодированного значения.

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

Пример Delphi:

Длина:= длина * 0,3048; { 0.3048 переводит футы в метры}

Это нормально, если вы не проводите рефакторинг, юнит-тестирование, рецензирование кода. И вы не хотите постоянных клиентов. Какая разница?

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

Потребность может прийти во многих формах:

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

  2. Пользователь должен иметь возможность изменить значение.

Я не вижу необходимости избегать жесткого кодирования. Я вижу необходимость изменить вещи, когда есть явная необходимость.

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

I tend to view it in terms of the project's scope and size.

Несколько простых проектов, над которыми я работаю соло? Конечно, я много чего пишу. Инструменты я пишу, что только я буду когда-либо использовать? Конечно, если это будет сделано.

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

В вашем примере текстовое поле должно быть локализуемым, так почему бы не класс, который обрабатывает это?

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

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

Я обычно добавляю набор вспомогательных методов для строк и чисел.

Например, когда у меня есть строки типа "да" и "нет", у меня есть функция с именем __, поэтому я вызываю __("да"); который начинается в проекте, просто возвращая первый параметр, но когда мне нужно сделать более сложные вещи (например, internationaizaton), он уже есть, и параметр может использоваться как ключ.

Другим примером является НДС (форма британского налога) в интернет-магазинах, недавно он изменился с 17,5% до 15%. Любой, кто жестко закодировал НДС, выполнив:

$vat = $price * 0.175;

затем пришлось пройти через все ссылки и изменить его на 0,15, вместо этого супер полезным способом было бы иметь функцию или переменную для НДС.

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

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

По моему мнению, жесткое кодирование - это когда вы верите, что переменная / значение / определение и т. Д. Никогда не изменится, и создаст весь ваш код на основе этого убеждения.

Примером такого жесткого кодирования является книга "Обучи себя за 24 часа", которую все должны избегать.

Другие вопросы по тегам