Keep Code Left - How to write better code in almost any language

Post on 17-Jul-2015

272 views 2 download

Transcript of Keep Code Left - How to write better code in almost any language

Keep Code Left

Mick Andrew

GGMUG

January 8th 2015

2

Speaker Background

• Developing code or managing developers for 25+ years

• .Net developer since 2000

• Unix/C, some Java, some Javascript

• Director of Development at Sage

– Sage is hiring …. Check us out at www.sage.com

3

Agenda

• Can one hour help you write better code?

• The approach of Keep Code Left

• How do this help in Code Reviews?

• Reading the whole code

• Examples

• Worked examples on real production code

• Questions and Discussions welcome throughout the

talk!

4

Keep Code Left

• A style of writing code for better readability

• Goal of KCL is to provide easy-to-apply rules which

foster

– simpler code logic

– which is easier to read

– and leads to fewer bugs during future maintenance

– Simple verification at review time

• Enables us to write code with simpler logic

• Learn to read many lines of code at once

– See the flow

5

Code Reviews / Inspections / Walkthroughs

• There are at least three independent goals for code reviews:– Share knowledge

– Look for bugs

– Verify standards compliance

• These can be in conflict; dependencies on the reviewing team’s..– Domain knowledge

– Coding skill level

– Personalities

• Standards compliance is the easiest to apply effectively– Less dependencies on individual skills

– Spot patterns/anti-patterns without specific domain knowledge

• KCL provides a cookbook approach to assist at both... – the time of coding, and

– for reviewing with no domain knowledge necessary

6

KCL: Claims and Mindset

• Ideal code has no branches (if statements)

– Few real-world methods are ideal!

• The one “main purpose” of any method should be in code

which is not indented

• If you need to branch, think about why

• Equivalent branch statements can be written several ways

if (condition == true)if (!condition == false)

– Think about which way you should write any boolean expression

– e.g. if (i > j) versus if (j <= i)

– What should be in the then clause versus the elseclause… and do you need the else clause anyway?

7

Let’s review some code:

what happens in the else?

Methoda();Methodb();

// Some useful commentvar foo = new Whatever(s);string s = Getastring(foo);

int x = DoSomething(s);x = Manipulate(x);return x;

}

int DoSomething(string s){

if (s != null){

ImportantMethod (s);int rc = SomethingElse(s);return modify(rc);

}else{

8

We scroll up a bit:

int x = DoSomething(s);x = Manipulate(x);return x;

}

int DoSomething(string s){

if (s != null){

ImportantMethod(s);int rc = SomethingElse(s);return modify(rc);

}else{

throw new ArgumentException("null string");}

}

9

Let’s review the same logic with KCL

Before..

Methoda();Methodb();

// Some useful commentvar foo = new Whatever(s);string s = Getastring(foo);

int x = DoSomething(s);x = Manipulate(x);return x;

}

