There's an old phrase attributed to the former British Prime Minister
Benjamin Disraeli which states there are three types of lies: "lies,
damn lies and statistics". The insinuation here is that statistics are
so easy to make up they are unreliable. However, statistics are
extensively used in empiracle science so surely they have some merit? In
fact, they have a lot of merit. But only when they are used
corrrectly. The problem is they are easy to misuse. And when misused,
misinformation happens which in turn does more more harm than good.
There are strong parallels to this narrative in the world of software engineering. Object orientated lanuages introduced the notion of inheritance, a clever idea to promote code reuse. However, inheritance - when misused - can easily lead to complex hierarchies and can make it difficult to change objects. The misuse of inheritance can reek havoc and since all it takes to use inheritance (in Java) is to be able to spell the word "extends", it's very easy to reek such havoc if you don't know what you are doing. A similar story can be told with polymorphism and with design patterns. We all know the case of someone hell bent on using a pattern and thinking more about the pattern than the problem they are trying to solve. Even if they understand the difference between a Bridge and an Adapter it is still quite possible that some part of the architecture may be over engineered. Perhaps it's worth bearing in mind that every single one of the GOF design pattern is already in JDK, so if you really want it in your architecture you don't have to look very far - otherwise only use when it makes sense to use it.
This 'Powerful use, damaging misuse' anti-pattern is ubiquitous in Java systems. Servlet Filters are a very handy feature for manipulating requests and reponses, but that's all they are meant to do. There is nothing in the language to stop a developer treating the Filter as a classical object, adding public APIs and business logic to the Filter. Of course the filter is never meant to be used this way and when they are trouble inevitably happens. But the key point is that it's easy for a developer to take such a powerful feature, misuse it and damage architectures. 'Powerful use, damaging misuse' happens very easy with Aspects, even Exceptions (we have all seen cases where exceptions were thrown and it would have made more sense to just return a boolean) and with many other features.
When it is so easy to make mistakes, inevitably they will happen. The Java compiler isn't going to say - 'wait a sec do you really understand this concept?' and codestyle tools aren't sophisticated enough to spot misuse of advanced concepts. In addition, no company has the time to get the most senior person to review every line of code. And even the most Senior Engineer will make mistakes.
There's a lesson to be learnt here. As soon as you design anything which something else uses, whether it be a core component in your architecture, a utility library class or a REST API you are going to tell the world about, ask youself:
- How easy is it for people to misuse this? Is it at the risky levels of inheritance or the safer levels of encapsulation?
- What are the consequences of misuse?
- And what can you do to minimise misuse and its consequences?