Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

When I write code I always try to make my code as clean and readable as possible.

Every now and then there comes a time when you need to cross the line and go from nice clean code to slightly uglier code to make it faster.

When is it OK to cross that line?

share|improve this question

migrated from Jul 5 '11 at 1:54

This question came from our site for professional and enthusiast programmers.

You answered your own question, you cross the line when you need to cross the line – gnibbler Jul 5 '11 at 1:32
Also, your "dirty code" may work just as fast as "clean code" on hardware 6 months from now. Don't go overboard like Windows did, though. :) – Mateen Ulhaq Jul 5 '11 at 6:32
There is a significant difference between a difficult-to-understand algorithm, and difficult-to-understand code. Sometimes the algorithm you need to implement is complicated, and the code will necessarily be confusing, simply because it's expressing a complex idea. But if the code itself is the difficult point, then the code should be fixed. – tylerl Jul 5 '11 at 7:25
In a lot of cases a smart compiler / interpreter can optimise clean, readable code so it has the same performance as "ugly" code. So there's little excuse, unless profiling says otherwise. – Dan Diplo Jul 5 '11 at 8:27
When it comes to compilers these days, your ugly code will most likely be the same as your clean code (assuming you don't do any really weird stuff). Especially in .NET, it isn't like C++/MFC days where how you define your variables will have an impact on performance. Write maintainable code. some code will just end up being complex but that doesn't mean it's ugly. – DustinDavis Jul 7 '11 at 14:37
up vote 107 down vote accepted

You cross the line when

  • You have measured that your code is too slow for its intended use.
  • You have tried alternative improvements that don't require mucking up the code.

Here's a real-world example: an experimental system I am running was producing data too slowly, taking over 9 hours per run and using only 40% of CPU. Rather than mess up the code too much, I moved all the temporary files to an in-memory filesystem. Added 8 new lines of non-ugly code, and now CPU utilization is above 98%. Problem solved; no ugliness required.

share|improve this answer
You also make sure you keep the original, slower, cleaner code, both as a reference implementation and to fall back on when the hardware changes and your faster, hackier code no longer works. – Paul R Jul 5 '11 at 7:05
@PaulR How do you keep that code ? In form of comments ? That is wrong, imo - comments get outdated, nobody reads them, and personally if I see commented out code I usually remove it - this is what source control is for. A comment on a method explaining what it does is better, imo. – Evgeni Oct 9 '13 at 14:29
@Eugene: I usually keep the original version of a routine named foo and rename it foo_ref - typically it lives immediately above foo in the source file. In my test harness I call foo and foo_ref for validation and relative performance measurement. – Paul R Oct 9 '13 at 14:52
@Paul if you are doing that might be a good idea to fail the test if the optimized version is ever slower than the ref function. this can happen if the assumptions you made to make it go faster are no longer true. – user1852503 Nov 16 '14 at 18:18

It's a false dichotomy. You can make code fast and easy to maintain.

The way you do it is write it clean, especially with as simple a data structure as possible.

Then you find out where the time drains are (by running it, after you've written it, not before), and fix them one by one. (Here's an example.)

Added: We always hear about tradeoffs, right, such as a tradeoff between time and memory, or a tradeoff between speed and maintainability? While such curves may well exist, it should not be assumed that any given program is on the curve, or even anywhere near it.

Any program that is on the curve can easily (by giving it to a certain kind of programmer) be made both much slower, and much less maintainable, and then it will be nowhere near the curve. Such a program then has plenty of room to be made both faster and more maintainable.

In my experience, that's where lots of programs start out.

share|improve this answer
I agree. Indeed fast code that is not clean is going to get slower eventually as you can't properly modify it. – edA-qa mort-ora-y Jul 5 '11 at 6:01
I do not agree it is a false dichotomy; IMO there are scenarios especially in library code (not so much in application code) where the split is very real. See my answer for more. – Marc Gravell Jul 5 '11 at 6:18
Marc, you can link to answers in comments with the "link" URL.… – user1249 Jul 5 '11 at 7:30
We have all found times that we need to try and make the code go faster. But after experimentation with the profiler to find the best solution (were the code gets ugly) this does not mean the code needs to stay ugly. It is a matter of finding the best solution which may not at first seem obvious but once found can usually be coded cleanly. Thus I believe it is a false dichotomy and just an excuse not to tidy your room after you have had the fun with your toys. I say suck it up and tidy your room. – Loki Astari Jul 5 '11 at 7:33
I disagree that it's a false dichotomy. Because I do a lot of graphics work the most obvious example to me is in tight graphics loops: I don't know how often this is still done, but it used to be common for game engines written in C to use Assembly for core rendering loops in order to squeeze out every last drop of speed. That also makes me think of situations where you program in Python but use modules written in C++. "Hard to read" is always relative; any time you drop to a lower-level language for speed, that code is harder to read than the rest. – jhocking Jul 5 '11 at 13:08

In my OSS existence I do a lot of library work aimed at performance, that is deeply tied to the caller's data-structure (i.e. external to the library), with (by design) no mandate over the incoming types. Here, the best way to make this performant is meta-programming, which (since I'm in .NET-land) means IL-emit. That is some ugly, ugly code, but very fast.

In this way, I happily accept library code may be "uglier" than application code, simply becuase it has less (or maybe no) control over the inputs, so needs to achieve some tasks through different mechanisms. Or as I expressed it the other day:

"coding over the cliff of insanity, so you don't have to "

Now application code is slightly different, as that is where "regular" (sane) developers are typically investing much of their collaborative/professional time; the goals and expectations of each are (IMO) slightly different.

IMO, the answers above that suggest it can be fast and easy to maintain are referring to application code where the developer has more control over the data-structures, and isn't using tools like meta-programming. That said, there are different ways of doing meta-programming, with different levels of insanity and different levels of overhead. Even in that arena you need to choose the appropriate level of abstraction. But when you actively, positively, genuinely want it to handle unexpected data in the absolute fastest way; it may well get ugly. Deal with it ;p

share|improve this answer
Just because the code is ugly, doesn't mean it has to be unmaintainable. Comments and indentation are free, and ugly code can usually be encapsulated into a manageable entity (class, module, package, function, depending on the language). The code may be equally ugly, but then at least people will be able to judge the impact of changes they are about to make to it. – tdammers Jul 5 '11 at 7:14
@tdammers indeed, and I try to do so as far as possible; but it is a bit like putting lipstick on a pig. – Marc Gravell Jul 5 '11 at 7:15
Well, maybe one should make a distinction between ugly syntax and ugly algorithms - ugly algorithms are sometimes necessary, but ugly syntax is generally inexcusable IMO. – tdammers Jul 5 '11 at 7:17
@IMO ugly syntax is pretty unavoidable if what you are doing is by it's nature several levels of abstraction underneath the usual language level. – Marc Gravell Jul 5 '11 at 7:23
@marc ... thats interesting. My first reaction to meta/abstract being ugly was suspicion about the specific language/plateform being non-conducive to meta coding rather than some underlying law connecting the two. The thing that made me believe that was the example of progressive metalevels in mathematics ending in set-theory whose expression is hardly ugleir than algebra or even concrete arithematic. But then set-notation is probably a different language altogether and every abstration level beneath has its own language.... – explorest Jul 5 '11 at 18:41

When you've profiled the code and verified that it is actually causing a significant slowdown.

share|improve this answer
And what is "significant"? – Rook Jul 5 '11 at 2:10
@hotpaw2: it's the intelligent answer - it assumes the developers are at least somewhat competant. Otherwise yes, using something faster than bubble sort is (usually) a good idea. But too often someone will (to keep with sorting) swap quicksort for heapsort for a 1% difference, only to see someone else swap it back six months later for the same reason. – Мסž Jul 5 '11 at 3:40
There is never a reason to make non-clean code. If you can't make your efficient code clean and easy-to-maintain you're doing something wrong. – edA-qa mort-ora-y Jul 5 '11 at 6:02
@SF. - the customer will always find it too slow, if it can be faster. He doesn't care for "cleanless" of the code. – Rook Jul 5 '11 at 11:40
@Rook: Customer may find the (trivial) interface code too slow. Some pretty simple psychological tricks improve the user experience without actually accelerating the code - defer button events to a background routine instead of performing the actions on the fly, show a progressbar or something like that, ask some insignificant questions while the activity is performed in background... it's when these don't suffice, you may consider actual optimization. – SF. Jul 5 '11 at 12:41

Clean code is not necessarily exclusive with fast-executing code. Normally difficult-to-read code was written because it was quicker to write, not because it executes any faster.

Writing "dirty" code in an attempt to make it faster is arguably unwise, since you don't know for certain that your changes actually improve anything. Knuth put it best:

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified."

