25
How to write clean code using TDD Srinivasa GV [email protected] SAP Labs India

Agile_goa_2013_clean_code_tdd

Embed Size (px)

Citation preview

Page 1: Agile_goa_2013_clean_code_tdd

How to write clean code

using TDD

Srinivasa GV

[email protected]

SAP Labs India

Page 2: Agile_goa_2013_clean_code_tdd

Agenda 1. What is Clean Code ?

2. Some basics on Clean Code

3. What is TDD?

4. Fundamentals of TDD

5. Demo of TDD with Clean Code

Page 3: Agile_goa_2013_clean_code_tdd

3

Some definitions of Clean Code 1

Dave Thomas – godfather of the Eclipse

strategy: Clean code can be read, and

enhanced by a developer other than its

original author. It has unit and acceptance

tests. It has meaningful names.

1 Robert C. Martin Clean Code Prentice Hall

Page 4: Agile_goa_2013_clean_code_tdd

4

Thought leaders definition…

Grady Booch – author of OOAD with

applications: Clean code is simple and

direct. Clean code reads like well-written

prose and never obscures the designer’s

intent

Page 5: Agile_goa_2013_clean_code_tdd

5

Thought leaders definition…

Bjarne Stroustrup – inventor of C++:

Clean code does one thing well.

Page 6: Agile_goa_2013_clean_code_tdd

6

Why Clean Code ? – A story

Ram opens the project and enters the class.

He scrolls down to the method needing change.

He pauses, considering his options.

Oh, he’s scrolling up to the top of the function to check the initialization of a variable.

Now he scrolls back down and begins to type. Ooops, he’s erasing what he typed!

He types it again.

He erases it again!

He types half of something else but then erases that!

Page 7: Agile_goa_2013_clean_code_tdd

7

..

He scrolls down to another function that calls the function he’s changing to see

how it is called.

He scrolls back up and types the same code he just erased.

He pauses.

He erases that code again!

He pops up another window and looks at a subclass. Is that function

overridden?

Reading vs Writing ratio is > 10:1

Page 8: Agile_goa_2013_clean_code_tdd

8

Clean Codes

Meaningful Names

Functions

Comments

Formatting

Classes

Page 9: Agile_goa_2013_clean_code_tdd

9

Meaningful Names

Class Names

Classes and objects should have noun or noun phrase names

like Customer, WikiPage, Account, and AddressParser.

Avoid words likeManager, Processor, Data, or Info in the name of a class. A class name

should not be a verb.

Method Names

Methods should have verb or verb phrase names like postPayment, deletePage, or save.

Accessors, mutators, and predicates should be named for their value and prefixed

with get, set, and is according to the javabean standard.[4]

[4] http://java.sun.com/products/javabeans/docs/spec.html

Page 10: Agile_goa_2013_clean_code_tdd

10

Functions/Methods

One level of abstraction per Function:

Functions should do one thing. They should do it well. They should do it only.

Functions need to be short, well named and nicely organized.

Page 11: Agile_goa_2013_clean_code_tdd

11

An example

Bad Code Good Code

HTMLUtil.java

