Agile Partner - Agile Mëtteg - Clean Code

CP
by Cédric Pontet11 views·Updated Jul 12, 2011
Powered by AI

Need to present on this topic?

Create your own polished presentation in minutes. Just describe what you need.

Free to try, no credit card required

Slide outline

  1. Inline javascript in the onclick event handler
  2. Good
  3. Long method
  4. Useless comments
  5. Comments to explain what is being done
  6. Poor readability

Transcript

Objectives

Is code really important ?

The only part of software development that cannot be skipped

Letter-writing

« Plan to throw one away, you will anyhow »

Fred Brooks - The Mythical Man-Month – 1975-1995

... Unacceptable !

Construction metaphor

  • Intellectual toolbox
  • Do not reinvent the wheel!

Craftsmanship : idea of quality in the work

  • A better code A better programmer
  • We are professional!

Cleaning code ?!

  • Cleaning is an iterative process (Boy scout camp rule)
  • Code smells

Why write

clean code ?

How to keep your code clean ?

Beware of Train wrecks!

  • _account.getContactPerson()
  • _account.getContactPerson().getSchedule()
  • _account.getContactPerson().getSchedule().getVacations().add...

How to achieve this ?

Use your IDE refactoring features

  • Extract method
  • Rename
  • Extract interface
  • Promote variable
  • Encapsulate field
  • Reorder parameters

People network

Who are you ?

Who are we ?

What's our role ?

User story

As a software craftsman

I want to write better code

So that my fellow developers understand

its intent

And we can maintain it easily

What do we expect ?

As the mess builds, the productivity of the team continues to decrease, asymptotically approaching zero. As productivity decreases, management does the only thing they can; they add more staff to the project in hopes of increasing productivity. […] they, and everyone else on the team, are under horrific pressure to increase productivity. So they all make more and more messes, driving the productivity ever further toward zero.

Wanna get scared ?

Corrective

maintenance

This is "one" method, where only the code blocks have been kept

Clean Code, Robert C. Martin

Integration

Integration

Testing

Problem definition

Detailed

design

System testing

Coding and

debugging

Notice anything wrong here ?

The Total Cost of Owning a Mess

A crap odyssey

What about this one ?

Requirement development

Planning

Unit

testing

Software architecture

Software development process

What is code ?

  • Source code
  • Coding...

and debugging

Improving the -ities

Clean Code

Easy to neglect...

  • But represents 50-65% of the overall effort
  • And source of 50-75% of the bugs

A mechanical process? (Code = Encode)

  • No! The same thing can be coded in a lot of different ways.
  • Some ways may be better than others

Who cares as long as it runs!

  • Readability
  • Understandability
  • Testability
  • Flexibility
  • Modularity
  • Evolutivity
  • Reusability
  • Maintainability
  • But then don’t ask for maintenance or additional features…

Have you seen the deadline!?

  • Good code and good programmers help productivity

What was hard to write should be hard to read!

  • Not a professional attitude
  • Code will be more read than written...

Let's talk about bugs

Buzz

Defects can be introduced during

  • Requirements
  • Architecture
  • Design & coding

Clean code

  • Less bug introduced during design & coding
  • All kind of bugs cost less to fix

Cost of bugs

The later a bug is detected and fixed, the more it costs

Software development 1st metaphor

Code is the center of our work

Our code base is the working software

It is often the only faithfull description/documentation of the software

Modeling and designing means nothing without implementing code

A beautiful model on paper is no use to the end user

The quality of the code impacts the overall quality of the software

Agile Mëtteg – 24 Feb 2011

Waterfall approach

Coding is part of Design, Development & Test

Clean Code & Metaphors

What is bad code ?

... for each iteration

  • Unreadable
  • Not easy to understand
  • Classes are tightly coupled
  • Not easy to change
  • Does not communicate the intent
  • Shows too much of the internals

Code smells

  • Duplicated code
  • Long methods
  • Too many arguments
  • Switch statements
  • Large class
  • Comments

Iterative approach

Eric Ferrot

eferrot@agilepartner.net