In other words, write the code clean first. Then, profile the resulting program and see if that segment is, in fact, a performance bottleneck. If so, optimize the section as necessary, and be sure to include plenty of documentation comments (possibly including the original code) to explain the optimizations. Then profile the result to verify that you actually made made an improvement.

share|improve this answer

Since the question says "fast hard to read code", the simple answer is never. There's never an excuse for writing code that's hard to read. Why? Two reasons.

  1. What happens if you're hit by a bus on your way home tonight? Or (more optimistically, and more typically) taken off this project and reassigned to something else? The small benefit you imagine you've made with your tangled mess of code is totally outweighed by the fact that nobody else can understand it. The risk this poses to software projects is hard to overstate. I worked once with a major PBX manufacturer (if you work in an office you probably have one of their phones on your desk). Their project manager told me one day that their core product - the proprietary software that turned a standard Linux box into a fully-feature phone exchange - was known inside the company as "the blob". Nobody understood it any more. Every time they implemented a new feature. they'd hit compile then stand back, close their eyes, count to twenty, then peek through their fingers to see if it worked. No business needs a core product they no longer control, but it's a frighteningly common scenario.
  2. But I need to optimise! OK, so you've followed all the excellent advice in other answers to this question: your code is failing its performance test cases, you've profiled it carefully, identified the bottlenecks, come up with a solution... and it's going to involve some bit-twiddling. Fine: now go ahead and optimise. But here's the secret (and you may want to sit down for this one): optimisation and reduction in source code size are not the same thing. Comments, white space, brackets and meaningful variable names are all huge aids to readability that cost you absolutely nothing because the compiler will throw them away. (Or if you're writing a non-compiled language like JavaScript - and yes, there are very valid reasons to optimise JavaScript - they can be dealt with by a compressor.) Long lines of cramped, minimalist code (like the one muntoo has posted here) have nothing to do with optimisation: that's a programmer trying to show how clever they are by packing as much code into as few characters as possible. That's not clever, it's stupid. A truly clever programmer is one who can communicate their ideas clearly to others.
share|improve this answer
I can't agree that the answer is "never". Some algorithms are inherently very difficult to understand and/or to implement efficiently. Reading the code, regardless of the number of comments, may be a very difficult process. – Rex Kerr Jul 6 '11 at 22:43

When it is throw-away code. I mean that literally: when you write a script to perform a one-off calculation or task, and know with such certainty you will never have to do that action again that you can 'rm source-file' without hesitation, then you may choose the ugly route.

Otherwise it is a false dichotomy--if you think you need to make it ugly to do it faster, you're doing it wrong. (Or your principles about what is good code need revising. Using goto is in fact quite elegant when it is the proper solution to the problem. It rarely is however.)

share|improve this answer
There is no such thing as throw-away code. If I had a penny for every time "throw-away code" made it into production because "it's working, we don't have the time to rewrite it", I'd be a millionaire. Every line of code you write should be written such that another competent programmer can pick it up tomorrow after you're struck by lightning tonight. Otherwise don't write it. – Mark Whitaker Jul 5 '11 at 6:41
I do not agree it is a false dichotomy; IMO there are scenarios especially in library code (not so much in application code) where the split is very real. See my answer for more. – Marc Gravell Jul 5 '11 at 6:41
@mark, if the "another competent programmer" is really competent, then the throw-away code should not be a problem either :) – user1249 Jul 5 '11 at 7:32
@Mark - Easy. Just write the throw-away code so that it will fail any production testing, perhaps in some unfixable manner. – hotpaw2 Jul 5 '11 at 12:28
@Mark, if your “throw-away code” makes it into production, then that is not throw-away code. Notice that I took the time in my answer to clarify that I am talking about code that is literally throw-away: i.e., delete after first use. Otherwise I agree with your sentiment and said as much in my answer. – maaku Jul 5 '11 at 15:09

Whenever the estimated cost of lower performance in the marketplace is greater than the estimated cost of code maintenance for the code module in question.

People still do twisted hand-coded SSE/NEON/etc. assembly to try and beat some competitor's software on this year's popular CPU chip.

share|improve this answer
A good business perspective, sometimes programmers need to look beyond the merely technical. – this.josh Jul 5 '11 at 6:40

Don't forget you can make hard-to-read code easy to understand by appropriate documentation and commenting.

In general, profile after you've written easy-to-read code that does the desired function. Bottlenecks might require you to do something that makes it look more complicated, but you fix that by explaining yourself.

share|improve this answer

protected by Yannis Oct 9 '13 at 7:44

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.