Running on Java 24-ea+24-2960 (Preview)
Home of The JavaSpecialists' Newsletter

267Performance Impact of Design Patterns

Author: Dr. Heinz M. KabutzDate: 2019-02-18Java Version: 11Category: Performance
 

Abstract: The Java Development Kit is filled with great examples of how design patterns can be used to make the Java code easier to maintain. But what is the performance impact of all this indirection and additional object creation? In this newsletter we explore how the compiler makes well-factored Java code faster.

 

Welcome to the 267th edition of The Java(tm) Specialists' Newsletter. I mentioned the rain in the previous newsletter. Greece declared a state of emergency for our Prefecture of Chania. It was wet, wet, wet. 30% of roads in the area of Platanias were destroyed. We live on the Akrotiri, an area that is amongst the driest in Chania. Even we got our fair share of moisture from the heavens. But fortunately no bridges were swept away in our neighborhood. My wife did wreck one of her wheels in the gaping potholes left behind by the torrents.

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Performance Impact of Design Patterns

As so many in my Generation X, I started programming in BASIC. My first real language was Pascal, followed closely by Scheme, C and Assembler. Only later did we learn object oriented principles. Our lecturer was a fast-talking, entertaining professor from Glasgow, whose thick Scottish accent no one in the class understood. He had handwriting to match. It wasn't as bad as mine, and so I earned pocket money typing his lecture notes into WordPerfect for my fellow classmates. Even though we were now coding in C++, a lot of our coding practices were from procedural C.

A quick mention: Turbo-boost your Java career and enroll in our Java Design Patterns Course. One week of intense study and you will master all the GoF patterns, and then some. All brought to you in the context of Java 11, running in modern JVM environments. Of my 20 courses, this is the one that has added value to programmers for the longest. Hundreds of Java developers around the world have already completed it. I also teach it on-site for groups of 10-16 programmers. Pop me an email and let's talk.

During my Masters degree, I coded a sophisticated CASE tool for the Specification and Description Language (SDL). This was integrated with a Stochastic Petri Net tool written by some fellow students and a matching Markov Chain Analyzer. We could click a button in my SDL tool, which translated the protocol to Petri Nets, analyzed them, and then pulled the results back into SDL.

A company in France saw what I was doing. The CASE tool was in C++, but could be compiled to run on Windows, Solaris and OS/2. They had a similar SDL editor for Solaris and wanted something for their customers that could work on Windows. So they purchased that part of my Masters thesis. My professor and I split the proceeds 50/50. My wife and I lived for almost a year on our share, as I was finishing my doctoral thesis.

In those days I was wildly productive as a programmer. If I wanted to introduce a new SDL element into my CASE tool, I would look for a similar element and copy-and-paste it. I had a switch statement for each function. I would search through my code base and update all that multi-conditional code. This approach worked and I could add new elements and functions quickly.

My wife and I spent a month in France whilst I added features to the tool. Here's a picture of me on my last day. Yes, that's a younger and thinner me. We went swimming twice a week and I didn't have goggles, so my eyes were red for the rest of the day. My colleagues bought me a pair:

My code was gruesome, but it worked. The picture behind me is actually a mirror. Despite it being a dog's breakfast inside, it was so reliable that their development manager asked me to add bugs to my code, so that it would crash at least as frequently as their commercial Solaris based product. True story. I refused.

Since I was the only one working on this codebase, it did not matter that you needed a PhD to maintain it. My French colleagues were delighted that they didn't have to see my code:

If anything, my system was blazingly fast. No polymorphism to speak of. Minimal memory requirements. But it wasn't something that I would want to work on for the rest of my life. CPU cycles had been more important than developer cycles.

At my first job, my mentor handed me the famous Gang-of-Four book and said: "Here, read this."

I did, and realized that I had used a lot of the patterns without knowing their name. The patterns were also filled with warnings of how their application could have a negative performance impact.

They talked about intrinsic vs extrinsic state. The GoF version of the Observer used intrinsic state. Each observer would have a link back to the observable in addition to its previous state. The java.util.Observer, deprecated since Java 9, passed this information into the update() method. Strategy and State mentioned the benefits of extrinsic state.

In Java, we can often get away with not caring whether we use intrinsic or extrinsic state. We can create objects without a care in the world and let the automatic memory management worry about the objects. There are occasions when we do need to concern ourselves, but only if the duplication is significant. Even then we have automatic background optimizations, such as String deduplication, that can eliminate some of the costs.

Another area that Java helps us is meronomy. Meronomy is the relationship between whole objects and their parts. For example, the Composite is used to represent part-whole hierarchies. The dictionary definition of part is: "when combined with others, makes up whole". And whole is: "the whole assemblage of parts or elements belonging to a thing". Why do we care? Well, in the absence of a tracing garbage collector, it is very important to know what type of relationship we have between objects. Is it a dependency, association, aggregation or composition? Without knowing this, we can easily get memory leaks in languages like C++. In Java, we (mostly) do not care about the differences. If an object is no longer referenced, it will be garbage collected. Beautiful.

Indirection is another one. It is mentioned a few times in the GoF. For example, in chapter 1, the last paragraph warns: "Design patterns should not be applied indiscriminately. Often they achieve flexibility and variability by introducing additional levels of indirection, and that can complicate a design and/or cost you some performance."

The Java Hotspot Compilers and similar technologies like Graal are very good at inlining code. Short methods can be inlined almost immediately. Since the decision what to inline is taken at runtime, the JVM ecosystem is allowed to make assumptions that might not be true in the future. If it turns out that it made a wrong choice, it can throw away the compiled code and recompile it differently.

One place we can see this in action is with polymorphism. I wrote about this in 2008 in Polymorphism Performance Mysteries, with a later explanation. Late binding is supposed to make things slower. But in Java, it is not necessarily slower than a multi-conditional statement would have been.

It is the age-old dichotomy between CPU cycles and developer cycles. There are very few systems where it is worthwhile to make the code faster at the expense of maintainability. This is why we should prefer automatic memory management (garbage collection) and decoupling in our designs. Even though it costs something, these performance degradations can be optimized away in bulk by the JVM. And even when they are not, maintainable and extensible code trumps "fast" code almost every time.

Design Patterns have always been criticised. There were those that felt the patterns in GoF were either too simple, in which case of no practical use (Strategy, Template Method, Adapter) or too complex, in which case also of no real-world utility (Bridge, Abstract Factory). Since almost all the patterns are found in the JDK and many other frameworks used by Java programmers, this argument is not valid.

In the late 90s, an excellent book called AntiPatterns [ISBN 0471197130] was published. A lot of programmers started criticizing the patterns movement by saying: "Have you heard of the new book called AntiPatterns?" They had not read it. I had. It certainly wasn't a critique of the patterns movement, but was describing how to fix wayward projects using a special type of pattern, the AntiPattern.

Lastly, we have alternate languages like Scala and now Kotlin. The argument goes that patterns like Builder are unnecessary in languages that allow named and/or default parameters. However, what this argument misses is that the Builder that we know from the book Effective Java, is not at all like the Builder Pattern that we find in the Gang-of-Four. The GoF Builder is more like a strategy for building things. A similar argument is made for a functional approach making patterns unnecessary. Actually, a lot of patterns like Observer and Command are enhanced by modern Java 8+ constructs like method references and lambdas.

We had a discussion at JCrete 2018 entitled Design Patterns - Should We Study Them? It is one of the few recordings that has reasonably good audio. The discussion at times became quite heated between the two camps. In the end we converged and could agree that it is better to not learn patterns than to learn them wrong. The problem is that of all the subjects in Java, design is one of the most difficult to teach, and subsequently, to learn.

Performance is thankfully not an issue. Java is great at making things faster if we follow common coding practices. Often without changing a line of code, we can see a 10-15% performance increase by moving to a new Java version. Highly optimized code typically sees less of an increase, and might even see a decrease. We should not deliberately write code that has a high computational time complexity. At the same time, we can focus on writing extensible, decoupled Java code, and let the compiler speed things up for us.

Kind regards from Crete

Heinz

P.S. Don't forget to accelerate your Java career with our new Java Design Patterns Course.

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '23 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...