Convention over configuration (or coding by convention) is one of the most important principles in modern development. We can find it in some form in almost every framework and tool. It states that instead of strictly configuring specific aspects of software we can use defined convention to achieve certain results. Rephrasing it, the paradigm consists of two parts:
- the convention itself – what rules should we stick to during application or solution creation. The best conventions are obvious, easy to remember and natural.
- the behavior based on the convention – a set of actions and consequences of using the convention. It defines the actual work that will be performed based on already created content matching the convention.
The principle aims to create simple solutions, letting programmers rapidly develop applications.
A straightforward example of the principle is a simplified convention of project directory structure. Example convention can state that:
- src/main directory contains applications sources,
- src/test directory contains unit test sources.
The behavior based on it can specify the following execution:
- classes located within src/main are compiled and jar based on them is created,
- classes located within src/test are compiled, src/main compiled classes are added to classpath, all tests are executed.
After creating a build system providing the above behavior we can easily reuse it anywhere. As long we stick to the convention, no additional work to execute defined actions will be required. There will be no need to define where sources and tests are located and how to run them.
Convention over configuration benefits us in many ways. In case of well defined conventions and properly written behavior:
- standardization across project modules is easier to maintain. In fact, it is possible to have a set of standards defined across many projects or even whole industry,
- less code and configuration to write and maintain,
- less configuration and less code (defining behavior) to write means less bugs,
- development speed increase, at least for non-complex and customized solutions. Rapid development is possible,
- conventions are easier to understand than custom solutions,
- knowledge of convention applies to many different projects.
While well defined conventions are very important, we cannot forget that it should be possible to easily overwrite them whenever necessary. While it might create backdoors and let developers avoid some conventions, without it we can easily get stuck and without major effort would be unable to implement the desired customization.
Great examples of the Convention over configuration paradigm usage are the Maven build system, Spring framework and Hibernate (implementing JPA). Lets look at them to see how they benefit from the principle.
Maven is a standard build system across the whole Java related industry. While Gradle and sbt are getting more and more popular, Maven still stands strong. The main convention behind Maven is the definition of project directory structure and dependency management. Almost every Java developer knows this standard:
- src/main/java – applications sources,
- src/main/resources – applications resources, configuration, etc.
- src/test/java – test sources,
- src/test/resources – test resources, configuration, etc.
- target – directory used for all outcome created during a build,
- target/classes/ – directory used for compiled application sources.
Maven strictly defines default actions that will be executed against each directory content. It specifies the compilation, test execution, artifacts deployment, and so on. Behind it is a life cycle concept and an assortment of provided Maven plugins with default configuration. Thanks to that we can create a project in minutes and reuse quite a complex execution. We just need to stick our project structure to the convention.
Another famous example of the Convention over configuration principle is Spring framework. Spring Boot component allows us to create a Spring application within seconds. With only just a few annotations we can easily create a working RESTful web service. Whilst sticking to the convention and rapidly developing, we are reusing a lot of behavior without even thinking about what is under the hood. Another spring component where the principle is even more visible is Spring Data. We can create custom repositories and define data querying methods by just defining method signatures. No code is written, almost no configuration applied, and a bunch of logic is available for our application. The defined behavior behind convention takes care of it.
I cannot skip the Hibernate and JPA examples. Here convention allows us to easily map object to relational database tables. Plain java object with a few annotations does the work. There is no need to define the transformation and serializing. Hibernate takes care of most of the background operations. Developers can focus on actual business logic implementation.
Convention over configuration is a powerful principle. It should be always considered and possibly used whenever a new solution is designed and created. It simplifies it and usually enforces robust design. We have a lot of great examples of its implementation. However, we cannot forget about flexibility. Almost every developer has, at least several times, jammed while trying to implement a solution breaking the boundaries of some framework conventions. It often ends with serious and tricky hacks, or even worse in patching third party libraries. For the sake of people touching your code, always keep in mind flexibility!