在什么时候配置文件变成编程语言?

103

我一直在思考配置文件与代码的关系,但随着时间和想法的变化,我的观点也在不断变化。然而,越来越多的时候,我都会回到我学习Lisp时所得出的结论:数据和代码之间几乎没有区别。对于配置文件而言,这个结论似乎更加明显。从正确的角度来看,Perl脚本只不过是Perl的一种配置文件而已。这对于诸如QA和分工等任务(例如谁应该负责修改配置文件)具有相当重要的影响。

从配置文件逐渐演变成完整的语言通常是缓慢而渐进的,这似乎是由于希望拥有一个通用系统。大多数项目从几个配置项开始,例如指定日志输出位置、数据查找位置、用户名和密码等等。但是,它们开始不断增长:功能可以开启或关闭,操作的时间和顺序开始受到控制,而且不可避免的是,有人想要添加逻辑(例如,如果机器是X,则使用10,如果机器是Y,则使用15)。在某个特定点上,配置文件会变成一种特定领域的语言,而且往往是编写不良的语言。

现在,为了阐明问题,这里是我的问题:

  1. 配置文件的真正目的是什么?
  2. 是否应尽可能保持配置文件简单?
  3. 谁应该负责对其进行更改(开发人员、用户、管理员等)?
  4. 它们应该在源代码控制下吗(参见问题3)?

正如我之前所说,我的答案不断变化,但现在我认为:

  1. 允许非程序员快速更改大量行为。
  2. 是的,任何非粗粒度的东西都应该写入代码中。
  3. 用户应该负责配置文件,而程序员则应该负责配置层,位于配置文件和代码之间,以便更细粒度地控制应用程序。
  4. 不需要,但更细粒度的中间层应该要有源代码控制。

27
当它们成为图灵完备时,当然可以! - aib
2
正则表达式虽然不是图灵完备的,但仍被视为一种计算机语言。 - Chas. Owens
“文件”对于某些配置情况并不十分充分,因此出现了像 gconf 这样的系统。 - Ali Afshar
1
gconf和文件之间实际上没有真正的区别。Gconf实际上只是一系列带有文件的目录,并具有内存表示。即使您要启动RDBMS,它也可以由单个文件表示。问题在于配置文件中有多少复杂性是安全/良好的。 - Chas. Owens
OpenBSD的pf(防火墙)配置格式是它自己的语言:http://man.openbsd.org/OpenBSD-current/man5/pf.conf.5#GRAMMAR - Neil McGuigan
显示剩余2条评论
19个回答

42

非常有趣的问题!

我倾向于将我的配置文件限制为非常简单的“键=值”格式,因为我完全同意您的观点:配置文件很快就会变成完整的程序。例如,任何曾经尝试过“配置”OpenSER的人都知道你所说的感觉:这不是配置,而是(痛苦的)编程。

当你需要你的应用程序以一种你今天无法想象的方式非常“可配置”时,你真正需要的是一个插件系统。你需要以一种使其他人能够编写新插件并在将来将其挂钩到你的应用程序中的方式开发你的应用程序。

所以,回答你的问题:

  1. 配置文件的真正目的是什么?

    我会说,它的目的是允许安装你的应用程序的人能够调整某些与部署相关的参数,例如主机名、线程数、你需要的插件名称和这些插件的部署参数(查看FreeRadius的配置以了解此原则的示例),等等...绝对不能用来表达业务逻辑。

  2. 是否应该尝试保持配置文件的简单性?

    一定要这样做。正如你所建议的,“在配置文件中编程”是可怕的。我认为应该避免这种情况。

  3. 谁应该对它们进行更改(开发人员、用户、管理员等)?

    一般来说,应该由部署应用程序的管理员负责。

  4. 它们是否应该受到源代码控制(参见问题3)?

    通常我不会对配置文件本身进行源代码控制,但是我会源代码控制一个包含所有参数和默认值以及描述其作用的注释的模板配置文件。例如,如果配置文件名为database.conf,那么我通常会对名为database.conf.template的文件进行源代码控制。当然,我说的是我作为开发人员的做法。作为管理员,我可能希望对每个安装所选择的实际设置进行源代码控制。例如,我们远程管理几百台服务器,我们需要跟踪它们的配置:我们选择使用源代码控制来实现这一点。
    编辑:虽然我认为上面对于大多数应用程序来说是正确的,但肯定有例外。例如,您的应用程序可能允许用户动态配置复杂规则。大多数电子邮件客户端允许用户定义管理其电子邮件的规则(例如,“所有来自'约翰道'且收件人不包括我应该被丢弃”的电子邮件)。另一个例子是允许用户定义新的复杂商业报价的应用程序。您还可以考虑像Cognos这样的应用程序,它允许用户构建复杂的数据库报告。电子邮件客户端可能会向用户提供简单的界面来定义规则,并生成一个复杂的配置文件(甚至可能是一些代码)。另一方面,商业报价的用户定义配置可能以结构化方式保存在数据库中(既不是简单的键值对结构也不是一段代码)。而其他一些应用程序甚至允许用户使用Python或VB等自动化能力语言进行编码。换句话说,您的情况可能会有所不同。

11

好的。你会有一些用户想要非常简单的配置,你需要给他们提供这样的配置。同时,你也会不断收到“你能加上这个吗?在配置文件中我该怎么做?”的请求,我不明白为什么你不能同时支持这两个群体。

我目前正在处理的项目使用Lua作为其配置文件。Lua是一种脚本语言,在这种情况下它工作得很好。我们有一个默认配置的示例可用。

