2

设计服务端软件配置的 4 条建议

 2 years ago
source link: https://www.zlovezl.cn/articles/how-to-design-config-file-for-software/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在设计和开发服务端(后端)软件时,配置文件是一个绕不开的话题。

配置文件是一种用于存放各类可配置项的特殊文件。每个软件都会预设一些默认配置,但这些默认值不可能适用于所有情况。因此,到了不同的环境中,我们常常需要用配置文件对其进行扩展和修改。

拿版本控制软件 git 举例。大部分用户的 home 目录(~)都存放着一份 .gitconfig 配置文件,里面写着自己的用户名和邮箱地址:

[user]
    name = piglei
    email = [email protected]

就像软件的任何一个主要功能一样,配置文件也会极大的影响软件的使用体验。良好的设计能让软件变得更易用,糟糕的设计则会带来许多意想不到的问题,将用户拒之门外。

在这篇文章中,我整理了 4 条关于“软件配置文件”的设计建议,希望能对你有所帮助。

1. 最好不给配置也能用

在网络世界里,每过一天,人们的耐心似乎就又比前一天减少了一丁点。一个制作精良的短视频,如果 3 秒钟之内无法抓住你,你的右手拇指就会条件反射般将它划走。

现在,假设你开发了一个非常有用的工具软件,并发布到了网上。软件的功能非常全面,所有人在使用它之前,需要编辑一份包含 20 项配置的配置文件。你猜,有多大比例的潜在用户会直接掉头走掉?

当我们想要一件东西时,总是一刻也不想等。因此,初始的配置过程麻烦与否,会强烈影响人们尝试软件的决心。在这方面,我认为最好的体验是:无需提供任何配置,便能直接使用软件 80% 以上的功能。

假如无法做到这一点,我们也应该试着从以下几个方面着手,尽量降低用户的配置成本,压缩从“开始安装”到“可使用”之间的等待时间。

1.1 预设合理的默认值

为了将必须由用户提供的配置项,压缩到最少。你得给软件的所有配置项预设一个足够合理的默认值。这些默认值应当能让尽可能多的用户满意。

举个例子,假如你的软件依赖一个可用的 Redis 服务。那么请将该项配置的默认值设为约定俗成的缺省地址: redis_url: redis://localhost:6379/0。这样,当用户的机器上刚好跑着一个 Redis 服务时,便可免去调整这个配置项的麻烦。

1.2 延迟部分配置项

软件复杂到一定程度后,可配置项也常常会多到令人咋舌。许多配置在开发者的眼里,常常都显得特别关键,无法通过预设默认值来简化。此时,想让用户少填一些配置,似乎成了不可能完成的任务。

面对这种情况,我们可以尝试把配置项拆分为两种类型:最少配置项其他配置项。用户在使用软件时,只需提供一份包含最少配置项的文件。剩下的配置,可延迟到使用软件时,通过友好的交互界面要求用户填写。

举个例子,你提供的软件包含一个 Web 站点。要使用它,用户只需提供 1 个配置项:MySQL 数据库地址即可。之后,他可以通过浏览器访问站点,逐步补完其他功能所需的剩余配置项。

2. 永远别默认“管理员密码”

在给配置项预设默认值时,有一点很容易做过头——将关键的安全类配置设置固定的默认值。举个例子,你的项目在第一次启动时,会创建一个具有最高权限的内置管理员角色。为了降低用户的配置成本,该角色的密码被硬编码了一个默认值:

# 重要:请在你的配置文件里修改该默认密码,否则将会带来严重
# 的安全风险。
SUPER_USER_PASSWORD = "proje2p#admin@321"

一旦系统设置了一个默认密码,那么 90% 以上的用户绝对不会去修改它——无论提醒文字说的多危险都没用。当软件传播开来后,这个固定密码会给许多黑客提供便利,带来灾难性的后果。

除了密码以外,任何秘钥类的配置也都不应该提供固定的默认值。你应该总是要求用户手动配置它们。或者,在软件第一次启动时,生成一个随机值也行。做法如下所示:

# 成功安装软件后,弹出提示文字:

恭喜,你已经成功安装了 nice_software。因为你没有在配置里提供
管理员密码,该值已经被设置为随机值:fuiwe2shdvwi23

在之后的流程里,你可以再次要求用户输入该随机密码进行验证,并提供一个新密码。这样也能有效降低安全风险。

