[fdd 2017] mark seemann - humane code

74
Humane Code Mark Seemann http://blog.ploeh.dk @ploeh

Upload: future-processing

Post on 22-Jan-2018

16 views

Category:

Software


4 download

TRANSCRIPT

Page 1: [FDD 2017] Mark Seemann - Humane code

Humane Code

Mark Seemann

http://blog.ploeh.dk

@ploeh

Page 2: [FDD 2017] Mark Seemann - Humane code

@ploeh

Software construction

@ploeh

Page 3: [FDD 2017] Mark Seemann - Humane code

@ploeh

Software development is

not a science

@ploeh

Page 4: [FDD 2017] Mark Seemann - Humane code

@ploeh

Software development is

not engineering@ploeh

Page 5: [FDD 2017] Mark Seemann - Humane code

@ploeh

Measurements

@ploeh

Page 6: [FDD 2017] Mark Seemann - Humane code

@ploeh

Measurements

@ploeh

Page 7: [FDD 2017] Mark Seemann - Humane code

@ploeh

Measurements

Lines of code

Code coverage

Cyclomatic complexity

Afferent coupling

Efferent coupling

@ploeh

Page 8: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class GoldCustomerSpecification : ICustomerSpecification{

public bool IsSatisfiedBy(Customer candidate){

bool retVal;if (candidate.TotalPurchases >= 10000)

retVal = true;else

retVal = false;

return retVal;}

}

Page 9: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class GoldCustomerSpecification : ICustomerSpecification{

public bool IsSatisfiedBy(Customer candidate){

return candidate.TotalPurchases >= 10000;}

}

Page 10: [FDD 2017] Mark Seemann - Humane code

read

written

@ploeh

Code is

more than it’s

Page 11: [FDD 2017] Mark Seemann - Humane code

@ploehhttps://www.flickr.com/photos/adewale_oshineye/2933030620

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”

@ploeh

Page 12: [FDD 2017] Mark Seemann - Humane code

@ploeh

Technology

@ploeh

Page 13: [FDD 2017] Mark Seemann - Humane code

@ploeh

Technology

Page 14: [FDD 2017] Mark Seemann - Humane code

@ploehTechnology

Empathy

Cognition

Psychology

Neuroscience

Page 15: [FDD 2017] Mark Seemann - Humane code

@ploeh

7 items±2

@ploeh

