Магические числа против именованных констант - PullRequest
15 голосов
/ 04 марта 2009

При написании кода, особенно при работе с датами и временем, вам приходится работать с большим количеством конкретных чисел, например: 60 секунд в минуту, 3600 = секунд в час.

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

например:

$x = time() + 3600;
$y = time() + 86400;
$z = time() + 604800;

// vs

define('MINUTE', 60);
define('HOUR',   60 * MINUTE);   // 3600
define('DAY',    24 * HOUR);     // 86400
define('WEEK',    7 * DAY);      // 604800

$x = time() + HOUR;
$y = time() + DAY;
$z = time() + WEEK;

Конечно, второе легче читать, но немного OTT для некоторых нижних значений, поэтому где именно вы рисуете линию? Лично я не вижу проблем с читаемостью 86400 (в своей голове я автоматически читаю это как «24 часа»), но нарисую линию на постоянной НЕДЕЛИ.

Ответы [ 22 ]

2 голосов
/ 09 марта 2009

Моим эмпирическим правилом при обучении (то есть более жесткими основными правилами, чем в реальной жизни) было любое число, кроме -1, 0, 1 или 2, которое использовалось более одного раза, НУЖНО, чтобы быть константой. Если вы используете его только один раз, вы можете просто прокомментировать, если вы предпочитаете ...

1 голос
/ 04 марта 2009

Я бы нарисовал линию в зависимости от размера проекта. Чем больше проект, тем больше абстракций и констант ... Так просто.

0 голосов
/ 04 марта 2009

Я бы сказал, ЧАС, МИНУТА и ДЕНЬ в порядке. Похоже, что переход на более гранулированный язык не обеспечивает большей читабельности.

0 голосов
/ 05 марта 2009

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

Константы скрыты внутри методов с соответствующими именами и не повторяются (вы можете выполнить модульное тестирование типа / констант, если хотите).

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

например. для иллюстрации что-то вроде:

class Time
{
   private long time;

   Time(long hours, long minutes, long seconds, long milliseconds) { ... }
   Time(long milliseconds) { ... }

   Time addMilliseconds(long increment)
   {
      return new Time(time + increment));
   }

   Time addSeconds(long increment)
   {
      return addMilliseconds(increment * 1000);
   }

   Time addMinutes(long increment)
   {
      addSeconds(increment * 60);
   }       

   Time addHours(long increment)
   {
      addMinutes(increment * 60);
   }

   [...]

   long getTimeInMilliseconds() { ... };
   long getTimeInSeconds() { ... };
   long getTimeInMinutes() { ... };

   [.. maybe some static factory methods ...]
}

Что можно использовать так:

Time oneHourAhead = new Time(now()).addHours(1);
Time tenMinutesAgo = new Time(now()).addMinutes(-10);
Time oneHourTenMinutesAhead = new Time(now()).addHours(1).addMinutes(10);
0 голосов
/ 05 марта 2009

Работа на высочайшем уровне абстракции.

Пример Ruby ActiveSupport

3.months.ago
1.year.from_now

Тот же принцип может применяться и к другим менее гибким языкам, Java позволит вам сделать что-то вроде:

TimeHelper.months().ago(3);

Если у вас нет объектов на вашем языке, вы можете сделать это:

$x = strtotime('now + 1 hour');
$y = strtotime('now + 1 day');
$z = strtotime('now + 1 week');

Намного меньше места для неправильного толкования. Зачем возиться с вещами ниже проблемного домена, если вам это не нужно?

0 голосов
/ 04 марта 2009

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

$ x = время () + ЧАС;

едва ли лучше. Откуда мы знаем, что $ x, функция time () и постоянная HOUR - это числа в секундах? Ну, мы не можем переименовать функцию time (), но мы можем, по крайней мере, написать

$ x_seconds = time () + SECONDS_PER_HOUR;

и теперь все понятно, без комментариев.

В этом отношении, откуда мы знаем, что вы не выполняете конкатенацию строк, то есть добавляете суффикс «am» или «pm». Вы можете сказать: «Ну, никто в здравом уме не назвал бы этот ЧАС», но я не уверен.

Некоторые люди защищают венгерскую нотацию для этой цели. Мне не нравится форма венгерского языка, которая украшает имена их базовым типом (int, handle и т. Д.), Но мне нравится оформление семантическим типом (секунды).

0 голосов
/ 04 марта 2009

Я использую именованные константы

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

Иногда я встраиваю число, как подсказку читабельности.

#define LPP57   57     // Lines per page

и т.д.

0 голосов
/ 04 марта 2009

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

Мой подход представляет собой сочетание некоторых из предыдущих ответов:

// properly named variables
int daysBeforeFriday = 4;

// expanded math expressions
int minutesBeforeFriday = 4 * 24 * 60;

// 4 days in seconds (clarification comments)
int secondsBeforeFriday = 4 * 24 * 60 * 60;

// etc..

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

Извините за использование C в качестве примера этого последнего случая, но посмотрите здесь , чтобы понять, что я имею в виду. ;)

0 голосов
/ 04 марта 2009

День всегда будет иметь 24 часа, а час всегда будет 60 минут.

Я думаю, что смысл называть их описательными константами а) числовое значение не ясно (604800?) б) значение может когда-нибудь измениться

0 голосов
/ 04 марта 2009

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

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