public boolean foo() {

try {

synchronized () {

if () {

} else {

}

for () {

if () {

if () {

if () {

if ()

{

if () {

for () {

}

}

}

} else {

if () {

for () {

if () {

} else {

}

if () {

} else {

if () {

}

}

if () {

if () {

if () {

for () {

}

}

}

} else {

}

}

} else {

}

}

}

}

}

if () {

}

if () {

for () {

if () {

if () {

if () {

if () {

if () {

for () {

}

}

} else {

if () {

for () {

if () {

} else {

if () {

}

}

}

if () {

if () {

if () {

for () {

}

}

}

} else {

}

}

}

} else {

if () {

for () {

if () {

} else {

if () {

}

}

}

if () {

if () {

if () {

if () {

for () {

}

}

} else {

if () {

if () {

for () {

}

}

} else {

if () {

for () {

}

}

}

}

}

} else {

}

} else {

}

}

}

}

}

}

if () {

for () {

for () {

if () {

} else {

if ()

else

}

}

if () {

try {

} catch () {

}

}

}

} else {

}

if () {

} else {

try {

if () {

for () {

if ()

else

}

}

if () {

for () {

}

}

if () {

for () {

}

}

if () {

for () {

}

}

if () {

for () {

}

}

} catch () {

}

if () {

for () {

try {

if ()

else

} catch () {

try {

} catch () {

}

}

}

}

}

try {

} catch () {

}

if () {

if () {

for () {

if () {

for () {

if () {

} else {

if ()

else

}

}

if () {

try {

} catch () {

}

}

}

}

}

}

if ()

try {

} catch () {

}

if () {

if () {

for () {

if () {

try {

} catch () {

}

}

}

}

}

if ()

return ();

}

} finally {

}

}

Manifesto for

Software Craftsmanship

In 2009 the idea of software craftsmanship was generalized

by people like Robert C. Martin and Correy Haines

Manifesto for

Agile Software Development

What is a craftsman ?

As aspiring Software Craftsmen we are raising the bar of professional software development by practicing it and helping others learn the craft. Through this work we have come to value:

We are uncovering better ways of developing

software by doing it and helping others do it.

Through this work we have come to value:

  • a professional whose work is consistently of high quality : "as an actor he was a consummate craftsman"
  • a creator of great skill in the manual arts : "the jewelry was made by internationally famous craftsmen"
  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan
  • Not only working software, but also well-crafted software
  • Not only responding to change, but also steadily adding value
  • Not only individuals and interactions, but also a community of professionals
  • Not only customer collaboration, but also productive partnerships

That is, while there is value in the items on

the right, we value the items on the left more.

That is, in pursuit of the items on the left we have found the items on the right to be indispensable.

218 lines of

if-then-else and

try-catch-finally

Who is scared now ?

Choosing good names for a function can go a long way toward explaining the intent of the function and the order and intent of the arguments

  • It’s hard to make a small switch statement
  • It’s also hard to make a switch statement that does one thing

Function arguments

Side effect =

A function promises to do one thing, but it also does other hidden things

Switch statement

Number of parameters

Have no side effects

  • The ideal number of arguments for a function is zero
  • When more than two or tree arguments, consider using parameter objects

"You know you are working on clean code when each routine turns out to be pretty much what you expected."

Ward Cunnigham

They can be tolerated if they appear only once, are used to create polymorphic objects, and are hidden behind an inheritance relationship so that the rest of the system can’t see them

Flag arguments are ugly

They loudly proclaim that the function does more than one thing

  • A side effect creates a temporal coupling
  • Temporal couplings are confusing, especially when hidden as a side effect
  • If you must have a temporal coupling, you should make it clear in the name of the function (i.e. checkPasswordAndInitializeSession)

render(true)

renderForSuite() and renderForSingleTest()

Use descriptive

names

  • Don’t be afraid to make a name long.
  • A long descriptive name is better than a short enigmatic name.
  • A long descriptive name is better than a long descriptive comment.
  • Use a naming convention that allows multiple words to be easily read in the function names

The name of a variable, function, or class, should answer all the big questions. It

should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name does not reveal its intent.

Intention revealing names

It is not sufficient to add number series or noise words, even though the compiler is satisfied. If names must be different, then they should also mean something different

Functions

Make meaningful distinctions

Choosing good names takes time but saves more than it takes. So take care with your names and change them when you find better ones.

For

  • classes
  • methods
  • parameters
  • variables

Avoid disinformation

Avoid things such as

  • p1, p2, p3 for parameters
  • naming a variable "klass" because keyword "class" is reserved
  • creating "ProductInfo" or "ProductData" when you already have a class "Product"
  • naming a variable "theZork" because you already have another named "zork"
  • using "variable" in the name of a variable, "table" in the name of a table, "Object" in the name of an object
  • Even if you are coding a hypotenuse and "hp" looks like a good abbreviation, it could be disinformative
  • Do not refer to a grouping of accounts as an "accountList" unless it’s actually a "List"
  • Beware of using names which vary in small ways
  • Spelling similar concepts similarly is information

Reading Code from Top to Bottom : The Stepdown Rule

Functions should either

  • do something
  • or answer something
  • but not both
  • "L" lower-case or "one"
  • "O" upper-case or "zero"

Noise words are redundant.

We want every function to be followed by those at the next level of abstraction so that we can read the program, descending one level of abstraction at a time as we read down the list of functions

  • Customer
  • AssetFactory
  • OrderRepository
  • JobState
  • AuthorizationContext

Command query separation

Ubiquitous

Language

Prefixing the name may be necessary as a last resort

Bertrand Meyer

  • Classes and objects should have noun or noun phrase names
  • A class name should not be a verb
  • Avoid words like "Manager", "Processor", "Data", or "Info"

One Level of Abstraction

per Function

Method Names

Don’t Add Gratuitous Context

cqrs

Class names

did you mean cars

The reason we write functions is to decompose a larger concept into a set of steps at the next level of abstraction

Either your function should change the state of an object, or it should return some information about that object

  • Methods should have verb or verb phrase names
  • When constructors are overloaded, use static factory methods with names that describe the arguments

Avoid things such as

  • Reusing the class name in a field name : Contact.ContactName
  • Prefixing all classe names by the application name : T2Request
  • Namespaces are used for that purpose

Typical example of working against your IDE

Domain Driven Design by Eric Evans

  • AuthenticateUser
  • SendPayment
  • AddNewOrderLine
  • OpenSession
  • Save

Product.GetById(id)

Product.GetByReference(reference)

Mixing levels of abstraction within a function is always confusing. Readers may not be able to tell whether a particular expression is an essential concept or a detail. Worse, like broken windows, once details are mixed with essential concepts, more and more details tend to accrete within the function.

Do One Thing

Some say

7 lines, no more

Small

  • controller
  • manager
  • driver
  • fetch
  • retrieve
  • get
  • Functions should do one thing
  • They should do it well
  • They should do it only

The first rule of functions is that they should be small.

Pick One Word

per Concept

The second rule of functions is that they should be smaller than that.

  • A consistent lexicon is a great boon to the programmers who must use your code
  • Avoid using the same word for two different purpose

Meaningful names

  • The programmer who maintains your code can ask a domain expert what it means
  • The code that has more to do with problem domain concepts should have names drawn from the problem domain

Use Solution Domain Names

Use Problem Domain Names

Use

  • computer science terms
  • algorithm names
  • pattern names
  • math terms
  • ... and so forth

Separating solution and problem domain concepts is part of the job of a good programmer and designer

Readers shouldn’t have to mentally translate your names into other names they already know.

Comments do not make up for bad code

Avoid mental mappings

Explain yourself in code

Single-letter names and numeric constants have a particular problem in that they are not easy to locate across a body of text.

One difference between a smart programmer and a professional programmer is that the professional understands that "clarity is king"

Use searchable names

