This site will look much better in a browser that supports web standards, but is accessible to any browser or Internet device.

Anomaly ~ G. Wade Johnson Anomaly Home G. Wade Home

January 15, 2015

Design Principle: Just in Time Decisions

One of the classic mistakes of software development results from thinking we know what we are doing. Entirely too many people in software start off each project believing they know enough about the project to lay out the whole design. Except in the rare circumstance that you are building an exact copy of something you have already designed and built, you are almost certainly wrong.

As we develop experience, most of us learn this lesson. The problem is actually pretty simple to state:

At the beginning of any project, you know less than at any other time in the project.

Throughout the project, we should always be learning things: edge cases we didn't consider, business plans that change, users we weren't told about, etc. As the solution unfolds, we discover more and more that will affect the design decisions we make. This is why most software teams have begun to reject Big Design Up Front. However, not doing all of the design at the beginning is not the same as doing no design at all.

Small Design as Needed

Many methodologies have taken the idea that we should build a list of features, use cases, or user stories that lay out what needs to be done and fill in the details as we go. Done well, this can result in a system that meets the needs of the stakeholders very quickly. Done badly, it can result in an unmaintainable mess.

So, how do we move in the direction of the better designs? I suggest that we do just enough design before we need it to give some structure to the code that will be written, but not design ahead any more than necessary. Unfortunately, this is the kind of advice that sounds good, but doesn't help. Kind of like Buy low, sell high.

One approach that does seem to work is to put off individual design decisions until you absolutely have to make them. If we can continue coding on a particular feature without making a decision, then don't make the decision. At some point, the code will close off potential decisions. At that point, we have gone too far, because the decision has effectively been made.

An Example

Let's say that we are making a system that depends on weather information. In the initial design discussions, we determine there are three potential services that contain the information that we need. At the beginning of the project, we may not need to decide which service to use. We could actually build the UI (a decision that we need to make early to get user feedback), with an interface to mock data.

This allows someone to explore the APIs to determine their difficulty of use. We can also determine if there is other information we might have wanted. This also gives us the possibility of considering whether we want to be able to switch providers, maybe using a secondary service as a backup if our primary one goes down.

All of this should just be research, without building anything. By not making a decision on the service right away, but focusing on the interface, we can get the interface in front of users and get feedback.

What if the users decide that there is some information that they really need that we haven't put on the UI? What if they decide that the way we are displaying some information is not useful? What if they need a map displaying the data differently? All of these pieces of information may affect which service we need to use. If we had originally guessed wrong, we will be spending time re-designing and re-coding access to the service, or worse telling the users something can't be done because of our earlier (premature) decision.

Once we have the UI nailed down to the point of knowing what data the user's need, we can make a decision about which service to code for. It's entirely possible that for business reasons we will need data from more than one service. This would be a major change in design if we had coded to assume only one service up front.

Keep Collecting Data

As long as the work you need to do does not depend on a decision, put the decision off. The longer you wait the more data you will have. This increases the chance that when you must make the decision, you will have the information you need to make a good decision.

All of us have had the experience of having to tell a user that we can't do some change they want because that's not how the system works. Much of the time, that was because a decision was made before we knew what we know now. Granted, sometimes the request really doesn't make any sense for the current system. But, you know the uncomfortable feeling of having to say no, just because.

Don't Go Too Far

We can't put off making design decisions for too long. If you wait too long, someone will write code that implicitly makes the decision for us. Unfortunately, that spot decision may not take into account all that we know about the system. If the developer in question makes a local decision that forces a global design decision we have waited too long.

The people that are making the major design decisions need to be close enough to the actual development to be aware of when this sort of issue is likely to occur.

Ideally, all of the developers should be aware of the design decisions that we know are coming. When a developer stumbles into one of these spots where an actual decision must be made, they could talk to the senior people making the decisions or bring the team together to decide.

Conclusion

The process of Just In Time Design Decisions consists of a few parts:

  • Do design before you actually write code.
  • Put off any design decisions until you absolutely must make them.
  • Keep the whole team aware of the goals and data about the system.
  • Get the right people together to make design decisions when you must.

When this works well, the results speak for themselves.

Posted by GWade at January 15, 2015 08:16 AM. Email comments