Code Complete ----- (Note2 Creating High-Quality Code)

Code Complete ----- Part2 Creating High-Quality Code

1. Design in Construction

===========================================================
    Design is a sloppy[无章法] process even if it produces a tidy[清爽] result.
    Design is about tradeoffs and priorites. [确定取舍和调整顺序的过程]
    Design involves restrictions.
    Design is nondeterministic.
    Design is a heuristic[启发式] process.
    ---------   Design Is Emergent[自然形成的]

===========================================================
Difficulties:
---- Essential Difficulties
---- Accidential Difficulties

At the software-architecture level, the complexity of a problem is reduced by dividing the system into subsystems.

The goal of all software-design techniques is to break a complicated problem into simple pieces. The more independent the subsystems are, the more you make it safe to focus on one bit of complexity at a time.

**** Desirable characteristics of a design****
---- Minimal complexity.
           Avod making "clever" designs which are usually hard to understand. Instead make "simple" and "easy-to-understand" designs. If your design doesn't let you safely ignore most other parts of the program when you're immersed in one specific part, the design isn't doing its job.

---- Loose coupling[松耦合]
        Hold connections among different parts of a program to minimum.

---- Ease of maintenance
---- Extensibility
---- Reusability
---- High fan-in
       ---- Have a high number of classes that use a given class.
       ---- Make good use of utility classes at the lower levels in the system.
---- Low fan-out
       class use a low-to-medium number of other classes(Less than 7)
---- Portability
---- Leanness[精简性]
        Voltaire said that a book is finished not when nothing more can be added but when nothing more can be taken away.
---- stratification[层次性]
---- Standard Techniques

Levels of Designs
---- Level1: Software System
---- Level2: Division into Subsystems or Packages
---- Level3: The subsystems are further divided into classes
---- Level4: Classes are divided into routines and data
---- Level5: The inside of each routine

common subsystems:
---- Business Rule
---- User Interface
---- Database Access
---- System dependencies

======================================================
Design Building Blocks: Heuristics
          ---- Find Real-Word Objects
          ---- Form Consistent Abstractions
          ---- Encapsulate Implementation Details
          ---- Inherit -- when inheritance simplifies the design
          ---- Information Hiding (sample: NewId(), typedef IdType int/string)
          *** Identify areas likely to change*** ---- Separate and Isolate these items
                  Common areas likely to change;
                    ---- Business Rules
                    ---- Hardware dependencies
                    ---- Input and Output
                    ---- Nonstandard language features
                   ---- Difficult design and construction areas
                    ---- Status varibles ------ Use an enumerated type instead of boolean variable
                                         ------ Use access routines rather than checking the variable directly
                    ---- Data-size constraints ----- #define MAX_COUNT 100
         ---- Look for Common Design Patterns
                      --- One potential trap with patterns is force-fitting code to use a pattern.
                      --- Another potential trap with patterns is feature-it-is[为了模式而模式](Just to try, rather than appropriate solution)
          ---- Keep Coupling loose
          ---- Aim for strong Cohesion
                --- Cohesion refers to how closely all the routines in a class or all the code in a routine support a central purpose ---- how focused the class is.
          ---- Buid Hierarchies
          ---- Formalize Class Contracts --- preconditions and postconditions
          ---- Assign Responsibilities
          ---- Design for Test
          ---- Consider using Brute Force
          ---- Draw a Diagram --- A picture is worth 1000 words--- kind of.
          ---- Keep your design modular

Divide and Conquer
      ---- Top-Down (From base class to derived ones)
      ---- Bottom-up (From derived to base)

---- Prototype
---- Collaborative design

Capturing your design work
    ---- Insert design documentation into the code itself
    ---- Capture design discussions and decisions on a Web
   ----  Write email summarizes
    ---- Use a digital camera
    ---- Save design flip charts
    ---- Create UML diagrams at appropriate levels of detail
=======================================================================================================

2. Woking Classes

Good Class Interfaces
    Good Abstraction
    --- A class presents a poor abstraction would be one that constained a collection of miscellaneous functions.
    --- Present a consistent level of abstraction in the class interface. (Each class should implement one and only one ADT)
    --- Be sure you understand what abstraction the class is implementing
    --- Provide services in pairs with their opposites
    --- Move unrelated information to another class
    --- Make interfaces programmatic rather than semantic when possible
    --- Consider cohesion and abstraction together

Good Encapsulation

Containment("has a" relationships)
    --- Implement "has a" through private inheritance as a last resort

Inheritance ("is a" relationships)

Enforce the singleton property by using a private constructor.
Prefer deep copies to shallow copies until proven otherwise.

Reasons to create a class
---- Model real-world objects
---- Model abstract objects
---- Reduce complexity
---- Isolate complexity
---- Hide implementaion details
---- Limit effects of changes
---- Hide global data
---- Streamline parameter passing
---- Make central points of control
---- Facilate reusalbe code
---- Plan for a family of programs
---- Package related operations
---- Accompish a specific refactoring
----- Avoid creating god [万能的] classes
----- Avoid classes named after verbs

=======================================================================================================
3. High-Quality Routines
    Design at the routine level

   Functional cohesion is the strongest and best kind of cohesion, occuring when a routine performs one and only one operation. Such as EraseFile()...

Several cohesion less than ideal,
---- Sequential Cohesion (in a specific order)
---- Communication Cohesion(make use of the same data)
---- Temporal cohesion(all done at the same time --- StartUp())
----------- Split the operations into individual routines

Unacceptable kinds of cohesion,
---- Procedural cohesion(Not do a complete job)
---- Logical cohesion(a control flag to select one of the operations.)


