views:

340

answers:

11

Is it advisable to zero-in on design of a component or architecture of a software with performance in mind? What I mean is, how ready should the design/architecture be to used in a performance-intensive environment?

While designing components, should we just follow good OO principles and just ensure that the component is 'extendable'. This way we tweak the design a bit here and a bit there as and when we run into performance issues. Although this way, we would often land up in performance issues where tweaking software a little bit might not help.

Alternatively, should we come up with a design, although complex, makes performance issues a cakewalk. We would still need to tweak the software, but the tweaking is often very simple as the design is performance-oriented.

Note: In neither of the cases listed above am I trying to tune the performance of the software before running into performance issues. To re-phrase the question, should the design of the software be performance-oriented?

Please do not answer me saying that it all depends on the environment in which a software is expected to run. The reason being that clients of any industrial-grade software just seem to want more and more and more all the time. You may not plan your software to be constantly running in performance-intensive environments, but what if it has to? Should we then re-design the software when we sense that?

This question has been troubling me from a week and I don't have an answer yet. What is your take on this?

A: 

You should always aim at efficiency over inefficiency, but not at the cost of maintainability. So yes, you should try to design for efficiency, but be wary of premature optimization. The favorite quote from Donald Knuth:

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."

akf
I thought money was the root of all evil?
DisgruntledGoat
Are you attempting to prove that premature optimization == money?
akf
+5  A: 

The design of a project must balance extendability, maintainability, performance, time-to-shipping and more.

I try to design the package+high-level diagrams for extendability, then design the low-level for performance.

Danny Varod
A: 

A well architected software that follows OOP best practices, makes wide use of design patterns is, or should by principle be, a well maintainable. Nowadays it is rare that low level optimizations have a real role, CPU and resources are quite overabundant.

Just code reusable, maintainable and scalable. Further real needs for low level optimization will be easily implemented in such a good environment. Only when really necessary, only when it is really the moment to take care of this issue.

AlberT
+2  A: 

I would say go with good object oriented principles as long as you do not know from the beginning that every little bit of performance will matter.

The big performance gains are in general reached through algorithmic optimization and not restructuring of the architecture (as long as the architecture follows normal best practice). The kind of performance gains that you get from choosing a harder-to-work-with design is most often irrelevant in all but the most performance demanding environments, so if absolute top performance is not a requirement from the beginning, go with good OO.

Mikael Auno
+2  A: 

I would say, that this is what makes the difference of a experienced software engineer and a software-newbie.

An experienced software engineer should always keep in mind the performance issues of his design.

Example: When you have an algorithm with O(n^3) performance behaviour inside your module with possible increasing n, the situation can arise, that your module will become very slow in circumstances.

Of course, there are many differences. When you have O(n^3) on an in-memory array, it might be less problematic as an O(n^2) on a disk operation.

So, experience is important to think about those things and to decide where the design must be changed or where a later tweaking can make it faster without problems.

Juergen
+22  A: 

When I'm writing this, two people have already replied with the Knuth quote on premature optimization. I think that's somewhat misleading. The thinking behind that, and behind much advice on this topic, seems to me to be that a program is a collection of algorithms, and if it is not efficient enough, we can determine which of the algorithms is too slow and replace that with something better.

This kind of thing ignores the interconnectedness of the program. The algorithms are all hidden behind some APIs. While the "vision" is that the algorithm behind the API is opaque and interchangeable with another, it ignores the constraints placed by the API on its caller. I've done a fair share of network programming, and there it is easy to write inefficient software by designing APIs that simply cannot work efficiently, so what do you do when you have to make fundamental changes to an API that's being used all over? (In network programming, an API that requires the caller to build a complete message in memory is easier to design and implement than one that allows streaming the data, for instance.)

