Simple Design

103
Simple Design Declan Whelan @dwhelan

Transcript of Simple Design

Simple Design

Declan Whelan@dwhelan

Simple Design

Declan Whelan@dwhelan

“Scrum is not a process ora technique for building products;rather, it is a framework withinwhich you can employ various

processes and techniques.”

Scrum Guide

www.XProgramming.com

red circle contains requirementsred circle contains requirements

green circle crates a container to enable inner practices to be successful

green circle crates a container to enable inner practices to be successful

day-to-day engineering practicesday-to-day engineering practices

Engineering Practices Matter

Simple Design

Simple Design

TestedTested

ClearClear

DryDry

SuccinctSuccinct

Simple Design

TestedTested

ClearClear

DryDry

SuccinctSuccinct

What is TDD?• Simple, high-feedback

incremental coding technique• Write tests as specs, prior

to code• Immediate feedback from

test execution

TDD Rules

1.Test everything that could possibly break.

2.Do not write any production code until you have written the code that will test it.

3.Code is not checked in until all unit tests pass.

TDD Rhythm

Exercise

public static List<SelectOption> createEndDaysList() { List<SelectOption> daysList = new ArrayList<SelectOption>(); Date dt = getCurrentDatePlus14Days(); int day = getDateDay(dt); for (int intLooper = 1; intLooper <= 31; intLooper++) { SelectOption option = new SelectOption(); if (day == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } daysList.add(option); } return daysList;}public static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption> monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}

public static List<SelectOption> createEndDaysList() { List<SelectOption> daysList = new ArrayList<SelectOption>(); Date dt = getCurrentDatePlus14Days(); int day = getDateDay(dt); for (int intLooper = 1; intLooper <= 31; intLooper++) { SelectOption option = new SelectOption(); if (day == intLooper) {

option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true);

} else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false);

} daysList.add(option); } return daysList;}public static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption>

monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option

= new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper));

option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper));

option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}

• Find a Partner

• Write pseudo code for tests you would write

Simple Design

TestedTested

ClearClear

DryDry

SuccinctSuccinct

Exercise

Stroop Effect

Green Red BluePurple Blue Purple

Blue Purple RedGreen Purple Green

The Stroop Effect

first set of words is easy to comprehend.

takes people much longer for people to comprehend the correct meaning in the second case

The Stroop Effect

first set of words is easy to comprehend.

takes people much longer for people to comprehend the correct meaning in the second case

“semantic interference” where naming is incongruent with meaning.

“semantic interference” where naming is incongruent with meaning.

This is because of “semantic facilitation” where name is congruent with meaning.

- people much faster at naming the ink color

This is because of “semantic facilitation” where name is congruent with meaning.

- people much faster at naming the ink color

IDE’s leverage this with syntax colouring.

IDE’s leverage this with syntax colouring.

Green Red BluePurple Blue Purple

blackyellow

Meaning:

Colour:

1. look at top and understand its meaning

2. look at actual coluor

MATCH - if ink colour of bottom word matches word at top

NOMATCH

1. look at top and understand its meaning

2. look at actual coluor

MATCH - if ink colour of bottom word matches word at top

NOMATCH

blueblack

Meaning:

Colour:

blackyellow

yellowred

redyellow

redyellow

blueblue

yellowblue

redred

bluered

yellowyellow

redyellow

redyellow

blueblack

yellowblack

blackblue

redblack

TheEnd

Debrief:

any change as you went longer?

any easier - maybe a little but still very tiring.

Debrief:

any change as you went longer?

any easier - maybe a little but still very tiring.

This is like reading code when you read code and the names of things are incongruent with their meaning,

We have to keep reminding ourselves ‘oh yeah this is the Foo class and it actually does Bar”

This is like reading code when you read code and the names of things are incongruent with their meaning,

We have to keep reminding ourselves ‘oh yeah this is the Foo class and it actually does Bar”

Its WAY harder to understand code that has poorly chosen names.

