Clean Code Notes

来源:互联网 发布:软件测试实例视频 编辑:程序博客网 时间:2024/05/20 08:26

Meaningful Names

Use intention revealing names

Avoid disinformation

  1. avoid names with meaning
  2. avoid type info (ex: accountList → accounts)
  3. avoid long names with minor differences
  4. avoid inconsistent spellings (cf. IntelliSense)

Make meaningful distinctions

  1. x, y → source, destination
  2. avoid noise words (info, data...)
  3. distinguish names to emphasize differences

Use pronounceable names

Use searchable names

Avoid encodings

Hungarian notation (ui16Counter...)

Member prefixes (m_)

Interfaces and implementations I don’t agree as this is not the case in .NET framework internals

Avoid mental mapping

Class names

Should be nouns.

Method names

Should be verbs.

Use get / set for accessors. Is for predicates. Not needed for properties.

Don’t be cute

Say what you mean. Mean what you say.

Pick one word per concept

fetch = get = retrieve

controller = manager = driver

And agree with colleagues !

Don’t pun

Do not use the same word for two different concepts :

add != insert != append

Use solution domain names

Patterns, etc.

Use problem domain names

Add meaningful context

… between variables and classes for example.

Don’t add gratuitous context

Avoid useless prefix (cf. IntelliSense)

Avoid unnecessary long names

Functions

Small!

Do one thing

Functions should do one thing. They should do it well. They should do it only.

A function is doing more than one thing if you can extract another function from it.

Functions with sections should be splitted.

One level of abstraction per function

Reading code from Top to Bottom

→ The Stepdown Rule

Switch statements

At least, avoid their duplication with polymorphism.

SRP (Single Responsibility Principle)

OCP (Open Closed Principle) :

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
Abstraction is the key.

Low coupling.

Solution : Move the switch to an abstract factory.

Use descriptive names

Long names are better than short enigmatic names.

“pretty much what you expected”

Function arguments

  1. niladic :
  2. monadic :
  3. dyadic :
  4. triadic : avoided when possible
  1. polyadic : should not be used Not so easy in practice it seems (even in .NET internals)

Difficult to test a lot of arguments.

Output arguments are harder to understand.

Flag arguments

… are ugly (SRP : more than one thing).

Solution : split the method.

Argument objects

Argument lists

Have no side effects

Also : output arguments should be avoided. If a function must change the state of something, have it change the state of its owning object.

Command query separation

Change the state or return information, don’t do both.

Prefer exceptions to returning error codes

Extract try/catch blocks

Error handling is one thing

The Error.java dependency magnet

cf. RDUrls class.

DRY (Don’t Repeat Yourself)

Duplication may be the root of all evil in software.

Structure programming

return, break and continue are ok for (short) functions.

No goto.

Comments

Comments are always failure.

Comments do not make up for bad code

Don’t comment bad code, rewrite it !

Explain yourself in code

Not in comments !

Good comments

Legal comments

(Informative)

Explanation of intent

Clarification

Warning of consequences

TODO

Amplification

javadoc in public APIs

Bad comments

Mumbling

Redundant comments

Misleading comments

Mandated comments

javadoc for internal code.

Journal comments

Noise comments

Scary noise

Don’t use a comment when you can use a function/variable

Position markers

Closing brace comments

Attribution and bylines

Commented-out code

HTML comments

Nonlocal information

Too much information

Inobvious connection

Function headers

Formatting

Vertical formatting

Small files are easier to understand.

The newspaper metaphor
Vertical openness between concepts

I usually remove blank lines between functions because we already have one with the closing bracket of the previous function.

Vertical density

It implies close association.

Vertical distance

Concepts that are closely related should be kept vertically close to each other.
In particular :

  1. Variable declarations (cf. Re# rule)
  2. Instance variables : grouped at the top.
  3. Dependent functions : should be vertically close, the caller above the callee if at all possible.
  4. Conceptual affinity (ex: method overrides)
  5. Vertical ordering (cf. newspaper)

In my/our code, I/we usually use regions :

Private fields.

Private methods.

Then : public methods.

Ctrl-M shortcuts ease automatic opening and closing of all functions/regions.

So I usually organize my code so that it reads from bottom to top. This might be because I start coding with Pascal and C++ when this order is required by the compiler.

Horizontal formatting

Horizontal openness and density

Ex : spaces around operators, precedence, argument separation...

Horizontal alignment

Should not be used anymore.

Indentation

Breaking indentation should be avoided.

I seldom break this rule for very short properties :

public Name { get { return name; } }

Dummy scopes are dangerous : like while ();

Team rules

A team should agree on a common set of rules.

Objects and data structures

Data abstraction

Hide implementations.

Data/Object anti-symmetry

Procedural code makes it easy to add new functions without changing the existing data structures.

OO code makes it easy to add new classes without changing existing functions.

Procedural code makes it hard to add new data structures because all functions must change.

OO code makes it hard to add new functions because all classes must change.

The law of Demeter

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

A method F in a class C should only call methods from :

  1. C
  2. An object created by F
  3. An argument to F
  4. An instance variable of C

Train wrecks

Chains of calls : a().b().c()

Hybrids

Half objects half data structures are the worst of both worlds.

Hiding structure

DTO (Data transfer objects)

DTO like Active Record should not implement business rules.

Error handling

Use exceptions rather than return codes

Write your try-catch-finally statement first

Try to write tests that force exceptions, and than add behavior to your handler to satisfy your tests.

Use unchecked exceptions

ie. not java throws’.

Provide context with exceptions

Define exceptions classes in terms of a caller’s needs

Wrapping 3rd party API is a best-practice.

Define the normal flow

To avoid if or exception catching for example.

Use the special case pattern : create a class that handles a special case.

Don’t return null

Other possibility : return empty enumerable.

I prefer returning null when I use[CanBeNull] and [NotNull] Re# attributes.

Don’t pass null

Same remark.

Boundaries

Using 3rd-party code

Best practice : add dedicated class that encapsulates third party object to hide it and to provide an interface tailored and constrained to the needs of the application.

Do not use  third party objects in public APIs.

Exploring and learning boundaries


转载自 :https://docs.google.com/document/pub?id=1rTYaIn4Br4tgYPx1oo8pz2I2aHT1YehOaBRM7__mxH8
原创粉丝点击