Language agnostic 幻数与命名常数

Language agnostic 幻数与命名常数,language-agnostic,Language Agnostic,在编写代码时,尤其是在处理日期和时间时,您必须处理许多特定的数字,例如:一分钟60秒,一小时3600秒 一些人坚持使用原始值来处理其中的许多内容,而另一些人则将其放入常量以增加可读性 例如: 当然,第二个更容易阅读,但对于一些较低的值来说稍微有点高,所以你到底在哪里划界?就个人而言,我认为86400的可读性没有问题(在我的头脑中,我自动将其读作“24小时”),但会以周常数划界。我会说小时,分秒必争。更细粒度似乎并不能提供更多的可读性 我会根据项目的规模来划定界限。项目越大,抽象和常量就越多。。。

在编写代码时,尤其是在处理日期和时间时,您必须处理许多特定的数字,例如:一分钟60秒,一小时3600秒

一些人坚持使用原始值来处理其中的许多内容,而另一些人则将其放入常量以增加可读性

例如:


当然,第二个更容易阅读,但对于一些较低的值来说稍微有点高,所以你到底在哪里划界?就个人而言,我认为86400的可读性没有问题(在我的头脑中,我自动将其读作“24小时”),但会以周常数划界。

我会说小时,分秒必争。更细粒度似乎并不能提供更多的可读性

我会根据项目的规模来划定界限。项目越大,抽象和常量就越多。。。就这么简单。

我的一位教授曾经告诉我们,除了1、-1和0之外,不要在代码中添加任何幻数。这有点极端,但它仍然留在我的脑海中,并指导着我,尽管我并没有完全遵守它


在您的示例中,我希望在所有情况下都使用符号名称。

我的方法是不使用命名常量,而是将单位分开,如下所示:

long twelvePM = 12 * 60 * 60 * 1000L;
long timeout = 60 * 1000L;
  $x = strtotime('now + 1 hour');
  $y = strtotime('now + 1 day');
  $z = strtotime('now + 1 week');
Time oneHourAhead = new Time(now()).addHours(1);
Time tenMinutesAgo = new Time(now()).addMinutes(-10);
Time oneHourTenMinutesAhead = new Time(now()).addHours(1).addMinutes(10);

通过这种方式,很明显这是以毫秒为单位的,如果我以后想更改值,它们很容易调整。

我几乎到处都会使用常量(或一些可爱的衍生工具,如Rails的
15.minutes
约定)。对我来说,这是关于简化所有的“输入”;如果我在一行中的某个地方看到“10*MINUTES”,我就知道我在处理时间问题(或者有人在踢屁股)。如果我看到10*60或600,我完全可能不觉得我们处理时间这么容易。

我倾向于几乎完全使用幻数上的常数。我认为它增加了可读性,并在程序中为您提供了一个点来修复任何错误。有几种神奇的60,例如:一分钟60秒,一小时60分钟。

一天总是有24小时,一小时总是60分钟

我认为将它们命名为描述性常量的关键在于 a) 数值不清楚(604800?)
b) 该值可能有一天会改变

如果有一个相对较好的参数,那么除0或1以外的任何数字都应该是命名常量。 即使在您的示例中,您断言86400的可读性没有问题,但您的度量单位仍然存在一些模糊性

如果我在维护您的代码,我更希望看到命名常量,如:

const int secondsInDay = 86400;
。。没有太多模棱两可的地方。:)
这取决于是否有人(包括你自己……我的意思是,我很难记住我上周写的东西,更不用说去年了!)需要在某个阶段维护你的代码。

我告诉我的学生:

如果你能阅读代码而不需要 评论,那么就没有必要了 常数。如果有必要的话 解释它需要的代码 评论

我还告诉他们:

思考是不好的。如果你写 让人们不得不挖掘的代码 通过它来理解它是什么 这不是一件好事


因此,如果你能向一位同事展示这些行,并且他们不需要常数也能理解,那么没有这些行你(可能)就很好了。很可能你会想要常数。

我保存在简单的;变量的名称和注释(如果有非常神奇的数字需要)足以通过代码审查

int someDelay = 1232323; // in milliseconds.

就个人而言,我喜欢使用命名常量,以防我必须更改常量的值,然后我只需在一个位置执行该操作。

86400不合适,因为您很容易将其键入84600、88400等


输入错误的常量将是一个编译错误

我肯定会使用常量,而您可以查看86400以及24小时,未来进行维护的程序员可能不会那么聪明,并且会对该数字的确切含义感到困惑。如果有一天你回来时忘记了86400的含义,你也会遇到这种情况

魔术弦怎么样?我倾向于这样做:

long twelvePM = 12 * 60 * 60 * 1000L;
long timeout = 60 * 1000L;
  $x = strtotime('now + 1 hour');
  $y = strtotime('now + 1 day');
  $z = strtotime('now + 1 week');
Time oneHourAhead = new Time(now()).addHours(1);
Time tenMinutesAgo = new Time(now()).addMinutes(-10);
Time oneHourTenMinutesAhead = new Time(now()).addHours(1).addMinutes(10);

是的,它可能运行得稍微慢一点。但从更大的角度来看,这真的很重要吗?

就我个人而言,我会用秒每分钟,秒每小时,等等。我甚至有时会用纳米秒。如果一种语言缺少整数文字的科学符号,我会一直这样做

确切地说,这与可读性无关。每天使用SECS_而不是86400的原因不仅仅与我们对读者的一般知识的期望有关。它是关于自我记录代码的,这意味着明确地显示您的工作

当然,每个人都知道一分钟有60秒。但他们也知道一小时有60分钟。如果您使用文字60,那么代码的目的可能很明显。但为什么要冒险呢

如果您使用SECS_PER_MIN,那么很明显您正在将以分钟为单位的时间(在您的示例中仅为1分钟)转换为以秒为单位的时间。例如,您不是在以分钟为单位的时间上增加一小时,也不是在以分钟为单位的角度上增加一度。以英寸为单位测量的长度不能增加5英尺

命名常量为周围的代码提供了更多上下文。对于添加时间的示例,我们只需看一行,就知道$x需要是以秒为单位的时间。常量的名称重申$x不是以毫秒、时钟滴答声或微秒为单位的时间。这使得每个人都更容易检查和维护单元的正确性:他们可以通过查看您打算做的是您实际做的来判断。他们甚至不必接受这样的想法,即你打算在以毫秒为单位的时间上增加60毫秒,但却弄错了,因为$x实际上是以秒为单位的

命名常量也有助于避免打字错误。当然,每个人都知道有86400秒
// The base unit of time is the second
const double second = 1.0;
const double ns = 1e-9 * second;
const double micros = 1e-6 * second;
const double ms = 1e-3 * second;
const double minute = 60.0 * second;
const double hour = 60 * minute;
const double day = 24 * hour;
const double week = 7 * day;
const double year = 365.24 * day; 
// Set up a 90 second timeout
timeout(90*second);
elapsedDays = floor(elapsedtime / day);
// 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..
#define LPP57   57     // Lines per page
3.months.ago
1.year.from_now
TimeHelper.months().ago(3);
$x = strtotime('now + 1 hour');
$y = strtotime('now + 1 day');
$z = strtotime('now + 1 week');
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);