Page 16: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class Odin{

private bool isEven;private string email;private decimal silverThreshold;private decimal z;private bool isValid;private string userName;private decimal y;private Tier tier;private decimal goldThreshold;private decimal x;private decimal totalPurchases;private IEnumerable<int> primes;private decimal goldDiscountRate;private string displayName;private DateTimeOffset t;private decimal silverDiscountRate;private IEnumerable<int> fibonacci;

Page 17: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class Odin{

private bool isEven;private string email;private decimal silverThreshold;private decimal z;

private bool isValid;private string userName;private decimal y;private Tier tier;private decimal goldThreshold;

private decimal x;private decimal totalPurchases;private IEnumerable<int> primes;private decimal goldDiscountRate;

private string displayName;

Page 18: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class Odin{

private string userName;private string displayName;private string email;private Tier tier;private decimal totalPurchases;

private decimal silverThreshold;private decimal silverDiscountRate;private decimal goldThreshold;private decimal goldDiscountRate;

private decimal x;private decimal y;private decimal z;private DateTimeOffset t;

private IEnumerable<int> primes;

Page 19: [FDD 2017] Mark Seemann - Humane code

@ploeh

Code should be humane

@ploeh

Page 20: [FDD 2017] Mark Seemann - Humane code

@ploeh

Productivity?

Page 21: [FDD 2017] Mark Seemann - Humane code

@ploeh

!= typingProductivity

@ploeh

Page 22: [FDD 2017] Mark Seemann - Humane code

@ploeh

read

written

@ploeh

Page 23: [FDD 2017] Mark Seemann - Humane code

@ploeh

Code is a liability

@ploeh

Page 24: [FDD 2017] Mark Seemann - Humane code

@ploeh

Software is an asset

@ploeh

Page 25: [FDD 2017] Mark Seemann - Humane code

@ploeh

Code is a liability

@ploeh

Page 26: [FDD 2017] Mark Seemann - Humane code

@ploeh

What can be done?

Page 27: [FDD 2017] Mark Seemann - Humane code

@ploeh

Abstraction

@ploeh

Page 28: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class GoldCustomerSpecification : ICustomerSpecification{

public bool IsSatisfiedBy(Customer candidate){

return candidate.TotalPurchases >= 10000;}

}

Page 29: [FDD 2017] Mark Seemann - Humane code

@ploeh

.method public hidebysig newslot virtual final instance bool IsSatisfiedBy(class Ploeh.Samples.LoCSample.Customer candidate)

{// Code size 22 (0x16).maxstack 2.locals init ([0] bool V_0)IL_0000: nopIL_0001: ldarg.1IL_0002: callvirt instance int32 Ploeh.Samples.LoCSample.Customer::get_TotalPurchasesIL_0007: ldc.i4 0x2710IL_000c: cltIL_000e: ldc.i4.0IL_000f: ceqIL_0011: stloc.0IL_0012: br.s IL_0014IL_0014: ldloc.0IL_0015: ret

} // end of method GoldCustomerSpecification::IsSatisfiedBy

Page 30: [FDD 2017] Mark Seemann - Humane code

@ploeh

908b e55d c3cc cccc 558b ec83 ec14 33c08945 ec89 4dfc 8955 f88b 05a8 1300 10833800 7405 e88f d7ff ff0f b645 fc89 45f40fb6 45f8 8945 f033 c933 d2e8 c0d6 ffff8945 ecff 75ec 8b4d f48b 55f0 e8b7 d6ffff90 8be5 5dc3 cccc 558b ec57 5683 ec208bf1 8d7d d8b9 0500 0000 33c0 f3ab 8bce894d f489 55f0 8b05 a813 0010 8338 007405e8 32d7 ffff 8b05 1018 0010 8b08 8b5508e8 7ad6 ffff 0fb6 45f0 500f b655 f48b4d08 ff15 3817 0010 8945 ec83 7dec 00755f8b 0dfc 1600 10e8 0cd7 ffff 8945 e88b0dfc 1600 10e8 fed6 ffff 8945 e48b 0db01700 10e8 f0d6 ffff 8945 e08b 45e0 8945dc8b 45e8 8b55 f488 5004 8b45 e889 45d88b45 e48b 55f0 8850 048b 45e4 508b 4ddc8b55 d8e8 10d6 ffff 8b4d e0e8 c8d6 ffff908d 65f8 5e5f 5dc2 0400 cccc 558b ec83ec0c 33c0 8945 f489 4dfc 8955 f88b 05a81300 1083 3800 7405 e87b d6ff ff8b 0db41700 10e8 80d6 ffff 8945 f4ff 75f8 0fb6

Page 31: [FDD 2017] Mark Seemann - Humane code

@ploeh

00000000 00000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 00000000 0000000000000000 00000000 01010000 01000101 00000000 0000000001001100 00000001 00000100 00000000 10101001 1110111100100101 01010110 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 11100000 0000000000000010 00100001 00001011 00000001 00001011 0000000000000000 00000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00010000 00000000 0001000000000000 00000000 00000000 00000010 00000000 0000000000000101 00000000 00000000 00000000 00000000 0000000000000000 00000000 00000101 00000000 00000000 0000000000000000 00000000 00000000 00000000 00000000 1001000000000000 00000000 00000000 00000100 00000000 0000000000000000 00000000 00000000 00000000 00000011 0000000001000000 10000101 00000000 00000000 00000000 00000000

Page 32: [FDD 2017] Mark Seemann - Humane code

@ploeh

Page 33: [FDD 2017] Mark Seemann - Humane code

@ploeh

Page 34: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class GoldCustomerSpecification : ICustomerSpecification{

public bool IsSatisfiedBy(Customer candidate){

return candidate.TotalPurchases >= 10000;}

}

Page 35: [FDD 2017] Mark Seemann - Humane code

@ploeh

Abstraction

@ploeh

Page 36: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class MethodInvoker : ISpecimenBuilder{

private readonly IMethodQuery query;

public MethodInvoker(IMethodQuery query){

if (query == null){

throw new ArgumentNullException("query");}

this.query = query;}

public IMethodQuery Query{

get { return this.query; }}

public object Create(object request, ISpecimenContext context){

if (context == null){

throw new ArgumentNullException("context");}

foreach (var ci in this.GetConstructors(request)){

var paramValues = (from pi in ci.Parametersselect context.Resolve(pi)).ToList();

if (paramValues.All(MethodInvoker.IsValueValid)){

return ci.Invoke(paramValues.ToArray());}

}

return new NoSpecimen(request);}

private IEnumerable<IMethod> GetConstructors(object request){

var requestedType = request as Type;if (requestedType == null){

return Enumerable.Empty<IMethod>();}

return this.query.SelectMethods(requestedType);}

private static bool IsValueValid(object value){

return !(value is NoSpecimen)&& !(value is OmitSpecimen);

}}

Page 37: [FDD 2017] Mark Seemann - Humane code

@ploeh

public class MethodInvoker : ISpecimenBuilder{

private readonly IMethodQuery query;

public MethodInvoker(IMethodQuery query){

if (query == null){

throw new ArgumentNullException("query");}

this.query = query;}

public IMethodQuery Query{

get { return this.query; }}

public object Create(object request, ISpecimenContext context){

if (context == null){

throw new ArgumentNullException("context");}

foreach (var ci in this.GetConstructors(request)){

var paramValues = (from pi in ci.Parametersselect context.Resolve(pi)).ToList();

if (paramValues.All(MethodInvoker.IsValueValid)){

return ci.Invoke(paramValues.ToArray());}

}

return new NoSpecimen(request);}

private IEnumerable<IMethod> GetConstructors(object request){

var requestedType = request as Type;if (requestedType == null){

return Enumerable.Empty<IMethod>();}

return this.query.SelectMethods(requestedType);}

private static bool IsValueValid(object value){

return !(value is NoSpecimen)&& !(value is OmitSpecimen);

}} @ploeh

Encapsulation

Page 38: [FDD 2017] Mark Seemann - Humane code

@ploeh

“An abstraction is the amplification of the essentialand the elimination of the irrelevant.”

https://commons.wikimedia.org/wiki/File:Robert_Cecil_Martin.png @ploeh

Page 39: [FDD 2017] Mark Seemann - Humane code

@ploeh

the amplification of the irrelevantand the elimination of the essential

@ploeh

Page 40: [FDD 2017] Mark Seemann - Humane code

@ploeh

“An abstraction is the amplification of the essentialand the elimination of the irrelevant.”

@ploeh

Page 41: [FDD 2017] Mark Seemann - Humane code

@ploeh

What is the value of cust.Tier?

var cust =new Customer{

Tier = Tier.Silver,TotalPurchases = 20000

};

var orders = GetOrders(cust);

1

2

Page 42: [FDD 2017] Mark Seemann - Humane code

@ploeh

public IReadOnlyCollection<Order> GetOrders(Customer customer){

Adjust(customer);return RetrieveOrdersFromDatabase(customer);

}

private static void Adjust(Customer customer){

if (customer.TotalPurchases >= 10000)customer.Tier = Tier.Gold;

// Many more similar checks go here...}

Page 43: [FDD 2017] Mark Seemann - Humane code

@ploeh

public IReadOnlyCollection<Order> GetOrders(Customer customer){

Adjust(customer);return RetrieveOrdersFromDatabase(customer);

}

private static void Adjust(Customer customer){

if (customer.TotalPurchases >= 10000)customer.Tier = Tier.Gold;

if (customer.RecentOrders <= 0)customer.NeedsPromo = true;

if (customer.LovesHaskell)customer.Segment = Segment.Omg;

Page 44: [FDD 2017] Mark Seemann - Humane code

@ploeh

{Adjust(customer);return RetrieveOrdersFromDatabase(customer);

}

private static void Adjust(Customer customer){

if (customer.TotalPurchases >= 10000)customer.Tier = Tier.Gold;

if (customer.RecentOrders <= 0)customer.NeedsPromo = true;

if (customer.LovesHaskell)customer.Segment = Segment.Omg;

if (customer.TotalPurchases >= 20000)customer.Tier = Tier.Platinum;

if (customer.RecentOrders <= 0)

Page 45: [FDD 2017] Mark Seemann - Humane code

@ploeh

private static void Adjust(Customer customer){

if (customer.TotalPurchases >= 10000)customer.Tier = Tier.Gold;

if (customer.RecentOrders <= 0)customer.NeedsPromo = true;

if (customer.LovesHaskell)customer.Segment = Segment.Omg;

if (customer.TotalPurchases >= 20000)customer.Tier = Tier.Platinum;

if (customer.RecentOrders <= 0)customer.Tier = Tier.Basic;

if (customer.KnowsCobol)customer.Segment = Segment.Employable;

Page 46: [FDD 2017] Mark Seemann - Humane code

@ploeh

public IReadOnlyCollection<Order> GetOrders(Customer customer){

Adjust(customer);return RetrieveOrdersFromDatabase(customer);

}

private static void Adjust(Customer customer){

if (customer.TotalPurchases >= 10000)customer.Tier = Tier.Gold;

if (customer.RecentOrders <= 0)customer.NeedsPromo = true;

if (customer.LovesHaskell)customer.Segment = Segment.Omg;

Page 47: [FDD 2017] Mark Seemann - Humane code

@ploeh

Some code forces you to read it

Page 48: [FDD 2017] Mark Seemann - Humane code

@ploeh

Nothumane

Page 49: [FDD 2017] Mark Seemann - Humane code

@ploeh

read

written

@ploeh

Page 50: [FDD 2017] Mark Seemann - Humane code

@ploeh

Nothumane

Page 51: [FDD 2017] Mark Seemann - Humane code

@ploeh

How can we make code more humane?

@ploeh

Page 52: [FDD 2017] Mark Seemann - Humane code

@ploeh

Command Query Separation

Example

Page 53: [FDD 2017] Mark Seemann - Humane code

@ploeh

Commandschange the state of the system

Queriesreturn data

An operation should be either a Command or a Query but not both

Page 54: [FDD 2017] Mark Seemann - Humane code

@ploeh

change the state of the system

private static void Adjust(Customer customer){

if (customer.TotalPurchases >= 10000)customer.Tier = Tier.Gold;

// Many more similar checks go here...}

Commands

Page 55: [FDD 2017] Mark Seemann - Humane code

@ploeh

public IReadOnlyCollection<Order> GetOrders(Customer customer){

// Adjust(customer);return RetrieveOrdersFromDatabase(customer);

}

Queriesreturn data

Page 56: [FDD 2017] Mark Seemann - Humane code

@ploeh

public IReadOnlyCollection<Order> GetOrders(Customer customer){

Adjust(customer);return RetrieveOrdersFromDatabase(customer);

}

Page 57: [FDD 2017] Mark Seemann - Humane code

@ploeh

Command Query SeparationJust one example

Challenging enough already

Page 58: [FDD 2017] Mark Seemann - Humane code

@ploeh

Command Query Separation

Page 59: [FDD 2017] Mark Seemann - Humane code

@ploehReused Abstractions Principle

Command Query Separation

Liskov Substitution PrincipleInterface Segregation Principle

Dependency Inversion Principle

Separation of Concerns

Single Responsibility PrincipleCohesion

You Aren’t Going to Need It

Open Closed Principle Law of Demeter

Principle of Least Surprise

Don’t Repeat YourselfHollywood Principle

Page 60: [FDD 2017] Mark Seemann - Humane code

@ploeh

There are many waysto do thingsif you know them

Page 61: [FDD 2017] Mark Seemann - Humane code

@ploeh@ploeh

Page 62: [FDD 2017] Mark Seemann - Humane code

@ploeh@ploeh

Page 63: [FDD 2017] Mark Seemann - Humane code

@ploeh@ploeh

Page 64: [FDD 2017] Mark Seemann - Humane code

@ploeh

read

written

@ploeh

Page 65: [FDD 2017] Mark Seemann - Humane code

@ploeh

Code should be humane

@ploeh

Page 66: [FDD 2017] Mark Seemann - Humane code

@ploeh

The more code you have, the

worse

Programming is mostly a soft skill

Programming is learning,

thinking, and teaching

@ploeh

Page 67: [FDD 2017] Mark Seemann - Humane code

@ploeh

The more code you have, the

worse

Programming is mostly a soft skill

Programming is learning,

thinking, and teaching

@ploeh

Page 68: [FDD 2017] Mark Seemann - Humane code

@ploeh

The more code you have, the

worse

Programming is mostly a soft skill

Programming is learning,

thinking, and teaching

@ploeh

Page 69: [FDD 2017] Mark Seemann - Humane code

@ploeh

The more code you have, the

worse

Programming is mostly a soft skill

Programming is learning,

thinking, and teaching

@ploeh

Page 70: [FDD 2017] Mark Seemann - Humane code

@ploeh

Page 71: [FDD 2017] Mark Seemann - Humane code

@ploeh

Page 72: [FDD 2017] Mark Seemann - Humane code

@ploeh

Page 73: [FDD 2017] Mark Seemann - Humane code

@ploeh

Page 74: [FDD 2017] Mark Seemann - Humane code

@ploeh

Mark Seemann

http://blog.ploeh.dk

http://bit.ly/clean-humane-code

http://bit.ly/ploehralsight

@ploeh