Its WAY harder to understand code that has poorly chosen names.

We have to choose a lot names esp. with trends towards smaller classes and methods.

We have to choose a lot names esp. with trends towards smaller classes and methods.

A lot of value in putting energy into names

A lot of value in putting energy into names

Choosing Good NamesChoosing Good Names

Choosing Good NamesChoosing Good Names

Use the telephone test for readability. If someone could understand your code when read aloud over the telephone, it's

clear enough. If not, then it needs rewriting.

Telephone TestTelephone Test

Goal Donor vs Gold Owner

Date genymdhmsWe want to promote conversation about code.

We want to promote conversation about code.

Pronounceable NamesAvoid Encodings

Choosing Good NamesChoosing Good Names

UpdatePerfIndValueDecCountCmd

Pronounceable Names

UpdatePerfIndValueDecCountCmd

DecrementAggregateCommand

Pronounceable Names

Date genymdhms

Pronounceable Names

Date genymdhms

Date generatedTimestamp

Pronounceable Names

LPSTR lpCmdLine

m_name

Avoid Encodings

LPSTR commandLine

nameUsed to make sense.

IDEs now help with type and scope - don’t need to have names reflect types.

Used to make sense.

IDEs now help with type and scope - don’t need to have names reflect types.

Not so important to embed types or scope information in the variable.

IDEs help

Not such a problem with small names.

Not so important to embed types or scope information in the variable.

IDEs help

Not such a problem with small names.

Choosing Good NamesChoosing Good Names

Intention-Revealing Name

Role-Suggesting NamePattern to guide each decision.

Derived a pattern for each programming decision he made.

Pattern to guide each decision.

Derived a pattern for each programming decision he made.

Intention-Revealing Name

applyMeasureConstraintTo EnableSortingByMeasure()

Think about method names based on how they will look in calling code. Why was this method invoked and not some other? That is a question that can profitably be answered by the name of the method. The calling method should be telling a story. Name methods so they help tell that story.

Kent Beck - pg 79

Think about method names based on how they will look in calling code. Why was this method invoked and not some other? That is a question that can profitably be answered by the name of the method. The calling method should be telling a story. Name methods so they help tell that story.

Kent Beck - pg 79

Intention-Revealing Name

applyMeasureConstraintTo EnableSortingByMeasure()

applyMeasureConstraint()

Role-Suggesting Name

int result

IndexCardPageLayout sut

Choosing Good NamesChoosing Good Names

Ubiquitous LanguageIf we start using different words we are bound to change the code to match our language.

If we start using different words we are bound to change the code to match our language.

Use names from the problem and solution domain.

Use names from the problem and solution domain.

CComBstr sVal

Ubiquitous Language

CComBstr sVal

CComBstr calibrationToolName

Ubiquitous Language

sVal is terrible.

s implies String which I already know from CComBstr

every variable has a value so Val in name is useless

sVal is terrible.

s implies String which I already know from CComBstr

every variable has a value so Val in name is useless

People are dropping sophisticated tools to measure things in drilled wells.

They calibrate these tools and these tools have name - that’s what that is

People are dropping sophisticated tools to measure things in drilled wells.

They calibrate these tools and these tools have name - that’s what that is

Having bad names in code is costlyHaving bad names in code is costly

Rx rx

Ubiquitous Language

Ask participants!Ask participants! Healthwatch for a pharmacy chain.

Had pharmacists on the team and Rx is the term they would use.

Healthwatch for a pharmacy chain.

Had pharmacists on the team and Rx is the term they would use.

Could be better in terms of role playing ..

e.g. refillable

Could be better in terms of role playing ..

e.g. refillable

People need to know the domain.

The code, via ubiquitous language, helps the team learn the domain

People need to know the domain.

The code, via ubiquitous language, helps the team learn the domain

Rx rx

Rx refillable

Ubiquitous Language

applyPhq9DateRangeConstraint()

Ubiquitous Language

