大多数计算机应用程序都可以使用配置来指定行为,无论是通过命令行标志、环境变量还是配置文件。作为一名软件开发人员,处理配置时会遇到一些挑战,例如解析不合法的输入、验证它以及在程序的任意位置访问它。以 Python 为例,在这篇文章中,我想分享一些可以帮助您安全有效地处理配置的最佳实践,并且我希望和您达成共识:这些是在您自己的代码中应该遵循的合理原则。
引言
除了最简单的程序外,所有的程序都有一组参数来控制它们的行为。作为具体的例子,考虑 ls 工具的输出格式、nginx 监听的端口或 git 在提交消息中使用的电子邮件地址。根据应用程序的大小和复杂性,可能有许多这样的参数,它们可能只影响一个小的执行细节或者整个程序行为。
当您处理配置时,有很多方面需要考虑:首先,它是如何从外部传递到您的程序中的,如何解析和验证?其次,如何在程序内部处理、访问和在组件之间传递?根据应用程序的类型,您必须考虑在程序运行时用户如何检查和更新它。从操作的角度来看,您可能必须考虑如何管理、测试多个配置并将其部署到生产环境中。
每一个主题都可能变得相当复杂,值得深入探讨。不过,在这篇博文中,我只想关注第二个方面。我将介绍一些处理程序内部配置的指导原则,这些原则是经过时间检验的,我想推荐给任何开发中小型应用程序的人。
在过去,我用各种编程语言(如 Go、Scala 和 Python)构建和维护应用程序。在这篇文章中,我想以 Python 为例,因为它的动态特性允许使用很多机制用以提高开发速度和灵活性(例如,在运行时修改类),但从长远来看可能会使维护和重构更加困难。
一个简单的例子
当谈到软件应该如何工作以及组件应该如何交互的重要思想时,有时很难与实际编码联系起来。为了避免出现这种情况,让我们跳到下面的代码示例中,看看我想在本文中解决的一些问题:
# 常见的错误做法:使用字符串键访问字典
config = {
"user": {
"email": "[email protected]"
},
"port": 8080
}
# 随意访问,容易出错
print(config["user"]["email"])
print(config["port"])
在评论中,我已经给出了一些关于该代码可能存在的缺点,但是让我们现在更详细地探讨一下。
指导原则
编程是一项在智力上具有挑战性的任务,因此我认为作为软件工程师,我们应该将尽可能多的复杂任务委托给我们的工具,如 IDE、linter、格式化程序、编译器或类型检查程序。如果可以使用一个工具来发现错误和提高代码质量,那么我认为这就证明了用这种工具来编写代码是合理的。
另外,如果尽管我们仔细检查和使用了工具,但代码中仍有错误,那么应该在应用程序启动时尽快报告,这会产生一个重要的警告消息,并且在许多情况下,程序会立即退出。最糟糕的事情莫过于在一次看似成功的部署的几个小时后,半夜里发现某个配置密钥丢失。
基于这些基础,我认为处理应用程序内部配置的数据结构应该遵循以下四个原则:
- 它应该使用标识符而不是字符串键来访问配置值。
- 它的值应该是静态类型的。
- 应该尽早验证。
- 它应该声明在它使用的地方。
让我在下面解释这些原则及其作用。
一、使用标识符而不是字符串键值
可能与近年来文件交换和序列化格式的某种'JSONification'有关,以 PEP 484 为标准的字符串键词典 Dict[str, Any] 似乎已经成为许多 Python 开发人员的一站式数据结构。很简单,只需使用 json.loads() 处理一个 json 格式的字符串后放入 Python 字典,然后使用像 config["port"] 或 config["user"]["email"] 一样的代码随意访问它,就像我在介绍性示例中所做的那样。(这种方法不是 Python 独有的,例如 Scala 的 Lightbend 配置库也有一个类似 conf.getInt("foo.bar") 的 API。)如果需要新的配置条目,只需将其添加到 JSON 文件中,并在整个代码中立即使用它。


