You shouldn't follow rules... blindly

Some resources on the Internet are written in a very imperative style - you must do that in this way. And beware those that don’t follow the rule! They remind me of a french military joke (or more precisely a joke about the military) - but I guess other countries probably have their own version, regarding military rules. They are quite simple and can be summarized in two articles:

Art. 1: It’s mandatory to obey the orders of a superior.

Art. 2: When the superior is obviously wrong, refer to article 1.

What applies to the military domain, however, doesn’t apply to the software domain. I’ve been fighting for a long time about good practices having to be put in context, so that a specific practice may be the right in one context but plain wrong in another context. The reason is that in the latter case, disadvantages outweigh advantages. Of course, some practices have a wider scope than others. I mistakenly thought that some even have an all-encompassing scope, meaning they give so many benefits, they apply in all contexts. I have been proven wrong this week, regarding 2 of such practices I use:

  • Use JavaConfig over XML for Spring configuration
  • Use constructor injection over attribute injection for Dependency Injection

The use-case is the development of Spring CGLIB-based aspects (the codebase is legacy and interfaces may or may not exist) to collect memory metrics. I must admit this context is very specific, but that doesn’t change that it’s still a context.

First thing first, Spring aspects are not yet completely compatible with JavaConfig - and in any case, the Spring version is also legacy (3.x), so JavaConfig is out of the question. But at least annotations? In this case, two annotations may come into play: @Aspect for the class and @Around for the method that has to be used. The first is used in a very straightforward way, while the second needs to be passed the pointcut…​ as a String argument.

public class MetricsCollectorAspect

    @Around("execution(...)") // This spans many many lines
    public Object collectMetrics {

The corresponding XML is the following:

<bean id="metricsCollectorAspect" class="" />
    <aop:aspect ref="metricsCollectorAspect">
        <aop:pointcut id="executedMethods" expression="execution(...)" />
        <aop:around method="collectMetrics" pointcut-ref="executedMethods" />

Benefits of using annotations over XML? None. Beside, the platform’s product we use do not embed Spring configuration fragments, so that it’s quite easy to update it and check results in deployed environment - pointcut included. XML: 1, annotations 0.

Another fun stuff: I’ve been an ardent defender of using constructor injection. This has some advantages, including highlighting dependencies, fewer boiler plate code and immutability. The 3.x version of Spring uses a version of CGLIB that cannot create proxies when there’s no no-args constructor on the proxied class. The paradox is that "good" design prevents proxying, while "bad" design - attribute injection with no-args constructor allows it. Sure, there are a couple of solutions to allow this: add interfaces to allow pure Spring proxies, add a no-args constructor on or filter out those unproxyable classes, but none of them are without impact.

Morality: rules are meant to help you, not hinder you. If you cannot follow them because of a good reason (like the cost is prohibitive), just ignore the. Just write down in comments the reason why you didn’t for your future code’s maintainers.

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
You shouldn't follow rules... blindly
Share this