Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

While responding to this question, I began to wonder why so many developers believe a good design should not account for performance because doing so would affect readability and/or maintainability.

I believe that a good design also takes performance into consideration at the time it is written, and that a good developer with a good design can write an efficient program without adversely affecting readability or maintainability.

While I acknowledge that there are extreme cases, Why do many developers insist an efficient program/design will result in poor readability and/or poor maintainability, and consequently that performance should not be a design consideration?

share|improve this question
7  
It would be nearly impossible to reason about it in a large scale, but for small pieces of code it is quite obvious. Just compare the readable and the efficient versions of, say, quicksort. –  SK-logic Sep 27 '11 at 11:52
6  
Mu. You should start by supporting your statement that many developers insist that efficiency leads to unmaintainability. –  Peter Taylor Sep 27 '11 at 11:57
2  
SK-logic: In my opinion that's one of the best parts of all the stackexchange sites, since one gets to question the obvious, which can be healthy every now and then. What might be obvious to you might not be obvious to someone else, and vice versa. :) Sharing is caring. –  Andreas Johansson Sep 27 '11 at 12:07
2  
@Justin, no. That thread seems to me to presuppose a situation in which there's a forced choice between efficient code or maintainable code. The questioner doesn't say how frequently he finds himself in that situation, and the answerers don't seem to claim to be in that situation frequently. –  Peter Taylor Sep 27 '11 at 13:41
1  
-1 for the question. When I read it I thought this is a straw man to evict the only true answer: "Because they don't use python." –  Ingo Sep 27 '11 at 14:49

14 Answers 14

up vote 33 down vote accepted

I think such views are usually reactions to attempts at premature (micro-)optimization, which is still prevalent, and usually does way more harm than good. When one tries to counter such views, it is easy to fall into - or at least look like - the other extreme.

It is nevertheless true that with the enormous development of hardware resources in recent decades, for most of the programs written today, performance ceased to be a major limiting factor. Of course, one should take into account expected and achievable performance during design phase, in order to identify the cases when performance may be(come) a major issue. And then it is indeed important to design for performance from the beginning. However, overall simplicity, readability and maintainability is still more important. As others noted, performance optimized code is more complex, harder to read and maintain, and more bug-prone than the simplest working solution. Thus any effort spent on optimization must be proven - not just believed - to bring real benefits, while degrading the long term maintainability of the program as little as possible. So a good design isolates the complex, performance intensive parts from the rest of the code, which is kept as simple and clean as possible.

share|improve this answer
6  
"When one tries to counter such views, it is easy to fall into - or at least look like - the other extreme" I have issues all the time with people thinking I hold the opposite view when I'm merely balancing out the pros with the cons. Not just in programming, in everything. –  jhocking Sep 27 '11 at 15:20
    
I'm so sick of everyone discussing about this that I get angry and take extremes.. –  Andreas Bonini Sep 27 '11 at 17:27
    
There have been several good responses, but I think yours made the best attempt at detailing the origins of this mentality. Thanks to everybody involved! –  justin Sep 30 '11 at 15:24

There are also some famous pieces of highly optimised code that will bend most peoples brains that support the case that highly optimised code is difficult to read and understand.

Here's the most famous I think. Taken from Quake III Arena and attributed to John Carmak, although I think there's been several iterations of this function and it wasn't originally created by him (isn't Wikipedia great?).

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the fuck?
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
    //      y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}
share|improve this answer

You can have both well-readable and good-performing code to some extent if you are using a lot of libraries, especially home-grown ones. These libraries are supposed to be widely used in other projects, therefore have few errors.

Programming at a higher level is key to productivity.

For maintenance, in newer versions of libraries, interfaces (method-signature) should be same, inner implementation should vary.

Personally, I write lots of extension methods. The idea is to compose all of your home-grown libraries with as much static methods as you can.

You can combine the above techniques with method chaining, by returning from your static library method the main object the method has worked on, with inner state of the object changed.

share|improve this answer

Because experienced programmers have learned that it's true.

We've worked with code that is lean and mean and doesn't have performance issues.

We've worked on a lot of code that, to address performance issues is VERY complex.

One immediate example that comes to mind is that my last project included 8,192 manually sharded SQL tables. This was needed because of performance issues. The setup to select from 1 table is a lot simpler than to select from and maintain 8,192 shards.

share|improve this answer

One problem is that finite developer time means that whatever you seek to optimise takes away from spending time on the other issues.

There's a rather good experiment done on this referenced in Meyer's Code Complete. Different groups of developers were asked to optimise for speed, memory usage, readability, robustness and so forth. It was found that their projects scored high in whatever they were asked to optimise in, but lower in all the other qualities.

share|improve this answer
    
Obviously you can devote more time but eventually you begin questioning why developers would take time off programming emacs to express love for their children, and at that point you're basically Sheldon from the Big Bang Theory –  deworde Sep 27 '11 at 22:09

Because the cost of global warming (from those extra CPU cycles scaled by hundreds of millions of PCs plus massive data center facilities) and mediocre battery life (on user's mobile devices), as required to run their poorly optimized code, rarely shows up on most programmer's performance or peer reviews.

It's an economic negative externality, similar to a form of ignored pollution. So the cost/benefit ratio of thinking about performance at all is mentally skewed from reality.

Hardware designers have been working hard adding power save and clock scaling features to the latest CPUs. It's up to programmers to let the hardware take advantage of these capabilities more often, by not chewing up every CPU clock cycle available.

ADDED: Back in ancient times, the cost of the one computer was millions, so optimizing CPU time was very important. Then the cost of developing and maintaining the code became greater than the cost of the computers, so optimization fell way out of favor compared with programmer productivity. Now, however, another cost is becoming greater than the cost of computers, the cost of powering and cooling all those data centers is now becoming greater than the cost of all the processors inside.

share|improve this answer
    
Apart from the question if PCs contributed to global warming, even if it were real: It is a fallacy, that more energy efficiency leads to less energy demand. Almost the opposite is true, as can be seen from the first day a PC appeared on the market. Before that, some hundreds or thousends Mainframe (each one virtually equipped with their own power plant) used much less energy than today, where 1 CPU minute computes much more than then at a fraction of the cost and energy demand. Yet, the total energy demand for computing is higher than before. –  Ingo Sep 27 '11 at 14:56

Coming at your question from the side of a developer who works on high-performance code, there are several things to consider in design.

  • Do not prematurely pessimize. When you have the choice between two designs that are equal in complexity, choose the one that has the best performance characteristics. One of the famous C++ examples is the prevalence of post-increment of counters (or iterators) in loops. This is a totally unnecessary premature pessimization that MAY not cost you anything, but it MIGHT, so don't do it.
  • In many cases you have no business to go anywhere near micro-optimization yet. Algorithmic optimizations are a lower-hanging fruit and are nearly always a lot easier to understand than really low-level optimizations.
  • If and ONLY if performance is absolutely critical, you get down and dirty. Actually, you isolate the code as much as you can first, and THEN you get down and dirty. And it gets really dirty in there, with caching schemes, lazy evaluation, memory layout optimization for caching, blocks of inline intrinsics or assembly, layer-upon-layer of templates, etc. You test and document like crazy here, you know it's going to hurt if you have to do any maintenance in this code, but you have to because performance is absolutely critical. Edit: By the way, I'm not saying this code cannot be beautiful, and it should be made as beautiful as it can be, but it's still going to be very complex and often convoluted compared to less optimized code.

Get it right, get it beautiful, get it fast. In that order.

share|improve this answer
10  
+1 for the "right-beautiful-fast" ordering! –  FrustratedWithFormsDesigner Sep 27 '11 at 13:50
    
I like the rule of thumb: 'get it beautiful, get it fast. In that order'. I am going to start using that. –  Loki Astari Sep 27 '11 at 14:45
    
Exactly. And isolate the code in the third point, as much as possible. Because when you move to difference hardware, even something as small as a processor with a different cache size, these things may change. –  KeithB Sep 27 '11 at 15:45
    
@KeithB - you make a good point, I will add it to my answer. –  Joris Timmermans Sep 27 '11 at 16:00
    
+1: "Get it right, get it beautiful, get it fast. In that order." Very nice summary, with which I agree 90%. Sometimes I can only fix certain bugs (get it right) once I get it beautiful (and more understandable). –  Giorgio Sep 27 '11 at 17:14

I think most programmers get that gut feeling simply because most of the time, performance code is code based on a lot more informations (about the context, hardware knowledge, global architecture) than any other code in applications. Most code will only express some solutions to specific problems that are encapsulated in some abstractions in a modular way (like functions) and that means limiting the knowledge of the context to only what enter that encapsulation (like function parameters).

When you write for high performance, after you fix any algorithmic optilizations, you get into details that requires far more knowledge about the context. That might naturally overwhelm any programmer that don't feel focused enough for the task.

share|improve this answer

It is not so much that those things cannot coexist. The problem is that everyone's code is slow, unreadable, and unmaintainable on the first iteration. The rest of the time is spent working on improving whatever is most important. If that is performance, then go for it. Don't write spitefully awful code, but if it just has to be X fast, then make it X fast. I believe that performance and cleanliness are basically uncorrelated. Performant code does not cause ugly code. However, If you spend your time tuning every bit of code to be fast, guess what you did not spend your time doing? Making your code clean and maintainable.

share|improve this answer

If I can presume to "borrow" @greengit's nice diagram, and make a small addition:

|
P
E
R
F
O  *               X <- a program as first written
R   * 
M    *
A      *
N        *
C          *  *   *  *  *
E
|
O -- R E A D A B I L I T Y --

We've all been "taught" that there are tradeoff curves. Also, we have all assumed we are such optimal programmers that any given program we write is so tight it is on the curve. If a program is on the curve, any improvement in one dimension necessarily incurs a cost in the other dimension.

In my experience, programs only get near any curve by being tuned, tweaked, hammered, waxed, and in general turned into "code golf". Most programs have plenty of room for improvement in all dimensions. Here's what I mean.

share|improve this answer
    
+1 for addition, and for the link. –  treecoder Sep 27 '11 at 13:34
    
Personally I think there is another end to the curve where it goes up again on the right hand side (as long as you move far enough to the right (which probably means re-thinking your algorithm)). –  Loki Astari Sep 27 '11 at 14:49
2  
+1 for "Most programs have plenty of room for improvement in all dimensions." –  Steven Sep 27 '11 at 15:01
    |
    P
    E
    R
    F
    O  *
    R   * 
    M    *
    A      *
    N        *
    C          *  *   *  *  *
    E
    |
    O -- R E A D A B I L I T Y --

As you can see...

  • Sacrificing readability can increase performance -- but only so much. After a certain point, you have to resort to "real" means like better algorithms and hardware.
  • Also, losing performance at the cost of readability can happen only to some extent. After that, you can make your program as much readable as you want without affecting performance. For example adding more helpful comments doesn't toll performance.

So, performance and readability are but modestly related -- and in most cases, there's no real big incentives preferring the former over latter. And I am talking here about high level languages.

share|improve this answer

The point is not readability should always trump efficiency. If you know from the get go that your algorithm needs to be highly efficient, then it will be one of the factors you use to develop it.

The thing is most uses cases don't need blinding fast code. In many cases IO or user interaction causes much more delay then your algorithm execution causes. The point is that you should not go out of your way to make some thing more efficient if you don't know it is the bottle neck.

Optimizing code for performance often makes it more complicated because it generally involves doing things in a clever way, instead of the most intuitive. More complicated code is harder to maintain and harder for other developers to pick-up (both are costs that must be considered). At the same time, compilers are very good at optimizing common cases. It is possible that your attempt to improve a common case means that the compiler does not recognize the pattern anymore and thus can not help you make your code fast. It should be noted that this does not mean write whatever you want without concern to performance. You should not be doing anything that is clearly inefficient.

The point is to not worry about little things that might make things better. Use a profiler and see that 1) what you have now is an issue and 2) what you changed it to was an improvement.

share|improve this answer

In my opinion performance should be a consideration when it's an actual problem (or e.g. a requirement). Not doing so tends to lead to microoptimizations, which might lead to more obfuscated code just to save a few microseconds here and there, which in turn leads to less maintainable and less readable code. Instead one should focus on the real bottlenecks of the system, if needed, and put emphasis on performance there.

share|improve this answer

Precisely because highly performing software components are generally orders of magnitude more complex than other software components (all other things being equal).

Even then it is not as clear cut, if performance metrics are a critically important requirement then it is imperative that the design have complexity to accomodate such requirements. The danger is a developer who wastes a sprint on a relatively simple feature trying to squeeze a few extra milliseconds out of his component.

Regardless, complexity of design has a direct correlation with the ability of a developer to quickly learn and become familiar with such a design, and further modifications to functionality in a complex component can result in bugs that might not be caught by unit tests. Complex designs have many more facets and possible test cases to consider making the goal of 100% unit test coverage even more of a pipe dream.

With that being said it should be noted that a poorly performing software component could perform poorly just because it was foolishly written and unnecessarily complex based on the ignorance of the original author, (making 8 database calls to build a single entity when just one would do, completely unnecessary code that results in a single code path regardless, etc...) These cases are more a matter of improving code quality and performance increases happening as a consequence of the refactor and NOT the intended consequence necessarily.

Assuming a well designed component however, it will always be less complex than a similarly well designed component tuned for performance (all other things being equal).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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