Complexity: Excessive code sharing
It’s great when you write a service that is so generic that all future services can just plug into it without you having to make any changes. Writing generic code makes it very easy to reuse. I use generic code a lot and love the benefits I get from it, but the downside is that, if it is overused, it can lead to unclear or fragile code, thereby increasing complexity.
Generic solution example
The function ‘executeCommand’ is very generic and can accept a command message from another service, and then run based on the contents of the message. By looking at the code, it is difficult to see what this service is actually doing, because the details of the commands are held in some other service which are decoupled from this service. This in effect has created extra abstraction, causing extra complexity.
This would be a lot simpler if this code was not generic and instead executed the commands by name, for example:
executeCountLogins(); executeCountLogouts(); executeCountRegistrations();
This is a very basic example, but it shows that more verbose code is simpler and easier to understand, but adds more maintenance.
Problems with DRY and inheritance
In my post on DRY and Composite Reuse Principle I cover these problems in more detail but in a nut shell it causes coupling. When code is shared changes to that code affects everything using it, and this is where you get random parts of code breaking when you make small changes in "unrelated areas".
Generic code versus simplicity is something to consider carefully to find the right balance. Personally, I aim to:
- Keep the maintenance as low as possible by using generic code where it makes a great impact, and
- Keep the simplicity from clear, verbose code where I don’t expect much maintenance.