Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

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

I'm interested in things a programmer should learn/know to provide extremely good application architecture design.

As known any design can be regarded as good one for certain circumstances but when it comes to extending app feature set or providing some optimization and etc. it turns out that app was poorly designed or lacks some abstraction. How to be able to predict and include such stuff into app design?

And from the other hand, software is here to be robust, efficient and fast. And it's main purpose from some point of view is to bring money (by saving or gaining them). So if one goes deep with abstraction and considered certain stuff that will be needed in 2 or more years, he's not going to end up with good app architecture (he's gonna have lots of unnecessary stuff). So how to understand to which extent certain stuff in app architecture is needed?

Hope I made myself clear, else please comment on vague parts.

share|improve this question
I would start reading books on the subject. The basic concepts do not change, the tools or the frameworks might change, but the fundamental designs ( in my opinion ) change. – Ramhound Apr 5 '11 at 11:24
up vote 6 down vote accepted

How to be able to predict and include such stuff into app design?

You can't predict the unknowable. Therefore, you have to follow the golden rule of Late Binding. Do not "lock in" decisions; allow components, classes, modules to be removed and replaced as you learn.

if one goes deep with abstraction and considered certain stuff that will be needed in 2 or more years, he's not going to end up with good app architecture (he's gonna have lots of unnecessary stuff). So how to understand to which extent certain stuff in app architecture is needed?


Read up on Agile methods, particularly "Scrum".

Prioritize the features. Design the features you need first. Release them. Get paid for them. Move on to the next set of features.

Do not anticipate deeply or far into the future.

Follow the rule of Late Binding and build just what is needed and no more.

"Deep with abstraction" often becomes a game to avoid building useful software.

share|improve this answer
+1 YAGNI – NickC Apr 6 '11 at 17:04

There are many valuable books on design, but book learning has limitations. To complement book learning, here are three things that improve design acumen:

  1. Learn to think and be thorough: Programming is primarily an intellectual task. Learning to think through the consequences of ideas and to communicate precisely assists in the conceptualization (i.e. design) of program structure (whether procedural or object oriented). Work hard at thinking through the details of your design -- you may need to step away from the computer and draw some lines and shapes on paper.
  2. Designing for tests: Cruft is often inevitable. A better approach is responding to poor design by refactoring. In Working Effectively with Legacy Code, Michael Feathers posits his own definition of legacy code: "[L]egacy code is simply code without tests." Writing code that can be tested is often also well designed. Improve poor design rather than start over.
  3. Code reviews: The fastest way to learn to design components well is for someone more experienced to explain that you're doing it wrong and why you're doing it wrong. The team must share ownership for quality and be ruthless with each others' code. Read Best Kept Secrets of Peer Code Reviews. Initiate ruthless, thorough, pre-commit code reviews for all changes.


Becoming capable of providing quality application design takes a lot of time. Read Teach Yourself Programming in Ten Years by Peter Norvig.

share|improve this answer
+1 for peer reviews. Also consider design (pre-coding) reviews. – louisgab Apr 5 '11 at 15:36

I think you need to make a clear distinction between application design and system design (devising the architecture of an application).

Application design is, what you see from the outside. It revolves around feature design, user experience design and even marketing decisions (deployment and monetarization strategies). Of course application design cannot be unaware of technical limitations, but taking them into account is the part that almost everybody get's right, while all the rest is, what a lot of people get wrong.

System design is possibly what you mean. It revolves around dissecting an application into independent units (tiers, services and other modules), according to the application design and then reiterating this step again until you are left with manageable units.

The key to flexible system design is low coupling, which is achieved through information hiding, one part being encapsulation (i.e. tying nasty and fragile implementation details up in robust objects) and the other abstraction (i.e. choosing not to depend on a concrete module, but the smallest possible abstraction of it).

For example, if you have a class DataStore, providing access to stored users and pictures, thus acting as IUserStore and as IPictureStore, you want the individual renderers to depend on those abstractions and inject the implementation. Because at some point, you might decide, that you want to keep your user data on your server, but to store your pictures with some 3rd party cloud service, which means dividing the DataStore into two classes might be neccessary. All components that solely depend on abstractions, are unaffected.

What you want is a system, where single components can be modifyied in isolation, without effect to the system.
The only question left for you to answer is, when to consider a component itself as a system and to further modularize it and when to stop. The SRP is a radical rule, but its hard to stick to.
I prefer a more pragmatic approach. As long as a component is easy to grasp, leave it as is. When it grows past a point, where you can understand it within a minute or reimplement it within half a day, it's time to single out and isolate individual responsibilities.

But this is a line to draw for yourself, and it's something that naturaly happens in the field.

So to summarize:

  • Do not abstract ahead of requirements. Use abstractions to express requirements clearly and exactly, keeping them simple and obvious.
  • Do not modularize ahead of complexity. Naturally keep together what's simple and break down what's complex.
  • Do not implement ahead of abstractions. Make no unneccessary assumptions, depend on abstractions, rather than details.
share|improve this answer

Your Answer


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.