int DoSomething(string s){

if (s != null){

ImportantMethod(s);int rc = SomethingElse(s);return modify(rc);

}else{

10

Let’s review the same logic with KCL

After..

Methoda();Methodb();

// Some useful commentvar foo = new Whatever(s);string s = Getastring(foo);

int x = DoSomething(s);x = Manipulate(x);return x;

}

int DoSomething(string s){

if (s == null)throw new ArgumentException("null string");

ImportantMethod(s);int rc = SomethingElse(s);return modify(rc);

}

11

KCL: anti-patterns

• This example show how branch (if) statements are often coded poorly in code samples (and real code!!)

int DoSomething(string s){

if (s != null){

Something1(s);int rc = Something2(s);return modify(rc);

}else{

throw new ArgumentException("null string");}

}

This is the main body of the

code but it is indented in an if

statement

Why is this condition coded the way it is?

It pushes the main body to the right – anti-pattern

This is a Keep Code Left anti-pattern:

A standalone return or throw in an else block

2

3

1

12

Let’s fix it – Introducing the Filter

pattern

• The first statement in the example method causes all

of our problems. By inverting the if condition we can

apply a KCL pattern called a Filter

int DoSomething(string s)

{

if (s == null)

throw new ArgumentException("null string");

Something1(s);

int rc = Something2(s);

return rc;

}

We have made a Filter. The code “filters out”

non-interesting cases which do not qualify for the

body of the method to be applied. Get out of the

method as quickly as possible

1

Body of the method is now

completely left, with no

branching.

2

13

Examples of good KCL layout

if (condition)return;

if (condition)return;

code;code;code;return;

if (condition)return;

code;while (condition){

if (condition)continue;

code;code;if (condition)

break;code;code;

}return;

if (condition)return;

code;code;if (condition)

return;code;code;return;

14

Examples of KCL red flag layout

if (condition){

code;code;code;

}else{

return error;}

code;return typical-case;

if (condition){

if (condition){

code;code;code;code;

}else{

code;}

}else{

code;}

if (condition){

code;code;code;

}else{

return error;}

if (condition)return typical-case;

return error;

15

Keep Code Left rules

• Keep Code Left is for almost any language.

• Filter out uninteresting or inapplicable cases at the start of the method. – Often return null, zero, false, or empty objects.

• Filter out more cases as soon as possible– Good KCL code will start with filters, then some logic, then more filters, then more logic,

keeping most of the code left.

• Keep the main body of the code with as few branches as possible. Keep it to the left.

• Think about each if condition. Should it be inverted?

• Avoid the else keyword (is it really necessary?)

• return statements should always be in the “then” part of a branch, rarely in the else.

• Put smaller code blocks in the then clause. Don’t leave “hidden” elseclauses after long then clauses.

• Apply Keep Code Left rules in loops, using the continue and break statements.

– Filter conditions out for each iteration of the loop.

• Look at the code as a whole. Use your eyes to see the structure of several lines all at once. (Practice!)

– Do this when reviewing all code.

16

… as with all “rules”

• Look to apply them in all cases…

• BUT!

• Be happy with applying the 80/20 rule

– Don’t throw out the approach because you find a difficult case

– KCL does not solve every programming problem

– “red flag” doesn’t mean its wrong… just that it might be, and

is a good place to examine

– Don’t use an exception case as an excuse to discard the

entire approach

17

Keep Code Left red flags

• Watch for these code patterns and statements

– while you are writing code

– When you are code reviewing (easier than reviewing the

logic!)

• if statements which contain many lines of code

• else statements(!)

• else statements which contain one or two lines, often

error handling.

• Methods which end with return 0/false/null/throw exception/empty objects;

– methods should end with the goal, not an error case

• Code with lots of braces{ { { } } }

18

See all the code at once

• Look at the code in the next two slides and see which

you can grasp as a whole, rather than line-by-line

• How easily can you see the “goal” of this code?

19

Sample A

public static void KeepCodeLeft()

{

foreach (var id in tmpArr)

{

var item = Sitecore.Context.Database.GetItem(id);

if (item != null)

{

MultilistField mf = item.Fields["Templates"];

if (mf != null)

{

foreach (var targetId in mf.TargetIDs)

{

var targetItem = Sitecore.Context.Database.GetItem(targetId);

if (targetItem != null && !string.IsNullOrEmpty(targetItem["Template"]))

{

listContentTypes.Add(targetItem["Template"]);

}

}

}

}

}

}

20

Sample B

public static void KeepCodeLeft()

{

foreach (var id in tmpArr)

{

var item = Sitecore.Context.Database.GetItem(id);

if (item == null)

continue;

MultilistField mf = item.Fields["Templates"];

if (mf == null)

continue;

foreach (var targetId in mf.TargetIDs)

{

var targetItem = Sitecore.Context.Database.GetItem(targetId);

if (targetItem == null || string.IsNullOrEmpty(targetItem["Template"]))

continue;

listContentTypes.Add(targetItem["Template"]);

}

}

}

21

Refactoring for KCL

• If the code is working, think carefully before

refactoring just to satisfy any preferred coding style

– even KCL !

• Refactor when you are modifying the code for another

reason

– Bug fix

– Enhancement

• Whenever you refactor

– TEST

– TEST

– TEST!

22

Lets refactor some real code!

23

Questions?

• Share good examples

• Share problem cases

• Mick Andrew

• mick.andrew@sage.com

• http://www.linkedin.com/in/mickan

• http://www.slideshare.net

– Search for “Keep Code Left”