惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 聂微东
IT之家
IT之家
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Y
Y Combinator Blog
博客园 - 【当耐特】
The Cloudflare Blog
宝玉的分享
宝玉的分享
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
Visual Studio Blog
小众软件
小众软件
博客园_首页
Last Week in AI
Last Week in AI
J
Java Code Geeks
V
V2EX
雷峰网
雷峰网
Apple Machine Learning Research
Apple Machine Learning Research
阮一峰的网络日志
阮一峰的网络日志
腾讯CDC
博客园 - 司徒正美
Engineering at Meta
Engineering at Meta
The GitHub Blog
The GitHub Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
MyScale Blog
MyScale Blog
云风的 BLOG
云风的 BLOG
The Register - Security
The Register - Security
M
MIT News - Artificial intelligence
Microsoft Azure Blog
Microsoft Azure Blog
T
The Blog of Author Tim Ferriss
N
Netflix TechBlog - Medium
F
Full Disclosure
B
Blog
H
Help Net Security
C
Check Point Blog
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Jina AI
Jina AI
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
L
LangChain Blog
P
Proofpoint News Feed
D
Docker
Microsoft Security Blog
Microsoft Security Blog

卡瓦邦噶!

服务器高性能网络调优 | 卡瓦邦噶! 为何写作 | 卡瓦邦噶! 读《金阁寺》 | 卡瓦邦噶! 雨季又来 | 卡瓦邦噶! MTU Probe 引起的初始延迟 | 卡瓦邦噶! 3.5 秒的固定延迟问题 | 卡瓦邦噶! 学习网络的一点经验 | 卡瓦邦噶! ARP 问题诊断 | 卡瓦邦噶! 网络断断续续…… | 卡瓦邦噶! Piccolo P2P 镜像分发 | 卡瓦邦噶! 一起看电影 | 卡瓦邦噶! 《征服C指针》 | 卡瓦邦噶! 我的姥姥 | 卡瓦邦噶! Python的哲学 Python 3.5的新特性 学校不教的计算机课 垃圾回收(GC)的三种基本方式 在编程中体验纯粹的快乐 从《美丽新世界》谈自由 在快钱实习 迷人的嗓音和迷人的故事——《Sleepyhead》 Python 的十个自然语言处理工具 记一个愚蠢的bug 一年炉石传说的游戏体验 《以撒的结合:重生》网页版图鉴 分清 C++的指针、引用和数组 笑话三则 自由比皇帝更伟大——《悲惨世界》笔记 Git 10 周年访谈:Linus 讲述背后故事 用 0x3f3f3f3f 设定最大int值的优点 Joel给计算机系学生的建议 一个词法分析器的简单实现 怎样才算健康的生活方式 MacVim 配置攻略 学习培训课程的视频效果好吗? 语言的控制 可悲的大多数 CSS样式思维导图 2014年终总结 奥巴马成为首位写程序的美国总统 青岛老城区的下水道好在哪里? 做优秀 UI 的七个建议(第二部分) 选择爱情的骑士 Git简明教程 Java集合总览 读 《1984》 java问答:终极父类(六)——等待/唤醒和接口 Java 问答:终极父类(五)——toString() Hyperlapse快速视频背后的技术细节 平庸之恶 Java程序员须知的七个日志管理工具 苏州 逛书摊随想 关于考试作弊 你的工作不仅仅是编程 推荐在线学习Java的英文资源 关注女性命运——《千禧年三部曲》 用好你的幻灯片——《演说之禅》 使用ReentrantLock和Lambda表达式让同步更纯净 新手学编程,从哪里开始? 程序员都是工程师吗? 不要学习代码,要学会思考 Java 问答:终极父类(四)——hashCode() Java 问答:终极父类(三)——finalize()和 getClass() 程序员职业之路的选择 我是一名摄影家 写给何小树的城市指南 为什么一些语言会比别的快? Java的常见误区与细节 跟朋友在一起玩游戏 死神永生——读《三体》 五种类型的程序员 创业圣经——读《黑客与画家》 纪念加西亚·马尔克斯 Junit中处理异常的另一种方式:catch-exception Java8采用Martin Fowler的方法创建内部DSL Linux HotSopt虚拟机GC线程的CPU占用率 J2EE概念介绍 如何成为一名黑客 Java 问答:终极父类(二)——equals()方法 为什么我喜欢Java Java 问答:终极父类(一)——clone()方法 七个改变世界的Java项目 java中默认类型转换的小问题 传统与创新 欢迎来到互联网 莫言和马尔克斯——读《生死疲劳》 位运算的妙用 读《人为什么活着》 写博客教会我的事情 中国特色操作系统 2013年总结 《永不妥协》影评 恨不相逢未嫁时——《廊桥遗梦》影评 如何优雅地使用PPT 给明年依然年轻的我们 天才与柱子 黑客守则和黑客精神 Looking for Freedom——《被解救的姜戈》 简洁之道
像设计 UI 一样去设计配置项
laixintao · 2022-06-19 · via 卡瓦邦噶!

在蚂蚁金服工作的时候,见到和使用了很多设计糟糕的系统,其中涉及最糟糕的叫做一个  AntX 的东西,现在想起来还会吓得发抖。

具体的实现已经记不太清了,因为自己从来也没有真正掌握过。只是记得这个其实是一个动态配置的系统,要使用它,在你的应用中要写入3个模板文件,其中一个模板会先进行 render,再去用这些变量 render 另外一个模板;render 的过程用到的变量是在一个 web 界面上配置的,并不存在于代码中;实际 render 出来的结果,有一些是程序编译的时候注入实际变量,貌似有一部分还是在运行时进行注入的。

复杂的模板文件、每一个模板还是使用不同的语法、需要在 web 配置、配置区分编译时和运行时变量、区分不同的环境变量。这听起来就是一个灾难了,我相信整个公司也找不到几个人能把这个最终配置生成的过程说的明明白白。最终大家也承认这套系统无法继续维护了,程序中已经存在有很多变量其实是没有用到的,但是程序跑的好好的,谁也没有动力去梳理一遍。最后,大家决定写一个新的配置系统来替代它。

Config 是面向用户的东西,应该像 UI 一样追求简洁,易懂,避免歧义。因为配置错误而导致的事故数不胜数,其实,很多都是由配置的作者以及使用者的理解有代沟造成的。这篇博客就来讲一讲我觉得不错的配置实践。

There should be one– and preferably only one –obvious way to do it.

软件的输入有很多种,命令行参数、环境变量、stdin、配置文件等都可以作为配置项去控制软件的行为。很多软件对同一个配置提供多种配置方式,增加了复杂度。

比如 Etcd 的这个 BUG:grpc gateway 在使用 –config-file 的时候默认是 false,不使用 –config-file 的时候是 true。即使 –config-file=/dev/null 也会变成 false。当时花了很长时间去排查。

我觉得对于服务端的软件,其实大部分配置都要求从配置文件中配置就可以。在 lobbyboy 这个项目中验证了一下自己的想法。lobbyboy 作为一个 server 端软件,所有的配置只能从配置文件输入,除了 -c 可以改变配置文件的 Path 之外没有别的命令行参数。

Nginx 的命令行也没有多少参数,大部分配置都是通过配置文件来控制的。

当然对于 Client 端软件来说,就比较复杂了,很多参数同时支持环境变量、args、xxxrc 文件配置,会比较用户友好一些。比如 iredis 的配置文件读取顺序是:

  • Options from command line
  • $PWD/.iredisrc
  • ~/.iredisrc (this path can be changed with iredis --iredisrc $YOUR_PATH)
  • /etc/iredisrc
  • default config in IRedis package.

