When I'm doing design for a task, I keep fighting this nagging feeling that aside from being a general outline it's going to be more or less ignored in the end. I'll give you an example:

I was writing a frontend for a device that has read/write operations. It made perfect sense in the class diagram to give it a read and a write function. Yet when it came down to actually writing them I realized they were literally the same function with just one line of code changed (read vs write function call), so to avoid code duplication I ended up implementing a do_io function with a parameter that distinguishes between operations. Goodbye original design.

This is not a terribly disruptive change, but it happens often and can happen in more critical parts of the program as well, so I can't help but wondering if there's a point to design more detail than a general outline, at least when it comes to the program's architecture (obviously when you are specifying an API you have to spell everything out).

This might be just the result of my inexperience in doing design, but on the other hand we have agile methodologies which sort of say "we give up on planning far ahead, everything is going to change in a few days anyway", which is often how I feel.

So, how exactly should I "use" design?

  • 1
    The do_io seems to be an internal implementation detail of that class. The public interface will and probably should still be read(...) and write(...) as it is a lot more verbose about the intention of the call. Commented Mar 12, 2014 at 9:15

8 Answers 8


If it made perfect sense to provide read and write operations, why remove them?

From the user point of view it still makes perfect sense. The implementation details should not interfere with a provided interface.

What you can do is to create an internal do_io that gets called by read and write.

In the end the design process follows these steps:

  • define the interface
  • draw a rough design
  • refine without changing the agreed interface
  • 1
    +1 "Optimization" decisions to avoid code duplication do not necessarily call for a change in the original design. Commented Nov 21, 2011 at 8:45

Architecture design of a program evolves over time. I don't think at the beginning you have every piece of information you will need to have a correct design.

So, if you stick to the design you thought at the beginning you will probably limit yourself.

Unless you are creating a public api I think its OK to make changes to the design along the way.

Also one of the best things to do is invest in a tool that can extract the design from the code ( like NDepend for C# )


Agile claims to answer this problem, with some success, However Fred Brooks had the answer 40 years ago, when he wrote "Write one to throw away, because you will anyway". Those who do not study history are doomed to repeat it.

So what do do is treat the design as a plan, which is made for the sole purpose of changing it. Designs that cannot be changed are doomed. You must be prepared to throw away bad ones.

If the design is one of a public API, interface or such like, much care needs to be take as the cost of change is high, however, the inability to change will doom it to failure.

Do not for one second think you are good enough, and know enough to get it right first, second or even third time.


It is a fact of life in most real-life projects that things change:

  • (as you noted) the environment / platform / APIs the program is going to use may be different than originally assumed
  • the requirements may change at any point
  • the market / surrounding world may change, obsoleting some requirements (or the whole project)
  • ...

This is why Agile methods oppose Big Design Up Front, because it just gives a false sense of security, involves a lot of useless effort, and makes adapting to the inevitable changes more difficult.

However, Agile does not equal to "give up on planning far ahead". Agile methods do involve the necessary amount of careful and thoughtful planning, just no more. They are very disciplined, and different from "cowboy coding". Doing the right amount of design is a continuous attempt to find the right balance between over- and underdesigning. But IMHO it is better to err a little on the side of too much, than to do too little.

The initial design should not try to cover everything, but should give you a secure feeling that you know how to move on with the implementation, you have answers to the fundamental questions about the architecture, and you have a mental model of how the known use cases are going to work in real life. In the Agile view, the real test of a design is implementation, so it is OK to start writing code even during the design phase, just to get a feeling of how the envisioned design would look like, or to quickly prototype / validate some assumption. Note though that most of these early work are to be thrown away once the answer to the given question is determined. It is almost always a Bad Thing to start building a real production app from an early prototype.

And it is also OK to go back and modify the design if you make a new important realization during implementation. This is an important feedback on two levels:

  • your concrete design needs to be adapted to the changing world, and
  • your design process needs to be adapted to cover such possibilities in the future (i.e. next time think through the use case of reading from and writing to the device better in advance).

Its always important when you are creating any document to understand what it's purpose is.

I think we have to be careful what we call "architecture" documents. It's all a matter of scope.

If you are talking about a system that requires several teams or groups of teams, then you are talking about a document who's purpose is to detail out at a minimum:

  • What are the components in the system
  • How are the components connected
  • What are each components responsibilities
  • Who should be working on each component

If your document is for a smaller system then you can reduce the number of items you need to include because some assumptions will be inherent to the existing system. For example suppose you are putting a feature together that will need to have work done in a website and some new calls in an API, then your document will serve as a way to nail down the following:

  • What logic will live in the website
  • What logic will live in the API
  • What will the API calls contracts be (best guess)

These outline documents serve to bring conversations to the front on who should do what and how should they integrate. Once those decisions are made then teams can operate largely autonomously with a much lower chance of integration issues.

The more integration issues you perceive, the more detailed you should documents should be.


You seem to have stumbled across a common conundrum in Software Development. It is not possible to plan an entire system before you start to build it, because there are too many things you don't yet know.

This is the reason why Agile methodologies use iterative development, because it allows regular feedback to change the direction of the software, rather than letting things get further and further from what is actually needed. Each change will affect the design.

So having said all of this, I actually would have written two methods for the specific scenario you describe above, but I would have encapsulated the shared logic in a third private method that can be used by the two methods. This way, the public methods are responsible for just one thing and are easy to name, read_file and write_file say exactly what they do, whereas do_file is ambiguous.

Books such as Clean Code, Robert C Martin and Emergent Design, Scott L Bain will give you more detailed insights into this subject.


This might be just the result of my inexperience in doing design, but on the other hand we have agile methodologies which sort of say "we give up on planning far ahead, everything is going to change in a few days anyway", which is often how I feel.

It is not possible to plan every single detail in advance. It is perfectly acceptable to make changes here and there.

However, it is important to plan ahead. Doing agile doesn't mean no design and no planning at all, but it means that you are expecting changes.

So, how exactly should I "use" design?

You should use your design as it is. Since it is not written in the stone, it is easy to change it.


The amount of time you spend on the architecture should be determined by the degree of risk in that part of the system.

Generally you'll want to make a decision fairly early on the architectural style(s) - layered, component, pub-sub, etc, etc. No amount of clean code and loose coupling is going to make it easy to switch styles late in a project.

Doing that will give you a basic idea of the different building blocks in your system and what the roadmap will be as your system and requirements evolve over time.

Once you get into use cases I believe you should do enough design to ensure you understand the problem and solution fully. If it's boiler plate code that you've done again and again then the risk of getting it wrong (in an architectural sense - you'll still need to test of course) is pretty low and so the amount of up-front design is likely to be fairly minimal. If it's a new problem, or one with an unclear solution or one that is potentially risky to the business then it'll deserve much more time thinking things through.

There are of course a wide range of ways of doing this - UML, prototypes, white board sketches, etc. Whichever method you use - the key thing is to remember is that their purpose is to help you think and communicate about your design.

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