Good Routine Names
---- Describe everything the routine does
---- Avoid meaningless, vague, or wishy-washy verbs[无意义,模糊,表述不清], "Handle", "Perform","Process","DealWith"
---- Don't differentiate routine names solely by number
---- Make names of routines as long as necessary
---- To name a function, use a description of the return value
---- To name a procedure, use a strong verb followed by an object<In object-oriented languages, you don't need to include the name of the object.>
---- Use opposites precisely
     Add/Remove  increment/decrement  open/close  begin/end  insert/delete show/hide
     create/destroy lock/unlock source/target  first/last min/max start/stop get/put get/set next/previous up/down old/new
---- Establish conventions for common operations (id.Get()/GetID()/ID()....)

Here are a few guidelines for using routine parameters
---- Put parameters in input-modify-output order
    <C++ #define IN #define OUT void Function(IN int a, Out int& b)>
---- If several routines use similar parameters, put the similar parameter in a consistent order.
---- Use all the parameters
---- Put status or error variables last
---- Don't use routine parameters as working variables
---- Document interface assumptions about parameters
---- Limit the number of a routine's parameters to about seven
---- Consider an input, modify, and output naming convention for parameters, i_, m_ , o_
---- Pass teh variables or objects that the routine needs to maintain its interface abstraction
---- Use named parameters
---- Make sure actual parameters match formal parameters.

When to use a function and when to use a procedure
In short, use a function if the primary purpose of the routine is to return the value indicated by the function name. Otherwise, use a procedure.
<if (report.FormatOutPut(fomat) == Success )> (Not recommended)
<report.FormatOutPut(format, outputStatus)   if (outputStatus == Success)>

Setting the function's return value
---- Check all possible return paths --- It's good practice to initialize the return value at the beginning of the function to a default value.
---- Don't return references or pointers to local data.

Macro
---- Fully parenthesize macro expressions ()
---- Surround multiple-statement macros with curly braces {}

=======================================================================================================
3. Defensive Programming 
         --- Garbage in , Nothing or Error message out rather than Gargbage in , Garbage out
    
Protecting your program from invalid inputs
---- Check the values of all data from external sources.
---- Check the values of all routine input parameters
---- Decide how to handle bad inputs

Assertions
---- used during development

Assertions can be used to check assumptions like these:
---- That an input parameter's value falls within its expected range (or an output parameter's value does)
---- That a file or stream is open (or closed) when a routine begins executing (or when it ends executing)
---- That a file or stream is at the beginning (or end) when a routine begins executing (or when it ends executing)
---- That a file or stream is open for read-only, write-only, or both read and write
---- That the value of an input-only variable is not changed by a routine
---- That a pointer is non-null
---- That an array or other container passed into a routine can contain at least X number of data elements
---- That a table has been initialized to contain real values
---- That a container is empty (or full) when a routine begins executing (or when it finishes)
---- That the results from a highly optimized, complicated routine match the results from a slower but clearly written routine

Guidelines for using Assertions
---- Use error-handling code for conditions you expect to occur, use assertions for conditions that should never occur.
---- Use assertions to document and verify preconditions and postconditions
---- For highly robust code, assert and then handle the error anyway

Error-Handling Techniques
---- Return a neutral value
---- Substitute the next piece of valid data
---- Return the same answer as the previous time
---- Substitute the closest legal value
---- Log a warning message to a file
---- Return an error code
---- Call an error-processing routine/object
---- Display an error message wherever the error is encountered
---- Handle the error in whatever way works best locally
---- Shut down

Barricade your program to contain the damage caused by errors
Data(is assumed to be dirty and unstrusted)  -----> Classes(responsible for cleaning the data, make up the barricade) ----> Classes(can assume data is clean and trusted)

Routines that are outside the barricade should use error handling because it isn't safe to make any assumptions about the data. Routines inside the barricade should use assertions, because the data passed to them is supposed to be sanitized [清理] before it's passed across the barricade.

#define DEBUG

#if defined(DEBUG)
#define DebugCode(code_fragment) { code_fragment }
#else
#define DebugCode(code_fragment)
#endif

...
DebugCode(
    statement 1;
    statement 2;
    ....
)

=======================================================================================================
4 .  The Pseudocode Programming Process

----- Use English-like statements that precisely describe specific operations
----- Avoid syntactic elements from the target programming language.
----- Write pseudocode at the level of intent
----- Write pseudocode at a low enough level that generating code from it will be nearly automatic.

Design the routine
---- Check the prerequisites
----  Define the problem the routine will solve (in enough detail)
      ---- The information the routine will hide
      ---- Inputs and Outputs
      ---- Preconditions that are guranteed to be true before the routine is called.(input values within certain ranges, streams initialized, files opened or closed, buffers filled or flushed, etc)
      ---- Postconditions that the routine gurantees will be true before it passes control back to the caller(output values within specified ranges, streams initialized, files opened or closed, buffers filled or flushed, etc)
---- Name the routine
---- Decide how to test the routine
---- Research functionality available in the standard libraries
---- Think about error handling
---- Think about efficiency
---- Research the algorithms and data types
---- Write the pseudocode
---- Think about the data
---- Check the pseudocode
---- Try a few ideas in pseddocode, and keep the best(iterate)


----- Write the routine declaration
----- Turn the pseudocode into high level comments
---- Fill in the code below each comment
---- Check whether code should be further factored


---- Check the code
---- Clean up the leftovers (Remove redundant comments)

--- Repeat steps as needed
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值