Clean Code Learning

--Meaningful Names

* Use Intention-Revealing Names

* Avoid Disinformation

* Make meaningful distinctions (XXXData & XXXInfo)

* Use pronounceable names

* Use Searchable names (easily grep)

* Avoid Encodings 

* Hungarian Notation

* Member Prefixes (The more we read the code, the less we see the prefixes.)

* Avoid Mental Mapping (clarity is king)

* Class Names (noun or noun phrase names, like customer,account)

* Method Names (verb or verb phrase names, like postPayment, save)

* Don't be cute (Say what you mean. Mean what you say)

* Pick One Word per Concept ("DeviceManager" & "ProtocolController" 

Why are both not controllers or both not managers?)

* Don't Pun (Avoid using the same word for two purposes.)

  * Use Solution Domain Names (go ahead and use computer science (CS) terms, 

algorithm names, pattern names, math terms)

* Use Problem Domain Names (At least the programmer who maintains your code 

can ask a domain expert what it means)

* Add Meaningful context 

* Don’t Add Gratuitous Context

--Functions

* Small! (Blocks and Indenting: if else while ... 

the function called within the block can have a nicely descriptive name.)

  * Do One Thing (Sections within Functions: what “one thing” is ?)

* One Level of Abstraction per Function (like a top-down narrative.)

* Switch Statements (can't avoid switch, but we can make sure that each switch

statement is buried in a low-level class and is never repeated. )

* Use Descriptive Names.

* Function Arguments

* common Monadic Forms (Try to avoid Using an output argument instead of a

return value for a transformation is confusing.)

* Flag arguments (ugly)

* Dyadic Functions 

* Triads

* Argument Objects

* Argument Lists

* Verbs and Keywords (assertEquals might be better written 

as assertExpectedEqualsActual(expected, actual).)

* Have No Side Effects

* Output Arguments

* Command Query Separation (Functions should either do something

or answer something, but not both.)

* Prefer Exceptions to Returning Error Codes

* Extract Try/Catch Blocks (it is better to extract the bodies of the try 

and catch blocks out into functions of their own.)

* Error Handling Is One Thing

* Don’t Repeat Yourself

* Structured Programming (every function, and every block 

within a function, should have one entry and one exit.)

--Comments

* Comments Do Not Make Up for Bad Code

* Explain Yourself in Code

* Good comments:

- Legal Comments

- Infomative Comments

- Explanation of Intent

- Clarification

- TODO Comments

* Bad comments:

- Mumbling

- Redundant comments

- Misleading Comments

- Mandated Comments

      /**

*

* @param title The title of the CD

* @param author The author of the CD

* @param tracks The number of tracks on the CD

**/

- Journal Comments

* Changes (from 11-Oct-2001)

* --------------------------

* 11-Oct-2001 : Re-organised the class and moved it to new package

* com.jrefinery.date (DG);

* 05-Nov-2001 : Added a getDescription() method, and eliminated NotableDate

* class (DG);

* 12-Nov-2001 : IBD requires

- Noise Comments

      /**

* Default constructor.

*/

protected AnnualDateRule() {

}

- Position Markers

- Commented-Out Code (Don't Do this!)

- HTML comments

- Nonlocal Information

--Formatting

* Dependent Functions (If one function calls another, they should be vertically close)

... ... ...

--Objects and Data Structures

Procedural code (code using data structures) makes it easy to add new functions without

changing the existing data structures. OO code, on the other hand, makes it easy to add

new classes without changing existing functions.

* The Law of Demeter

a module should not know about the innards of the objects it manipulates.

* Train Wrecks, Hiding Structure

Objects expose behavior and hide data. This makes it easy to add new kinds of objects

without changing existing behaviors. It also makes it hard to add new behaviors to existing

objects. Data structures expose data and have no significant behavior. This makes it easy to

add new behaviors to existing data structures but makes it hard to add new data structures

to existing functions.

--Error Handling

* Use Exceptions Rather Than Return Codes

* Use Unchecked Exceptions

* Define Exception Classes in Terms of a Caller’s Needs

* Define the Normal Flow (Don't deal with business logic under catching exceptions)

* Don’t Return Null

* Don't pass null

--Boundaries

* Using Third-Party Code

We should avoid letting too much of our code know about the third-party particulars. It’s better

to depend on something you control than on something you don’t control, lest it end up

controlling you.

--Unit Tests

* Keeping Tests Clean

* A Dual Standard

* Rules:

- Fast Independent Repeatable Self-Valldating Timely

--Classes

* Classes Should be Small

* The Single Responsibility Principle

* Cohesion

--Systems

* Separate Constructing a System from Using It

* Dependency Injection

* Cross-Cutting Concerns

* Java Proxies

* AspectJ Aspects

--Emergence

* Refactoring

* No Duplication

* code expressive

* Simple Design

--Concurency

* Single Responsiblity Principle 

- Concurrency-related code has its own life cycle of development

- Limit the scope of data

- Use copies of data

- Threads should be as independent as possible

* Thread-Safe Collections (concurrentHashMap)

* Executions Models (Bound Resources, Mutual Exclusion, Starvation, Deadlock,Livelock) 

* Producer-Consumer

* Readers-Writers

* Keep Synchronized Sections Small

* Testing Threaded Code

- Get your nonthreaded code working first

- Make your threaded code pluggable

- Make your threaded code tunable

- run with More thread than processors

- run on different platforms

--Successive refinement

* examples

--Junit Internals

* refactors

--Refactoring serialdate

* First, make it work

* Then Make it Right 

--Smells and Heuristics

- Inappropriate Information

- Obsolete Comment

- Redundant Comment

- Poorly Written Comment

- Commented-Out Code

- Build Requires More Than One Step

- Tests Require More Than One Step

- Too Many Arguments

- Output Arguments

- Flag Arguments

- Dead Function

- Multiple Languages in One Source File

- Obvious Behavior Is Unimplemented

- Incorrect Behavior at the Boundaries

- Overridden Safeties

- Duplication

- Code at Wrong Level of Abstraction

- Base Classes Depending on Their Derivatives

- Too Much Information

- Dead Code

- Vertical Separation

- Inconsistency

- clutter

- Artificial Coupling

- Feature Envy

- Selector Arguments

- Obscured Intent

- Misplaced Responsibility

- Inappropriate Static

- Use Explanatory Variables

- Function Names Should Say What They Do

- Understand the Algorithm

- Make Logical Dependencies Physical

- Prefer Polymorphism to If/Else or Switch/Case

- Follow Standard Conventions

- Replace Magic Numbers with Named Constants

- Be Precise

- Structure over Convention

- Encapsulate Conditionals

- Avoid Negative Conditionals

- Functions Should Do One Thing

- Hidden Temporal Couplings

- Don’t Be Arbitrary

- Encapsulate Boundary Conditions

- Functions Should Descend Only One Level of Abstraction

- Keep Configurable Data at High Levels

- Avoid Transitive Navigation

- Avoid Long Import Lists by Using Wildcards

- Don’t Inherit Constants

- Constants versus Enums

- Choose Descriptive Names

- Choose Names at the Appropriate Level of Abstraction

- Use Standard Nomenclature Where Possible

- Unambiguous Names

- Use Long Names for Long Scopes

- Avoid Encodings

- Names Should Describe Side-Effects

- Insufficient Tests

- Use a Coverage Tool!

- Don’t Skip Trivial Tests

- An Ignored Test Is a Question about an Ambiguity

- Test Boundary Conditions

- Exhaustively Test Near Bugs

- Patterns of Failure Are Revealing

- Test Coverage Patterns Can Be Revealing

- Tests Should Be Fast

猜你喜欢

转载自sunxboy.iteye.com/blog/1699124