Application is usually required to run in different environments. To manage the differences between the environments, we usually introduce the concept of Environment Specific Configuration. In Rails application, by default, Rails have provided 3 different environments, they are the well known, development, test and production. And we can use the environment variable RAILS_ENV to tell Rails which environment to be loaded, if the RAILS_ENV is not provided, Rails will load the app in development env by default.
This approach is very convenient, so we want to apply it to anywhere. But in node.js, Express doesn’t provide any configuration management. So we need to built the feature by ourselves.
The environment management usually provide the following functionalities:
Allow us to provide some configuration values as the default, which will be loaded in all environments, usually we call it common.
Specific configuration will be loaded according to the environment variable, and will override some values in the common if necessary.
Rails uses YAML to hold these configurations, which is concise but powerful enough for this purpose. And YAML provided inheritance mechanism by default, so you can reduce the duplication by using inheritance.
In express and node.js, if we follow the same approach, comparing to YAML, we prefer JSON, which is supported natively by Javascript. But to me, JSON isn’t the best option, there are some disadvantages of JSON:
JSON Syntax is not concise enough
Matching the brackets and appending commas to the line end are distractions
Lack of flexility
As an answer to these issues, I chose coffee-script instead of JSON. Coffee is concise. And similar to YAML, coffee uses indention to indicate the nested level. And coffee is executable, which provides a lot of flexibilities to the configuration. So we can implement a Domain Specific Language form
To do it, we need to solve 4 problems:
Allow dev to declare default configuration.
Load specific configuration besides of default one.
Specific configuration can overrides the values in the default one.
Code is concise, clean and reading-friendly.
Inspired by the YAML solution, I work out my first solution:
YAML is data centric language, so its inheritance is more like “mixin” another piece of data. So I uses underscore to help me to mixin the specific configuration over the default one, which overrides the overlapped values.
But if we jump out of the YAML’s box, let us think about the Javascript itself, Javascript is a prototype language, which means it had already provide an overriding mechanism natively. Each object inherits and overrides the value from its prototype. So I worked out the 2nd solution:
This approach works, but looks kind of ugly. Since we’re using coffee, which provides the syntax sugar for class and class inheritance. So we have the 3rd version:
module.exports = new Config[process.env.NODE_ENV]()
Now the code looks clean, and we can improve it a step further if necessary. We can try to separate the configurations into files, and required by the file name: