Here I will dive deeper into the next three chapters of part two code complete.
A bad routine has bad names, a bad layout, multiple purposes, too many parameters, poor documentation, uses global variables, and doesn't defend against bad data.
The most important reason to create a routine is to reduce complexity; using a routine doesn't require knowing its inner workings.
Introduce an intermediate, understandable abstraction Putting a section of code into a well-named routine is one of the best ways to document its purpose.
Avoid Duplicate code
- Creation of similar code in two routines implies an error in decomposition. Pull the duplicate code from both routines, put a generic version of the common code into a base class, and then move the two specialized routines into subclasses.
- Routines can encapsulate or hide the assumption about the order in which operations must be performed or routines are called.
- Putting complicated boolean tests in routines hides the details, summarizes its purpose, and emphasizes its significance.
- No block of code is too small to put into a routine, especially if it improves readability.
Design at the Routine Level
A cohesive routine contains operations that are related; otherwise, it probably does more than one thing.
Functional cohesion is the strongest and best kind of cohesion, occurring when a routine performs one and only one operation. Examples of highly cohesive routines include sin(), GetCustomerName(), EraseFile(), CalculateLoanPayment(), and AgeFrom-Birthdate().
Good Routine Names
A routine with a long, complicated name may stem from the routine doing too much; break the routine into multiple routines.
Name functions after the returned value; name procedures with a strong verb and an object to provide its context.
Don’t differentiate routine names solely by the number, To name a function, use a description of the return value and use opposites precisely.
How to Use Routine Parameters
Put parameters in input-modify-output order; if several routines use similar parameters, order the parameters consistently.
If you consistently pass too many arguments to a function, the coupling among your routines is too tight.
Pass the variables or objects that a routine needs to maintain its interface abstraction.
Protecting Your Program From Invalid Inputs
To handle "garbage-in," check values from external sources, values of method parameters, and then decide how to handle bad inputs.
Defensive programming is useful as an adjunct to the other quality-improvement techniques described in the book. The best form of defensive coding is not inserting errors in the first place.
Using the iterative design, writing pseudocode before code, writing test cases before writing the code, and having low-level design inspections are all activities that help to prevent inserting defects.
They should thus be given a higher priority than defensive programming. Fortunately, you can use defensive programming in combination with the other techniques.
Use error handling code for conditions you expect to occur; use assertions for conditions that should never occur.
Use assertions to document precondition and postconditions. Don't put executable code in one.
Error Handling Techniques
Correctness means never returning an inaccurate result; robustness means always trying to do something that allows the program to keep running.
Beware using a neutral value, substituting the next valid data, returning the last result, or substituting the closest legal value.
Exceptions weaken encapsulation by requiring the caller to know which exceptions might be thrown from the code that's called.
Barricade Your Program to Contain the Damage Caused by Errors
If public methods of a class checking and sanitizing data, then private methods can assume it is safe.
Convert data to the proper type ASAP; otherwise, you increase complexity and increase the chance that someone can crash your program.
Determining How Much Defensive Programming to Leave in Production Code
Remove code that results in hard crashes in production; but during development, this is invaluable for debugging.
Pseudocode for Pros
When writing pseudocode, avoid syntactic elements from the target programming language.
Catching errors at the "least-value stage," or when the least effort has been invested, contributes to success.
Constructing Routines by Using the PPP
- Design the Routine - Once you’ve identified a class’s routines, the first step in constructing any of the class’s more complicated routines is to design it.
- Check the prerequisites Before doing any work on the routine itself, check to see that the job of the routine is well defined and fits cleanly into the overall design.
- Define the problem the routine will solve State the problem the routine will solve in enough detail to allow the creation of the routine.
- Research the algorithms and data types If functionality isn’t available in the available libraries, it might still be described in an algorithms book. Before you launch into writing complicated code from scratch, check an algorithms book to see what’s already available.
- Write the pseudocode You might not have much in writing after you finish the preceding steps. The main purpose of the steps is to establish a mental orientation that’s useful when you actually write the routine.
Test-first development- Test-first is a popular development style in which test cases are written prior to writing any code.
Refactoring is a development approach in which you improve code through a series of semantic preserving transformations.
Design by contract is a development approach in which each
routine is considered to have preconditions and postconditions.