Most of our projects have at least three build configurations: dev, test, and prod. In the past we would configure build scripts to produce appropriate build artifacts for each configuration. This led to our build scripts becoming littered with conditions and clauses which only grew with the complexity of each build configuration.
This can be avoided by creating self-discovering build artifacts. Such artifacts have only one build configuration. Target-specific decisions (such as which database to use, whether to enable advanced features, etc.) are deferred until application startup.
During application startup the project interrogates the environment it has been launched within and infers an appropriate set of configurations. For Web APIs this may involve searching through environment variables. For single-page apps it may involve interpreting the hostname on which the app is running. Desktop applications may toggle features on or off based on a license key.
By creating self-discovering build artifacts we no longer have to deal with multiple build artifacts nor do we need to make decisions about any of the following details at build-time:
- Which database will the Web API use?
- Which e-mail server will the Web API use (if any)?
- How heavily will the Web API cache its responses?
- Which endpoints will the SPA try to communicate with?
- Which endpoints will the mobile application try to communicate with?
This has eliminated a lot of complexity from our build scripts.