A.1. Guidelines The following subsections list the guidelines that are introduced in this book. Some guidelines are repeated in multiple chapters, as they can be applied in multiple contexts. A.1.1. Big Picture
Don't Reinvent the Wheel
-
Look for existing solutions to problems before creating new solutions (Chapter 2).
Think About the Big Picture
-
Decisions within a system should be congruent with the big picture (Chapter 3).
Document Your Assumptions and Your Decisions
-
Keep a journal for retrospectives (Chapter 3).
Don't Repeat Yourself (DRY)
-
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system (Chapter 3).
Plan Globally, Develop Locally
-
Incremental implementations should fit into a global plan (Chapter 4).
A.1.2. Extreme Abstraction
Splitters Can Be Lumped More Easily Than Lumpers Can Be Split
-
It is easier to combine two concepts than it is to separate them (Chapter 2).
Clump Data So That There Is Less to Think About
-
Clumping data cuts down on the number of concepts that have to be kept in mind (Chapter 2).
When You're Abstract, Be Abstract All the Way
-
Do not describe data items using primitive data types (Chapter 2).
Strings Are More Than Just a String
-
Treat String as a primitive data type. Describe attributes with abstract data types, instead of as Strings (Chapter 2).
Never Let a Constant Slip into Code
-
Use a symbolic name for all values (Chapter 2).
To Text or Not to Text
-
Use text between programs, not within programs (Chapter 5).
If It Has Collection Operations, Make It a Collection
-
Collections separate object usage from object storage and hide implementation of aggregate operations (Chapter 5).
Don't Change What It Is
-
Create new terms rather than trying to apply new meanings to current terms (Chapter 12)
A.1.3. Extreme Separation
Adapt a Prefactoring Attitude
-
Eliminate duplication before it occurs (Chapter 3).
Don't Overclassify
-
Separate concepts into different classes based on behavior, not on data (Chapter 5).
Place Methods in Classes Based on What They Need
-
If a method does not require instance data, it should not be a member of the class. Conversely, if all the method requires is the instance data, it should be a member of the class (Chapter 6).
Honor the Class Maxims
-
Make loosely coupled cohesive classes (Chapter 6).
Do a Little Job Well and You May Be Called Upon Often
-
Methods and classes that perform specific jobs can be reused more often (Chapter 6).
Separate Policy from Implementation
-
Keeping the what separated from the how makes the what more readable and maintainable (Chapter 6).
Separate Concerns to Make Smaller Concerns
-
Split responsibilities among multiple methods and multiple classes to simplify each method and class (Chapter 7).
Test or Production; That Is the Question
-
Place all test-only methods in a test interface (Chapter 8).
Build Flexibility for Testing
-
Plan for flexibility in your design to allow for ease of testing (Chapter 8).
Decouple with Associations
-
Association classes decouple the two classes being associated (Chapter 9).
Split Interfaces
-
Split a single interface into multiple interfaces if multiple clients use different portions of the interface (Chapter 10).
Do a Little and Pass the Buck
-
Add proxies to interfaces to add functionality (Chapter 11).
Business Rules Are a Business unto Themselves
-
Keep business rules separate from other logic (Chapter 13).
A.1.4. Extreme Readability
A Rose by Any Other Name Is Not a Rose
-
Create a clearly defined name for each concept in a system (Chapter 2).
Prototypes Are Worth a Thousand Words
-
A picture of an interface, such as a screen, can be more powerful than just a description (Chapter 2).
Communicate with Your Code
-
Your code should communicate its purpose and intent (Chapter 3).
Explicitness Beats Implicitness
-
Being explicit reduces misinterpretation (Chapter 3).
Declaration over Execution
-
Declarative-style programming can provide flexibility without code changes (Chapter 5).
Use the Same Layout to Get the Same Layout
-
Use templates or scripts for classes and methods to create consistent logic (Chapter 10).
The Easiest Code to Debug Is That Which Is Not Written
-
Never write functionality that already exists in usable form (Chapter 11).
Use the Client's Language
-
Use the client's language in your code to make it easier to compare the logic in the code to the logic of the client (Chapter 13).
A.1.5. Interfaces
Create Interface Contracts
-
Design with well-defined interfaces and enforce the contracts for those interfaces (Chapter 3).
Validate, Validate, Validate
-
At each interface, validate that the input matches the contract (Chapter 3).
Test the Interface, Not the Implementation
-
Use the contract of the interface to develop the functional tests, not the implementation behind it (Chapter 10).
Adopt and Adapt
-
Create the interface you desire and adapt the implementation to it (Chapter 11).
Don't Let the Cold Air In
-
With interfaces exposed to the outside world, ensure that input validation and logging occurs (Chapter 14).
A.1.6. Error Handling
Decide on a Strategy to Deal with Deviations and Errors
-
Determine for your system what are deviations and what are errors, and how to deal with both (Chapter 3).
Report Meaningful User Messages
-
Error messages should be reported in the context of what the user can do about the error, instead of in terms of what the underlying error is (Chapter 3).
Never Be Silent
-
If a method encounters an error, it should report it, not remain silent (Chapter 6).
Consider Failure an Expectation, Not an Exception
-
Plan how operations should respond to failures (Chapter 13).
A.1.7. General Issues
Don't Speed Until You Know Where You Are Going
-
Make the system right, before you make it fast (Chapter 3).
The Spreadsheet Conundrum
-
Recognize when you are making the row/column decision (Chapter 3).
Consistency Is Simplicity
-
A consistent approach to style and solutions can make code easier to maintain (Chapter 3).
If It Can't Be Tested, Don't Require It
-
Every functionality requirement, whether formally or informally stated, should have a test created for it. If you cannot test a requirement, there is no way to determine whether you have met it (Chapter 4).
Plan for Testing
-
Developing test strategies in advance can lead to a better design (Chapter 4).
Figure Out How to Migrate Before You Migrate
-
Considering the migration path might help you discover additional considerations in other areas of the design (Chapter 7).
Know Who It Is
-
Determine uniqueness criteria for objects that should be unique (Chapter 7).
Perform a Retrospective After Each Release
-
Examining your design and how you created it can help in the next release (Chapter 8).
Nothing Is Perfect
-
There is usually a better solution, but you can stop with good enough (Chapter 8).
See What Condition Your Condition Is In
-
Use state-based analysis to examine object behavior (Chapter 9).
Get Something Working
-
Create something basic before adding refinements (Chapter 10).
Plan Your Logging Strategy
-
Determine where and how you are going to log (Chapter 11).
More Is Sometimes Less
-
Use a prewritten module with more features than you currently need and adapt it to your current needs (Chapter 11).
Be Ready to Import and Export
-
Data should be available for use outside the system via a well-defined data interface (Chapter 12).
Avoid Premature Generalization
-
Solve the specific problem before making the solution general (Chapter 14).
A.1.8. Security
If You Forget Security, You're Not Secure
-
Security should not be an afterthought. Consider it during all phases of development (Chapter 4).
Consider Privacy
-
Systems need to be designed with privacy in mind (Chapter 13).
A.1.9. General Objects
Avoid Premature Inheritance
-
Inheritance needs time to evolve (Chapter 5).
Think Interfaces, Not Inheritance
-
Interfaces provide more fluidity in the relationships between classes (Chapter 6).
Overloading Functions Can Become Overloading
-
By using unique names, functions can be more self-describing (Chapter 6).
When in Doubt, Indirect
-
Indirection, using either methods or data, adds flexibility (Chapter 11).
|