创建应用程序/产品配置的设计模式/指南

4
我想知道是否有关于创建“应用程序配置”结构、数据和文件的设计模式、指南或记录的智慧/最佳实践。我意识到这个问题在一些帖子中已经被部分涉及,但我希望以下问题能够从另一个角度来看待这个话题。
基本上,创建配置结构需要进行什么样的分析?
需要考虑哪些因素?
应用程序配置分析/创建何时开始?是主要设计活动的后续工作(由应用程序设计决定),还是与主要设计相互依存,并且是自身架构努力的一部分?
将配置数据结构化的一种方法与另一种方法相比,有什么优缺点?
需要捕获哪些要求或意识到哪些要求(灵活性、覆盖能力、去重、选择等)?
开发糟糕的应用程序配置所付出的成本是什么?
具体而言,我的兴趣在于开发配置设置的层次结构。
是否有任何实际的项目具有足够的复杂程度,其配置可以被研究?
我的问题不针对文件的格式或类型(无论是使用平面ini、json、xml还是其他),而是关于如何首先到达配置方面的问题。
谢谢。

这是一个有趣的问题。我建立的大多数系统都是为了满足客户的需求,所以从我的角度来看,这里没有一般公式可以应用。 - piry
3个回答

0
许多应用程序会被部署(即安装、配置和运行)多次。例如,一个应用程序可能会在开发人员的机器上部署;然后在一个或多个测试机器上(如UAT、Staging或预生产环境)部署;然后可能在多台生产机器上部署。在生产中进行多次部署可能出于各种原因,例如:
  • 您想要部署服务器应用程序的多个副本,然后使用负载平衡技术将客户端请求路由到这些服务器副本。
  • 您想要在公司拥有办事处的每个地理位置部署应用程序的单独实例。
  • 您的应用程序具有插件架构,您想要部署几个应用程序实例,每个实例都具有不同的插件集。

您可能需要为应用程序的每个部署拥有“大致相似但略有不同”的一组配置文件。如果您使用复制和粘贴方法创建这些多个配置文件集,那么这可能会导致维护问题。我知道两种方法可以减少这个问题。

第一种方法是使用Config4*作为您的配置文件语法(免责声明:我是Config4*的主要维护者),因为它的语法提供了各种方式,例如“if-then-else”和“include”语句,使配置文件能够适应其部署环境,同时仍然重用常见的name=value设置。我建议您阅读Config4*入门指南PDF)的第2章(HTML)和第3章(HTML),以了解其语法和API的概述。不幸的是,墨菲定律规定,您的应用程序将使用一些使用Config4*之外的东西(例如XML或Java属性文件)进行配置的第三方库,因此Config4*无法帮助您。但是,我认为仍然值得阅读上述文档,因为Config4*的某些能力可能会引发思考。
第二种方法是为每种配置文件编写一个“模板”,其中模板主要包含纯文本,但有一些占位符。以下是一个示例模板配置文件,使用记号${foo}表示占位符。
serverName  = "${serverName}"
listenPort  = "${serverPort}"
logDir      = "/data/logs/${serverName}";
idleTimeout = "5 minutes";
workingDir  = "/tmp";

如果您为应用程序使用的所有配置文件都执行此操作,那么您可能会发现,在模板配置文件上执行全局搜索和替换,并用相对较少数量占位符的值生成特定部署的可运行配置文件。我曾在一个项目中使用这种方法,在每个部署中有超过2000行配置文件,大约有60个部署,因此产生了超过100,000行的配置文件。要应用于模板文件的搜索和替换数据比从中生成的准备部署配置文件少约50倍,因此更容易维护。如果您正在寻找一种在模板文件中全局搜索和替换占位符的简便方法,则可以考虑Apache Velocity
无论您是手写配置文件还是从模板生成它们,都需要考虑配置文件中数据的运行时验证问题。不幸的是,相对较少的配置文件格式提供模式验证。我所知道的仅有以下几种。Config4* 提供了一个易于使用的模式验证引擎(在上述文档的第3章中讨论)。还有一种JSON 的模式验证语言。当然,也有众多XML 的模式验证语言,但它们通常具有陡峭的学习曲线。

感谢Ciaran的详细回复。这是一个很好的开始,你提供的参考资料让人深思。 - user3217644

0

在编译/构建应用程序阶段之前,应该在运行时(应用程序启动期间)读取配置。无论在哪里运行,您的二进制文件都应该始终保持相同。

在启动期间,应用程序应该从文件系统、环境变量、配置服务器等接收正确的配置。另一种可能性是从同一来源接收有关应使用哪个配置的信息,然后加载已经捆绑在软件包中的正确配置。第二个选项不太灵活,但可能更容易入手。

能够在开发环境中覆盖特定配置的某些部分非常有用(例如通过命令行)。有时,您也可以使用它来快速调试生产问题。但总体而言,我会避免继承和覆盖配置的某些部分,因为这很快就会变得难以管理,并且难以看到整个可用属性集。我建议将配置拆分为两个部分。一个是所有环境通用的(常量、路径、公司邮件服务器等),另一个是在不同运行时之间变化的内容(URL、数据库密码等)

还要考虑测试。您的组件必须在集成测试期间得到适当的初始化。提前考虑这一点,否则您将不得不与框架作斗争。


0
我从Ciaran McHale的回答中得到的基本观点是,如果软件包的最终用户可能有多个部署,则该软件包应该配备一个接口,以有效地生成不同的配置文件。你的问题是什么原则应该指导配置文件的基本结构。即使我们创建了一个接口,这个问题仍然很重要,因为它将有助于接口的设计和实现。一个关键点是,配置过程是将通用代码适应其环境的一种方式,我们总是可以将环境分为两个部分:数字或服务器领域和非数字或应用领域。因此,一个普遍且非主观的事实是,配置值可以分为三类:仅依赖于服务器的那些、仅依赖于应用程序的那些和两者都依赖的那些。我认为将这三个类别分开放在不同的文件中很重要,特别是如果它们是直接管理的,没有接口。同样,每个文件应该被划分为对应于软件包与之交互的不同环境部分的部分:数据库、电子邮件服务器等。如果需要配置模块,则它们就像核心环境的一部分-同样的原则适用。我的观察是,一些大型系统甚至会为每个部分使用不同的文件。例如,Apache有不同的配置文件用于不同的站点和不同的模块。我想到的另一个观点是,没有理由不使用函数作为配置值:如果一个函数需要在不同的服务器或不同的应用程序中定义不同,那么它就是一个配置值。我想不出其他的一般原则。

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