Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Demystifying Extreme Programming: Just-in-time design

Why do today what you can put off till tomorrow?

Roy Miller, Software Developer, RoleModel Software, Inc.
Roy W. Miller has been a software developer and technology consultant for almost ten years, first with Andersen Consulting (now Accenture) and currently with RoleModel Software, Inc. in North Carolina. He has used heavyweight methods and agile ones, including XP. He co-authored a book in the Addison-Wesley XP Series (Extreme Programming Applied: Playing to Win) and is currently writing a book about complexity, emergence, and software development (the working title is Growing Software: Debunking the Myth of Prediction and Control). Contact Roy at rmiller@rolemodelsoft.com. or roy@roywmiller.com.. You can also visit his personal Web site at www.roywmiller.com.

Summary:  People who aren't familiar with XP are bothered by the concept of just-in-time (JIT) design -- designing and implementing what you know you need right now and not worrying about future design issues until absolutely necessary. While this approach might seem unwise or even reckless, XP advocate Roy Miller wraps up his series by showing you how safe and easy JIT design is -- and how it just might revolutionize the way you write code.

View more content in this series

Date:  01 Jul 2003
Level:  Intermediate

Comments:  

In Extreme Programming Explained (see Resources), Kent Beck described a "simple" design as one that:

  • Passes all the tests
  • Communicates developer intent clearly
  • Contains no duplicate code
  • Has the minimum number of classes and methods necessary to accomplish the first three

That definition is good, but it also makes some assumptions. Most importantly, it assumes you have programmer tests -- and that they all pass all the time. XP demands that you write tests before you write code, so a simple design is one that grows over time in a test-first manner. This approach implies that the design doesn't emerge fully formed from a design phase, which in turn begs the question: if you're designing as you go, where do you start? That question resurfaces at multiple points throughout the project -- every time you need to make a design decision.