你会注意到,它主要是key=value语句,其中value可以是Lua内置类型中任何一种。那里最复杂的东西就是列表,而它们并不是真正的复杂(只是一种语法问题)。

现在我只是在等着有人问如何将他们服务器的端口设置为每次启动时一个随机值...


2
使用实际的编程语言比从配置文件中生成代码要整洁得多,这是一个好习惯。 - Benjamin Confino
1
+1 - 这是正确的方法。对于新手来说,Lua确实具有非常“配置文件”式的语法。而对于那些不是新手的人来说,它也允许强大的操作。 - Andrew Y
有趣的是,Lua 的前身语言之一本质上是作为配置文件格式而开始的,并逐渐包含了基本的 if-then-else 和最小化的循环。当设计 Lua 时,作者们知道即使不是专业程序员也可以使用它,因此语法必须友好。这是一门非常优秀、出色的语言! - Ti Strga

8

最近我在一个项目中工作,意识到我想要在配置文件中使用条件语句。原本配置文件很简单,格式如下:


key = val
key2 = val
name = `hostname`

我不想编写一个小型语言,因为除非我非常仔细地编写它,否则无法提供有用的灵活性。

相反,我决定采用两种形式:

  1. 如果文件以“#!”开头并且可执行,则解析运行结果。

  2. 否则按原样读取。

这意味着现在我可以允许用户编写像这样的“配置文件”:

 #!/usr/bin/perl
if ( -x /bin/foo ) 
{
   print <<EOF;
foo=me
bar=you
EOF
}
else
{
   print <<EOF;
foo=bar
bar=foo
EOF
}

这样,如果用户想要使用动态配置文件,我就可以获得其强大功能;而不需要编写自己的小型语言,从而保持了简单性。


5

每个(足够长寿的)配置文件模式最终都会成为一种编程语言。由于你所描述的所有含义,对于配置文件设计者来说,明智的做法是意识到她正在撰写一种编程语言,并相应地进行规划,以免将来的用户负担不良遗产。


3
我对配置文件有不同的理念。关于应用程序如何运行的数据仍然是数据,因此应该放在数据存储中,而不是代码中(在我看来,配置文件是代码)。如果最终用户需要能够更改数据,则应用程序应提供界面来进行操作。
我只使用配置文件来指向数据存储。

3
你可以通过计算理论来定义什么是编程语言。如果你的配置文件格式是 图灵完备,那么它合理地被视为编程语言。根据这个定义,一个描述 推箱子级别的文件格式也被视为编程语言(见 这里)。图灵完备以下的复杂级别也可能被认为是编程语言,例如 正则文法 下推自动机
另一种看待这个问题的方法是,许多配置文件只能进行数据标记,而真正的编程语言必须能够实现 算法。例如,JSON是一种配置文件格式,而ECMA Script是一种编程语言。

2

以下是我的想法:

  1. 使应用程序的运行时行为易于修改。这取决于需要,可以由程序员或非程序员进行修改。这可以在开发期间完成,但我通常将配置文件视为在任何时间都可以帮助使程序更加灵活的一种方式。

  2. 是的。考虑到您可能需要各种选项来控制运行时的不同行为,我认为配置文件应尽可能简单化。我更喜欢将配置设置分组并尽可能简化它们。

  3. 这取决于做出更改的原因和内容。如果用户将对其进行更改,则应该制作前端以将细节隐藏起来。对于普通非开发人员也常常如此。

  4. 我经常使用版本控制来管理“默认”配置,并对实际运行时每个系统进行覆盖。

至于向配置文件添加逻辑 - 我会避免这样做。我认为最好让配置文件在应用程序中切换逻辑,而不是在配置文件中添加逻辑。根据我的经验,配置文件中的行为会导致缺乏可维护性和理解性。我强烈建议保持配置文件尽可能简单。


2
我同意这个问题的前提。我的做法是,尽早预测会发生这种情况,因此从来不自己编写配置系统。
  • 要么我使用操作系统的配置设施(如plist、gconf或适当的其他工具),
  • 要么使用简单的平面文件,可以通过现成的INI解析器处理。
  • 要么咬紧牙关,将一个轻量级的语言解析器(通常是lua,有时是tcl)插入到应用程序中,
  • 或者将数据存储在SQLite或类似的关系数据库中。

并且接受不得不与所做的选择共存的事实,如果不能接受,则进行重构以使用更适合应用程序的上述选择之一。

关键是,没有真正使用自制的配置解决方案的理由。首先,让用户学习一个新的、特定于应用程序的配置格式对他们来说更加困难。其次,使用现成的解决方案可以免费获得许多错误修复和更新的好处。最后,功能膨胀被解决了,因为你实际上不能只添加一个功能而不进行重大改造,因为配置系统根本不在你的手中。


1

这取决于您与团队中其他开发人员达成的协议。您是将配置文件仅用作配置文件,还是创建模型驱动应用程序。

配置文件变成编程语言的症状:

  • 名称=值对开始相互依赖
  • 您感觉需要有流程控制(例如if (this) than that
  • 配置文件的文档成为进一步开发的必要条件(而不仅仅是使用应用程序)
  • 在读取配置值之前,它需要具有某些上下文(即值取决于配置文件本身外部的某些内容)

1

配置文件总会慢慢变得丑陋、不合逻辑,成为“全功能编程语言”。设计良好的编程语言需要艺术和技巧,而配置语言转化为编程语言往往令人震惊。

一个好的方法是使用精心设计的语言,比如Python或Ruby,并使用它创建一个DSL来配置。这样你的配置语言可以保持简单,但实际上却是完整的编程语言。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接