Flexibility and Complexity

A Conversation with Martin Fowler, Part IV

by Bill Venners
November 25, 2002

Summary
Martin Fowler, chief scientist at Thoughtworks, Inc. and author of numerous books on software design and process, talks with Bill Venners about how to combat design decay, the cost of flexibility and reusability, four criteria for a simple system, and test-first design of interfaces.

Over the last decade, Martin Fowler pioneered many software development techniques in the development of business information systems. He's well known for his work on object-oriented analysis and design, software patterns, Unified Modeling Language, agile software processes (particularly extreme programming), and refactoring. He is the author of Analysis Patterns (Oct. 1996), Refactoring (June 1999; coauthored with Kent Beck, et al.), UML Distilled (Aug. 1999; with Kendall Scott), Planning Extreme Programming (Oct. 2000; with Kent Beck), and the soon to be released Patterns of Enterprise Application Architecture (Nov. 2002), all published by Addison Wesley.

In this six-part interview, which is being published in weekly installments, Fowler gives his views on many topics, including refactoring, design, testing, and extreme programming. In Part I, Fowler makes the business case for refactoring and testing, and describes the interplay between refactoring, design, and reliability. In Part II, Fowler discusses design principles of avoiding duplication, separating presentation and domain logic, being explicit, and describes how refactoring depends on code ownership. In Part III, Fowler differentiates between planned and evolutionary design, suggests that focusing on superficial problems can lead to the discovery of substantial problems, and claims that doing a good job won't slow you down. In this fourth installment, Fowler discusses design decay, flexibility and reusability versus complexity, four criteria for a simple system, and interface design.

Design Decay and Refactoring

Bill Venners: Why do designs decay over time?

Martin Fowler: If you have a notion of planned design, that the design is something that's right at the beginning, then it's kind of inevitable that the design will decay. So many things in life do decay. The point is that you need to know how to keep a design from decaying. That's what refactoring is about, techniques to reverse the decaying process. Refactoring is relatively new technique. We're still not used to what it gives us. But one thing it gives us is you can use refactoring to stop the decaying of designs. In fact, you can reverse the process and actually make designs improve over time.

Flexibility and Complexity

Bill Venners: In Refactoring you write, "Before I used refactoring I always looked for flexible solutions. Because design changes were expensive, I would look to build a design that would stand up to changes I could forsee. The problem with building a flexible design is that flexibility costs." What is the cost and what is the alternative?

Martin Fowler: The cost of flexibility is complexity. Every time you put extra stuff into your code to make it more flexible, you are usually adding more complexity. If your guess about the flexibility needs of your software is correct, then you are ahead of the game. You've gained. But if you get it wrong, you've only added complexity that makes it more difficult to change your software. You're obviously not getting the payback.

It's not hard to guess wrong about flexibility needs. You can guess wrong if requirements change. What you think is a requirement for flexibility now may go away or change in the future. You can also guess wrong if you put extra code into the program to improve flexibility but you don't get it quite right. You get more complexity without getting the flexibility you were after.

The alternative is to use the XP approach and not put the flexibility in at all. XP says, since most of the time we get it wrong, just don't put the flexibility in there. Now if you can't evolve your design safely, then that is a foolish route to take. But if you can evolve your design safely, it becomes quite a nice approach. In fact it becomes a self-reinforcing approach. If you strive to keep your design as simple as possible by avoiding speculative flexibility, then it's easier to change the code because you have less complication to deal with. The code is easier to understand and easier to change. As a result, you can make changes much more quickly.

Flexible versus Reusable

Bill Venners: What about reuse? Is flexible just another word for reusable?

Martin Fowler: No, but the problem is that in order to get code that's reusable you need to make it very flexible. And a lot of the time your reuse benefit doesn't pay off, either because you end up never needing to reuse it, or because the anticipated modes of reuse weren't what you thought they were. Often the flexibility you put in isn't the flexibility you ultimately need.

Bill Venners: Are there times when it makes sense to make something more reusable? How would I decide?

Martin Fowler: My attitude with reuse is that reuse is something you evolve. You build an application to solve the problems of the application. If you build another similar application, then you begin to factor out some common pieces. If you build a third similar application, you factor out more common pieces. Then you'll begin to have something like a reusable framework. My definite recommendation is don't attempt to define a reusable framework first and then build applications on top of it. Rather, evolve the framework while building the applications.

Up-Front Design versus Refactoring

Bill Venners: How would you describe the balance between up front design and refactoring?

Martin Fowler: Before I really came across refactoring, particularly in conjunction with automated testing, I tended to look at design as something I have to get right at the beginning. Now, I look at design as something I can often do a fairly small amount of up front. I let most of the design flow from the evolutionary process. So I feel that there's been a shift in balance. Before, I might have preferred—and these percentages are purely illustrative—80% of my design in planned mode and 20% of it as the project went on. Now I'd perhaps reverse those percentages.

Bill Venners: Much more evolutionary than up-front now.

Martin Fowler: Much more evolutionary design. Much less up-front.

Criteria for a Simple System

Bill Venners: In Refactoring, you quote Kent Beck's four criteria for a simple system: 1) Runs all the tests. 2) Reveals all the intention. 3) No duplication. 4) Fewest number of classes or methods. What is simplicity to you?

Martin Fowler: I think it is difficult to come up with a definition of simplicity. I quite like Kent's four rules. The first one reminds us that we have to run all the tests.

Bill Venners: But what does that have to do with simplicity? I could have something very complicated that runs all its tests.

Martin Fowler: Yes, but to have a well designed system it's got to work. If you remove the constraint that my system actually got to work...

