文章目录

  • 引言
  • 方式1:把单位放在参数名中
  • 方式2:使用强类型
  • 应用范围
  • 后记


引言

有一个代码可读性陷阱无处不在,一旦你意识到它,就很容易避免:他就是 参数单位的省略

观察下面三个程序:

Python

time.sleep(300)

Java

Thread.sleep(300)

Haskell

threadDelay 300

它们分别延时了多长时间?Python程序延时了5分钟,Java程序延时了0.3秒,Haskell程序延时了0.3毫秒。

如何从上面的代码看出来呢?根本做不到。你必须把这些函数的用法记下来:time.sleep的单位是秒,threadDelay 的单位是微秒。如果你经常查阅文档,就能记住这些知识,但是我们怎样才能让那些没有遇到过 time.sleep 的人也知道它的用法呢?

方式1:把单位放在参数名中

不要这样写代码:

def frobnicate(timeout: int) -> None:
    ...

frobnicate(300)

这样做吧:

def frobnicate(*, timeout_seconds: int) -> None:
    #  *  强制后面的参数在调用时使用关键字参数
    ...

frobnicate(timeout_seconds=300)

在第一种情况下,我们甚无法通过函数调用看出 300 是超时时间,即使我们知道 300 是超时时间,但它的单位呢?毫秒?秒?天?相比之下,第二种情况的函数调用不需要额外说明也能看懂。

对于支持命名参数的语言来说,使用命名参数是一个好办法,但这并不总是可行的。在 Python 中, time.sleep 的延时时间取决于 secs 参数,但由于函数实现的原因,我们不能像 sleep(secs=300) 这样调用 sleep 函数,在这种情况下,我们可以给该值一个名称。

不要这样写代码:

time.sleep(300)

应该这么做:

sleep_seconds = 300
time.sleep(sleep_seconds)

现在,代码的含义是十分清楚的,不需要查阅文档就能读懂。

方式2:使用强类型

将单元放入参数名中的另一种方法是使用比intfloat更强的类型。例如,我们可以使用timedelta类型。(译者注:如果某编程语言没有内置这种类型,我们也可以自定义该类型)

不要这样写代码:

def frobnicate(timeout: int) -> None:
    ...

frobnicate(300)

应该这么做:

def frobnicate(timeout: timedelta) -> None:
    ...

timeout = timedelta(seconds=300)
frobnicate(timeout)

对于一个给定的浮点数,你需要在被告知单位的情况下才能理解它的意义。如果幸运的话,它的单位在变量名或参数名中,但如果不幸的话,这只会在文档中说明或者根本没有说明。对于像timedelta这样的参数类型,我们都知道它的意义,这样做也消除了代码的模糊性。

应用范围

上面的建议并不局限于变量和函数参数,它还适用于API、metric names、序列化格式、配置文件、命令行参数等。除了最常见的timeout单位,它还适用于货币金额、长度、数据大小等。

例如,不要像这样编写返回结果:

{
   "error_code": "E429",
   "error_message": "Rate limit exceeded",
   "retry_after": 100,
}

用下面的方式替代:

{
   "error_code": "E429",
   "error_message": "Rate limit exceeded",
   "retry_after_seconds": 100,
}

不要这样设计你的配置文件:

request_timeout = 10

建议像下面这样:

request_timeout = 10s
request_timeout_seconds = 10

还有,不要这样设计你的命令行程序:

show-transactions --minimum-amount 32

建议这样设计:

show-transactions --minimum-amount-eur 32

show-transactions --minimum-amount "32 EUR"

后记

第一次尝试翻译技术类文章,可能会有一些纰漏,翻译的不好还请各位大佬多多见谅。

原文:Please put units in names or use strong types | written by Ruud van Asseldonk