So, don't fall for simplistic and pithy quotes. You shouldn't sweat the small stuff (and especially don't worry at all about the things that people in the 70s did; compilers are much smarter now) but completely ignoring performance issues with the attitude "We can always profile and improve things later if needed" can lead you to a dead end where you have to do significant reimplementation.

Oh, and I would also advise against "designing for extensibility". Do the simplest thing that works, and if you later find that generalization of something you have makes things easier or simpler, do it then. In my experience, going for a needlessly-general design just results in a harder-to-use component that often isn't really very extensible because the initial design couldn't actually foresee what kinds of things the component should do in the general case and how.

jk
Further, Knuth's quote is primarily applicable to aggressive optimizations and shortcuts in implementation. Choosing appropriate algorithms and data structures based on their performance characteristics with respect to your requirements is entirely appropriate, especially when considering asymptotic performance. Otherwise we would rarely use hash tables, always opting for association lists. They're simple and not a premature optimization!
Michael E
If performance is important, then performance must be listed as a requirement. Of course, for it to be a requirement it must also have concrete criteria to satisfy, e.g., "must be able to process 10k events/sec running in the target environment" where "target environment" is also precisely defined.If you have that, then of course any design must accommodate performance.It's worth noting that Knuth's quote regarding premature optimization could also be applied generalization: do not prematurely generalize.
Chris Cleeland
+2  A: 

I must second jk's answer with all my heart.

Knuth's quote is somewhat in-applicable in real life outside some small domain of problems which don't involve architecting.

As an example, I recently had to spend 3-4 months re-architecting from scratch a fairly involved system because the original design assumed that 100% of data will be loaded in one chunk from database. Which was fine for 3 years until the data set grew to ~100x of what the original designer anticipated, and the system started to alternate between merely running out of memory at 2G usage or crashing horribly.

Now, the solution was conceptually simple - allow retrieval of data from DB in batches. Doing so intelligently worked. But what could have been extra couple of weeks of work in the original design stage had they bothered to think about performance turned into 3 month ordeal because every little function, object and API as well as overall architecture were explicitly written to assume "100% of data is there".

In general, any situation where the volume of data is a performance concern and chunking of data is the main feasible solution, that chunking MUST be designed for beforehead.

DVK
+1  A: 

As Goetz said: Write Dumb Code: http://java.sun.com/developer/technicalArticles/Interviews/devinsight_1/

Bart Kiers
I especially love this part - so true!:"Most performance problems these days are consequences of architecture, not coding -- making too many database calls or serializing everything to XML back and forth a million times."
DVK
A: 

Almost in an "it depends" way, I think you really need to take into consideration what your requirements are. If one of the highest priority requirements is "must be able to to sustain some crazy level of throughput/performance" then you would be crazy not to plan and design for that up front in the overall architecture and technology selection.

Ophidian
A: 

I find it interesting that only Mikael Auno mentioned the word "requirement."

While Knuth's quote is TRVTH, it all comes down to the requirements. Is scalability one of them? What is the expected load? If your answer is "I don't know," ask.

If these are requirements, add load testing to your acceptance tests.

You still want to design for maintainability. Defer performance considerations to the Last Responsible Moment, then profile - don't guess. Micro-optimization is a waste of the company's money.

Sometimes the responsible moment occurs fairly early; I'm not going to design an enterprise CRM system where all the data is stored as XML files on disk. What I am going to do is abstract the persistence layer.

In the end Kolibri's comment is correct - the answer (as usual) is "it depends."

EDIT: On re-reading, I'm afraid I violated the OP's constraint of "Please do not answer me saying that it all depends on the environment in which a software is expected to run." I stand by my answer, though. If (when) the requirements change, a simple design is generally easier to modify. The unstated assumption is that we know ahead of time how the requirements are going to change. The request may be "make it scale by an order of magnitude" or "permit moving a customer between organizations." Architecting for the former may make the latter more difficult to implement.

TrueWill
A: 

Do not make any optimiyation in advance. But the ARCHITECTURE ha a huge impact on the potential performance of the system.

I sugges rading the following book: Release It!: Design and Deploy Production-Ready Software

takacsot