clean functions in a flash index cards version 0.2

24
Clean Functions in a Flash Index Cards Version 0.2

Upload: shanta

Post on 23-Feb-2016

33 views

Category:

Documents


0 download

DESCRIPTION

Clean Functions in a Flash Index Cards Version 0.2. Contents. Decomposing Message Composed Method Intention Revealing Method Explaining Message Method Comment Comments Long Methods - The Geography Metaphor Long Methods - The Bedroom Metaphor Code Smell: ‘Long Method’ - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Clean Functions in a Flash  Index Cards Version  0.2

Clean Functionsin a Flash

Index CardsVersion 0.2

Page 2: Clean Functions in a Flash  Index Cards Version  0.2

Contents1. Decomposing Message2. Composed Method3. Intention Revealing Method4. Explaining Message5. Method Comment6. Comments7. Long Methods - The Geography Metaphor8. Long Methods - The Bedroom Metaphor9. Code Smell: ‘Long Method’10. Refactorings for Writing Composed Methods11. Simplifying Conditionals: Decompose Conditional12. Simplifying Conditionals: Replace Nested Conditional with Guard Clause13. Simplifying Conditionals: Encapsulate Conditionals14. Simplifying Conditionals: Avoid Negative Conditionals15. Functions With Sections Do More Than One Thing16. Functions That Do One Thing Cannot Be Reasonably Divided Into Sections 17. Ensuring Functions Do One Thing18. Short Methods - No Guarantees19. Short Methods - A Means to an End20. How Long Should a Method be?21. Effects of Extract Till You Drop22. Object Oriented Decomposition Versus Functional Decomposition

Page 3: Clean Functions in a Flash  Index Cards Version  0.2

• How do you invoke parts of a computation?• Send several messages to ‘this’ (old-fashioned

functional decomposition)– Use Composed Method to break the method into

pieces– Make each method an Intention Revealing Method– Use Explaining Message to communicate intent

separate from implementation

Decomposing Message1

Page 4: Clean Functions in a Flash  Index Cards Version  0.2

How do you divide a program into methods?• Divide your program into methods that perform one identifiable task • Keep all of the operations in a method at the same level of abstraction• This will naturally result in programs with many small methods, each a few lines

long

Composed Method2

Page 5: Clean Functions in a Flash  Index Cards Version  0.2

• What do you name a method?• Name it after what it does (not how it does it)

Intention Revealing Method3

Page 6: Clean Functions in a Flash  Index Cards Version  0.2

How do you communicate your intent when the implementation is simple?• Send a message to 'this'. • Name the message so that it communicates what is to be done rather than how it is

to be done. • Code a simple method for the message.

public boolean isEmpty(){ size == 0; }private void addElement(Element element){ elements[size++] = element; }public void highlight(Rectangle area){ reverse(area); }

Consider introducing an explaining message when you are tempted to comment a single line of code

worse: flags |= LOADED_BIT; // Set the loaded bit

better: private void setLoadedFlag() { flags |= LOADED_BIT; }

Explaining Message4

Page 7: Clean Functions in a Flash  Index Cards Version  0.2

How do you comment methods?

• Communicate important information that is not obvious from the code in a comment at the beginning of the method

• I expect you to be skeptical about this pattern

• Experiment:– Go through your methods and delete only those comments that duplicate exactly

what the code says– If you can’t delete a comment, see if you can refactor the code to communicate the

same thing, especially using Composed Method and Intention Revealing Method – I will be willing to bet that when you are done you will have almost no comments

left.

Method Comment5

Page 8: Clean Functions in a Flash  Index Cards Version  0.2

• Every comment you write is a failure to express yourself well in code

• Comments are often used as a deodorant for the rotten whiffs of bad code

• Strive to eliminate comments in your code

• Whenever you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous

• Apply the Method Comment pattern

Comments6

Page 9: Clean Functions in a Flash  Index Cards Version  0.2

• We humans are very good at navigating complex terrains by recognising landmarks

• Take a long function and turn it on its side, and it looks like a landscape. How do we know our way around inside a large function? We memorised the landscape and so we recognise the landmarks.

• If you drop someone new into a landscape of code, they’ll recognise nothing. They’ll be completely bewildered. They won’t know where to go, or even how to begin, they’ll just have to wander around.

• Don’t listen to your reptilian hindbrain. Don’t favour long methods just because they are comfortable in that you can treat them as landscapes

• Remember that lots of little well named functions will save you and everybody lots of time because they are going to act as signposts along the way, helping everybody navigate through your code

Long MethodsThe Geography Metaphor7

Page 10: Clean Functions in a Flash  Index Cards Version  0.2

