Where Is the Up-Front Design?

If you were building code in the 1990s, odds are good that your team expended a considerable amount of up-front effort to produce design models. You might have worked with use cases to understand the requirements and subsequently created class diagrams, state models, sequence diagrams, collaboration diagrams, component models, and so on.

Chances are that you create few of these models today. The interest in Agile has led to teams abandoning the production of detailed design models. “Agile says we don’t have to do design,” or so I’ve heard.

Just what does Agile say about design? The Agile principles (part of the Agile Manifesto; see http://agilemanifesto.org/principles.html) suggest that the software must be valuable to the customer, that it can accommodate changing requirements at any time, that it works, that it has a good design, and that it is no more complex than need be. There’s no definition for “good” and no notion of when design actually occurs.

The challenge with Agile is that you are expected to respond to change. A new feature is requested, one that you might not have ever before imagined. You must figure out how to code support for the feature into a system that wasn’t explicitly designed to accommodate it.

Suppose you spend a lot of time determining what an “entire” new system must do. You derive the perfect set of corresponding design models and then build out the system. Your team is fast (or so they think) because they’re not spending time doing TDD. Each of the analysis, design, and implementation steps take two months, meaning you ship after six months.

Any new requirement cropping up thereafter isn’t covered by your extensive up-front design. Sometimes that’s OK, but more often than not, this is where your system starts the faster path to degradation. You’re able to work in some of the new feature requests simply, but you notice that many other changes are difficult. Some changes require bad hacks, as your system’s design can’t accommodate them otherwise. Many of the new feature requests require widespread changes throughout the system. The time to analyze the system to know where the changes must go increases.

The speed of building continues to slow as the system’s dependency structure degrades. Your team slows down even further as the new changes introduce difficult-to-fix and sometimes seemingly unrelated defects. You wish you had better control over your system in the form of fast unit tests.

It’s still worthwhile to sketch an initial design, given what you know about what the system must do. But it’s not worthwhile to expend substantial effort in detailing the initial design. Concern yourself with high-level structure: what are the key classes and dependencies in the system, what are interfaces between subsystems and to external systems, and what are some of the core message flows? You can derive a good high-level, starter design in a small fraction of the two months that you might have otherwise taken.

TDD is a means of addressing design on a continual basis. Consider that you are taking all the time saved in initial detailed design efforts and spreading it out across the rest of the product’s life span. The studies (Research on TDD) show that TDD initially takes more development effort but results in higher-quality code. What the studies don’t discuss is the amount of time you save by minimizing up-front design efforts.

You should certainly invest in up-front design, but accept that your models will almost always be wrong. Once you start coding, many changes can occur: the customer changes their mind, the marketplace changes, you learn more and discover better ways to address the design, or someone realizes requirements are missing or incorrect.

An up-front design is a good starting road map. Discussions around the design help uncover key elements about what the software must do and how you might initially lay it out. But the vast amount of detail required to build out your system will change. A class diagram is a fine thing to create, for example, but don’t sweat the low-level details: private vs. public, attribute detail, aggregation vs. composition, and so on. These will come out in the test-driving. Instead, focus on class names, dependencies, and maybe a few key public behaviors.

TDD allows you to retain the simplest possible design for a model based on the current business needs. If you keep your design as clean as possible over time, you have the best chance to incorporate new, never-before-conceived features. If you instead allow your system to degrade (and exhibit lots of duplication and difficult-to-understand code), you’ll have a tough time with any new feature request that comes along.

But Where’s the Real Meaty Design Talk?

We just had it. Reread the portfolio example. Granted, it’s a simple piece of an application, but the concepts all scale up to very large systems.

“No, I mean, where’s all that stuff about coupling, cohesion, single responsibility principle and the other SOLID design principles, dependency structures, code smells, law of Demeter, patterns, encapsulation, composition vs. inheritance, and so on?” Good question. First, this isn’t a book on classic OO design concepts. This is a book on TDD, and the goal of this chapter was to demonstrate how you can incrementally deal with a continually evolving design.

Second, regarding all those classic design concepts, you should really know all of that. You should also always be seeking to learn more about design. It’s all good as long as it makes incremental change easier. If you don’t know it all now, don’t worry. The simple design concepts will get you a large portion of the way there. But keep digging.

When you’re in the refactoring step of TDD, you want to have all the knowledge you possibly can about what constitutes a good design. You’ll also want to have all the knowledge possible about what your team thinks. You’re in a shared codebase, and you need to agree as a team on what is acceptable and what is not regarding design.

Most of the time, the classic design concepts are in alignment with the notion of simple design. Design patterns, for example, are primarily about the expressiveness of a solution. Some, such as Template Method, are explicitly about eliminating duplication.

Where Do Simple Design and Classic Design Concepts Clash?

There are a few places where you should supplant classic (aka old) concepts about design with modern, incremental design ideas. The following list covers some of the common clashes between old-school design and incremental design via TDD:

  • Accessibility: You still should prefer keeping members as private as possible. It makes some changes easier (for example, safely renaming a public member function requires a lot more work than renaming a private function). Though unlikely, exposing members unnecessarily might open you up to harm from nefarious or stupid clients.

    However, if you need to relax access to allow tests to verify that things actually work as intended, you shouldn’t worry most of the time. If everything is tested, the tests will likely protect your system against stupidity. Knowing the system works is far more compelling than over-doting on a vague concern about future abuse. If you’re still worried, there are clever but safe means that should relax everyone. Just remember that clever is often a glittery cousin of stupid.

    In tests, absolutely stop sweating unnecessary design clutter such as private vs. public. No one is calling your tests. Access specifiers in tests only serve to detract from readability.

  • Timeliness: Old-school design told you that you needed to try to derive a design as close to perfect as possible. With simple design, that’s simply not true. In fact, the more you come up with a design that accommodates every last possible forthcoming feature, the more you’ll pay in the meantime, and odds are also that you’ll still have substantial rework when the feature does arrive. It’s better to learn how to continually accommodate changes via simple, incremental design.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.35.255