除了密码和秘钥外,Web 服务启动时默认绑定的网卡设备,也很容易制造出安全漏洞。假如某软件在启动时,默认绑定所有的网卡接口,那么当用户在携带公网 IP 的机器上安装软件时,服务可能会在毫无准备的情况下被暴露给外网,风险极高。具体可参考 Redis 配置文件中的例子

3. 描述性文本格式优先

在一些使用了动态编程语言(比如 Python、Ruby、Lua 等)的项目中,常常会出现一种独特的配置文件格式:源代码文件

举个例子,假如你有一个项目,是用 Django 框架开发的,那么你在分发项目时,完全可以支持用户提供一个 Python 脚本来作为配置文件。

# 配置文件 my_settings.py 内容
CONTACT_USERNAME = 'contact_us'
CREATE_DEFAULT_ADMIN = True
ATTACHMENTS_DIR = '~/.attachments'

# 启动项目
$ start_project -s ./my_settings.py

第一眼看上去,这种做法非常不错。如果你四处转转,甚至能发现不少开源项目都在这么干——比如 Sentry 在使用 PythonGitLab 在使用 Ruby。在灵活性方面,源码和常见的描述性文本文件(YAML、JSON 等)有着天壤之别。采用源代码格式,意味着用户能通过编写代码,折腾出令人眼花缭乱的复杂配置。

但问题是,对于配置文件来说,灵活性(或者说“可编程性”) 并不是最重要的评价指标。要评价一份配置文件设计的好坏,是否“简单易懂”、是否“易于修改”,每个配置项是否有详尽的说明才是最重要的。而对比源代码和普通描述性文本文件,你会发现前者在这些维度上并不占优。

比如,不论你选了用哪门编程语言作为配置文件格式。当用户想使用你的软件时,就非得了解一些基本语法和数据结构不可。这很可能就会把一些不热衷于此的人拒之门外。

用源代码作为配置,在某些角度上还会鼓励用户把复杂的逻辑塞进配置文件里。有时这不算什么问题,但也有些时候——尤其是当用户需要同时管理许多份配置文件时,这些藏在配置里的复杂代码逻辑,会让维护变得尤其困难。

如上所述,在满足项目需求的前提下,你应该尽量选择简单的描述性文本格式作为配置文件——YAML、TOML、JSON 都行。它们虽然不如代码灵活,但胜在上手简单。

另外,即使同为文本格式,灵活性也各有差异。当你需要从多种格式中挑选一个时,选更简单、更灵活的那个就行。也就是说,如果 TOML 和 YAML 都可以,那就用 TOML 吧。

配置文件结构

在采用了文本格式作为配置文件后,一般项目的配置会形成类似下图这种三层结构:

using_toml.png
  1. 最左侧的主配置模块:由项目开发者维护,负责提供默认配置,同时也包含绝大多数“智能”的配置生成与简化逻辑
  2. 中间部分是用户在使用软件时,需要提供的个性化配置文件
  3. 如环境异常复杂,用户亦可针对具体场景,开发工具来辅助管理和操作配置文件,降低维护成本

4. 部分或完全支持环境变量

The 12-factor App 是一个非常流行的应用架构建议。它推荐使用环境变量来作为应用配置来源,并认定这就是最好的配置管理模式——比任何文件格式都要好。

和配置文件比起来,环境变量确实有着一些天生的优势:比如门槛低、易于修改、操作系统无关性,等等。在 Kubernetes 等云原生平台上,使用环境变量配置服务尤其方便。

正因如此,除了支持从文件中读取配置项以外,你的软件最好也允许用户通过环境变量来修改配置项。

一个示例的配置文件 sample.TOML

contact_username = 'piglei'

同样的配置项,也可通过环境变量来设置:

export CONTACT_USERNAME="piglei"

要实现这个功能,你可以直接在项目中读取环境变量的值:

# config.py
import os

# 优先读取环境变量,而后是配置文件
contact_username = os.environ.get('CONTACT_USERNAME', toml_config['contact_username'])

如果你觉得手动读取环境变量太麻烦,每种编程语言一般都有各自流行的配置管理库,其中一些就支持同时管理文件和环境变量里的配置。比如 Python 的 dynaconf、Go 的 viper 模块,都非常好用。

本文分享了一些设计服务端软件配置的经验之谈,我认为其中最重要的一点,就是认识到:用户总是希望立马用上软件,而不是先折腾半天配置。

希望我们能更积极地思考如何优化配置设计,为软件增添更多色彩。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK