Humane Code
Mark Seemann
http://blog.ploeh.dk
@ploeh
@ploeh
Software construction
@ploeh
@ploeh
Software development is
not a science
@ploeh
@ploeh
Software development is
not engineering
@ploeh
@ploeh
Measurements
@ploeh
@ploeh
Measurements
@ploeh
@ploeh
Measurements
Lines of code
Code coverage
Cyclomatic complexity
Afferent coupling
Efferent coupling
@ploeh
@ploeh
public class GoldCustomerSpecification : ICustomerSpecification
{
public bool IsSatisfiedBy(Customer candidate)
{
bool retVal;
if (candidate.TotalPurchases >= 10000)
retVal = true;
else
retVal = false;
return retVal;
}
}
@ploeh
public class GoldCustomerSpecification : ICustomerSpecification
{
public bool IsSatisfiedBy(Customer candidate)
{
return candidate.TotalPurchases >= 10000;
}
}
read
written
@ploeh
Code is
more than it’s
@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
@ploeh
Technology
@ploeh
@ploeh
Technology
@ploeh
Technology
Empathy
Cognition
Psychology
Neuroscience
@ploeh
7 items
±2
@ploeh
@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;
@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;
@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;
@ploeh
Code should be humane
@ploeh
@ploeh
Productivity?
@ploeh
!= typingProductivity
@ploeh
@ploeh
read
written
@ploeh
@ploeh
Code is a liability
@ploeh
@ploeh
Software is an asset
@ploeh
@ploeh
Code is a liability
@ploeh
@ploeh
What can be done?
@ploeh
Abstraction
@ploeh
@ploeh
public class GoldCustomerSpecification : ICustomerSpecification
{
public bool IsSatisfiedBy(Customer candidate)
{
return candidate.TotalPurchases >= 10000;
}
}
@ploeh
.method public hidebysig newslot virtual final
instance bool IsSatisfiedBy(class Ploeh.Samples.LoCSample.Customer ca
{
// Code size 22 (0x16)
.maxstack 2
.locals init ([0] bool V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: callvirt instance int32 Ploeh.Samples.LoCSample.Customer::get_
IL_0007: ldc.i4 0x2710
IL_000c: clt
IL_000e: ldc.i4.0
IL_000f: ceq
IL_0011: stloc.0
IL_0012: br.s IL_0014
IL_0014: ldloc.0
IL_0015: ret
} // end of method GoldCustomerSpecification::IsSatisfiedBy
@ploeh
8945 ec89 4dfc 8955 f88b 05a8 1300 1083
3800 7405 e88f d7ff ff0f b645 fc89 45f4
0fb6 45f8 8945 f033 c933 d2e8 c0d6 ffff
8945 ecff 75ec 8b4d f48b 55f0 e8b7 d6ff
ff90 8be5 5dc3 cccc 558b ec57 5683 ec20
8bf1 8d7d d8b9 0500 0000 33c0 f3ab 8bce
894d f489 55f0 8b05 a813 0010 8338 0074
05e8 32d7 ffff 8b05 1018 0010 8b08 8b55
08e8 7ad6 ffff 0fb6 45f0 500f b655 f48b
4d08 ff15 3817 0010 8945 ec83 7dec 0075
5f8b 0dfc 1600 10e8 0cd7 ffff 8945 e88b
0dfc 1600 10e8 fed6 ffff 8945 e48b 0db0
1700 10e8 f0d6 ffff 8945 e08b 45e0 8945
dc8b 45e8 8b55 f488 5004 8b45 e889 45d8
8b45 e48b 55f0 8850 048b 45e4 508b 4ddc
8b55 d8e8 10d6 ffff 8b4d e0e8 c8d6 ffff
908d 65f8 5e5f 5dc2 0400 cccc 558b ec83
ec0c 33c0 8945 f489 4dfc 8955 f88b 05a8
1300 1083 3800 7405 e87b d6ff ff8b 0db4
@ploeh
00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 01010000 01000101 00000000 00000000
01001100 00000001 00000100 00000000 10101001 11101111
00100101 01010110 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 11100000 00000000
00000010 00100001 00001011 00000001 00001011 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00010000 00000000 00010000
00000000 00000000 00000000 00000010 00000000 00000000
00000101 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000101 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 10010000
00000000 00000000 00000000 00000100 00000000 00000000
00000000 00000000 00000000 00000000 00000011 00000000
@ploeh
@ploeh
@ploeh
public class GoldCustomerSpecification : ICustomerSpecification
{
public bool IsSatisfiedBy(Customer candidate)
{
return candidate.TotalPurchases >= 10000;
}
}
@ploeh
Abstraction
@ploeh
@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.Parameters
select 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
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.Parameters
select 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
@ploeh
“An abstraction is
the amplification
of the essential
and the
elimination of the
irrelevant.”
https://commons.wikimedia.org/wiki/
File:Robert_Cecil_Martin.png @ploeh
@ploeh
the amplification
of the irrelevant
and the
elimination of the
essential
@ploeh
@ploeh
“An abstraction is
the amplification
of the essential
and the
elimination of the
irrelevant.”
@ploeh
@ploeh
What is the value of cust.Tier?
var cust =
new Customer
{
Tier = Tier.Silver,
TotalPurchases = 20000
};
var orders = GetOrders(cust);
1
2
@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...
}
@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)
@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;
@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)
@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)
@ploeh
Some code forces you to read it
@ploeh
Not
humane
@ploeh
read
written
@ploeh
@ploeh
Not
humane
@ploeh
How can we make code more humane?
@ploeh
@ploeh
Command Query Separation
Example
@ploeh
Commands
change the state
of the system
Queries
return data
An operation should be either a
Command or a Query but not both
@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
@ploeh
public IReadOnlyCollection<Order> GetOrders(Customer customer)
{
// Adjust(customer);
return RetrieveOrdersFromDatabase(customer);
}
Queries
return data
@ploeh
public IReadOnlyCollection<Order> GetOrders(Customer customer)
{
Adjust(customer);
return RetrieveOrdersFromDatabase(customer);
}
@ploeh
Command Query Separation
Just one example
Challenging enough already
@ploeh
Command Query Separation
@ploehReused Abstractions Principle
Command Query Separation
Liskov Substitution Principle
Interface 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
@ploeh
There are many ways
to do things
if you know them
@ploeh@ploeh
@ploeh@ploeh
@ploeh@ploeh
@ploeh
read
written
@ploeh
@ploeh
Code should be humane
@ploeh
@ploeh
The more
code you
have, the
worse
Programming
is mostly a
soft skill
Programming
is learning,
thinking, and
teaching
@ploeh
@ploeh
The more
code you
have, the
worse
Programming
is mostly a
soft skill
Programming
is learning,
thinking, and
teaching
@ploeh
@ploeh
The more
code you
have, the
worse
Programming
is mostly a
soft skill
Programming
is learning,
thinking, and
teaching
@ploeh
@ploeh
The more
code you
have, the
worse
Programming
is mostly a
soft skill
Programming
is learning,
thinking, and
teaching
@ploeh
@ploeh
@ploeh
@ploeh
@ploeh
@ploeh
Mark Seemann
http://blog.ploeh.dk
http://bit.ly/clean-humane-code
http://bit.ly/ploehralsight
@ploeh

[FDD 2017] Mark Seemann - Humane code

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
    @ploeh Measurements Lines of code Codecoverage Cyclomatic complexity Afferent coupling Efferent coupling @ploeh
  • 8.
    @ploeh public class GoldCustomerSpecification: ICustomerSpecification { public bool IsSatisfiedBy(Customer candidate) { bool retVal; if (candidate.TotalPurchases >= 10000) retVal = true; else retVal = false; return retVal; } }
  • 9.
    @ploeh public class GoldCustomerSpecification: ICustomerSpecification { public bool IsSatisfiedBy(Customer candidate) { return candidate.TotalPurchases >= 10000; } }
  • 10.
  • 11.
    @ploehhttps://www.flickr.com/photos/adewale_oshineye/2933030620 “Any fool can writecode that a computer can understand. Good programmers write code that humans can understand.” @ploeh
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
    @ploeh public class Odin { privatebool 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;
  • 17.
    @ploeh public class Odin { privatebool 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;
  • 18.
    @ploeh public class Odin { privatestring 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;
  • 19.
    @ploeh Code should behumane @ploeh
  • 20.
  • 21.
  • 22.
  • 23.
    @ploeh Code is aliability @ploeh
  • 24.
  • 25.
    @ploeh Code is aliability @ploeh
  • 26.
  • 27.
  • 28.
    @ploeh public class GoldCustomerSpecification: ICustomerSpecification { public bool IsSatisfiedBy(Customer candidate) { return candidate.TotalPurchases >= 10000; } }
  • 29.
    @ploeh .method public hidebysignewslot virtual final instance bool IsSatisfiedBy(class Ploeh.Samples.LoCSample.Customer ca { // Code size 22 (0x16) .maxstack 2 .locals init ([0] bool V_0) IL_0000: nop IL_0001: ldarg.1 IL_0002: callvirt instance int32 Ploeh.Samples.LoCSample.Customer::get_ IL_0007: ldc.i4 0x2710 IL_000c: clt IL_000e: ldc.i4.0 IL_000f: ceq IL_0011: stloc.0 IL_0012: br.s IL_0014 IL_0014: ldloc.0 IL_0015: ret } // end of method GoldCustomerSpecification::IsSatisfiedBy
  • 30.
    @ploeh 8945 ec89 4dfc8955 f88b 05a8 1300 1083 3800 7405 e88f d7ff ff0f b645 fc89 45f4 0fb6 45f8 8945 f033 c933 d2e8 c0d6 ffff 8945 ecff 75ec 8b4d f48b 55f0 e8b7 d6ff ff90 8be5 5dc3 cccc 558b ec57 5683 ec20 8bf1 8d7d d8b9 0500 0000 33c0 f3ab 8bce 894d f489 55f0 8b05 a813 0010 8338 0074 05e8 32d7 ffff 8b05 1018 0010 8b08 8b55 08e8 7ad6 ffff 0fb6 45f0 500f b655 f48b 4d08 ff15 3817 0010 8945 ec83 7dec 0075 5f8b 0dfc 1600 10e8 0cd7 ffff 8945 e88b 0dfc 1600 10e8 fed6 ffff 8945 e48b 0db0 1700 10e8 f0d6 ffff 8945 e08b 45e0 8945 dc8b 45e8 8b55 f488 5004 8b45 e889 45d8 8b45 e48b 55f0 8850 048b 45e4 508b 4ddc 8b55 d8e8 10d6 ffff 8b4d e0e8 c8d6 ffff 908d 65f8 5e5f 5dc2 0400 cccc 558b ec83 ec0c 33c0 8945 f489 4dfc 8955 f88b 05a8 1300 1083 3800 7405 e87b d6ff ff8b 0db4
  • 31.
    @ploeh 00000000 00000000 0000000000000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 01010000 01000101 00000000 00000000 01001100 00000001 00000100 00000000 10101001 11101111 00100101 01010110 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 11100000 00000000 00000010 00100001 00001011 00000001 00001011 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00010000 00000000 00010000 00000000 00000000 00000000 00000010 00000000 00000000 00000101 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 10010000 00000000 00000000 00000000 00000100 00000000 00000000 00000000 00000000 00000000 00000000 00000011 00000000
  • 32.
  • 33.
  • 34.
    @ploeh public class GoldCustomerSpecification: ICustomerSpecification { public bool IsSatisfiedBy(Customer candidate) { return candidate.TotalPurchases >= 10000; } }
  • 35.
  • 36.
    @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.Parameters select 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); } }
  • 37.
    @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.Parameters select 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
  • 38.
    @ploeh “An abstraction is theamplification of the essential and the elimination of the irrelevant.” https://commons.wikimedia.org/wiki/ File:Robert_Cecil_Martin.png @ploeh
  • 39.
    @ploeh the amplification of theirrelevant and the elimination of the essential @ploeh
  • 40.
    @ploeh “An abstraction is theamplification of the essential and the elimination of the irrelevant.” @ploeh
  • 41.
    @ploeh What is thevalue of cust.Tier? var cust = new Customer { Tier = Tier.Silver, TotalPurchases = 20000 }; var orders = GetOrders(cust); 1 2
  • 42.
    @ploeh public IReadOnlyCollection<Order> GetOrders(Customercustomer) { 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... }
  • 43.
    @ploeh public IReadOnlyCollection<Order> GetOrders(Customercustomer) { 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)
  • 44.
    @ploeh Adjust(customer); return RetrieveOrdersFromDatabase(customer); } private staticvoid 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;
  • 45.
    @ploeh private static voidAdjust(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)
  • 46.
    @ploeh public IReadOnlyCollection<Order> GetOrders(Customercustomer) { 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)
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
    @ploeh How can wemake code more humane? @ploeh
  • 52.
  • 53.
    @ploeh Commands change the state ofthe system Queries return data An operation should be either a Command or a Query but not both
  • 54.
    @ploeh change the stateof the system private static void Adjust(Customer customer) { if (customer.TotalPurchases >= 10000) customer.Tier = Tier.Gold; // Many more similar checks go here... } Commands
  • 55.
    @ploeh public IReadOnlyCollection<Order> GetOrders(Customercustomer) { // Adjust(customer); return RetrieveOrdersFromDatabase(customer); } Queries return data
  • 56.
    @ploeh public IReadOnlyCollection<Order> GetOrders(Customercustomer) { Adjust(customer); return RetrieveOrdersFromDatabase(customer); }
  • 57.
    @ploeh Command Query Separation Justone example Challenging enough already
  • 58.
  • 59.
    @ploehReused Abstractions Principle CommandQuery Separation Liskov Substitution Principle Interface 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
  • 60.
    @ploeh There are manyways to do things if you know them
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
    @ploeh Code should behumane @ploeh
  • 66.
    @ploeh The more code you have,the worse Programming is mostly a soft skill Programming is learning, thinking, and teaching @ploeh
  • 67.
    @ploeh The more code you have,the worse Programming is mostly a soft skill Programming is learning, thinking, and teaching @ploeh
  • 68.
    @ploeh The more code you have,the worse Programming is mostly a soft skill Programming is learning, thinking, and teaching @ploeh
  • 69.
    @ploeh The more code you have,the worse Programming is mostly a soft skill Programming is learning, thinking, and teaching @ploeh
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.