有一个代码可读性陷阱,一旦你意识到它就很容易避免,但这个陷阱无处不在:人们喜欢省略“单位unit”。
看看 Python、Java 和 Haskell 中的以下三个片段:
time.sleep(300) |
这些程序会休眠多长时间?Python 程序休眠 5 分钟,Java 程序休眠 0.3 秒,Haskell 程序休眠 0.3 毫秒。
你怎么能从代码中看出这一点呢?你不可能。
你只需要用心去体会time.sleep需要几秒钟,而threadDelay需要几微秒。
如果你经常查找,最终这些知识就会被记住,但我们怎样才能让那些以前没有遇到过time.sleep的人也能读懂代码呢?
选项1:把单位放在名称中
你可能喜欢这样:
def frobnicate(timeout: int) -> None: |
为了明确单位,这样写:
def frobnicate(*, timeout_seconds: int) -> None: |
对于支持命名参数的语言来说,使用命名参数是很好的,但这并不总是一种可能性。
即使在Python中,time.sleep被定义为一个名为secs的参数,由于实现的原因,我们也不能调用sleep(secs=300)。
在这种情况下,我们可以给这个值取一个变量名来代替:
sleep_seconds = 300 |
(banq注:使用DDD中值对象,为单位专门建立一个值对象。)
现在,代码是不含糊的,而且无需查阅文档就可以阅读。
选项2:使用强类型
将单位放在名称中的另一个选择是使用比整数或浮点数更强的类型。
例如,我们可以使用一个持续时间类型:
def frobnicate(timeout: timedelta) -> None: |
对于一个给定的浮点数,你需要被告知其单位是什么,以便能够解释它。
如果你幸运的话,这些信息就在变量或参数名称中,但如果你不幸运的话,就只能在文档中指定--或者根本就没有指定。
但是对于一个timedelta值来说,如何解释它是没有歧义的,这是类型的一部分。这也消除了代码中的歧义。
作用域范围
使用强类型或将单位放在名称中的建议并不限于变量和函数参数,它适用于API、公制名称、序列化格式、配置文件、命令行标志等。虽然持续时间是最常见的情况,但这个建议也不限于此,它也适用于货币金额、长度、数据大小等。
不要这么做:
{ |
应该这么做:
{ |
不要这么做:
request_timeout = 10
应该这么做:
request_timeout = 10s |