🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Over-architecting is a form of premature optimization.

Published October 23, 2014
Advertisement
Something I learned today: Over-architecting is a form of premature optimization.

"Uh, what exactly do you mean by that?"

If you've got a fixed use case to build something, you don't need to make a generalized implementation. Just build the dirty implementation with hard coded variables and values first. First, make it work. IFF you need more flexibility farther down the road, you can always come back and refactor the code. I've noticed that when I make my first iteration pass on solving a problem, it's certainly not going to be the last one, and it's certainly not the 100% perfect & correct solution. Only around the ~10th pass does it approach intended perfection, and that's only because all of the actual uses for a system have been implemented and generalized appropriately.

So, in short, do this for new systems:
1. Hard code the first implementation. Make it work. Move on.
2. Later, if you have a new variation, you can come back and just barely generalize the first implementation to be good enough. Make it right. Move on.
3. IFF you identified a performance problem empirically, you can optimize the problem. Make it fast.

Gradually, your hard coded solution rises to meet the exact level of flexibility your system needs to support, AS NEEDED. No more, no less. It's very lean. Everything which has been built is actively being used. Best of all, you save a lot of time.

"Why do this? It seems hackish and like a 'cowboy coder'".

The problem with "big design up front" is that the designer has a really difficult time accounting for factors which are only discoverable during implementation. The engineering tendency / instinct is to just say, "I can't predict every problem the system will encounter, therefore, I will try to engineer this solution to be as flexible as possible to account for future problems." For example, if your "need" is to build a dog house for your dog, you shouldn't let your design account for the future possibility of having multiple dogs, or your dog gaining weight, or switching from a small dog to a large dog. Just build the damned dog house today for the dog you have and be done with it, and if its not good enough later, change it then.
9 likes 6 comments

Comments

TheChubu

I understand what you mean. Thing is, when you build up this "right amount of flexibility" along the road, you might essentially make it useless.

IE, the case for flexibility isn't that given the current use case, if it could be considered flexible enough. Because if the current case was that set in stone, flexibility wouldn't be necessary, you'd just hardcode everything. The idea of flexibility is for allowing modifications in the future.

Now, if you build it along the road, in each iteration you're essentially saying "Hey, this is how the code should have been in the first place for accommodating the changes I'm making right now!". That way you're not saving time at all, you're just postponing the refactoring.

I like to think of this "thinking ahead" as a skill like any other, something you train and develop.

If you make a solution that for the current set of requirements can be considered as "over engineered", but it happens that some time later, that over engineering becomes the exact thing you need for the different requirements you have at that time, that's a win.

If you overengineer and you never make use of it, that's a loss.

I'm kinda sure you can just develop this kind of coding, rather than trying to shy away from it as you suggest. Then again, as you said, this is really difficult, so in many cases it might be worthwhile just to go with the shorter/hackier road for the time being...

October 26, 2014 07:33 AM
StarMire

+ Thanks for this. I tend to be a pretty hacky coder (when I code). Although I will say this:

Sometimes when I make a function, and I go that extra mile to make it flexible... there's something else there in that despite it perhaps not being useful, there's a certain pride you feel for having done something properly and more elegantly.

Maybe it's not just about optimization; part of it could feed into the enjoyment we can feel from programming.

Like when I draw, making stick figures doesn't give me the same satisfaction. Even if stick figures are all that are needed and excessive details are technically wasting time, sometimes going that extra bit can bring more satisfaction and thus provide more motivation for additional productivity. While doing it "wrong" can be a little demotivating when you look back at a mess (even if it's a functional mess).

Just a thought.

Great article!

October 26, 2014 08:20 AM
slayemin

I understand what you mean. Thing is, when you build up this "right amount of flexibility" along the road, you might essentially make it useless.

IE, the case for flexibility isn't that given the current use case, if it could be considered flexible enough. Because if the current case was that set in stone, flexibility wouldn't be necessary, you'd just hardcode everything. The idea of flexibility is for allowing modifications in the future.

Now, if you build it along the road, in each iteration you're essentially saying "Hey, this is how the code should have been in the first place for accommodating the changes I'm making right now!". That way you're not saving time at all, you're just postponing the refactoring.

I like to think of this "thinking ahead" as a skill like any other, something you train and develop.

If you make a solution that for the current set of requirements can be considered as "over engineered", but it happens that some time later, that over engineering becomes the exact thing you need for the different requirements you have at that time, that's a win.

If you overengineer and you never make use of it, that's a loss.

I'm kinda sure you can just develop this kind of coding, rather than trying to shy away from it as you suggest. Then again, as you said, this is really difficult, so in many cases it might be worthwhile just to go with the shorter/hackier road for the time being...

I completely understand what you mean. I think finding the right amount of engineering to put into a section of code is an art in engineering calibration which is only gained through lots of experience.

I wrote this post after I spent 3-4 hours writing up a really flexible/robust class composition for a scenario which didn't need it at all. In fact, if I had gone ahead with it, it would have added in a whole bunch of programming overhead. I stopped and said to myself, "whoa, whoa whoa... what are you doing?! This code is getting out of hand. Just hard code this in for now and if you need the extra flexibility in the future then you can do this. Chances are, you aren't going to need it."

October 26, 2014 11:01 PM
slayemin

+ Thanks for this. I tend to be a pretty hacky coder (when I code). Although I will say this:

Sometimes when I make a function, and I go that extra mile to make it flexible... there's something else there in that despite it perhaps not being useful, there's a certain pride you feel for having done something properly and more elegantly.

Maybe it's not just about optimization; part of it could feed into the enjoyment we can feel from programming.

Like when I draw, making stick figures doesn't give me the same satisfaction. Even if stick figures are all that are needed and excessive details are technically wasting time, sometimes going that extra bit can bring more satisfaction and thus provide more motivation for additional productivity. While doing it "wrong" can be a little demotivating when you look back at a mess (even if it's a functional mess).

Just a thought.

Great article!

"Is the glass half full or half empty?"
An engineer will say that the glass is twice as big as it needs to be ;)

I think, at the end of the day, what matters is whether the code works or not. All code needs to be maintained of course, so you can't be super sloppy, and all code needs to perform well enough, so you can't choose poor algorithms, but that's about where it stops mattering "how" something is coded behind the scenes. It can be dirty with lots of hard coded values. So long as there are no bugs and it does what it's designed to do, it's good. People who use the software will never care about how the code is written, just that it works well.

The code "elegance" you speak of is the final result you get after many iterations of refactoring, where a class beautifully handles everything which is thrown at it. With my approach, this elegance is more of an emergent property than something that's designed from the beginning. Oddly enough, the fast and dirty code can be considered beautiful in its own way when you consider how little effort was spent writing it and that it solves the problem its environment requires it to solve.

October 26, 2014 11:18 PM
gorogorosama
So true! Get it working as fast as possible (you will learn so much by this), and then worry about making it "elegant" if you still need to!
November 05, 2014 07:30 AM
Roger Pack

I guess the question at the end of the day is do you cobble something together and then "feel a bit of pain having to rearchitect it" (in case you never have to) or try to get something "good" going but...possibly run the risk of premature optimization.  Where's the balance, man? :)

December 13, 2017 06:55 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement