Pragmatic Programmer, The: From Journeyman to ... - VirtualPanic!

5 downloads 142 Views 2MB Size Report
a retrieval system, or transmitted, in any form or by any means, electronic, ..... One of the cornerstones of the pragma
I l@ve RuBoard

Front Matter Table of Contents About the Author

Pragmatic Programmer, The: From Journeyman to Master Andrew Hunt David Thomas Publisher: Addison Wesley First Edition October 13, 1999 ISBN: 0-201-61622-X, 352 pages

Straight from the programming trenches, The Pragmatic Programmer cuts through the increasing specialization and technicalities of modern software development to examine the core process--taking a requirement and producing working, maintainable code that delights its users. It covers topics ranging from personal responsibility and career development to architectural techniques for keeping your code flexible and easy to adapt and reuse. Read this book, and you’ll learn how to: Fight software rot; Avoid the trap of duplicating knowledge; Write flexible, dynamic, and adaptable code; Avoid programming by coincidence; Bullet-proof your code with contracts, assertions, and exceptions;

Capture real requirements; Test ruthlessly and effectively; Delight your users; Build teams of pragmatic programmers; and Make your developments more precise with automation. Written as a series of self-contained sections and filled with entertaining anecdotes, thoughtful examples, and interesting analogies, The Pragmatic Programmer illustrates the best practices and major pitfalls of many different aspects of software development. Whether you’re a new coder, an experienced programmer, or a manager responsible for software projects, use these lessons daily, and you’ll quickly see improvements in personal productivity, accuracy, and job satisfaction. You’ll learn skills and develop habits and attitudes that form the foundation for long-term success in your career. You’ll become a Pragmatic Programmer. I l@ve RuBoard

I l@ve RuBoard

Pragmatic Programmer, The: From Journeyman to Master Foreword Preface Who Should Read This Book? What Makes a Pragmatic Programmer? Individual Pragmatists, Large Teams It's a Continuous Process How the Book Is Organized What's in a Name? 1. A Pragmatic Philosophy The Cat Ate My Source Code Software Entropy Stone Soup and Boiled Frogs Good-Enough Software Your Knowledge Portfolio Communicate! Summary 2. A Pragmatic Approach The Evils of Duplication Orthogonality Reversibility Tracer Bullets Prototypes and Post-it Notes Domain Languages Estimating 3. The Basic Tools The Power of Plain Text

Shell Games Power Editing Source Code Control But My Team Isn't Using Source Code Control Source Code Control Products Debugging Text Manipulation Exercises Code Generators 4. Pragmatic Paranoia Design by Contract Dead Programs Tell No Lies Assertive Programming When to Use Exceptions How to Balance Resources Objects and Exceptions Balancing and Exceptions When You Can't Balance Resources Checking the Balance Exercises 5. Bend or Break Decoupling and the Law of Demeter Metaprogramming Temporal Coupling It's Just a View Blackboards 6. While You Are Coding Programming by Coincidence Algorithm Speed Refactoring Code That's Easy to Test Evil Wizards 7. Before the Project The Requirements Pit Solving Impossible Puzzles Not Until You're Ready The Specification Trap Circles and Arrows 8. Pragmatic Projects Pragmatic Teams Ubiquitous Automation

Ruthless Testing It's All Writing Great Expectations Pride and Prejudice A. Resources Professional Societies Building a Library Internet Resources Bibliography B. Answers to Exercises

I l@ve RuBoard

I l@ve RuBoard

Pragmatic Programmer, The: From Journeyman to Master Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and Addison-Wesley was aware of a trademark claim, the designations have been printed in initial capital letters or in all capitals. Lyrics from the song "The Boxer" on page 157 are Copyright © 1968 Paul Simon. Used by permission of the Publisher: Paul Simon Music. Lyrics from the song "Alice's Restaurant" on page 220 are by Arlo Guthrie, ©1966, 1967 (renewed) by Appleseed Music Inc. All Rights Reserved. Used by Permission. The authors and publisher have taken care in the preparation of this book, but make no express or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential damages in connection with or arising out of the use of the information or programs contained herein. The publisher offers discounts on this book when ordered in quantity for special sales. For more information, please contact: AWL Direct Sales Addison Wesley Longman, Inc. One Jacob Way Reading, Massachusetts 01867

