Meaningful Names
Use intention revealing names
Avoid disinformation
- avoid names with meaning
- avoid type info (ex: accountList → accounts)
- avoid long names with minor differences
- avoid inconsistent spellings (cf. IntelliSense)
Make meaningful distinctions
- x, y → source, destination
- avoid noise words (info, data...)
- 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
- niladic :
- monadic :
- dyadic :
- triadic : avoided when possible
- 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 :
- Variable declarations (cf. Re# rule)
- Instance variables : grouped at the top.
- Dependent functions : should be vertically close, the caller above the callee if at all possible.
- Conceptual affinity (ex: method overrides)
- 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 :
- C
- An object created by F
- An argument to F
- 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.