• Long functions are the way a 12 year old files things away

• You feel comfortable with everything scattered through a whole lot of deep indents

• This is not a good strategy for working and living in a team

• It is hard to be a team when you are surrounded by a mess all the time

• Later on as you mature and start working in a team you realize that the best place to put code is in nicely named places where it can be found later and understood

Long MethodsThe Bedroom Metaphor8

Page 11: Clean Functions in a Flash  Index Cards Version  0.2

• Number two in the stink parade (after Duplicated Code) is Long Method.

• Since the early days of programming people have realised that the longer a method is, the more difficult it is to understand.

• The object programs that live best and longest are those with short methods.

• You should be much more aggressive about decomposing methods

• Whenever you feel the need to comment something, write a method instead

Code Smell: ‘Long Method’9

Page 12: Clean Functions in a Flash  Index Cards Version  0.2

• A large part of refactoring (making code easier to understand and cheaper to modify) is composing methods to package code properly.

• Almost all the time the problems come from methods that are too long.

• The key refactoring is Extract Method.• When applying Extract Method is problematic, use the

following refactorings:

Refactorings for Writing Composed Methods10

• Inline Method• Inline Temp• Replace Temp with Query• Introduce Explaining Variable

• Split Temporary Variable• Remove Assignments to Parameters• Replace Method with Method Object• Substitute Algorithm

Page 13: Clean Functions in a Flash  Index Cards Version  0.2

Simplifying Conditionals: Decompose Conditional11

Refactoring: Decompose Conditional• You have a complicated conditional (if-then-else) statement.• Extract methods from the condition, then part, and else parts.

if (date.before (SUMMER_START) || date.after(SUMMER_END)) charge = quantity * _winterRate + _winterServiceCharge; else charge = quantity * _summerRate;

if (notSummer(date)) charge = winterCharge(quantity); else charge = summerCharge (quantity);

Page 14: Clean Functions in a Flash  Index Cards Version  0.2

Simplifying Conditionals: Replace Nested Conditional with Guard Clause12

Replace Nested Conditional with Guard Clause• A method has conditional behavior that does not make clear the normal

path of execution.• Use guard clauses for all the special cases.

double getPayAmount() {

double result; if (isDead)

result = deadAmount(); else {

if (isSeparated) result = separatedAmount();

else { if (isRetired)

result = retiredAmount();else result = normalPayAmount();

}; } return result;

};

double getPayAmount() {

if (isDead) return deadAmount(); if (isSeparated) return separatedAmount(); if (isRetired) return retiredAmount(); return normalPayAmount();

};

Page 15: Clean Functions in a Flash  Index Cards Version  0.2

Simplifying Conditionals: Encapsulate Conditionals13

Clean Code Heuristic G28: Encapsulate Conditionals

Boolean logic is hard enough to understand without having to see it in the context of an if or while statement. Extract functions that explain the intent of the conditional.

For example:

if (shouldBeDeleted(timer))

is preferable to

if (timer.hasExpired() && !timer.isRecurrent())

Page 16: Clean Functions in a Flash  Index Cards Version  0.2

Simplifying Conditionals: Avoid Negative Conditionals14

Clean Code Heuristic G29: Avoid Negative Conditionals

Negatives are just a bit harder to understand than positives. So, when possible, conditionals should be expressed as positives.

For example:

if (buffer.shouldCompact())

is preferable to

if (!buffer.shouldNotCompact())

Page 17: Clean Functions in a Flash  Index Cards Version  0.2

Functions with Sections Do More Than One Thing15

It is often tempting to create functions that have multiple sections that perform a series of operations. Functions of this kind do more than one thing, and should be converted into many smaller functions, each of which does one thing.This code does three things: • It loops over all the employees• checks to see whether each employee ought to

be paid• and then pays the employee.

public void pay() { for (Employee e : employees) { if (e.isPayday()) { Money pay = e.calculatePay(); e.deliverPay(pay); } } }

It would be better written as

public void pay() { for (Employee e : employees) payIfNecessary(e); } private void payIfNecessary(Employee e) { if (e.isPayday()) calculateAndDeliverPay(e);} private void calculateAndDeliverPay(Employee e) { Money pay = e.calculatePay(); e.deliverPay(pay); }

Page 18: Clean Functions in a Flash  Index Cards Version  0.2

Functions That Do One Thing Cannot Be Reasonably Divided Into Sections 16

public static int[] generatePrimes(int maxValue){ if (maxValue >= 2) // the only valid case { // declarations int s = maxValue + 1; // size of array boolean[] f = new boolean[s]; int i;

// initialize array to true. for (i = 0; i < s; i++) f[i] = true;

// get rid of known non-primesf[0] = f[1] = false;

// sieve

int j; for (i = 2; i < Math.sqrt(s) + 1; i++){ if (f[i]) // if i is uncrossed, cross its multiples.{

for (j = 2 * i; j < s; j += i) f[j] = false; // multiple is not prime

} }

// how many primes are there? int count = 0; for (i = 0; i < s; i++) { if (f[i]) count++; // bump count. }

int[] primes = new int[count]; // move the primes into the result for (i = 0, j = 0; i < s; i++){ if (f[i]) // if prime primes[j++] = i; } return primes; // return the primes } else // maxValue < 2 return new int[0]; // return null array if bad input. }}

• This small mess is an example of bad coding and commenting style.

• Notice that the generatePrimes function is divided into sections such as declarations, initializations, and sieve.

• This is an obvious symptom of doing more than one thing.

Page 19: Clean Functions in a Flash  Index Cards Version  0.2

Ensuring Functions Do One Thing17

Robert Martin’s ideas around Composed Method help us apply the pattern• To write Composed Methods we have to

1. Divide the program into functions that do one thing 2. Ensure functions descend only one level of abstraction

• But it is hard to know what one thing is• Actually, it is by making sure that the statements within our function are all at

the same level of abstraction that we make sure our functions are doing “one thing”

• But abstraction levels are fuzzy. This fuzziness is undesirable. • What we really want is an unambiguous, deterministic way to tell whether or not

a function is doing one thing. • The only way to really be sure that a function does one thing is to continue to

extract functions until you cannot extract any more. • After all, if you can extract one function from another, then the original function

was doing more than one thing by definition.• This approach is called Extract Till You Drop

Page 20: Clean Functions in a Flash  Index Cards Version  0.2

• While long methods are hard to understand, short methods aren’t guaranteed to be easy to understand

• When using Extract Method to break up a method into smaller pieces, you want to extract methods that are semantically meaningful, not just introduce a function call every seven lines.

• The most compelling reason for keeping methods small is the opportunity to communicate with intention revealing method names.

• Just splitting methods up using poor method names doesn’t help.

Short Methods - No Guarantees18

Page 21: Clean Functions in a Flash  Index Cards Version  0.2

• Short methods are not an end in themselves, they are what you get when you make your code easy to understand and maintain

• Short methods are just a means to the end of understandable and maintainable code

• What matters is not that all our methods are shorter than some magic number

• What matters is that they are so short that they can be rapidly understood, so that they are easy to maintain

Short Methods A Means to an End19

Page 22: Clean Functions in a Flash  Index Cards Version  0.2

How Long Should a Method be?20

The following guideline in Code Complete is way off the mark:

If you think it makes sense to make a certain routine 100, 150, or 200 lines long, it is probably right to do so…if you want to write routines longer than 200 lines, be careful…you are bound to run into an upper limit of understandability as you pass 200 lines of code.

We are much more aligned with the spirit of the following opinions by influential authors in the Extreme Programming community:

• I am immediately suspicious of any method with more than 5 to 10 lines.• After applying Composed Method, most of my methods are from 5 to 10 lines of

code each. It should take me no more than a minute or two to understand what a developer intended the method to do.

• Rarely more than 10 lines, usually about 5 lines. The typical result with Composed Method is that I can understand what a method does in a few seconds.

• Four lines is OK. Maybe five. Six? OK. Ten is way too big.

Page 23: Clean Functions in a Flash  Index Cards Version  0.2

Effects of Extract Till You Drop21

• Applying Extract Till You Drop results in functions that are all about 4 lines long.

• The blocks within if statements, else statements, while statements, and so on should not need braces, they should be one line long (braces are an opportunity to extract). Probably that line should be a function call.

• Functions should not be large enough to hold nested structures. The indent level of a function should not be greater than one or two.

Page 24: Clean Functions in a Flash  Index Cards Version  0.2

Object Oriented Decomposition Versus Functional Decomposition 22

• Surprise – pretty much all we are doing with Composed Method is classic functional decomposition (FD).

• FD is useful for individual algorithms and small programs, but it does not scale up to large programs, so modularise your program using OO decomposition, and apply FD within each class.

• FD is normally fine within a class, but should not be applied to very long methods in which many lines of code share many arguments and temporary variables

• Far from improving communications, applying Composed Method to such methods only obscures the situation because any piece of the method you break off requires six or eight parameters.

• Such methods are where classes go to hide. In such cases, you can still apply Extract Till You Drop, but instead of extracting methods, you extract classes.

• Instead of applying Composed Method, use one of the following refactorings: Introduce Parameter Object, Replace Method with Method Object