Preemptive optimisation: do not do it!
Yesterday I wrote about optimisation work flow and in this post I will be discussing why you should not preemptively optimise your program’s source code. You may wonder what could possibly be wrong with preemptively optimising the source code, it just makes your program faster right? And that is the trap: while it does make your program faster, if you do not measure the programs performance relative to your performance goals you are effectively taking a shot in the dark with very little real likelihood of hitting your (performance) mark and a real likelihood of unintended consequences in terms of the quality, understandability, complexity and bug count in your program’s source code.
For example, it faster on the CPU you are targeting to compare an integer to zero than to compare an integer to another integer. Therefore you have decided to write all your loops so they count down to zero instead of the normal approach of counting up from zero. This will save you a few cycles per iteration of your loop, but have you considered:
- Counting down and not up in a loop is not conventional in most programming languages and may result in you making math errors which can result in hard to track down bugs in your loop control logic or code inside your loop.
- Pointer arithmetic in languages like C/C++ is hard enough when counting up (e.g, pObj++) but counting down is even harder to understand as it is so incredibly rarely done and requires extra pointer math to set up.
- The programmer that comes after you to develop or maintain the source code may not realise you are counting down and not up in your loop and then implement functionality that relies on your loop counting up which would again cause bugs and confusion.
- That despite your loop being invoked for thousands or millions of iterations, your loop’s control logic is no where near as expensive in terms of CPU operations as function call X that comes right in the middle of your loop which costs millions of cycles by itself every iteration!
- That it is almost unheard of for loop control logic to be an issue performance wise even when it is in tightest inner loops.
- That most optimising compilers are perfectly able to make this optimisation for you during compilation on your target platform with none of the above programmer confusion?
My advice here is never optimise without measuring first: as at best you will save a few CPU cycles where it really does not matter at the cost of making your source more complex and harder to understand and at worse you will add subtle bugs to your program and make the source code more complex and harder to understand or maintain! I have lost count now of how many times I’ve tracked subtle bugs in programs down to programmers making preemptive optimisations without first measuring to see if any optimisation is required and if the extra level of complexity introduced by the optimisation is a desirable trade off.
Occasionally there will be an exception to this rule but in general if you are going to optimise something should always measure first and then optimise only if it is nessessary.
Optimisation Workflow
I believe the key to optimising any program is measurement: not writing l33t code which seems to be what a lot of programmers think optimisation is! The optimisation process is all about finding the slow parts of your program and speeding those slow parts up by refactoring your source code to meet your target performance goals. Without measuring the code or having target performance goals optimisation is a waste of time: as programmers are very bad at guessing where the slow parts of the program are and very good at optimising pieces of the program that do not need it.

