Design Before Coding

In the olden days, the rule was to do a lot of design before coding. The idea, if I recall, was that it was easier to change the design than to change the code. I presume that we all agree that the design will change over time, as we learn what we want, and what works.

Let's explore here the extent to which one should DesignBeforeCoding, and how best to do it.

As we change our design vs code setpoint, here are some dimensions where we might see variability (please add more):

Ease of change. When our understanding of the ideal design changes, we have to change all related design documents, and all related code. Presumably the less there is of each, the better. Designing without coding (for as long as you can) appears to have an advantage here.

Learning. As we work, we find out more about how to do our work. Our design (with whatever code exists) wants to change to respond to our learning. However, we learn about our design both by reviewing the (essentially abstract) design, and by reviewing the concrete implementation. When designing without coding, we have great difficulty learning anything from the (nonexistent) implementation.

Quality feedback. As we work, we and our customers will benefit from a growing confidence in the system. A good way to get this confidence is to have (a baby version of) the system, and to have it running its tests. As the system improves, the test scores improve, and confidence goes up. During the "before code" phase, we cannot gain this level of confidence.

Maintainability. Once the application code is (being) written, discoveries in the code that dictate changes in the design must be dealt with. There are three main strategies:

  1. code to the design, no matter how bad it is;
  2. code to the new design and do not update the design documents;
  3. code to the new design and update the design documents;.

If the design is to have value, you have to do the last, and it has the cost of dual updating. All too often, projects fall into one of the other two practices.

Designing in code

Why don't we design in code? The rational objections I can think of (please add more) are:

Code isn't expressive enough. There are important things in the design than you can't express in code. (Name one.)

Code isn't flexible enough. If the design is going to change rapidly, the code won't be able to keep up. This is clearly a function of how early in design we are, and how flexible the coding system is.

Design is less flexible. At least modern stabs at it, ala TheAlmightyThud. It's faster for me to just change the source code than six layers of diagrams and bad English. -- SunirShah

Designers shouldn't code. Do we perhaps mean "can't"?

So, if a coding system existed that was capable of expressing everything important, and flexible enough to keep up with change, and easy enough that even a designer could use it ... we should go with it?

Now if we can just find such a system ... -- RonJeffries

Here are more:

Code only allows one view of the system You can often understand a solution better when looking at it from multiple views. Most painters will do a sketch in charcoal first before stretching a canvas and starting to paint.

I find the opposite is true. I have far more options to view the design in code than in a design document. In code I can dynamically step through any path I desire. I can statically walk through the hierarchies of interest with various tools helping me trace links, from global searches (i.e., greps) to highlighted links. With a document, I can only look at the views created by the writer and I am largely restricted to the sequence created by the writer. The software development environment is a far more expressive media than written documents. -- WayneMack

I'd hate to drive over a bridge that was designed during construction! Sometimes you can get so caught-up in the code that you don't see the design for what it is. I have often seen guys (gals too!) get so caught up in the aesthetic of their code that they were no longer able to objectively view its underlying design.

Certainly, it would be nice to a have system that is different from what we have now but I think I would feel constrained by having to "do it all" in code. One of the cool things about approaching a design with different tools (from conceptual to concrete) is that it gives you multiple views of the same problem/solution. I think either extreme can be bad. DesignBeforeCoding seems just as bad as CodingBeforeModeling?. The problem is not designing in something other than code, it's making design one phase and coding another. Its not iterative. Better to IntersperseDesignAndCoding?. For example, Model a little, code a little, put some classes up on a white board, code a little more, look at a sequence diagram, refactor the code to remove complexity, and so on. I mean, why not get as many different perspectives on the solution as you can. Code is a funny thing. Is there such a thing as a design that is not language specific? I mean, does a good C++ design make a good design for Java? I doubt it. If you do all your designing before coding, you don't take advantage of your solution domain. Do none and you can be blinded by your solution domain. -- RobertDiFalco

>isn't flexible enough, isn't expressive enough

