No Internals in Configuration API

Configuration is part of the application API, so the same rules apply to it: no leak of implementation detail.


Unfortunately, I see breaking this rule pretty often. I guess this is because the basic premise is not as obvious as it should be: configuration is an API.

As an example, consider a Java application using an LDAP-based authentication implemented with Spring framework. Typically, one has to provide settings of the connection to the external LDAP server in the runtime environment:

spring.ldap.urls=ldap://myserver:1234
spring.ldap.username=admin
spring.ldap.password=secret

Because the LDAP server is not part of the application, the configuration is expected to be set by the user. This is where apparent internals become externals.

If the user uses the same configuration properties the implementation details leak into the API. Technically, this will work fine, but the trouble comes later. Consider, for example, that the application gets rid of Spring completely and starts using a new fancy technology instead:

quarkus.security.ldap.dir-context.url=ldap://myserver:1234
quarkus.security.ldap.dir-context.principal=admin
quarkus.security.ldap.dir-context.password=secret

Now what? We could just use the new properties from now on, but this will break the old versions already installed. Breaking the contract is not very nice to the users, APIs should stay forever. Introducing a breaking change always requires good communication with customers, brings additional work and has a negative impact on user experience.

We can implement a migration mechanism setting the new properties based on the old ones. But this will increase the complexity of the system and make the code maintenance more expensive. It’s always better to make things right from the beginning:

myapp.ldap.url=ldap://myserver:1234
myapp.ldap.username=admin
myapp.ldap.password=secret

Here, no implementation concerns are exposed to the configuration API, the user doesn’t know (and doesn’t care) what kind of technology or framework is used - those all are just implementation details and must never leak into the API.

The application prefix myapp will further ensure no future collisions with other internal configurations.

The internals can be then configured based on the application properties (e.g. with Spring):

spring.ldap.urls=${myapp.ldap.url}
spring.ldap.username=${myapp.ldap.username}
spring.ldap.password=${myapp.ldap.password}

This approach leads to a solid configuration API, with clarity of application-specific property names, cheap maintenance, no potential breaking changes and great user experience.

Happy configuring!