The answer is that you design just what you need to complete the customer stories for the current iteration -- not a bit more. That goes for business logic and infrastructure, too. If a user needs to create employees in the system for this iteration, then build the business objects and the infrastructure you need to support adding employees. Don't add the capability to remove an employee yet. Don't even think about that piece of the design for now. Remember the YAGNI (You Aren't Gonna Need It) principle: don't build in features, or "hooks," that you don't know you need yet.

Resisting the urge to be stupid

In all the years I've been in IT and using XP, I can't think of a single case outside of a committed XP team where I could say, "Ignore that part of the design for now," and escape unharmed. It seems like a radical idea -- like you're ignoring a problem and hoping it will go away. In a way, that's sort of true. But it's not as bad as you might think, as I'll discuss shortly.

I worked on a system recently that required "integrated user help." Look carefully at the requirement: Users need to get help within the application. Does it matter what form that help takes? Not right now. Pop open a window with static help text in it and you're done. We could assume that context-sensitive help is a requirement, but that's much harder to implement. We also don't know we need it yet. That's the key. Don't design (and work on) features that you don't know you need yet. As it turned out, we didn't need context-sensitive help. Users of the system were technically savvy. They just needed a ready reference. A PDF was perfectly acceptable, and cost much less to build in.

But saying you should design for today doesn't mean you should be foolish. There are plenty of cases where you have to think a bit beyond today in order to keep from shooting yourself in the foot. This is where layering can help, and where it's wise to think ahead. For example, imagine you're building a system that's data intensive. You'll have to hit a particular database quite a bit. You've done this many times before in your career, but don't assume the answer you came up with last time is exactly the right answer this time. Apply the principles you know, but leave room for learning. In essence, I'm suggesting that you apply patterns (such as Gang of Four, among others) without getting stuck.

In the case of persistence, for instance, you probably should create a "persistence layer" in your application. That's just good encapsulation and smart layering. But don't try to create a generic, all-purpose persistence layer, since at this point you're not sure you need it. Instead, build the simplest persistence layer that could possibly work at this point. Maybe have a class that hides the raw details of your persistence mechanism, but for now uses SQL strings underneath it. That will probably change, but it's a good start. You aren't being stupid, but you aren't assuming too much either -- a difficult but necessary balance.


From story cards to code

Let's use a simple example to illustrate deferring decisions until you need to make them. As we did last month, we'll create a basic banking system for "Roy Miller's Savings and Loan" (deposits are now being accepted). Suppose we have the following story cards, prioritized in this order:

  1. Check the account balance.
  2. Deposit funds.
  3. Withdraw funds.
  4. Transfer funds to another account.

You and your partner start working on the first story, "Check the account balance." According to the story, you need an Account class, and you need to be able to ask it for its balance. That's all. You might feel compelled to ask what the user interface needs to look like, but there aren't any cards for that so don't even think about it. You can add it later. Since you should be writing tests first, you should have a failing test that tells you what the Account class needs to look like. Your class should look similar to Listing 1:


Listing 1. Account class
package com.sample;

public class Account {
	protected int balance;

	public int balance() {
		return balance;
	}

}

You now have all you need to say that the first card -- Check the account balance -- is done. While you know that eventually you'll need to be able to deposit funds, you can add that capability when you work on the "Deposit funds" card. Resist the urge to do that too soon. In many ways, JIT design is a matter of disciplining yourself to keep from taking steps that are too big.

According to the next card, you need to deposit funds. No problem. Write the test, see the code fail, then get it to pass. Your code should look something like Listing 2:


Listing 2. Account with deposit capability
package com.sample;

public class Account {
	protected int balance;
	
	public int balance() {
		return balance;
	}
	
	public void deposit(int amount) {
		balance += amount;
	}

}

You're now done with the second card. We still can't withdraw anything, but so what? That's another card, which you're now free to tackle. Write a test that the code in Listing 3 will pass.


Listing 3. Account with withdraw capability
package com.sample;

public class Account {
	protected int balance;
	
	public int balance() {
		return balance;
	}
	
	public void deposit(int amount) {
		balance += amount;
	}
	
	public void withdraw(int amount) {
		balance -= amount;
	}

}

You're done again. You can now move on to what is potentially the most dangerous card in the stack so far: the "Transfer funds to another account" card. This is the most dangerous card for two reasons. First, it's the last card, so we can't see what's coming up. Not knowing increases the temptation to build in some "extras" that we don't know we need yet. Second, the feature itself can quickly get fancier than necessary. This is where it pays to be disciplined. We have to resist the urge to create too much, no matter how much we want to.

The first thing to do is write a test for the simplest possible transfer behavior, such as the code in Listing 4:


Listing 4. JUnit test for transferring funds
package com.sample;

import junit.framework.TestCase;

public class TC_Account extends TestCase {

	public TC_Account(String name) {
		super(name);
	}

	public void testTransferFunds() {
		Account accountOne = new Account();
		accountOne.balance = 1;
		Account accountTwo = new Account();
		accountTwo.balance = 1;

		accountOne.transferFundsTo(1, accountTwo);			

		assertEquals(0, accountOne.balance());
		assertEquals(2, accountTwo.balance());
	}
}

Getting the test to pass should be simple and will help you to resist getting too fancy. You should write a transferFundsTo() method so that Account looks similar to Listing 5:


Listing 5. Account with transfer capability
package com.sample;

public class Account {
	protected int balance;
	
	public int balance() {
		return balance;
	}
	
	public void deposit(int amount) {
		balance += amount;
	}
	
	public void withdraw(int amount) {
		balance -= amount;
	}

	public void transferFundsTo(int amount, Account account) {
		withdraw(amount);
		account.deposit(amount);
	}

}

Notice what our code has so far: first, our Account class isn't a bean (it essentially has a getter -- but no setter -- for its one data member). Based on the cards we've got right now, however, it doesn't need to be. Second, what happens when somebody tries to transfer funds from one account to another, but the source account doesn't have a large enough balance? Currently, the balance will just go negative. Of course we'll need to address this issue, but not yet. Third, we don't validate the incoming amounts for deposit(), withdraw(), or transferFundsTo(). It's not hard to handle that situation, and adding the code won't take long, but we'll resist the urge to do more than we have to for right now. Finally, we don't have a user interface, and we can't save any data yet. We can't have a "real" system without them, but we'll create them when we need them, not before.


The power of being myopic

When you try to design to an extremely low level of detail before you start writing code you plan to keep, you're assuming you can know what the end result should look like. That's a dangerous assumption. If things change while you're in the middle of coding, your design becomes invalid. There are three ways you can handle this likely situation: you can deny it will happen and just rigorously adhere to your design. The result, however, is that users get the system they thought they wanted when the project started, not the system they end up wanting when the project's done.

Another common approach is to do the up-front design anyway, then do a comprehensive redesign when change happens. However, this approach disrupts the project's rhythm and just repeats the problem at multiple points during the project (big design up front, big redesign two months later, and so on).

The wisest choice is to be intentionally shortsighted. Remember, though, being intentionally short-sighted is not the same as being stupid, irresponsible, or unprofessional.

If you approach design with a JIT mentality -- writing tests for the current iteration's cards, then making those tests pass -- you can avoid over-designing and having to redesign. Instead, defer design decisions you don't have to make. When you defer design decisions, you're reserving your option to change. This approach leads to better systems.


Resources

About the author

Roy W. Miller has been a software developer and technology consultant for almost ten years, first with Andersen Consulting (now Accenture) and currently with RoleModel Software, Inc. in North Carolina. He has used heavyweight methods and agile ones, including XP. He co-authored a book in the Addison-Wesley XP Series (Extreme Programming Applied: Playing to Win) and is currently writing a book about complexity, emergence, and software development (the working title is Growing Software: Debunking the Myth of Prediction and Control). Contact Roy at rmiller@rolemodelsoft.com. or roy@roywmiller.com.. You can also visit his personal Web site at www.roywmiller.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10835
ArticleTitle=Demystifying Extreme Programming: Just-in-time design
publish-date=07012003
author1-email=rmiller@rolemodelsoft.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).