Don't the words flexible and expressive here add up to the fact that we need a higher level of abstraction than a programming language to express design. Surely expression in code involves unnecessary work (you are forced to be explicit about things that aren't specific to the problem at hand).

Code overspecifies the design - There may be more than one way to code up a "design" - depending on the level of detail in that design. We wouldn't want overspecification to rule out many viable implementation strategies. For example, we may choose to tinker with the storage/computation trade-off when we discover a performance problem. Why mandate a particular approach too early?

Other pages that have something to do with this one: ModelFirst, TheSourceCodeIsTheDesign.

On projects, I agree that design, code, and test should not be separate phases or deliverables, or even really managed separately at the project level. So I wouldn't really say one comes before the other or not.

However, on a three day task, I do design before code. I'll spend a day or so doing use cases, algorithm design, and class and public method design. I then start coding, and change the design as I code (my rule of thumb is that if my design doesn't change by at least 20%, I spent too much time on it). I don't update my design documents, and when the three days are up, I usually throw them away. -- StanSilver

See also CritiqueOfUseCases.

What do you mean "algorithm design?" You shouldn't be always thinking that hard about algorithms. DoTheSimplestThingThatCouldPossiblyWork. ComplexityMatters only rarely.

On a three ideal engineering day task, an XP developer would typically do maybe a half-hour of CRC, where the main classes to be involved would be identified. Then she would write unit tests for the functionality, then implement the functionality. For us, a three-day task is a pretty big one, although 18 months ago, more of our tasks tended to be 3 to 5 days. We early on learned that an estimate of 5 or more days too often meant "I don't know how do to this", rather than "this will take me 5 days to do". -- RonJeffries

What do you do in those cases? -- JimPerry

We do a SpikeSolution.

Tangential discussion: ExtremeTimeSpans.

Why mandate...

How do we know we have a problem without an implementation? And I am suspicious of absolutes, but one that I have not seen a contradictory example for is There's always another way to code up a "design".

When does one implementation rule out another? If the implementation fulfills its functional tests, why are we changing it? The goal is the simplest code that works (because we try the simplest thing that could possibly work, and iterate if we find reasons why it doesn't). This presupposes that there are many implementations that satisfy the functional tests.

-- BillJamison

"Code only allows one view of the system."

No, it doesn't. VisualWorks 5i provides at least five views (but that is not where the name came from), inheritance hierarchy, class categories, parcels, namespaces, and (soon) location. Test cases are another view. Instance diagrams as given by Kent's Object Explorer are another. Yes, there are some views that are hard to express in code, but it is completely wrong to say that code only provides one view of the system.

"I'd hate to drive over a bridge that was designed during construction!" This is also bogus. Suppose that when you built a bridge, you tested it by driving 100 ton trucks over it, blowing on it with 100 mile an hour winds, and then aging it 200 years before backing up time to the present. If any part failed, you replaced that part with a better one and retested. That is what we do with software. We should only release it when it passes all our test cases, and we are confident in our test cases and in the code. Programs are entirely different from bridges.

-- RalphJohnson

The bridge metaphor is even more bogus than that. Not only can we test it, but we can change software several magnitudes more easily than demolishing and reconstructing a bridge. And if we screw up, we can undo if we have source control. Failure is an option because it's cheap and you can revert your mistakes. Indeed, modern engineering projects have computer simulated models to allow this kind of malleable development. Don't forget that TheSourceCodeIsTheDesign. -- SunirShah

I think the notion that the idea that there is a 'construction phase' in software development, analogous to working from plans in civil engineering, is terribly counter-productive. It belittles too much of the design and design validation work that happens during episodes of programming and testing. -- MichaelFeathers

The idea that ThereIsNoConstructionPhase deserves its own Wiki page -- PaulCrowley

I've found that doing design before writing code is hard and doing design after writing code is easy. So I usually use the following steps to write well-designed code: -- CurtisBartley

In the olden days, the rule was to do a lot of design before coding.

Aarrgghh!! This couldn't be more wrong. In the (so-called) olden days no one designed commercial and business systems. Those that did, used a central architect who kept the design to herself. The mode of the day was CodeAndDebug with little to 'no design' upfront. Only recently have commercial and business software developers started thinking about process and such crazy ideas as rationalizing the problem domain before jumping into the solution (or even the idea that the solution domain is distinct from the problem domain). Honestly, I think DesignUpFront is a very recent evolution in mainstream Software Development. I will agree that many larger systems (such as operating systems) used to write reams of specifications before they wrote code -- this was really a drag and usually had little to do with design and more with busy work. Code only gives us one view of the world. It's not the only nor is it even the best view. -- RobertDiFalco

What timeframe are you thinking when you write "olden days"? I think of 15-25 years, during which I saw plenty of BigDesignUpFront on mid-sized commercial systems. -- DaveSmith

I guess many people have different experiences but only recently have I seen smaller mainstream projects (especially for internal IS projects) consider light-weight processes, design, and architecture more. I have to say that I saw plenty of specifications (DFD's, subsystem specifications, state-diagrams, etc), and way too much paper documentation, but little to no actual design work done. So, for me, 7-12 years ago most of the application projects I worked on were essentially CodeAndDebug (as opposed to TestAndCode?) using 3rd and 4th generation languages -- mostly various flavor of database centric languages. Of course, this could always have more to do with my evolution as an engineer.

Actually, this might be a good place to TakeaWikiReading. Those of you who have been working over 5 years, how well planned or how much design went into the majority of projects you worked on over the last 4 to 5 years as opposed to the last couple of years? Please don't include government, academic, or research projects as I'm more interested in commercial and IS application development. Also note that we are talking about Design and not tedious specifications. -- RobertDiFalco

--- WikiReading?

[I am not sure about you bias against government work, but I'll respond in spite of being guilty of that infraction for the last 3 years :-) ] Hahah! I'm not, I just want to get a reading of more mainstream projects. I assumed that government or academic work would be necessarily more formal that IS application or commercial development. -- RobertDiFalco

Most of the projects I have been involved in used a significant amount of up front design work. None of it was ever recorded in formal documents, much to the consternation of our CMM folk. The level of design work done varied within the project depending upon the individuals responsible for a specific area.

The areas which had no up front design tended to result in a BigBallOfMud solution with much internal bickering over the RightThing to do.

The areas which had up front design but were the result of political compromises because of warring factions resulted in strict software structural break downs with little thought to the underlying capabilities. The result was a complex object hierarchy which provides confusion but no benefit.

The areas which had up front design and good working relations between the participants resulted in some highly flexible, bug free approaches, but not much predefined software structure.

In summary: design used to define approaches was good, design used to define structure failed, no design (non-XP project) also failed. -- WayneMack

It sounds more to me like the key was good working relations and lots of communication. XP rails against BigDesignUpFront because of the problems it leads to when overdone. However, if you examine XP a bit more closely you see that there is lots of communication, lots of planning, and lots of practices that force people to cooperate. That last doesn't force good relationships to happen but it will force bad ones to blow themselves apart so that new ones can replace them. Consider that a UserStory is written, estimated, probably split apart one or more times, broken down into tasks and then broken down into tests, coded and then probably recoded at least partially and probably more than once -- that's a lot of attention to each and every story. What's yielded at the earlier parts of planning (up to and including breaking the story into tasks) is what you seem to be referring to as an approach rather than a strictly structural design. But XP doesn't rely strictly on a unified approach and good team work to get a good design. The practice of RefactorMercilessly causes the desirable design elements yielded by a good approach to coalesce into a coherent design. -- PhilGoodwin

Many years ago I worked on the HiltonFunctionBook? project. The "function book" was a physical book with pages about 36 x 24 inches (that's 91 x 61 cm). In this book were calendared all the bookings for convention and function space (where "function" means "social or business event") for up to 5 years into the future. It must be understood that "function space" is a very plastic concept, where walls are movable, facilities access could be altered by including or excluding certain walls or special-purpose floor panels, and so on.

Our task was to automate this booking function. We spent 6 months before writing a line of code - not in design but in definition. All we were doing was defining the problem domain, trying to determine how one might map it to data and methods. In the beginning, we didn't even know how to describe the things we were to track. (The project was a success, by the way.)

Although many of our discoveries in the definition phase were used in the implementation, we really did not DesignBeforeCoding so much as DefineBeforeCoding? (or is that DescribeBeforeCode?). -- GarryHamilton

Should we DesignBeforeCoding, and if so, how much?

Clearly (he said) we should minimize the time between problem and solution. Doing zero design, not even thinking for a second "How'm I gonna do this ... oh, I know ...", seems to be a bad idea.

Doing zero coding also seems to be a bad idea.

So the answer is somewhere in the middle ... tell me where you think it is.

Doing zero coding also seems to be a bad idea.

I don't know; isn't that the holy grail?

If the goal is expressed as something like DoTheSimplestThingThatCouldPossiblyWork, then some things follow: As far as I'm concerned, design here is a part of a process: analyze, design, implement, test, lather, rinse, repeat. For simple tasks it may mean little more than some time behind a closed door or going for a walk before coding; for major initiatives it may involve a team closeted in a room for hours or days. In the latter cases some form of notation to communicate the design forward may be useful, but this does not necessarily imply the traditional BigDesignUpFront approach with a separate n-binder "Project Q Design" document that must be referenced and updated at every stage. -- JimPerry

I hadn't read it before writing the above, but SoftwareDevelopmentAsaCooperativeGame has some insight into what I was getting at in differentiating the design process from The Design as permanent artifact. -- JimPerry

"Doing zero design ... seems to be a bad idea" Why? What problem are you imagining will happen? I'm imagining you wouldn't know what to type in, since you wouldn't have thought of the IntentionRevealingSelector. I'm assuming if you type without thought, you'll type something like etaoinShrdlu: cmpFwp. But I take your point, some people might think I had something bigger in mind.

See IpAddressExample for last night's experience.

What we really do that could be described as design is about like this.

Consider a story: Dayton hourly employees pay $15 per month union dues, except for employees with id 123, 456, and 789, who pay $10.

We have already implemented the system so that it charges all hourly employees $20 an hour.

We need to get the EngineeringTask(s) for the story. We brainstorm, or if it were hard, CRC.

This is design:
  1. Create a Union object answering union dues, in the Employee Profile.
  2. Generate a Union object for all employees, based on Employee Group.
  3. a. We'll have to have a master dictionary from EG to Union. Populate this with info for all Unions. (Get from Customer.)
  4. Change the Union Dues Station to get the ee's dues rate from the Union object instead of the hard-coded $20.

For most stories, this takes us one minute. When I started on, say, task 3, I'd browse the station, see where it multiplies by 20, change that to say (self unionDuesRate: aJob). (aJob is a parameter to the station's execution, and the job has a pointer to the person.) unionDuesRate: aJob asks the job. The job asks the dated person. The dated person asks the union object. The union object answers the rate. Done. -- RonJeffries

One might ask where all these stations and things came from. In the first week of the project we considered several metaphors for how the system would work. You might call the metaphor an architecture. We implemented the simplest payroll that could possibly work in another week. We have evolved it ever since. -- RonJeffries

Considering other similar or related problems at the same time can help you arrange your design so that the next problem is also more likely to fall closer to zero coding. YouArentGonnaNeedIt, so don't write the code for the new case, but a little more thought during the already focussed mental activity of design costs very little and can pay off disproportionately.

XP holds that the payoff from thinking about the next problem is too low to justify doing it. Of course, no one can avoid a stray thought, but the investment of any discernible time in the next problem is stealing from this problem, and fraught with peril. We say don't do it. -- RonJeffries

I'm interested in approaches where you can start coding immediately and have a good idea that what you develop will be part of the final solution or part of the learning that leads to the final solution. This can sound like hacking, but as others have mentioned, OO is very amenable to change especially when you RefactorMercilessly and keep breaking big things into small things. It also helps to proactively reconsider as you go. If you have to throw things away, fine. Move on. But at the end of the day, having tested working code even if it does not solve all the problem, feels so much more honest than a whole load of plans.

I remember Ron mentioning that in C3 they had something very small working immediately and it grew from there. I tend to think that most computational problems are like that. They aren't like buildings which require 5 tons of concrete and steel girders. In systems that I've worked on, there is a usually a little collaboration which captures the essence of the system before you consider distribution or physical architecture... and it can be coded quickly. Think about it. In all the systems that you've ever worked on, could you sit down in an afternoon and code up something which is the gist of it... which explains the fundamentals of the system, may or may not scale and supports some reduced feature set of the whole system?

Looking back on it now, I think I misnamed TheSourceCodeIsTheDesign. The idea there is really that coding is part of the process of designing.

-- MichaelFeathers

The investment of time in design should be proportional to the complexity and (un)familiarity of the task at hand. This discussion arose in the context of BigDesignUpFront/GeneratingCppFromSmalltalk where the design in question was of a new, presumably large, project, in a new language and design paradigm.

Adding a new concrete case of an unexceptional sort to the behavior of an existing understood (and well-designed) system is a different matter. Still, though you don't give a time for implementation, if we estimate - what - 15 minutes as described?, then the same proportion (given 1 minute's design in that case) of a 24-week project would be 1-2 weeks of design. -- JimPerry

In all the systems that you've ever worked on, could you sit down in an afternoon and code up something which is the gist of it.. which explains the fundamentals of the system, may or may not scale and supports some reduced feature set of the whole system?

Could I today or soon afterward, or could I upon starting the project? It depends on the project, but for the interesting ones, no, I couldn't do that beforehand. Perhaps some ridiculously reduced version:

 foreach $emp (@employees) {
    print "Pay ", $name{$emp}, " \$", $hours($emp} * $rate{$emp}, "\n";

Such a base is often useful to build on, but I'm not sure how often it captures what is interesting about the particular system. -- JimPerry

I can think of times when DesignBeforeCoding was good, and others where it wan't so helpful. I am not so much thinking of major system designs, at this moment. We spent months torturing ourselves over a complex piece of domain model, which, in retrospect, we could have just tossed together (and written some decent test cases for!) and altered as needed, given, as the final results showed but we didn't know up front, that it would be literally months before the design stabilized.

I also recall slaving away, for half a day or perhaps 2 days (but I think the former), over a tricky piece of assembler code for drawing a line, using register bits and loop unrolling, jumping into and out of the loop based on stuff. That think time paid for itself marvelously. I used the DijkstraGriesProgramDerivationTechnique, and when I finally typed it in, it simply worked. I believed then, and still do, that it would have taken days or weeks for me to test and debug my way out of that mess, so I decided I was simply going to get the code perfect before typing it in.

There are some problems, distributed computation, mutual exclusion, synchronization, which I still think you can't debug your way out of. And other problems, for which the correctness of the system is not really at stake, one is selecting between several plausible solutions - so choosing the less-than-perfect one is not really a problem. -- AlistairCockburn

Let us not pretend that there is no design before coding in XP. I hope no one said that. In the C3 project, there have been two kinds of DesignBeforeCoding. The pre-history was the first, 1-year long, failed attempt to produce a system - so the group knew the domain and some initial design ideas. There was then a "large" design effort, a 2-week workshop in which they searched for a metaphor for their system that would hold up over time, a domain architecture, if you will. In that 2-week period, they prototyped to check that the metaphor was holding up. Periodically, as needed, there are CRC sessions, "small" design efforts, to play out a design, before stepping to the workstations. The rule of YouArentGonnaNeedIt does not mean no design, it means KeepItSimple. C3 and XP protagonists please correct my writing as needed. -- AlistairCockburn
Could I suggest one possible way to explore this subject might be to look at what value we expect to derive from "design" and what alternatives might provide the same value?

My rationale for proposing this is that I do not believe we have a single, coherent definition of design, and reasonable people may disagree over any specific definition. Therefore, let's skip over this potentially contentious issue and try to define "Why would we want to do design?"


View edit of April 10, 2012 or FindPage with title or text search