客户端软件的配置最好遵守 XDG Base Directory Specification

Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.

让配置更加简单一些,在设计的时候,可以考虑这几个问题:

  1. 这个配置是否有必要?用户在大部分场景下是否用默认值就足够了?
  2. 多个配置是否可能用一个配置没有歧义地讲清楚?
  3. 可以这样考虑:添加一个新的配置的时候,如何使用最少的语言将这个配置解释清楚?

在 UI 的设计中,每一个像素都是重要的,每一个空间都要想办法争取节省,添加太多没必要的东西,将会把UI变得不直观。配置也是,配置不是一个无限大的文件,配置的添加是会带来成本的,不是程序运行的成本,而是人的成本,这比运行的性能更加重要。

说到动态配置,很多时候我都在怀疑这到底是不是一个伪需求。现在的应用都被设计成无状态的,可以随时重启的。那么我修改配置的时候,是否可以改一下配置文件然后重新部署?当然,如果有上千个实例的话,修改速度可能会成为一个问题。

有动态配置功能的时候,一个误区是开发者会将所有“感觉将来可能会修改”的配置都放到动态配置中。其实我觉得所有的配置都可以先作为 hardcode,如果发现需要修改的多了,再移动到配置文件或者动态配置中。

Json 绝对是一个糟糕的配置语言。它的优点在于机器读取和解析没有歧义,不像 Yaml 那样。

Why JSON isn’t a Good Configuration Language

但是它对于人类编辑来说,实在太不友好了:

  • json 只是易于解析但是太难编辑,非常容易出错。比如 [] 不允许在末位添加 ,,否则会出现格式错误。这样,你每次编辑的时候,添加一行会出现两行 diff.
  • json in json 更是噩梦。我发现一个规律,就是在有 json 的地方,就会有 json in json(指的是 json 里面有一些 value,是字符串,字符串只是添加了转义的 json)。甚至有可能有 json in json in json.
  • 比如很多list都设计成 items:[{key: name, value:jack}],一个list 这已经就已经有两层的嵌套了。
  • Json 对于 line editor,比如 sed,awk 也不够友好。
  • 不支持注释,导致无法在文档里面给出一个 self-explain 的 example.

If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.

很多配置的名字都和实现绑定,可能是一个思维定式。为一个配置想出来一个好的名字,可以尝试忘记实现的细节,想一想如何能够直白、没有歧义地、容易被记住地解释这个配置。

一个典型的例子是,配置尽量不要使用双重否定。比如 disallow_publish,最好使用 allow_publish.

uWSGI 里面有一个配置叫做 harakiri,是日语的“切腹自尽”的意思,表示一个进程在规定的时间内如果没有完成请求的处理,就会退出。比较贴切。

Redis 的 save 触发时间的配置我觉得设计的很好:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

################################ SNAPSHOTTING  ################################

#

# Save the DB on disk:

#

#   save <seconds> <changes>

#

#   Will save the DB if both the given number of seconds and the given

#   number of write operations against the DB occurred.

#

#   In the example below the behaviour will be to save:

#   after 900 sec (15 min) if at least 1 key changed

#   after 300 sec (5 min) if at least 10 keys changed

#   after 60 sec if at least 10000 keys changed

#

#   Note: you can disable saving completely by commenting out all "save" lines.

#

#   It is also possible to remove all the previously configured save

#   points by adding a save directive with a single empty string argument

#   like in the following example:

#

#   save ""

save 900 1

save 300 10

save 60 10000

可惜的是,这种设计好像没有什么模式可以遵循。

后记:其实这篇文章放在草稿箱里面很久了,只是有一些想法,但是不知道怎么描述比较合适。配置如同给变量起名字一样,是一个难以说清的话题。本文也只是潦草的表达了一些凌乱的想法,看了设计服务端软件配置的 4 条建议 这篇文章,决定将草稿箱里面沉睡已久的文章发出来。欢迎读者交流沟通。