This diagram emphasises the importance of measurement in the optimisation process: you cannot begin the process, evaluate your optimisations, even discard your optimistations or honestly finish the process without first measuring the program performance versus your target performance. As I have mentioned before the initial optimisations to a program tend to yeild larger returns and then returns drop off until much more time is invested. These initial easy optimisations are not usually the sort of changes new programmers expect: they expect sexy l33t code like inline assembler for big performance wins, not tweaking compiler flags or removing calls to a pure virtual method on a base object in an inner loop.
Programming Software Development: Architecture Hardware Programming Programming Languages Teaching
by Daniel
leave a comment
RE: Teaching students memory managment
Jani Hartikainen has written an excellent post in reply to my earlier post about teaching software engineering students memory management, and his post is well worth a read. I started off writing a comment on his post as a reply but I ended up writing more than I expected as I refined my ideas.
I agree teaching a higher level language with built in memory management as a first programming language is the more humane option as far as first time students are concerned. As learning your first programming language and all the associated concepts is hard enough without all the nasty memory related gotchas in a language like C or C++. Although the nice thing about learning something like C or php (as Jani suggests) is that teaching object orientation can be avoided initially, as that particular concept does seem to be something that some students struggle with a lot the first time they encounter it.
However I do think a low level language that has manual memory management should be at least experienced by every programmer, as it is a fundamental concept of programming effectively. And I believe that having minimal experience with some form of manual memory management would help most programmers write higher performance programs. But perhaps I was being a bit over zealous recommending that everyone learns a language like C/C++ as a first language, although I think at least a short course featuring a language with manual memory management would be invaluable to all programmers. The course would not even need to cover object orientation as you can teach that in higher level languages that are easier to manipulate than C++: the key point of the course would be to teach memory management and its implications for writing fast high quality software.
As much as I go on about knowing assembler, I admit its not something I write very often at all, however it is something that is incredibly handy to be able to read and comprehend. Even the most basic level of understanding of the instructions for loading data from or to memory and registers, branching and basic math operations would allow you to check the compiler has actually generated the assembly code you expected. This is especially useful for debugging unexpectedly slow code in compiler optimised builds. You also don’t need to know about all the fancy vendor specific assembly instructions, as I’ve mentioned the basics are usually sufficient to be able to understand roughly what a slow piece of code is doing to then rewrite the higher level source code in a way that prompts compiler to generate faster assembly code. Actually writing assembly code should always be the last resort and only done by experts after all other higher level refactorings are attempted, as higher level optimisation or refactoring work is usually more effective and easier to understand. Also, assembler is not usually easily portable to other hardware platforms and most programmers find it harder to debug assembler than normal C/C++ source code. Plus as Jani mentions it is scary to find a block of inline assembler in the C++ program you are working as it is much harder to decipher than regular source code unless it is very well documented.
This ability to check what is going on ‘under the hood’ of your language is essential for those hard to track down bugs and when optimising your application for performance, especially where the compiler has reordered the program flow or generated unexpectidally slow code. This can also be applied to high level languages as well as C/C++: checking that the IL byte code generated by your C# compiler or the Java byte code generated by the JVM is doing what you expected can be very useful in understanding your program’s execution and performance.
Python or Ruby?
I’ve really needed to get round to learning a powerful object oriented scripted or interpreted programming language to replace windows batch files (which I currently use) for a while now. As Microsoft seems determined to gut their functionality with each new Windows release and I find myself wanting more functionality and power than batch scripts can provide. So I have been looking for a high level scripted or interpreted language for platform independent scripting, rapid application prototype and generally messing about with at home. Ideally the language is scripted or interpreted (so no compilation required), has a unit test harness available, ideally some form of IDE/debugger, some decent solid libraries (e.g, database, visualisation/graphing etc) and is object oriented.
I know I don’t want to use the following languages mostly for reasons of personal taste:
- Perl as I can never remember it’s syntax and I can’t seem to read any script I’ve written in Perl after a week or so.
- php as I already use it for web development (and like it a lot) but it does not really seam suitable for scripting or quick application development that is not running on a web server.
- Java I’ve never gotten on with, but that was probably more to do with falling out with my Java lecturer at university. Although I should probably revisit Java at some point as it seems very popular at the enterprise level.
- I also want something not Microsoft specific, as much as I love C# I want something I can use easily on my Mac or Linux boxes at home without compiling.
So far I’ve narrowed it down to either Python or Ruby. Originally I was going to learn Python as I like its use of white space for scoping, its wide range of libraries and maturity as a language. However there seems to be a lot of buzz about Ruby these days, especially its Rails framework and all the buzz has piqued my interest. Further investigation into Ruby has me now leaning towards learning it mostly for the trivial reason (as the languages are equally matched in my mind) that Ruby has the similar concept and syntax of public, protected and private for methods which is familiar to me as a C++ and C# programmer.
In fact I am more then leaning towards Ruby as I bought a copy of ‘The Ruby Programming Language‘ at lunchtime, mostly as it was getting good reviews online and because the original developer of Ruby was a co-author. I always enjoyed Bjarne Stroustrup‘s ‘The C++ Programming Language‘ book, getting the language creators view on their creation is always fascinating and provides valuable insights.
So expect to see more posts about Ruby as I work my way through the book and experiement. I can even post code snippets with syntax highlighting thanks to the Google Syntax Highlighter in the form of a handy plug-in for WordPress!
Resist the perfect solution, embrace the working solution!
It would seem that as a profession Software Engineers when left to their own devices will attempt to make a perfect solution to a problem, rather than accepting a working solution. This may sound innocent enough as being 75% perfect (with a working solution) is usually not too painful in time and effort to achieve, however the last 25% is typically brutal to achieve (if it is even possible to begin with).
This trend towards perfection is probably due to the medium with which we work: programming languages and mathematics. Both mathematics and programming languages are completely unlike the physical elements most conventional non-software related engineering disciplines have to work with. Our elements are much closer to pure thought stuff than the physical elements, limited only by our imagination and creativity as to how we can manipulate and combine these components to achieve a solution. This is computing’s greatest strength, as in many ways we are limited only by our conceptual abilities.
This is also perhaps one of our greatest weaknesses, as it makes accepting a non-ideal solution harder than it should be, as our natural inclination is towards the perfect solution. I think this manifests most visibly in the industry wide ‘not invented here‘ syndrome. Where engineers will resist taking components or systems developed else where and using them in their own systems and programs. Instead preferring to design and implement their own ‘better’ solution, usually this resistance will take the form of pointing out the flaws in the component and they could make it better.
This misses one of the key points of reusing components: reusing components saves time and effort that can then be better used to assemble our pre-built components in more creative and powerful solutions to the problem at hand. To insist on building our 100% perfect sub components every time means that you are spending time and effort on making sub components slightly more perfect than existing sub components. This time and effort could otherwise be better used in our higher level solution composition than spent perfecting low level components that have already been made, usually in several different ways by several different groups and tested thoroughly over several generations of software.
Think of what would happen if another engineering discipline like automobile manufacturers where to use such a methodology: rediscovering and design something as basic as a wheel, internal combustion or making steel every time they designed and built a new model of vehicle, the pace of automotive development and inovation would slow to a crawl.
Programmers Ranks
After discussing the differences between programmer ranks this week with a more junior co-worker, I thought this would make a good post as it seems to be something that is not spoken about much. This I think is not very helpful for junior programmers looking to develop themselves. Generally there are roughly three ranks of programmers: junior (beginner), programmer (intermediate), senior (advanced) and then lead programmer (advanced plus people skills). Some companies use different names for these ranks or have a few more specialised ranks e.g, Co-Op or student programmers but so far I’ve generally found the ranks to be somewhat similar in terms of what is expected.
Junior Programmer
The junior programmer is the lowest rank in the programmer family, most programming team’s populations usually consist of about 25% junior programmers. This is where everyone starts out in the industry. Junior programmers are primarily implementers of other peoples designs and are usually heavily supervised by more senior team members. It is usual for programmers to remain at the junior rank for a few development cycles as they mature and gain experience.
Programmer
The rank of programmer is the middle rank of the programmer family, most teams usually consist of about 50% programmers and as such this is usually the most commonly encountered rank of programmer. Programmers are veterans of the development process and are expected to be able to design and implement features given a feature brief, some contacts, some supervision and peer (or senior) review of their designs. They are also expected to be the first line of support for junior programmers, helping with problems the juniors cannot solve.
Senior Programmer
Senior programmer is effectively the highest rank for a programmer, as a lead programmer is really a specialised senior programmer. Senior programmers usually make up about 25% of a development team, this is mostly due to a few factors: they are rare (every team wants them and they take a long time to develop), cost (this amount of talent is not cheap) and individual preferences (they cannot be easily forced to do something they don’t want to do). Senior programmers are veterans of many many development cycles and as such have experience of just about every type of project, working environment and methodology. This depth of experience is their strength: they typically have a few more junior programmers under their supervision, vet design documents, solve the hard problems that bubble up from the lower ranks, act as diplomats coordinating with other departments and generally providing guidance and a calming influence when things go wrong. In terms of work, senior programmers are expected to conceive of, design, prototype, implement and review whole systems or domains of a project and to set the direction of the domains they are responsible for without supervision. Productivity wise a senior programmer can be worth several lesser programmers in terms of output, quality and direction.
Lead Programmer
A lead programmer is a highly specialised senior programmer. The easiest way to describe a lead programmer is that if the project fails it is their fault, at least according to managment. So a lead programmer is the programmer that is responsible for the overall project design, planning, direction, progress and ultimate sucesss. This role usually requires more people and planning skills than the senior programmer role, so where a lead programmer can have a break from leading for a cycle and act as a senior programmer on some other leads project, a senior programmer cannot always act as a lead due to a potential lack of the nessessary skills. It must also be pointed out that some senior programmers don’t want the responsibility, high amounts of planning, meetings and people skills required by the lead roles. Such individuals prefer to stick to programming and are in no way less valuable than a lead.