Encoding type or scope information into names simply adds an extra burden of deciphering

  • Single-letter names can ONLY be used as local variables inside short methods.
  • The length of a name should correspond to the size of its scope
  • If a variable or constant might be seen or used in multiple places in a body of code, it is imperative to give it a search-friendly name

Use pronouncable names

bBusy : boolean

chInitial : char

cApples : count of items

dwLightYears : double word (systems)

fBusy : boolean (flag)

nSize : integer (systems) or count (application)

iSize : integer (systems) or index (application)

fpPrice: floating-point

dbPi : double (systems)

pFoo : pointer

rgStudents : array, or range

szLastName : zero-terminated string

u32Identifier : unsigned 32-bit integer (systems)

stTime : clock time structure

fnFunction : function name

Avoid encodings

If you can’t pronounce it, you can’t discuss it without sounding like an idiot.

Hungarian notation

  • Do not use it
  • Modern IDE give you type information
  • Makes it harder to change the name or type of a variable, function, or class.

/*Comments*/

Reading code like reading a book, or a newspaper article

  • Done poorly, commenting is a waste of time, and often harmful
  • Good code is its own best documentation
  • Try first to improve the code so it doesn't need comments
  • Comments should say things about the code that the code can't say about itself
  • Comments are often out of date

One convention for the team

  • Use your IDE to enforce it
  • Think about maintainability

Horizontal formatting

Vertical formatting

Uncle Bob says

Length

Openness

  • White lines to separate concepts (i.e. methods in a class)
  • Keep our lines short
  • One operation per line

Density

Openness and Density

  • Lines of code that are tightly related should appear vertically dense

Distance

  • Use horizontal white space to associate things that are strongly related
  • Use white space wisely to improve readability
  • Closely related concepts vertically close to each other
  • One function calling another should be vertically close
  • The caller should be above the callee
  • Variables should be declared close to their usage
  • Instance variables should be declared at the top of the class

Indentation

  • A source file is a hierarchy rather like an outline

Remove noise

Redundant comments / Noise

Use source control

Commented-Out Code

Code is more often read than it is written

Source : Clean Code by Robert C. Martin

Formatting

Explanation of intent

Misleading comment

Use TODO

"Don't document bad code - rewrite it"

Code markers

Comment tricky code

Kernighan & Pauger

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Self documenting code

Martin Fowler

Xml docs in Nonpublic Code

Xml docs in Public APIs

Code formatting is about communication

Difference between objects and data structures

  • The goal is to show the logical organization of the code
  • Looking good is only secondary

Classes

  • Objects hide their data behind abstractions and expose functions that operate on that data
  • Data structures expose their data and have no meaningful functions

Organization

Encapsulation

Variables

  • Class interface hides implementation details
  • Keep variables and utility functions private
  • Loosening encapsulation is always a last resort
  • Public static constants
  • Private static variables
  • Private instance variables

Functions

  • Public functions
  • Private utilities called by a public function right after the public function itself
  • Use exception rather than return code
  • Don’t swallow exceptions
  • Use finally block to clean up
  • Provide context when throwing exception
  • Fail fast
  • Handle exceptions as soon as possible

Reduce coupling

As with functions, smaller is the primary rule when it comes to designing classes

Small

Consistent abstraction

One responsibility

  • Use interfaces to decouple classes from each other
  • Avoid bidirectional dependencies
  • Avoid semantic or time dependant coupling
  • Avoid deep inheritance hierarchies
  • Organizing for change
  • One reason to change
  • Single Responsibility Principle
  • The interface of the class exposes the members with same level of abstraction

Objects and

data structures

Error

handling

Many small classes

Cohesion

  • The more variables a method manipulates the more cohesive that method is to its class
  • High cohesion means that variables and methods are co-dependant
  • Split one class into two to make them more cohesive
  • Breaking a large function into many smaller functions often gives us the opportunity to split several smaller classes out as well

Objects expose behavior and hide data

  • easy to add new kinds of objects without changing existing behaviors
  • hard to add new behaviors to existing objects

Data structures expose data and have no significant behavior

  • easy to add new behaviors to existing data structures
  • hard to add new data structures to existing functions

Exceptions should stay exceptionnal

Typical data structure

Data transfer object

Performance cost

Don't forget alternatives

  • defensive programming
  • design by contracts : pre-conditions, post-conditions, invariants

Many client-specific interfaces are better than one general-purpose interface

ISP

Clients should not be forced to depend upon interfaces they do not use

Otherwise, clients are subject to changes in those interfaces. This results in an inadvertent coupling between all the clients.

When a client depends upon a class that contains interfaces that the client does not use, but that other clients do use, then that client will be affected by the changes that those other clients force upon the class.

Interface Segregation Principle

There should never be more than one reason for a class to change

Depend on abstractions, not on concretions

SRP

A. High level modules should not depend upon low level module. Both should depend upon abstractions.

B. Abstractions should not depend upon details. Details should depend upon abstractions

DIP

Single Responsibility Principle

Separation of concerns

Every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.

Dependency Inversion Principle

The goal of the dependency inversion principle is to decouple application glue code from application logic. Reusing low-level components (application logic) becomes easier and maintainability is increased.

This is facilitated by the separation of high-level components and low-level components into separate packages/libraries, where interfaces defining the behavior/services required by the high-level component are owned by, and exist within the high-level component's package.

SOLID

Open for extension

Closed to modification

OCP

Abstraction is the Key

Square is not Rectangle

Objects should be replaceable with instances of their subtypes without altering correctness

The behavior of a Square object is not consistent with the behavior of a Rectangle object.

Behaviorally, a Square is not a Rectangle.

And it is behavior that software is really all about.

Open/Close Principle

By creating base classes with override-able functions, we are able to create new classes that do the same thing differently without changing the base functionality.

Further, if properties of the abstracted class need to be compared or organized together, another abstraction should handle this.

LSP

Polymorphism

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

In other words, if you are calling a method defined at a base class upon an abstracted class, the function must be implemented properly on the subtype class.

Liskov Substitution Principle

Robert C. Martin aka Uncle Bob

Keep it simple AND stupid

Keep it simple, Stupid!

Simplicity should be a key goal in design, and that unnecessary complexity should be avoided.

DRY

KISS

Reducing repetition of information of all kinds

Keep it simple and straightforward

Don't repeat yourself

Keep it short and simple

Kelly Johnson

Especially useful in multi-tier architectures

Andy Hunt and Dave Thomas

Programmers should not add functionality until it is necessary

Duplication is evil

You ain't gonna need it

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

DIE

YAGNI

Ron Jeffries

Always implement things when you actually need them, never when you just foresee that you need them

Ron Jeffries

Principles

Principle of Least Surprise

Principle of Least Knowledge

POLS

  • Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
  • Each unit should only talk to its friends; don't talk to strangers.
  • Only talk to your immediate friends.

When two elements conflict, or are ambiguous, the behaviour should be that which will least surprise the user

In particular a programmer should try to think of the behavior that will least surprise someone who uses the program, rather than that behavior that is natural from knowing the inner workings of the program

Law of

Demeter

Coupling refers to the degree of direct knowledge that one class has of another

Loose coupling

Lieberherr & Holland - 1989

Karl Weick

A loosely coupled system is one where each of its components has little or no knowledge of the definitions of other separate components

Do not reinvent the wheel

Successive refinement

Use what is already out there

They will save you time and tedious effort

Refactoring

  • IDEs
  • Libraries
  • Frameworks
  • Tools
  • Code metrics

TDD mantra

Red, Green, Refactor

First make it work, then make it right

Cédric Pontet

cpontet@agilepartner.net

Conclusion

This presentation is mainly based on these two books

Refactor ruthlessly

Maintaining clean code = Managing code complexity

Think about the "What", then the "How"

Your tests harness is your safety net

Don’t be limited by your language

Direct benefit : design emergence

Tests are code and should be cleaned up like production code

We also recommend these

Become a software craftsman

1

Inline javascript in the onclick event handler

2

Good

Bad

3

Long method

4

Useless comments

5

Comments to explain what is being done

6

Poor readability