Bill Venners: Oh, you're saying running the tests is necessary but not sufficient.

Martin Fowler: Exactly. Once the tests run you ask yourself, did you remove all the duplication? The third criteria, reveals all the intention, is the really hard part, because it is very subjective. You should be able to read the code and see what it does. The design intent of the code should just be apparent as you look at the code. A simple example is a well-named method. Rather than naming a method x74-3, and then providing a comment that says what the method does, why don't you just say what the method does in the name? That's more intention revealing. Ask yourself, does the structure of your code, the way the code is named, etc., really reveal the intention of your code?

Once all of that is out of the way, you obviously don't want more lines of code than you need. Only at the end do you minimize the number of classes and methods—only once all the other criteria are true. It is more debatable which order to apply the second and third criteria, reveals all the intention and has no duplication. But running the tests has to be the number one thing, and the minimum amount of code criteria should be the last thing.

Designing Interfaces

Bill Venners: The way I think about design, I tend to think a lot in terms of interfaces. The literature on patterns and agile methods, Design Patterns (the Gang of Four book), Kent Beck's Extreme Programming Explained, your Refactoring book, talk a lot about code, which is both interfaces and implementations. What is the design role of thinking in terms of interfaces?

Martin Fowler: I think thinking in terms of interfaces is very fundamental. My take on the Gang of Four book is that it said more about the role of interfaces than almost any other book on object-oriented design.

Bill Venners: How's that?

Martin Fowler: Because every other book on object-oriented design might say somewhere in the book, "Oh yeah, interfaces are important." But I think the Gang of Four book put a very strong piece in the early chapters about what it means to program to an interface. And then almost every pattern in that book is about how interfaces can vary independently to implementations and the benefits of programming to an interface.

I think that's also true of extreme programming. The whole value of test-first design (test-driven development as Kent is calling it), in fact the primary driving reason of it, is because when you are writing the tests first you are thinking about the interface. Writing a test is designing the interface. When you write the test first, then implement the code, you are figuring out the interface first, then implementing the interface. First figure out the interface, then implement it. And then you have a whole bunch of automated tests that describe how the interface works.

Bill Venners: I hadn't gotten that from my reading of the literature. The way I kind of approach it is, I design the interface first, then sometimes I write the test first, sometimes write the test second, sometimes don't write the test.

Martin Fowler: Not a problem.

Bill Venners: If writing the test first kind of correlates to thinking about designing the interface, then it is kind of the same thing.

Martin Fowler: Oh yeah. But I think writing the test first speaks a lot more to many developers. It is hard to think about interfaces, but when you sit there and you say, I've got to come up with a test that's going to make this tiny little piece of functionality work. It will have you thinking, what's the nicest way to write this test? And you're thinking about the interface. It is not stated explicitly, but that's what you're doing. You're thinking about the interface. You're also doing it incrementally. You're not saying, here I've got to do this class, let's come up with the interface of this entire class and then implement it. You're saying, this class needs to have a very small piece of responsibility. Write the test for it. Come up with the interface for that as you're writing the test.

Resources

Refactoring: Improving the Design of Existing Code, by Martin Fowler with Kent Beck, John Brant, William Opdyke, and Don Roberts is at Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/0201485672/

To Be Explicit, an article by Martin Fowler first published in IEEE Software:
http://www.martinfowler.com/articles/explicit.pdf

Public versus Published Interfaces, an article by Martin Fowler first published in IEEE Software:
http://www.martinfowler.com/articles/published.pdf

The Pragmatic Programmer: From Journeyman to Master, by Andrew Hunt and David Thomas, is at Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/020161622X/

IntelliJ IDEA, a Java IDE with refactoring support:
http://www.intellij.com/idea/

Eclipse, an open source IDE with refactoring support:
http://www.eclipse.org/

A catalog of summaries of refactorings mentioned in the book, Refactoring:
http://www.refactoring.com/catalog/index.html

A refactoring portal maintained by Martin Fowler contains links to refactoring tools and other refactoring sites:
http://www.refactoring.com/

Martin Fowler's links to extreme programming resources:
http://martinfowler.com/links.html

Articles written by Martin Fowler about XP and agile methods:
http://martinfowler.com/articles.html#agile

Patterns of Enterprise Application Architecture, by Martin Fowler is at Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/0321127420/

UML Distilled: A Brief Guide to the Standard Object Modeling Language, by Martin Fowler and Kendall Scott is at Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/020165783X/

Planning Extreme Programming, by Kent Beck and Martin Fowler is at Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/0201710919/

Analysis Patterns: Reusable Object Models , by Martin Fowler is at Amazon.com at:
http://www.amazon.com/exec/obidos/ASIN/0201895420/

Martin Fowler's website contains many articles, book chapters, and other information from Martin:
http://www.martinfowler.com/

Talk back!

Have an opinion? Readers have already posted 18 comments about this article. Why not add yours?

About the author

Bill Venners is president of Artima Software, Inc. and editor-in-chief of Artima.com. He is author of the book, Inside the Java Virtual Machine, a programmer-oriented survey of the Java platform's architecture and internals. His popular columns in JavaWorld magazine covered Java internals, object-oriented design, and Jini. Bill has been active in the Jini Community since its inception. He led the Jini Community's ServiceUI project that produced the ServiceUI API. The ServiceUI became the de facto standard way to associate user interfaces to Jini services, and was the first Jini community standard approved via the Jini Decision Process. Bill also serves as an elected member of the Jini Community's initial Technical Oversight Committee (TOC), and in this role helped to define the governance process for the community. He currently devotes most of his energy to building Artima.com into an ever more useful resource for developers.