public static String testableHtmlContent(

PageData pageData,

boolean includeSuiteSetup

) throws Exception {

WikiPage wikiPage = pageData.getWikiPage();

StringBuffer buffer = new StringBuffer();

if (pageData.hasAttribute("Test")) {

if (includeSuiteSetup) {

WikiPage suiteSetup =

PageCrawlerImpl.getInheritedPage(

SuiteResponder.SUITE_SETUP_NAME, wikiPage

);

if (suiteSetup != null) {

WikiPagePath pagePath =

suiteSetup.getPageCrawler().getFullPath(suiteSetup);

String pagePathName = PathParser.render(pagePath);

buffer.append("!include -setup .")

.append(pagePathName)

.append("\n");

}

}

WikiPage setup =

PageCrawlerImpl.getInheritedPage("SetUp", wikiPage);

if (setup != null) {

WikiPagePath setupPath =

wikiPage.getPageCrawler().getFullPath(setup);

String setupPathName = PathParser.render(setupPath);

buffer.append("!include -setup .")

.append(setupPathName)

……

……....

………………………………..ANOTHER 40 more lines

HTMLUtil.java

public static String renderPageWithSetupsAndTeardowns(

PageData pageData, boolean isSuite

) throws Exception {

boolean isTestPage = pageData.hasAttribute("Test");

if (isTestPage) {

WikiPage testPage = pageData.getWikiPage();

StringBuffer newPageContent = new StringBuffer();

includeSetupPages(testPage, newPageContent, isSuite);

newPageContent.append(pageData.getContent());

includeTeardownPages(testPage, newPageContent, isSuite);

pageData.setContent(newPageContent.toString());

}

return pageData.getHtml();

}

ANOTHER 3 MORE FUNCTIONS

includeSetupPages,

newPageContnet,

includeTearDownPages

Page 12: Agile_goa_2013_clean_code_tdd

12

Comments

Try to avoid comments except for absolute minimum required

Explain Yourself in Code – write expressive code

// Check to see if the student is eligible for full marks

if ((student.flags & YEARLY_FLAG) &&

(student.attendance > 200))

if (student.isEligibleForFullMarks())

Page 13: Agile_goa_2013_clean_code_tdd

13

Formatting

Code formatting is important – it’s because code communicates

Vertical Formatting - The topmost parts of the source file should provide the high-

level concepts and algorithms (Vertical openness, Vertical Density, Vertical

Distance, Vertical Ordering)

Horizontal Formatting (Horizontal openness and Density, Indentation)

Page 14: Agile_goa_2013_clean_code_tdd

14

An example for vertical openness between concepts

Good Code Bad Code

package fitnesse.wikitext.widgets;

import java.util.regex.*;

public class BoldWidget extends ParentWidget {

public static final String REGEXP = "'''.+?'''";

private static final Pattern pattern = Pattern.compile("'''(.+?)'''",

Pattern.MULTILINE + Pattern.DOTALL

);

public BoldWidget(ParentWidget parent, String text) throws Exception {

super(parent);

Matcher match = pattern.matcher(text);

match.find();

addChildWidgets(match.group(1));

}

public String render() throws Exception {

StringBuffer html = new StringBuffer("<b>");

html.append(childHtml()).append("</b>");

return html.toString();

}

}

package fitnesse.wikitext.widgets;

import java.util.regex.*;

public class BoldWidget extends ParentWidget {

public static final String REGEXP = "'''.+?'''";

private static final Pattern pattern = Pattern.compile("'''(.+?)'''",

Pattern.MULTILINE + Pattern.DOTALL);

public BoldWidget(ParentWidget parent, String text) throws Exception {

super(parent);

Matcher match = pattern.matcher(text);

match.find();

addChildWidgets(match.group(1));}

public String render() throws Exception {

StringBuffer html = new StringBuffer("<b>");

html.append(childHtml()).append("</b>");

return html.toString();

}

}

Page 15: Agile_goa_2013_clean_code_tdd

15

Classes

Classes Should Be Small

It’s not about the number of lines, but about the number of responsibilities

Classes should have one responsibility—one reason to change.

Cohesion

Classes should have a small number of instance variables. Each of the methods of

a class should manipulate one or more of those variables.

Follow S.O.L.I.D principles (Single responsibility, Open/Closed, Liskov

Substitution, Interface Segregation, Dependency Injection)

Page 16: Agile_goa_2013_clean_code_tdd

16

An example for Single Responsiblity

Source:

http://www.globalnerdy.com

Page 17: Agile_goa_2013_clean_code_tdd

Test Driven Development

“Accountants practice Dual Entry Bookkeeping as part of the GAAP1

TDD is Dual Entry Bookkeeping for software”

Robert C Martin

Page 18: Agile_goa_2013_clean_code_tdd

Test First – Test Driven Development

TDD Cycle

1. Write a failing test

2. Write the code to pass the test

3. Clean up / Refactor

(either production or test code)

Start

Test

Code

Test

Refactor

Page 19: Agile_goa_2013_clean_code_tdd

Test Driven Development

Demo

Page 20: Agile_goa_2013_clean_code_tdd

Test Driven Development Demo

User Story:

Roman to Arabic Numerals Conversion

As a user who imports external documents into the system I want the system to convert

Roman numerals into Arabic values (e.g. year numerals or list numbers) so that searching

and ordering is possible.

Additional Info:

The system shall deal with roman numerals as described in wikipedia

The system shall deal with the range from I (1) to MMM (3000)

Acceptance Criteria:

The system will convert MCMLXXXIV to 1984

Page 21: Agile_goa_2013_clean_code_tdd

TDD Benefits I

Focus on Essentials since

tests codify requirements

test drives feature implementation

you build the simplest thing that is

needed right now

Confidence

safety net

encourages changes

bug repellent

Page 22: Agile_goa_2013_clean_code_tdd

TDD Benefits II

Better Code Quality

Consumable API

Decoupling and testability

Living Technical Documentation

Tests as executable specification

Tests document usage of API

Page 23: Agile_goa_2013_clean_code_tdd

Which benefits did you observe?

Expected: Test driven development –

– tests and productive coding are created in parallel – in small steps ; steps are like how we analyze the problem

– 100% coverage by default

– TDD Cycle: Green – Red – Green – Refactor

– debugger wasn’t required

– Self validating tests

Code Quality

– Easy to read

Continuous Integration

– Software was executable all the time

Refactoring

– Avoid Technical Debt

– The refactoring to get checks for invalid numbers was always secured by existing unit tests.

Page 24: Agile_goa_2013_clean_code_tdd

Thank you !

Contact: [email protected] / M: 9741594154

Page 25: Agile_goa_2013_clean_code_tdd

25

References

Test – Driven Development By example – Kent Beck

Clean Code A Handbook of Agile Software Craftsmanship – Robert C. Martin

Refactoring Improving the design of Existing Code – Martin Fowler