seven ineffective coding habits of many programmers

89
Seven Ineffective Coding Habits of Many Programmers @KevlinHenney

Upload: kevlin-henney

Post on 08-Jul-2015

1.228 views

Category:

Software


0 download

DESCRIPTION

Presented at Build Stuff (20th November 2014) Habits help you manage the complexity of code. You apply existing skill and knowledge automatically to the detail while focusing on the bigger picture. But because you acquire habits largely by imitation, and rarely question them, how do you know your habits are effective? Many of the habits and conventions programmers have for naming, formatting, commenting and unit testing do not stand up as rational and practical on closer inspection. This session examines seven coding habits that are not as effective as many programmers — whether working with Java, .NET, native or scripting languages — might believe, and suggests alternatives.

TRANSCRIPT

Page 1: Seven Ineffective Coding Habits of Many Programmers

Seven Ineffective

Coding Habits of

Many Programmers

@KevlinHenney

Page 2: Seven Ineffective Coding Habits of Many Programmers
Page 3: Seven Ineffective Coding Habits of Many Programmers
Page 4: Seven Ineffective Coding Habits of Many Programmers
Page 5: Seven Ineffective Coding Habits of Many Programmers

It turns out that style matters in programming for the same reason that it matters in writing. It makes for better reading.

Douglas Crockford JavaScript: The Good Parts

Page 6: Seven Ineffective Coding Habits of Many Programmers
Page 7: Seven Ineffective Coding Habits of Many Programmers

Noisy Code

Page 8: Seven Ineffective Coding Habits of Many Programmers

Signal-to-noise ratio (often abbreviated SNR or

S/N) is a measure used in science and engineering

that compares the level of a desired signal to the

level of background noise.

Signal-to-noise ratio is sometimes used informally

to refer to the ratio of useful information to false or

irrelevant data in a conversation or exchange.

http://en.wikipedia.org/wiki/Signal_to_noise_ratio

Page 9: Seven Ineffective Coding Habits of Many Programmers

To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?

William Shakespeare

Hamlet

Page 10: Seven Ineffective Coding Habits of Many Programmers

Continuing existence or cessation of

existence: those are the scenarios. Is it

more empowering mentally to work towards

an accommodation of the downsizings and

negative outcomes of adversarial

circumstance, or would it be a greater

enhancement of the bottom line to move

forwards to a challenge to our current

difficulties, and, by making a commitment

to opposition, to effect their demise?

Tom Burton

Long Words Bother Me

Page 11: Seven Ineffective Coding Habits of Many Programmers

public class RecentlyUsedList { private List<string> items; public RecentlyUsedList() { items = new List<string>(); } public void Add(string newItem) { if (items.Contains(newItem)) { int position = items.IndexOf(newItem); string existingItem = items[position]; items.RemoveAt(position); items.Insert(0, existingItem); } else { items.Insert(0, newItem); } } public int Count { get { int size = items.Count; return size; } } public string this[int index] { get { int position = 0; foreach (string item in items) { if (position == index) return item; ++position; } throw new ArgumentOutOfRangeException(); } } }

Page 12: Seven Ineffective Coding Habits of Many Programmers

public class RecentlyUsedList { private List<string> items; public RecentlyUsedList() { items = new List<string>(); } public void Add(string newItem) { if (items.Contains(newItem)) { int position = items.IndexOf(newItem); string existingItem = list[position]; items.RemoveAt(position); items.Insert(0, existingItem); } else { items.Insert(0, newItem); } } public int Count { get { int size = items.Count; return size; } } public string this[int index] { get { int position = 0; foreach (string value in items) { if (position == index) return value; ++position; } throw new ArgumentOutOfRangeException(); } } }

public class RecentlyUsedList { private List<string> items = new List<string>(); public void Add(string newItem) { items.Remove(newItem); items.Add(newItem); } public int Count { get { return items.Count; } } public string this[int index] { get { return items[Count - index - 1]; } } }

Page 13: Seven Ineffective Coding Habits of Many Programmers
Page 14: Seven Ineffective Coding Habits of Many Programmers
Page 15: Seven Ineffective Coding Habits of Many Programmers

Comments

A delicate matter, requiring taste and judgement. I tend to err on the side of eliminating comments, for several reasons. First, if the code is clear, and uses good type names and variable names, it should explain itself. Second, comments aren't checked by the compiler, so there is no guarantee they're right, especially after the code is modified. A misleading comment can be very confusing. Third, the issue of typography: comments clutter code.

Rob Pike, "Notes on Programming in C"

Page 16: Seven Ineffective Coding Habits of Many Programmers

There is a famously bad comment style:

i=i+1; /* Add one to i */

and there are worse ways to do it:

/**********************************

* *

* Add one to i *

* *

**********************************/

i=i+1;

Don't laugh now, wait until you see it in real life.

Rob Pike, "Notes on Programming in C"

Page 17: Seven Ineffective Coding Habits of Many Programmers

A common fallacy is to assume authors of incomprehensible code will somehow be able to express themselves lucidly and clearly in comments.

Kevlin Henney https://twitter.com/KevlinHenney/status/381021802941906944

Page 18: Seven Ineffective Coding Habits of Many Programmers
Page 19: Seven Ineffective Coding Habits of Many Programmers

Unsustainable Spacing

Page 20: Seven Ineffective Coding Habits of Many Programmers

To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?

William Shakespeare

Hamlet

Page 21: Seven Ineffective Coding Habits of Many Programmers

Continuing existence or cessation of

existence: those are the scenarios. Is it

more empowering mentally to work towards

an accommodation of the downsizings and

negative outcomes of adversarial

circumstance, or would it be a greater

enhancement of the bottom line to move

forwards to a challenge to our current

difficulties, and, by making a commitment

to opposition, to effect their demise?

Tom Burton

Long Words Bother Me

Page 22: Seven Ineffective Coding Habits of Many Programmers

Continuing existence or cessation of existence:

those are the scenarios. Is it

more empowering mentally

to work towards an

accommodation of the

downsizings and negative

outcomes of adversarial

circumstance, or would it be

a greater enhancement of

the bottom line to move

forwards to a challenge to

our current difficulties, and,

by making a commitment to

opposition, to effect their

demise?

Page 23: Seven Ineffective Coding Habits of Many Programmers

How many programmers lay out their code

Column 80

Page 24: Seven Ineffective Coding Habits of Many Programmers

How people read

Page 25: Seven Ineffective Coding Habits of Many Programmers

To answer the question "What is clean design?"

most succinctly: a clean design is one that

supports visual thinking so people can meet their

informational needs with a minimum of

conscious effort.

Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/

Page 26: Seven Ineffective Coding Habits of Many Programmers

You convey information by the way you arrange

a design's elements in relation to each other. This

information is understood immediately, if not

consciously, by the people viewing your designs.

Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/

Page 27: Seven Ineffective Coding Habits of Many Programmers

This is great if the visual relationships are

obvious and accurate, but if they're not, your

audience is going to get confused. They'll have to

examine your work carefully, going back and

forth between the different parts to make sure

they understand.

Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/

Page 28: Seven Ineffective Coding Habits of Many Programmers

public int howNotToLayoutAMethodHeader(int firstArgument,

String secondArgument)

public int ensureArgumentsAreAlignedLikeThis(

int firstArgument,

String secondArgument)

public int orEnsureArgumentsAreGroupedLikeThis(

int firstArgument, String secondArgument)

public int butNotAlignedLikeThis(int firstArgument,

String secondArgument)

Page 29: Seven Ineffective Coding Habits of Many Programmers

int doNotFormat = likeThis(someArgumentOrExpression,

anotherArgumentOrExpression);

int insteadFormat =

somethingLikeThis(

someArgumentOrExpression,

anotherArgumentOrExpression);

int orFormat = somethingLikeThis(

someArgumentOrExpression,

anotherArgumentOrExpression);

Page 30: Seven Ineffective Coding Habits of Many Programmers

int asItIs = unstable(someArgumentOrExpression,

anotherArgumentOrExpression);

int butThisIs =

stable(

someArgumentOrExpression,

anotherArgumentOrExpression);

int andThisIs = stable(

someArgumentOrExpression,

anotherArgumentOrExpression);

Page 31: Seven Ineffective Coding Habits of Many Programmers

public ResultType arbitraryMethodName(FirstArgumentType firstArgument,

SecondArgumentType secondArgument,

ThirdArgumentType thirdArgument) {

LocalVariableType localVariable = method(firstArgument,

secondArgument);

if (localVariable.isSomething(thirdArgument,

SOME_SHOUTY_CONSTANT)) {

doSomethingWith(localVariable);

}

return localVariable.getSomething();

}

Page 32: Seven Ineffective Coding Habits of Many Programmers

public ResultType arbitraryMethodName(

FirstArgumentType firstArgument,

SecondArgumentType secondArgument,

ThirdArgumentType thirdArgument) {

LocalVariableType localVariable =

method(firstArgument, secondArgument);

if (localVariable.isSomething(

thirdArgument, SOME_SHOUTY_CONSTANT)) {

doSomething(localVariable);

}

return localVariable.getSomething();

}

Page 33: Seven Ineffective Coding Habits of Many Programmers

XXXXXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXX

XX XXXXXXXXXXXXX XXXXXXXXXXX

XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXX XXXXXXXXXXXXX

XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXX

Page 34: Seven Ineffective Coding Habits of Many Programmers

public ResultType arbitraryMethodName(

FirstArgumentType firstArgument,

SecondArgumentType secondArgument,

ThirdArgumentType thirdArgument) {

LocalVariableType localVariable =

method(firstArgument, secondArgument);

if (localVariable.isSomething(

thirdArgument, SOME_SHOUTY_CONSTANT)) {

doSomething(localVariable);

}

return localVariable.getSomething();

}

Page 35: Seven Ineffective Coding Habits of Many Programmers

XXXXXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXX

XX XXXXXXXXXXXXX XXXXXXXXXXX

XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXX XXXXXXXXXXXXX

XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXX

Page 36: Seven Ineffective Coding Habits of Many Programmers

public ResultType arbitraryMethodName(

FirstArgumentType firstArgument,

SecondArgumentType secondArgument,

ThirdArgumentType thirdArgument)

{

LocalVariableType localVariable =

method(firstArgument, secondArgument);

if (localVariable.isSomething(

thirdArgument, SOME_SHOUTY_CONSTANT))

{

doSomething(localVariable);

}

return localVariable.getSomething();

}

Page 37: Seven Ineffective Coding Habits of Many Programmers

XXXXXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX

XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXX

XX XXXXXXXXXXXXX XXXXXXXXXXX

XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXX XXXXXXXXXXXXX

XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXX

Page 38: Seven Ineffective Coding Habits of Many Programmers
Page 39: Seven Ineffective Coding Habits of Many Programmers

Lego Naming

Page 40: Seven Ineffective Coding Habits of Many Programmers

Agglutination is a process in linguistic morphology

derivation in which complex words are formed by

stringing together morphemes, each with a single

grammatical or semantic meaning. Languages that

use agglutination widely are called agglutinative

languages.

http://en.wikipedia.org/wiki/Agglutination

Page 41: Seven Ineffective Coding Habits of Many Programmers

pneumonoultramicroscopicsilicovolcanoconiosis

Rindfleischetikettierungsüberwachungsaufgabenübertragungsgesetz

fylkestrafikksikkerhetsutvalgssekretariatslederfunksjonene

Page 42: Seven Ineffective Coding Habits of Many Programmers
Page 43: Seven Ineffective Coding Habits of Many Programmers

Proxy

validate

Service

Value

get

create

Manager

check

Controller

set

Factory

Object

do enable

process

disable

Exception

add

remove

Page 44: Seven Ineffective Coding Habits of Many Programmers

public interface ConditionChecker { boolean checkCondition(); }

Page 45: Seven Ineffective Coding Habits of Many Programmers

public interface Condition { boolean isTrue(); }

Page 46: Seven Ineffective Coding Habits of Many Programmers

public Connection createConnection(Provider...) throws ConnectionFailureException ...

Page 47: Seven Ineffective Coding Habits of Many Programmers

public Connection connectTo(Provider...) throws ConnectionFailure ...

Page 48: Seven Ineffective Coding Habits of Many Programmers

ClassNotFoundException

EnumConstantNotPresentException

IllegalArgumentException

IllegalAccessException

IndexOutOfBoundsException

NegativeArraySizeException

NoSuchMethodException

TypeNotPresentException

UnsupportedOperationException

Page 49: Seven Ineffective Coding Habits of Many Programmers

ClassNotFound

EnumConstantNotPresent

IllegalArgument

IllegalAccess

IndexOutOfBounds

NegativeArraySize

NoSuchMethod

TypeNotPresent

UnsupportedOperation

Page 50: Seven Ineffective Coding Habits of Many Programmers

ArithmeticException

ArrayStoreException

ClassCastException

InstantiationException

NullPointerException

SecurityException

Page 51: Seven Ineffective Coding Habits of Many Programmers

Arithmetic

ArrayStore

ClassCast

Instantiation

NullPointer

Security

Page 52: Seven Ineffective Coding Habits of Many Programmers

IntegerDivisionByZero

IllegalArrayElementType

CastToNonSubclass

ClassCannotBeInstantiated

NullDereferenced

SecurityViolation

Page 53: Seven Ineffective Coding Habits of Many Programmers

Omit needless words.

William Strunk and E B White

The Elements of Style

Page 54: Seven Ineffective Coding Habits of Many Programmers
Page 55: Seven Ineffective Coding Habits of Many Programmers

Underabstraction

Page 56: Seven Ineffective Coding Habits of Many Programmers

http://fragmental.tw/2009/04/29/tag-clouds-see-how-noisy-your-code-is/

Page 57: Seven Ineffective Coding Habits of Many Programmers

http://fragmental.tw/2009/04/29/tag-clouds-see-how-noisy-your-code-is/

Page 58: Seven Ineffective Coding Habits of Many Programmers

if (portfolioIdsByTraderId.get(trader.getId()) .containsKey(portfolio.getId())) { ... }

Dan North, "Code in the Language of the Domain" 97 Things Every Programmer Should Know

Page 59: Seven Ineffective Coding Habits of Many Programmers

if (trader.canView(portfolio)) { ... }

Dan North, "Code in the Language of the Domain" 97 Things Every Programmer Should Know

Page 60: Seven Ineffective Coding Habits of Many Programmers
Page 61: Seven Ineffective Coding Habits of Many Programmers

Unencapsulated State

Page 62: Seven Ineffective Coding Habits of Many Programmers

An affordance is a quality of an object, or an environment, which allows an individual to perform an action. For example, a knob affords twisting, and perhaps pushing, while a cord affords pulling.

http://en.wikipedia.org/wiki/Affordance

Page 63: Seven Ineffective Coding Habits of Many Programmers

public class RecentlyUsedList { private List<string> items = new List<string>();

public List<string> Items { get { return items; } } public void Add(string newItem) { if(newItem == null) throw new ArgumentNullException(); items.Remove(newItem); items.Insert(0, newItem); } ... }

Page 64: Seven Ineffective Coding Habits of Many Programmers

public class RecentlyUsedList { private List<string> items = new List<string>();

public List<string> Items { get { return items; } } public void Add(string newItem) { if(newItem == null) throw new ArgumentNullException(); items.Remove(newItem); items.Insert(0, newItem); } ... }

Page 65: Seven Ineffective Coding Habits of Many Programmers

public class RecentlyUsedList { private List<string> items = new List<string>();

public List<string> Items { get { return items; } } public void Add(string newItem) { if(newItem == null) throw new ArgumentNullException(); items.Remove(newItem); items.Insert(0, newItem); } ... }

var list = new RecentlyUsedList();

list.Add("Hello, World!");

Console.WriteLine(list.Items.Count);

list.Items.Add("Hello, World!");

Console.WriteLine(list.Items.Count);

list.Items.Add(null);

Page 66: Seven Ineffective Coding Habits of Many Programmers

Don't ever invite a

vampire into your

house, you silly boy.

It renders you

powerless.

Page 67: Seven Ineffective Coding Habits of Many Programmers

public class RecentlyUsedList { private IList<string> items = new List<string>();

public int Count { get { return items.Count; } } public string this[int index] { get { return items[index]; } } public void Add(string newItem) { if(newItem == null) throw new ArgumentNullException(); items.Remove(newItem); items.Insert(0, newItem); } ... }

Page 68: Seven Ineffective Coding Habits of Many Programmers

public class RecentlyUsedList { private IList<string> items = new List<string>();

public int Count { get { return items.Count; } } public string this[int index] { get { return items[Count – index - 1]; } } public void Add(string newItem) { if(newItem == null) throw new ArgumentNullException(); items.Remove(newItem); items.Add(newItem); } ... }

Page 69: Seven Ineffective Coding Habits of Many Programmers
Page 70: Seven Ineffective Coding Habits of Many Programmers
Page 71: Seven Ineffective Coding Habits of Many Programmers

Getters and Setters

Page 72: Seven Ineffective Coding Habits of Many Programmers
Page 73: Seven Ineffective Coding Habits of Many Programmers
Page 74: Seven Ineffective Coding Habits of Many Programmers
Page 75: Seven Ineffective Coding Habits of Many Programmers
Page 76: Seven Ineffective Coding Habits of Many Programmers

public class Money implements ... { ... public int getUnits() ... public int getHundredths() ... public Currency getCurrency() ... ... public void setUnits(int newUnits) ... public void setHundredths(int newHundredths) ... public void setCurrency(Currency newCurrency) ... ... }

Page 77: Seven Ineffective Coding Habits of Many Programmers

public final class Money implements ... { ... public int getUnits() ... public int getHundredths() ... public Currency getCurrency() ... ... }

Page 78: Seven Ineffective Coding Habits of Many Programmers

public final class Money implements ... { ... public int units() ... public int hundredths() ... public Currency currency() ... ... }

Page 79: Seven Ineffective Coding Habits of Many Programmers

When it is not necessary to change, it is necessary not to change.

Lucius Cary

Page 80: Seven Ineffective Coding Habits of Many Programmers
Page 81: Seven Ineffective Coding Habits of Many Programmers

Uncohesive Tests

Page 82: Seven Ineffective Coding Habits of Many Programmers

Everybody knows that TDD stands for Test Driven Development. However, people too often concentrate on the words "Test" and "Development" and don't consider what the word "Driven" really implies. For tests to drive development they must do more than just test that code performs its required functionality: they must clearly express that required functionality to the reader. That is, they must be clear specifications of the required functionality. Tests that are not written with their role as specifications in mind can be very confusing to read.

Nat Pryce and Steve Freeman "Are Your Tests Really Driving Your Development?"

Page 83: Seven Ineffective Coding Habits of Many Programmers

public class RecentlyUsedList { ... public RecentlyUsedList() ... public int Count { get... } public string this[int index] { get... } public void Add(string newItem) ... ... }

Page 84: Seven Ineffective Coding Habits of Many Programmers

[TestFixture] public class RecentlyUsedListTests { [Test] public void TestConstructor() ... [Test] public void TestCountGet() ... [Test] public void TestIndexerGet() ... [Test] public void TestAdd() ... ... }

Page 85: Seven Ineffective Coding Habits of Many Programmers

method test

test

test

method

method

test

test

Page 86: Seven Ineffective Coding Habits of Many Programmers

namespace RecentlyUsedList_spec { [TestFixture] public class A_new_list { [Test] public void Is_empty() }

[TestFixture] public class An_empty_list { [Test] public void Retains_a_single_addition() [Test] public void Retains_unique_additions_in_stack_order() }

[TestFixture] public class A_non_empty_list { [Test] public void Is_unchanged_when_head_item_is_readded() [Test] public void Moves_non_head_item_to_head_when_it_is_readded() }

[TestFixture] public class Any_list_rejects { [Test] public void Addition_of_null_items() [Test] public void Indexing_past_its_end() [Test] public void Negative_indexing() } }

Page 87: Seven Ineffective Coding Habits of Many Programmers

namespace RecentlyUsedList_spec { [TestFixture] public class A_new_list { [Test] public void Is_empty() }

[TestFixture] public class An_empty_list { [Test] public void Retains_a_single_addition() [Test] public void Retains_unique_additions_in_stack_order() }

[TestFixture] public class A_non_empty_list { [Test] public void Is_unchanged_when_head_item_is_readded() [Test] public void Moves_non_head_item_to_head_when_it_is_readded() }

[TestFixture] public class Any_list_rejects { [Test] public void Addition_of_null_items() [Test] public void Indexing_past_its_end() [Test] public void Negative_indexing() } }

Page 88: Seven Ineffective Coding Habits of Many Programmers

A test case should be just that: it should correspond to a single case.

Page 89: Seven Ineffective Coding Habits of Many Programmers

At some level

the style

becomes the

substance.