The PHQ-9 is the nine item depression scale of the Patient Health Questionnaire.

The PHQ-9 is a powerful tool for assisting primary care clinicians in diagnosing depression as well as selecting and monitoring treatment.

public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>();

for (int[] x : theList) if (x[0] == 4) list1.add(x);

return list1;}

Source: Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, pages 18-19

The complexity here is not in the code. The complexity is accidental driven by the names used.

The complexity here is not in the code. The complexity is accidental driven by the names used.

Choosing Good NamesChoosing Good Names

public List<int[]> getFlaggedCells() { List<int[]> flaggedCells = new ArrayList<int[]>();

for (int[] cell : gameBoard) if (cell[STATUS_VALUE] == FLAGGED) flaggedCells.add(cell);

return flaggedCells;}

public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>();

for (int[] x : theList) if (x[0] == 4) list1.add(x);

return list1;}

Source: Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, pages 18-19

Ubiquitous language

Using names

Ubiquitous language

Using names

Choosing Good NamesChoosing Good Names

public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<Cell>();

for (Cell cell : gameBoard) if (cell.isFlagged()) flaggedCells.add(cell);

return flaggedCells;}

public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>();

for (int[] x : theList) if (x[0] == 4) list1.add(x);

return list1;}

Source: Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, pages 18-19

Choosing Good NamesChoosing Good Names

public List<Cell> getFlaggedCells() { List<Cell> result = new ArrayList<Cell>();

for (Cell cell : gameBoard) if (cell.isFlagged()) result.add(cell);

return result;}

public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>();

for (int[] x : theList) if (x[0] == 4) list1.add(x);

return list1;}

Source: Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, pages 18-19

Mention use of ‘each’Mention use of ‘each’

Choosing Good NamesChoosing Good Names

Exercise

public static List<SelectOption> createEndDaysList() { List<SelectOption> daysList = new ArrayList<SelectOption>(); Date dt = getCurrentDatePlus14Days(); int day = getDateDay(dt); for (int intLooper = 1; intLooper <= 31; intLooper++) { SelectOption option = new SelectOption(); if (day == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } daysList.add(option); } return daysList;}public static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption> monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}

public static List<SelectOption> createEndDaysList() { List<SelectOption> daysList = new ArrayList<SelectOption>(); Date dt = getCurrentDatePlus14Days(); int day = getDateDay(dt); for (int intLooper = 1; intLooper <= 31; intLooper++) { SelectOption option = new SelectOption(); if (day == intLooper) {

option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true);

} else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false);

} daysList.add(option); } return daysList;}public static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption>

monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option

= new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper));

option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper));

option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}

• Find a Partner• Highlight names you would improve• Write a better name

interloper :)

Simple Design

TestedTested

ClearClear

DryDry

SuccinctSuccinct

DRY: Don’t Repeat YourselfEvery piece of knowledge must have a single, unambiguous, authoritative representation within a system.

Avoiding Duplicate CodeAvoiding Duplicate Code

Once and Only OnceData, structure, or logic should exist in only one place in the system.

Avoiding Duplicate CodeAvoiding Duplicate Code

Test-Driven Development1.Write new code only if an automated test has failed.

2.Eliminate duplication.

Avoiding Duplicate CodeAvoiding Duplicate Code

Single Choice PrincipleWhenever a software system must support a set of alternatives, one and only one module in the system should know their exhaustive list.

Avoiding Duplicate CodeAvoiding Duplicate Code

Duplication may be the root of all evil in software.

Avoiding Duplicate CodeAvoiding Duplicate Code

Copy & Paste

function something() {

}

function something() {

}

function something() {

}

function somethingElse() {

}

function something() {

}

function somethingElse() {

}

function something() {

}

Duplicate Code

Copy & Paste

☞ Duplicate Code

Edit the Copy

Duplicate Code

Avoid duplication by expressing commonality and variability

explicitly.

function somethingElse() {

}

function something() {

}

Exercise

Can you spot the duplicate code?

How would you make the commonality and variation

explicit?

Can you spot the commonality and variation?

public static List<SelectOption> createEndMonthList(Date expiryDate) { int selectedMonth = getDateMonth(expiryDate); SelectOptionsSource months = new SelectOptionsSource(1, 12, selectedMonth); SelectOptions monthOptions = new SelectOptions(months); return monthOptions.create();}public static List<SelectOption> createEndDaysList() { int selectedDay = getDateDay(getCurrentDatePlus14Days()); SelectOptionsSource days = new SelectOptionsSource(1, 31, selectedDay); SelectOptions dayOptions = new SelectOptions(days); return dayOptions.create();}public static List<SelectOption> createEndYearList() { int selectedYear = getDateYear(getCurrentDatePlus14Days()); SelectOptionsSource years = new SelectOptionsSource(1985, 1985 + 30, selectedYear); SelectOptions yearOptions = new SelectOptions(years); return yearOptions.create();}

public static List<SelectOption> createEndMonthList(Date expiryDate) { int selectedMonth = getDateMonth(expiryDate); SelectOptionsSource months = new SelectOptionsSource(1, 12, selectedMonth); SelectOptions monthOptions = new

SelectOptions(months); return monthOptions.create();}public static List<SelectOption> createEndDaysList() { int selectedDay = getDateDay(getCurrentDatePlus14Days());

SelectOptionsSource days = new SelectOptionsSource(1, 31, selectedDay); SelectOptions dayOptions = new SelectOptions(days); return dayOptions.create();}public static

List<SelectOption> createEndYearList() { int selectedYear = getDateYear(getCurrentDatePlus14Days()); SelectOptionsSource years = new

SelectOptionsSource(1985, 1985 + 30, selectedYear); SelectOptions yearOptions = new SelectOptions(years); return yearOptions.create();}

public static List<SelectOption> createEndMonthList(Date expiryDate) { int selectedMonth = getDateMonth(expiryDate); SelectOptionsSource months = new SelectOptionsSource(1, 12, selectedMonth); SelectOptions monthOptions = new SelectOptions(months); return monthOptions.create();}public static List<SelectOption> createEndDaysList() { int selectedDay = getDateDay(getCurrentDatePlus14Days()); SelectOptionsSource days = new SelectOptionsSource(1, 31, selectedDay); SelectOptions dayOptions = new SelectOptions(days); return dayOptions.create();}public static List<SelectOption> createEndYearList() { int selectedYear = getDateYear(getCurrentDatePlus14Days()); SelectOptionsSource years = new SelectOptionsSource(1985, 1985 + 30, selectedYear); SelectOptions yearOptions = new SelectOptions(years); return yearOptions.create();}

public static List<SelectOption> createEndMonthList(Date expiryDate) { int selectedMonth = getDateMonth(expiryDate); SelectOptionsSource months = new SelectOptionsSource(1, 12, selectedMonth); SelectOptions monthOptions = new

SelectOptions(months); return monthOptions.create();}public static List<SelectOption> createEndDaysList() { int selectedDay = getDateDay(getCurrentDatePlus14Days());

SelectOptionsSource days = new SelectOptionsSource(1, 31, selectedDay); SelectOptions dayOptions = new SelectOptions(days); return dayOptions.create();}public static

List<SelectOption> createEndYearList() { int selectedYear = getDateYear(getCurrentDatePlus14Days()); SelectOptionsSource years = new

SelectOptionsSource(1985, 1985 + 30, selectedYear); SelectOptions yearOptions = new SelectOptions(years); return yearOptions.create();}

Select Options

Commonality Variability Resolution

Behaviour Collaborator Encapsulate Collection

Select Options

Commonality Variability Resolution

Data Structure Value of State Simple Java Type

Select Options

Encapsulate Collection

Select Options

ParameterObject

Simple Design

TestedTested

ClearClear

DryDry

SuccinctSuccinct

Single Responsibility PrincipleSingle Responsibility Principle

There should be one and only one reason for a class to change.

SRP ViolationSRP Violation

public class UserSettingService {

public void changeEmail(User user, String email) {

if(checkAccess(user)) {

updateEmail(user, email)

}

}

public boolean checkAccess(User user) {

...

}

public boolean updateEmail(User user, String email) { ... }}

SRP RestoredSRP Restored

public class UserSettingService { private SecurityService securityService; private EmailService emailService; public void changeEmail(User user, String email) {

if(securityService.checkAccess(user)) { emailService.updateEmail(user, email) } }public class SecurityService { public boolean checkAccess(User user) { ... }}public class EmailService {

public boolean updateEmail(User user, String email) {

... }}

Simple Design

TestedTested

ClearClear

DryDry

SuccinctSuccinct

Want More?

Agile Engineering Training KWMarch 17-18, 2015http://bit.ly/aetkwUse ‘p2p’ for 10% discount

ReadingThe Elements of Programming StyleKernighan and Plauger

PrefactoringExtreme Abstraction Extreme Separation Extreme ReadabilityKen Pugh

Agile in a FlashSpeed-Learning Agile DevelopmentJeff Langr and Tim Ottinger

ReadingClean CodeA Handbook of Agile Software CraftsmanshipRobert C. Martin

Domain Driven DesignTackling Complexity in the Heart of SoftwareEric Evans

Implementation PatternsKent Beck

ReadingThe Pragmatic Programmer: From Journeyman to MasterAndrew Hunt and Dave Thomas

Extreme Programming Explained: Embrace ChangeKent Beck and Cynthia Andres

Test Driven Development: By ExampleKent Beck

Object-Oriented Software ConstructionBertrand Meyer

ReadingDesign Patterns: Elements of Reusable Object-Oriented Software Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides

Multi-Paradigm Design for C++James O. Coplien

Lean Architecture: for Agile Software DevelopmentJames O. Coplien and Gertrud Bjørnvig

Photo Credits

http://www.flickr.com/photos/27558040@N00/4151899795/

http://www.flickr.com/photos/popilop/331357312/

http://www.flickr.com/photos/arlette/3260468/

http://www.flickr.com/photos/36829973@N04/3546657245/

http://www.flickr.com/photos/40838054@N00/7261734660/

http://www.flickr.com/photos/93617791@N00/1347587396/

http://www.flickr.com/photos/8281413@N06/5070788991/

http://www.flickr.com/photos/23403402@N00/1197947341/

http://www.flickr.com/photos/54087404@N00/4638056301/

http://en.wikipedia.org/wiki/File:Leghold_trap.JPG

http://www.hostingwiththemostzing.com/?p=12

http://www.flickr.com/photos/36829973@N04/3546657245/

Photo Credits

http://www.flickr.com/photos/42644641@N07/5702962303/

http://www.flickr.com/photos/44124484001@N01/116962927/

http://www.flickr.com/photos/25509772@N00/2951851296/

http://www.flickr.com/photos/49016492@N08/4534101229/

http://www.flickr.com/photos/44123231@N05/5658726857/

http://www.flickr.com/photos/24367734@N00/46452239/

http://www.flickr.com/photos/17001563@N00/2847422081/

http://www.flickr.com/photos/59707463@N00/1312377396/

Photo Credits

Diagram Credits

Lisa Crispin and Janet GregoryAgile Testing: A Practical Guide for Testersand Agile TeamsAddison-Wesley Professional; January 9, 2009.

Mike CohnSucceeding with Agile: Software DevelopmentUsing ScrumAddison-Wesley Professional; November 5, 2009.

Diagram Credits

Jim HighsmithThe Financial Implications of Technical Debthttp://jimhighsmith.com/the-financial-implications-of-technical-debt/

Martin Fowlerhttp://martinfowler.com/bliki/TechnicalDebtQuadrant.html

Jim Highsmith in his article The Financial Implications of Technical Debt, states: