February 19, 2016

...Learn TDD with Codemanship

Performance-Optimise Your Code From The Outside-In

Something that comes up time and again on Codemanship training workshops is the tendency of many developers to prematurely optimise their code for performance, often at the expense of readability.

The classic example is Java programmers concatenating strings using the StringBuilder class. I'll ask them "Why are you using StringBuilder?", and they'll reply "For performance". And then I'll ask them "What test will fail if you don't use StringBuilder?", implying "What are the performance requirements, exactly?"

Two points about this: firstly, the Java compiler optimises string concatenation under the hood, using - yep, you guessed it - StringBuilder. So, in terms of machine-executable code, there's no performance difference between


"A" + "B"


...and


StringBuilder builder = new StringBuilder();
builder.append("A").append("B");


But secondly, even if there was a performance gain, we're trading it off against readability for no apparent reason.

In the heirarchy of software design needs, after "does it work?" typically comes "and can other programmers understand it?" So important is readability that, by default, I will happily trade other design concerns for more readable code. And that includes performance.

The only exception to that is when performance (or security, or scalability etc) impacts the answer to the question "does it work?" The code for processing my credit payment may be logically correct and readable, but if the system can't find the time to execute it, then it doesn't work all the same.

Performance optimisation starts on the outside of our software, with the customer and his or her needs. It's not simply a question of looking at the code and thinking "could I make this faster?" The performance of, say, a search algorithm should be driven by an understanding of how soon the user needs search results, and/or how many users need to do searches in a given timeframe.

For this reason, performance requirements are best explored with the customer when we're working to understand their requirements. So, on top of all the questions about the logic of our applications - like "What should happen if they try to sign up but their email is left blank?" - we should also seek to understand constraints on performance, like "How long, maximum, should processing their sign-up take?" and "How many sign-ups might we need to handle every hour?" and so on.

Then we can agree acceptance tests with them about performance that are driven by their needs, not by our desire to make all our code as efficient as possible just for the sake of it.

Always remember that everything we do, ultimately, is about user experience. We write code that works so the users can use it. We write code that's readable so that the user experience can evolve and improve with feedback. And we write code that's fast when the user needs things to happen quickly.





Posted 1 year, 10 months ago on February 19, 2016