< Day Day Up > |
2.2 Process and SimplicityKent Beck, the father of XP, says "Pick the simplest thing that will work." Building the simplest house or making the simplest of car repairs is difficult without the right tools and process. Building great software is no different. If you want to build simple software, you've got to strip all the extraneous junk out of your process that clutters your mind, your motivations, and your code. As you've seen in Chapter 1, I don't think that most development shops are moving in the right direction. The same forces that bloat frameworks, languages, and tools can also convolute the everyday development process:
Effective development processes do none of these things. The best development processes add just enough rigor to get the job done. They let you work primarily on the artifacts that you will deliver directly to your customer, and minimize the work spent on other documents that live to support the process. But few methods work out of the box. To make a development method effective, tailor it to your needs. Teams vary in size, skill, preference, and prejudice. If you don't like class diagrams or object interaction diagrams, don't use them. If pair programming feels like overkill, don't do it. If you can't deal with an on-site customer, use some other way to introduce an effective surrogate. If a particular diagram is not clear or useful, don't create it. As James Duncan Davidson, the author of Tomcat and Ant, once told me, "If it feels good, do it. If it doesn't, quit." 2.2.1 The Best of AgileProgramming methods like XP and SCRUM advocate simplicity, and make it easier to achieve. Many of the authors of these methods are part of the Agile Alliance, which defines Agile software development principles. These ideas are rapidly shaping the way modern teams build software. The methods run contrary to many of the other methods that you may use. These rules in particular cut against the grain:
Agile methods make it much easier to develop simple code. They can help you to minimize your development process to the bare essentials that you'll need to get the job done. Even if you don't fully embrace all Agile ideas, you can make tremendous gains by embracing some of the Agile principles:
These principles stand alone, and work well with just about any development process. When you use them together, you multiply their benefit. All of the principles build upon simplicity, a core value, but simplicity is difficult to maintain through successive iterations without refactoring. Automated unit tests and continuous integration build in a safety net to protect the code base from errors injected through refactoring. JUnit is rapidly becoming one of the most critical Java tools in my toolbox and the toolboxes of the best developers that I know. Other ideas can help you to tailor your process, too. You can remove some requirement documents such as rigid functional specifications and heavy-duty use cases, and replace them with better customer contact and simple stories. You can work from source code, and relegate heavy-duty diagrams to the whiteboard. Seek regular informal communication, whenever and wherever you need it. Eschew all wasteful meetings. Abhor complexity, in any form. These ideas are independent of any methodology. They represent a philosophy, from the inside out, based on simplicity. 2.2.2 Pick Your BattlesA couple of years ago, I had a mental breakthrough: I was coding scared. I was afraid of trying simple solutions because I feared that they would not be rich enough. I didn't want to ever discard code; often, I'd invested too much of myself in it. I was afraid to change anything because I might break something else. I wasn't always that way. As the frameworks that I used and the algorithms that I used became more complex, I became more fearful. Fearful programming is an easy habit to make, and also an easy one to break. All you've got to do is embrace the simple solution instead of cracking open that jar of scorpions that you've been dreading. If you feel trapped, you'll code scared. The secret is leaving yourself an escape hatch. The bottom line is this: you can't embrace simplicity without also embracing refactoring. Don't be afraid of serious changes, or even throwing away code. You'll likely find that you fear the wrong things. Because you've saved time with simple solutions along the way, you'll have more time to deal with your toughest problems when you need it most. Think of your programming as the simple decision chart in Figure 2-2. Your goal is to keep as much code as simple as possible for as long as possible. The left-hand side of the chart represents simplicity. The right side is your escape hatch. You can use the escape hatch to inject as much complexity as you require. You'll find that you won't need your escape hatch nearly as much as you thought. Figure 2-2. Your goal is to keep as many decisions as possible to the left of the diagramThe chart says to try something simple. How simple? Use your judgment. You don't want to waste time with solutions that you know will break; neither do you want to guess which things will break, or are likely to break. It's an important distinction that most programmers do not observe, especially as they become more experienced. The bottom line is this: when you guess wrong, and you guess simple, it's cheap. When you guess wrong, and you guess complex, it's very expensive. You can apply this type of thinking in many places. 2.2.2.1 AlgorithmsWhen you hear about simplicity, it's usually in the context of algorithms. I'm not saying that you should always reach for that bubble sort, but I am saying that you should leave all of the tiny, ugly optimizations out until you measure the need for change. Take the example of object allocation. Which code is easier to read, this one: String middle = "very, "; String prefix "This code is "; String suffix = "ugly." String result = ""; StringBuffer buffer = new StringBuffer( ); buffer.append(prefix); for (int i= 0; i<5; i++) { buffer.append(middle); } buffer.append(suffix); result = buffer.toString( ); or this one: String result = "This code is "; for (int i= 0; i<5; i++) { result = result + "much, "; } result = result + "simpler, and neater."; If you've ever read an earlier Java book with performance tips, you were probably warned that the first example is better code. In fact, some applications had real problems with object allocation. As a result, you can still see huge blobs of code like the first one all over the place. But remember what I said about developer intuition? It stinks, and things change. Now, compilers can heavily optimize object allocation. But let's give it the benefit of the doubt, and say that you are working on an older compiler. And let's further assume that the loop is a little longer. Would you really notice the difference? Unless you were doing nothing but processing huge numbers of strings, you would never see the difference. And you'd be forced to maintain a bigger blob of uglier code until the end of time. Trade a little less performance for better readability every time. Your correct guesses will save you more than enough time to refactor the wrong ones. 2.2.2.2 ArchitectureMost of the applications that you build with Java are distributed, and it's easy to distribute more broadly than you need. Distribution can add flexibility, scalability, and availability. Distribution also forces some decisions and architectures that make your code much more difficult to write and understand. When in doubt, guess simple. I'm not suggesting that you hardwire your application so that distribution is impossible. I'm merely making the point that distance will cost you. Keep in mind that the vendors that build generic J2EE architectures sell either hardware, software, or both. The network may be the computer, but it's an expensive, unreliable computer. Use it when you must, but lean on it only when it's necessary. 2.2.2.3 PerformanceMost of the developers that I know try to optimize as they go. The best of them are wrong more than half of the time. You probably can't predict exactly which piece of code will cause bottlenecks in your system. Don't try. When you do, you introduce (probably useless) complexity into your application, reducing your ability to maintain and adapt your code over time. Instead, code simple solutions and save your time for measuring and repairing the bottlenecks as they occur. Let your tools, like a good profiler, do the heavy lifting. 2.2.2.4 Design patternsThere's an inside joke among many Java consultants. You can often tell which books inexperienced developers are reading by reading their code. Sometimes, it's the reader's fault. When you read about a technique, you're anxious to try it out. But don't just start coloring on the walls. Use a coloring book first—like a sample application. Sometimes, the problem lies with authors, who often oversell ideas or solutions. Other times, the problem lies with frameworks. If you want to know what I mean, pick up a book that deals with EJB design patterns. Now, count the number of design patterns that do nothing more than work around EJB features that stink. Or look to the seminal Gang of Four patterns; they are workarounds for problems with C++. For this reason alone, many influential consultants abhor design patterns. I'm not in that camp. But let the need for a design pattern emerge before you work it into an application. In other words, wait until you have a problem before you look for a solution. |
< Day Day Up > |