4

I'm a newer enthusiast programmer. I've been doing small and big projects on and off for the past two or three years.

I always hit small snags in my code that add up to big memory hogs or unnecessary lines of code down the road. My philosophy on big projects has always been to just 'get it out of my head' and write all the code into a working product, then going back and reducing the code to a simpler, more optimized form. However, this doesn't always work: when doing database structures, I tend to have to go back many times to add in features that come up spur-of-the-moment. Entire blocks of code have to be erased because of a spontaneous brainchild.

My question to you is, is it more efficient to write an entire program and THEN go back and optimize it, or should I optimize code as I write it?

10

Premature optimization is the root of all evil.

That quote gets overused and applied beyond the original intended context, but the overall point certainly applies here: don't stop to optimize until you're sure you need to optimize it, and you won't be sure until after you've written most of the program.

  • Reading it closer to the original context is always great. +1 for link. – Stephen Sep 14 '11 at 12:42
9

is it more efficient to write an entire program and THEN go back and optimize it, or should I optimize code as I write it

Neither.

You're missing an entire huge component to the SDLC: design.

You should prove out concepts that you're unfamiliar with in a sandboxed environment (meaning it doesn't actually link in with the rest of your project, or if it does, it's easy to swap it out with something with a little more thought behind it).

Take the learnings from your prototype and write up a technical design. By now, you should have proven out any unknowns and figured out any potential small technical gotchas. The intent here is to fully flush out your design and make it as optimal as needed (refactoring for optimization while coding is a bad practice).

Then implement your design. There may be small oversights that you may have to account for, but by the time you start writing the code that will make its way into your main project, you will have your concept proven out (by prototyping) as well as an efficient design that accounts for as many edge cases as you and your peers can think of (technical design).

5

I will make you a counter proposal. Suppose you were to outline your classes first, whether this is through something like UML mocks, or simply class outlines it matters not, then, once you have determined what appears to be the best approach, begin writing. Once you have finished a noticeable portion of the project, then it is appropriate to go back and clean the cruft.

Depending on the scale of the project and the developer, this might be a set of classes, an individual class, or even (rarely) a method. But it is almost never a good idea to wait until everything is done to optimize. OTOH, it is also equally bad to optimize too soon. This leaves as the only option a process of writing and then cleaning, and writing and then cleaning.

2

Don't optimize at all until the running program tells you what needs optimizing.

Here's what I mean.

If we optimize without knowing what to optimize, we are a bit like the drunk looking for his keys.

1

In your case, it seems the best time to "optimize" depends on what you're doing.

If your code is very modular, fiddling with it later may not be very annoying, so it might be better to "optimize" later. If you depend a lot on your database schema, then fiddling with your database schema later may be annoying, so it may be better to "optimize" earlier.

("Optimize" is in quotes because I'm not so sure of what you mean by "optimize".)

1

For me it is often more productive to err on the side of optimizing in hindsight, just slapping in a basic implementation which is easy to reason about in terms of correctness and revisit as needed with profiler in hand. I prefer to iterate towards faster solutions when possible/practical because I like to see my system get fleshed out sooner even if I have to go back and drill down and tune it in key areas.

But I need to put big emphasis on the practical part, since it's not like you can write a software whose design revolves around interacting with teeny objects in a scalar, one-at-a-time fashion, and expect to find much room to optimize that without changing the design. There's no use having a race car if there's only 10 meters worth of road for it to drive over, and designing overly granular interfaces that deal with teeny things one-at-a-time can corner you like this with a design that leaves no breathing room for optimization.

So it helps when you anticipate a performance-critical area, which I do believe you can often anticipate without measuring*, to design sufficiently coarse, not granular, interfaces.

  • As said I believe you can anticipate where the performance-critical parts are in your system reasonably well, even if you may not be able to anticipate the details fully until measuring. All you have to do is ask basic questions like, "where are we going to be looping over a million things"? Well, if you are implementing a GUI system, it's obvious where you'll be looping over a million things, and that'll be in the GUI drawing functions where you can potentially be looping over a million pixels to process. It's not unreasonable to deduce, in foresight, that this area is probably going to be a performance-critical so that you design it with sufficient breathing room to optimize and optimize it in the future.

For example, instead of having your system revolve around interacting with granular Pixel objects, design it to revolve around interacting with collections of Pixels with Image objects which could represent millions of pixels at once. Similarly instead of Particle objects, interact with a ParticleSystem. Instead of Creature, interact with Creatures. Instead of a callback which is designed to process one teeny thing at a time (one pixel at a time, e.g.), have a callback which is designed to process a range of things at a time (a range of pixels at one time). These types of things will leave you so much more breathing room to optimize without changing the design.

General-Purpose Libraries

That said, this advice is oriented towards people like yourself who want to move on and tackle big projects. If you are, say, in the mindset of designing a general-purpose library of data structures whose intentions are to be as widely applicable as possible, and that's basically the end product, then you might save more time putting thought into how to make it as efficient as possible upfront -- of course still measuring and tuning and iterating as you go, but not just slapping in a basic implementation if you're pretty sure you're just going to have to rewrite it.

In those cases, efficiency and applicability are related concepts, since if your library is skewed in performance characteristics and lacks well-rounded data structures, people might not use them so much or you might end up feeling the introduce more and more data structures when tuning the former ones might have sufficed. So there it can sometimes really pay to just try to get the most efficient version you can mostly upfront. I've found over the years as I've gotten better at optimizing code and especially for locality of reference that I can get away with using fewer and fewer data structures, ending up with more well-rounded data structures I can use in a wider range of areas instead of ones with skewed performance characteristics that are narrowly applicable. The end result is much less code to maintain and enhanced productivity, even though that came about from an optimization mindset.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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