可配置
---

让我们写的 Web 应用可配置是一项很有挑战性，也很实用的技能。

起先，我们在本地开发的时候为本地创建了一套环境，也创建了本地的配置。接着我们需要将我们的包部署到测试环境，也生成了测试环境的相应配置。这其中如果有其他的环境，我们也需要创建相应的环境。最后，我们还需要为产品环境创建全新的配置。

下图是 Druapl 框架的部署流:

![Drupal Deployment Flow](assets/article/chapter4/deployment-flow.png)

在不同的环境下，他们使用不同的 Content。这些 Content 的内容不仅仅可以是一些系统相当的配置，也可以是一些不同环境下的 UI 等等。而在这其中也会涉及到一些比较复杂的知识，下面只是做一些简单的介绍。

###环境配置

最常见的例子就是我们需要在不同的环境有不同的配置。大原则就是我们不能直接使用产品的环境测试，因此我们就需要为不同的环境配置不同的数据库：

 - 开发环境。即开发者用于开发的环境，大部分的数据都是由我们自己注入的，在开发的过程中我们也会添加一些数据。
 - 集成测试环境/测试环境。和开发环境一样，这些数据也是由我们注入的，而这些数据主要用于测试目的。当应用出现Bug时，我们可能就需要添加新的测试及其测试数据。
 - 模拟环境（Staging)。在软件最终发布前，开发或者设计人员对软件进行调整后可以及时预览改变的测试环境，这个环境更接近于产品最终发布后的运行环境。因此，这个环境的数据一般来说就是产品环境的一些旧数据——可能是几个月前，几年前的数据。
 - 产品环境。即线上环境，都是真实的用户数据。

因此从理论上来说，我们就需要4~5个不同的数据库配置。而这些不同的数据库配置并不代表着他们使用的是相同的数据库。我们可以在本地环境使用 SQLite，而在我们的产品环境使用 MySQL。不过，最好的情况是我们应该使用同一个配置。这样当出现问题的时候，我们也很容易排查、

而除了数据库配置之外，我们还有一些其他配置。因此针对于不同的环境的配置最好独立地写在不同的文件里。并且这些配置最好可以以文件名来区分，如针对于开发环境，就是 ``dev.config.js``，针对于测试环境就是 ``test.config.js``。

因此，为了实现不同的环境使用不同的配置，我们就需要有一个变更控制。如果我们只有相应的配置，而没有对应的运行机制那就有问题了。

###运行机制

当我们的应用程序在服务器上运行得好好的时候，我们可能就不想因为修改配置而去重启机器，这时候我们就需要配置热加载。即我们修改配置后，不需要重启服务即可以使用新的配置。对应的还有一种，便是我们需要重启机器才能实现配置。

无论是哪种方式都需要修改配置来实现。而在我们使用的过程中热加载可能需要消耗一些系统资源，因为我们的系统需要不断地读取配置的状态并对其进行判断。并且如果我们的应用运行在多个机器上的时候，我们可能需要一个个的上支个性。而如果是冷启动的话，就可以考虑使用自动部署的方式来完成。

对应的，我们也需要在我们的代码中实现判断这些配置的逻辑。

###功能开关

当我们上线了新功能之后，这时候如果有个 Bug，那么我们是下线么？要知道这个版本里面包含了很多的 Bug 修复。如果在设计这个新功能的时候，有一个可配置的 Toogle，那么我们就不需要下线了。只需要切换这个toggle，就可以解决问题了。

对于有多套环境的开发来说，如果我们针对不同的环境都有不同的配置，那么这个灵活的开发会帮助我们更好的开发。

####Feature Toggle

它是一种允许控制线上功能开启或者关闭的方式，通常会采取配置文件的方式来控制。其过程如下图所示：

![Feature Toggle](assets/article/chapter4/feature-toggle.png)

当我们需要 A 功能的时候，我们就只需要把 A 功能的开关打开。当我们需要 B 功能，而不需要 A 功能的时候，我们就可以把相应的功能关掉。像在 Java 里的 Spring 框架，就可以用 PropertyPlaceHolder 来做相似的事。使用 bean 文件创建一个 properties

```xml
<util:properties id="myProps" location="WEB-INF/config/prop.properties"/>
```

然后注入这个值：

```
@Value("#{myProps['message']}")
```

我们可以直接判断这个值是否是真，从而显示这个内容。

```
<spring:eval expression="@myProps.message" var="messageToggle"/>

<c:if test="${messageToggle eq true}">
    message
</c:if>
```

这是一种很实用，而且很有趣的技术。

参考书籍：**《配置管理最佳实践》**