(781) 944-3700 Visit AWL on the Web: http://www.awl.com/cseng

Library of Congress Catalogtng-in-Publication okay") == 0) { TEST(1 == 1); }

else if (args[0].compareTo("fail ") == 0) { TEST(1 == 2); }

else { throw new RuntimeExceptionC "Bad argument"); } } }

Exercise 21:

from When to Use Exceptions While designing a new container class, you identify the following possible error conditions: 1. No memory available for a new element in the add routine 2. Requested entry not found in the fetch routine 3. null pointer passed to the add routine

How should each be handled? Should an error be generated, should an exception be raised, or should the condition be ignored?

Answer 21:

Running out of memory is an exceptional condition, so we feel that case (1) should raise an exception.

Failure to find an entry is probably quite a normal occurrence. The application that calls our collection class may well write code that checks to see if an entry is present before adding a potential duplicate. We feel that case (2) should just return an error. Case (3) is more problematic—if the value null is significant to the application, then it may be justifiably added to the container. If, however, it makes no sense to store null values, an exception should probably be thrown.

Exercise 22:

from How to Balance Resources Some C and C++ developers make a point of setting a pointer to NULL after they deallocate the memory it references. Why is this a good idea?

Answer 22:

In most C and C++ implementations, there is no way of checking that a pointer actually points to valid memory. A common mistake is to deallocate a block of memory and reference that memory later in the program. By then, the memory pointed to may well have been reallocated to some other purpose. By setting the pointer to NULL, the programmers hope to prevent these rogue references?in most cases, dereferencing a NULL pointer will generate a runtime error .

Exercise 23:

from How to Balance Resources Some Java developers make a point of setting an object variable to NULL after they have finished using the object. Why is this a good idea?

Answer 23:

By setting the reference to NULL, you reduce the number of pointers to the referenced object by one. Once this count reaches zero, the object is eligible for garbage collection. Setting the references to NULL can be significant for long-running programs, where the programmers need to ensure that memory utilization doesn't increase over time .

Exercise 24:

from Decoupling and the Law of Demeter

We discussed the concept of physical decoupling in the box . Which of the following C++ header files is more tightly coupled to the rest of the system? person1.h:

#include "date.h"

