软件与配置

前段时间不间断的开发新项目,实际是想得多,写得少,最后落实到代码中,大概也就200多k文件。现在回头看一下,觉得还挺满意的,因为每个新项目会找出些不一样的地方,不求做到最好,但求标新立异,否则岂不是失去了开发的意义,也辜负了“程序猿”这个需要些许创造性的工作。

每次新项目达到一个阶段,能回顾一下,总是极好的。这次细想一下,有什么值得总结的地方,就又回到了“软件配置”这个极庸俗的话题上来了。

在我看来,任何软件都少不了配置,但是在之前的文章中我也提到过,配置是软件的大敌。任何软件配置越复杂,学习成本也就越高,这是一种反人类的趋势,所以这种软件,要么被更新,更简单的软件取代,要么就根本无人问津,消失在软件的海洋中。

当然,配置也可以被广泛的定义,形式是多种多样的,有些还是群众们喜闻乐见的,不能一棒子打死了。下面谨罗列一下我心目中的配置文件类型,和它们的适用范围。

第一阶段,单纯的key-value

这应该是最常见的一种配置,也最接近配置文件的本意。所谓人各有所好,软件在部署的过程中会遭遇不同的平台,也会遇到不同的适用情况和环境,这个时候就需要依靠配置文件来告诉软件应该怎样正确的运行。操作系统中的环境变量就是一种最常见的配置,PATH定义了用户需要的可执行文件的搜索范围,SHELL决定了和人交互的shell版本。在web应用中,数据库连接,域名,api签名秘钥等等都应当以配置的形式出现,否则就是给懒惰的开发者增加麻烦。

为什么说是“懒惰的开发者”,应为这些配置其实都可以通过在源代码中通过if-else条件来解决,要是碰到个勤快的开发(也许也是愚蠢的开发),就会把签名秘钥写在代码中,通过if-else来判断哪种环境应该调用哪种签名生成规则。但是在编程界,“懒惰是一种美德”,前面的做法非但徒增开发的难度,也不够灵活,用逼格更高的话来说,就是“不够优雅”。

所以需要用到key-value类型的配置。通常情况下,这种配置文件的出现形式会是一个json文件或是一个xml文件。假如这种配置文件不需要做到跨语言调用的话,跟进一步的做法是直接使用软件可用的脚本语言,通常会于源代码的语言保持一致。像我们写nodejs应用,使用js文件来做配置,就会比用json来的更加灵活。

第二阶段,预定义方法

下面提到的配置类型都有别于狭义的配置文件。比如说某些预先定义好的方法。我们可以在软件中预先定义好一些方法,这些方法我们不知道会不会用到,也不知道什么时候会用到,唯一明确的一点就是,我们知道这些方法能接受哪些参数,并且会得到哪些输出。我们在定义这些方法时,假如能确保他们的参数形式保持一致,那就更好了。这样对于习惯拿来主义的用户或我们自己,就更加的便利了。

具体的例子,比方说rails中的路由就是个这样的例子(从routes.rb文件的位置也可以看出它就是个配置文件),作者给我们定义好了一系列的方法,getpost,最有意思的就是resource。我们知道这些方法需要什么样的参数,能得到什么样的效果,假如我们不用这些配置,那么写上完整的路由控制代码,也能达到一样的目的。但是不需要,因为我们“很懒惰”。

第三阶段,钩子

如果你对于软件的使用者有足够的信心或信任,那么完全可以将一些接口留给用户来实现,软件中的钩子就是一个很好的例子,这在很多full-stack的框架中是很常见的,另一个场景是git的hook,在每个命令的前后,git都预留了钩子由用户来实现,这样它的可玩性就高了很多,到了github上,网站把很多常用的钩子打包成一个个模块,用户只需要给需要的模块打上勾就行了,这也可以称为配置的一种形式。

第四阶段,可编程性

这已经脱离了配置的范畴了,一些软件提供强大的api,用户通过这些api来拓展软件,甚至集成到软件本身。比如nginx使用lua来作为对单纯配置的拓展,实现了任何你所需要的功能。而github有一个很有意思的项目,叫做hubot,是一个智能机器人项目,以消息的输入输出作为基本要素,用户可以加上任意的adapter,为hubot增加应答规则。其核心非常简单,但是众人拾柴火焰高,也许日久天长,这种基于规则库的低级智能,真的能发展成影响到每个人生活方方面面的智能管家。

第五阶段,无配置文件

从智能的话题延伸出去,既然软件本身需要具有智慧,那么为什么不能领悟它自己的需求,而要由人来给它写好配置?最起码,软件要能记忆曾经执行的过的操作,记录过的配置。

以两个monitor软件为例,’supervisor’是一款老牌的进程监控软件,由python写成,’pm2’是后起之秀,由nodejs写成,但是他们都不局限于监控python或nodejs进程,而可以做到全平台任意进程的监控。

假如初次使用这两款软件,更多的人会习惯于’supervisor’的操作方式,先写好一个配置文件,也许叫做supervisor.conf,定义好有哪些程序需要运行,执行文件的路径,环境变量,等等。然后我们敲下’supervisord start’来让这些进程运行起来,一切看起都很完美。

然后我们开始使用pm2,一开始会惊奇于它没有要求任何配置文件,你找到需要执行的文件,敲下pm2 start app.js,程序就开始执行,然后我们就可以通过start|restart|reload|kill等一系列命令操作这个进程。这个过程没有任何要求编写配置文件的步骤。

这怎么可能?我一开始的反应是这样,然后开始在各个目录中翻找所谓的’默认配置’,发现一无所获,后来我阅读了pm2的源代码,发现其实所有的配置,都在第一次启动进程的时候被忠实的记录下来。事情本该如此,既然第一次我已经告诉了软件需要的所有参数和变量,为什么有那么多的软件,还需要进行人为的干预来决定需要的参数,这不是一个优秀软件应该具备的素质。

我最近在修改一个在团队内部用了一段时间的部署工具sneaky。一直以来它都工作的很好,唯一的烦恼是在发布一个新项目前需要编写一段配置文件,填上发布的目标地址,端口,必要的时候再加上一些钩子。近期的一次更新已经将原本需要的5到6个配置项缩减到最少1个。下一步,当然是干掉配置文件。我们告诉它,把软件部署到某某服务器,然后到了下次,我们需要干同样的事时,软件已经比我们先知道它要做的事。这才是软件的未来。

Comments