class Personl { private: Date myBirthdate;

public: Person1(Date &birthDate); //...

Answer 24:

person2.h:

class Date; class Person2 { private: Date *myBirthdate;

public: Person2(Date &birthDate); //...

A header file is supposed to define the interface between the corresponding implementation and the rest of the world. The header file itself has no need to know about the internals of the Date class?it merely needs to tell the compiler that the constructor takes a Date as a parameter. So, unless the header file uses Dates in inline functions, the second snippet will work fine.

What's wrong with the first snippet? On a small project, nothing, except that you are unnecessarily making everything that uses a Personl class also include the header file for Date. Once this kind of usage gets common in a project, you soon find that including one header file ends up including most of the rest of the system—a serious drag on compilation times.

Exercise 25:

from Decoupling and the Law of Demeter For the example below and for those in Exercises 26 and 27, determine if the method calls shown are allowed according to the Law of Demeter. This first one is in Java.

public void showBalance(BankAccount acct) { Money amt = acct. getBalance() ; printToScreen(amt .printFormat()) ; }

Answer 25:

The variable acct is passed in as a parameter, so thegetBalance call is allowed. Calling

amt.printFormat(), however, is not. We don't "own"amt and it wasn't passed to us. We could eliminate showBalance's coupling to Money with something like this:

void showBalance(BankAccount b) { b.printBalance(); }

Exercise 26:

from Decoupling and the Law of Demeter This example is also in Java.

public class Colada { private Blender myBlender; private Vector myStuff; public Colada() { myBlender = new Blender(); myStuff = new Vector() ; }

private void doSomething() { myBlender.addlngredients(myStuff.elements()); } }

Answer 26:

Since Colada creates and owns bothmyBlender and myStuff, the calls to addIngredients and

elements are allowed .

Exercise 27:

from Decoupling and the Law of Demeter This example is in C++.

void processTransaction(BankAccount acct, int) { Person *who; Money amt; amt.setValue(123.45); acct.setBalance(amt); who = acct .getOwner() ; markWorkflow(who->name(), SET_BALANCE); }

Answer 27:

In this case, processTransaction owns amt ?it is created on the stack, acct is passed in, so both

setValue and setBalance are allowed. ButprocessTransaction does not ownwho, so the call who->name() is in violation. The Law of Demeter suggests replacing this line with

markWorkflow(acct.name(), SET_BALANCE);

The code in processTransaction should not have to know which subobject within a BankAccount holds the name—this structural knowledge should not show through BankAccount's contract. Instead, we ask the BankAccount for the name on the account. It knows where it keeps the name (maybe in a Person, in a Business, or in a polymorphic Customer object).

Exercise 28:

from Metaprogramming Which of the following things would be better represented as code within a program, and which externally as meta failcount=0 expect_okay() { if echo "$*" | $CMD #>/dev/null 2>&1

then : else echo "FAILED! $*" failcount='expr $failcount + 1'

fi } expect_fail() { if echo "$*" | $CMD >/dev/null 2>&1

then echo "FAILED! (Should have failed): $*" failcount='expr $failcount + 1'

fi }

report() { if [ $failcount -gt 0 ] then echo -e "\n\n*** FAILED $failcount TESTS\n" exit 1 # In case we are part of something larger else exit 0 # In case we are part of something larger fi } #

# Start the tests # expect_okay F123456789876543210E # Should run thru

# Fails, speed too high expect_fail1 # Fails, empty expect_fail F10E1 # Fails, empty expect_fail F1238 # Fails, skips expect_okay FE # Never turn on expect_fail F1E # Emptying while running expect_okay F10E Should be ok report # Report results expect_fail F5

The tests check to see if illegal speed changes are detected, if you try to empty the blender while running, and so on. We put this in the makefile so we can compile and run the regression test by simply typing

% make % make test

Note that we have the test exit with 0 or 1 so we can use this as part of a larger test as well. There was nothing in the requirements that spoke of driving this component via a script, or even using a language. End users will never see it. But we have a powerful tool that we can use to test our code, quickly and exhaustively.

Exercise 42:

from The Requirements Pit Which of the following are probably genuine requirements? Restate those that are not to make them more useful (if possible). 1. The response time must be less than 500 ms. 2. Dialog boxes will have a gray background. 3. The application will be organized as a number of front-end processes and a back-end server. 4. If a user enters non-numeric characters in a numeric field, the system will beep and not accept them. 5. The application code and data must fit within 256kB.

Answer 42:

1. This statement sounds like a real requirement: there may be constraints placed on the application by its environment. 2. Even though this may be a corporate standard, it isn't a requirement. It would be better stated as "The dialog background must be configurable by the end user. As shipped, the color will be gray." Even better would be the broader statement "All visual elements of the application (colors, fonts, and languages) must be configurable by the end user." 3. This statement is not a requirement, it's architecture. When faced with something like this, you have to dig deep to find out what the user is thinking. 4. The underlying requirement is probably something closer to "The system will prevent the user from making invalid entries in fields, and will warn the user when these entries are made."

5. This statement is probably a hard requirement.

I l@ve RuBoard

Suggest Documents