SlideShare une entreprise Scribd logo
1  sur  150
Télécharger pour lire hors ligne
Clean Code


How to write comprehensible Code


regarding cognitive abilities of human mind




01.03.2011
XPUG Rhein / Main
Mario Gleichmann
Mario Gleichmann



twitter:   @mariogleichmann

blog:      gleichmann.wordpress.com (brain driven development)

site:      www.mg-informatik.de

mail:      mario.gleichmann@mg-informatik.de
The cost of Software Development
Intellectual Complexity




     ''Making changes is generally easy
if you exactly know what needs to be changed''
Programming is a cognitive process
Functionality
Simplicity




Intellectually manageable programs
Communication




'existing code is much more read than new code is written'
Fear
Empathy
Cognition
Capacity
Chunking
Cognitive overload
Knowledge base
Working Memory
Program Comprehension
What's the goal ?
def find( start :Char, end :Char, pths :List[ (Char,Char) ] ) :List[ (Char,Char) ] = {

    var rout = (start,start) :: Nil
    var dends :List[(Char,Char)] = Nil

    while( !rout.isEmpty && rout.head._2 != end ){

        var conts = from( rout.head._2, pths )
                        .filter( pth => !dends.contains( pth ) && !rout.contains( pth ) )

        if( conts.isEmpty && !rout.isEmpty ) {

            dends = rout.head :: de
            rout = rout.tail
        }
        else{
            rout = conts.iterator.next :: rte
        }
    }
    rout.reverse.tail
}
Program
  model
Bottom up
Goals   &   sub-goals
Top down
Domain Model
'G'
                                      'F'
'I'




            'B'




                  'C'
      'A'
                                            'H'


                              'D'



                                    'G'
                        'E'
What's the goal ?
def findRoute( start :WayPoint, target :WayPoint, map :Set[Path] ) :Sequence[Path] = {

    var route = new Stack[Path]
    var deadEnds :Set[Path] = new HashSet[Path]

    route push Path( start, start )

    while( !route.isEmpty && route.top.endPoint != target ){

        var continuingPaths = pathsFrom( route.top.endPoint, map )
                                   .without( deadEnds ).without( route )

        if( continuingPaths.isEmpty && !route.isEmpty ) {

            deadEnds += route.pop
        }
        else{
            route push continuingPaths.first
        }
    }
    route.reverse
}
Hypothesis
      &
Verification
Plans & beacons
public class PrimeGenerator {

    static int[] sieveUpTo( int maxValue ){

    if( maxValue < 2 ) return new int[0];

    boolean[] grid = new boolean[maxValue + 1];
    for( int i = 0; i <= maxValue; i++ ){
        grid[i] = true;
    }

    grid[0] = grid[1] = false;

    for( int i = 2; i < Math.sqrt( maxValue + 1 ) + 1; i++ ){
        if( grid[i] ){
             for( int j = 2*i; j <= maxValue; j += i ){
                  grid[j] = false;
             }
        }
    }
    …
}
Mental Model
Concepts
Concepts




 Stack
Concepts

           Push




                  Pop
  Stack
Concepts

Store              Push




                          Pop
          Stack
Concepts
               Not
Store        'lose'   Push
           Elements




                             Pop
          Stack
Concepts
                    Not
    Store         'lose'   Push
                Elements




                                  Pop
Collection     Stack
Concepts
                             Not
     Store                 'lose'       Push
                         Elements




                                               Pop
Collection              Stack



  Add        Remove           Iterate
Elements     Elements        Elements
Concepts

Store              Push




                          Pop
         Stack


                          LIFO
Concepts

Store               Push




                           Pop
         Stack


                           LIFO


                   FIFO
Concepts

Store               Push




                           Pop
          Stack


                           LIFO

        Queue
         FIFO
                   FIFO
Concepts

     Store                    Push




                                     Pop
Collection          Stack


                                     LIFO
  AddAddAdd
Elements
   Elements
       Elements   Queue
                   FIFO
                             FIFO
Assimilation
public class Folding {


    public static <T> T fold( List<T> list, Monoid<T> monoid ){

        return list.isEmpty() ?
                          monoid.unit() :
                          monoid.conjunct( head( list ), fold( tail( list ), monoid ) );
    }



    private static <T> T head( List<T> list ){
        return list.isEmpty() ? null : list.get( 0 );
    }

    private static <T> List<T> tail( List<T> list ){
        return list.size() >= 2 ? list.subList( 1, list.size() ) : EMPTY_LIST;
    }
}
public interface Monoid<T> {

    public T unit();

    public T conjunct( T t1, T t2 );
}
public class MonoidInstanceTest extends TestCase{
...

 public void testStringAsMonoid(){
      assertEquals( "helloworld", stringMonoid.conjunct( "hello", "world" ) );
      assertEquals( "hollamundo", stringMonoid.conjunct( "hola", "mundo" ) );

      assertEquals( "hola", stringMonoid.conjunct( "hola", stringMonoid.unit() ) );
      assertEquals( "hola", stringMonoid.conjunct( stringMonoid.unit(), "hola" ) );
 }


 public void testIntegerAsMonoid(){
      assertEquals( 6, poductIntMonoid.conjunct( 2, 3 ) );
      assertEquals( 42 , productIntMonoid.conjunct( 7, 6 ) );

      assertEquals( 11, productIntMonoid.conjunct( 11, productIntMonoid.unit() ) );
      assertEquals( 11, productIntMonoid.conjunct( productIntMonoid.unit(), 11 ) );
  }
...
}
public class MonoidTest extends TestCase{
...
  private static <T> void assertAssociativity( Monoid<T> monoid, T t1, T t2, T t3 ){

        assertEquals( monoid.conjunct( t1, monoid.conjunct( t2, t3 ) ),
                         monoid.conjunct( monoid.conjunct( t1, t2 ), t3 ) );
    }

    private static <T> void assertNeutrality( Monoid<T> monoid, T value ){

        assertEquals( monoid.conjunct( value, monoid.unit() ), value );
        assertEquals( monoid.conjunct( monoid.unit(), value ), value );
    }


    public void testMonoidInstances(){
        assertAssociativity( stringMonoid, "s1", "s2", "s3" );
        assertNeutrality( stringMonoid, "s1" );
        ...
        assertAssociativity( productSumMonoid, 1, 2, 3 );
        assertNeutrality( productSumMonoid, 1 );
    }
}
public class Monoids {


   public static Monoid<String> stringMonoid = new Monoid<String>(){

         public String unit() { return ""; }

         public String conjunct(String t1, String t2) { return t1 + t2; }
   };



   public static Monoid<Integer> productIntMonoid = new Monoid<Integer>(){

         public Integer unit() { return 1; }

         public Integer conjunct(Integer t1, Integer t2) { return t1 * t2; }
   };

   ...
public class Monoids {


   ...

   public static Monoid<Integer> sumIntMonoid = new Monoid<Integer>(){

         public Integer unit() { return 0; }

         public Integer conjunct(Integer t1, Integer t2) { return t1 + t2; }
   };

   ...
public class FoldTest extends TestCase{


      public void testStringConcat(){

          assertEquals(     "Hello world !!!",
                           fold( asList( "Hello", " ", "world" + " " + "!!!" ), stringMonoid ) );
      }


      public void testSum(){

          assertEquals( 15, fold( asList( 1, 2, 3, 4, 5 ), sumIntMonoid ).intValue() );
      }


      public void testProduct(){

          assertEquals( 120, fold( asList( 1, 2, 3, 4, 5 ), productIntMonoid ).intValue() );
      }

...
public reorderBook( String isbn ){
   ...

    if( isbn.substring( 0, 2 ).equals( ''978'' ){

          pubNr = isbn.substring( 6, 10 );
    }
    else{

          pubNr = isbn.substring( 8, 12 );
    }
    ...
}
public reorderBook( String isbn ){
   ...

    if( isbn.substring( 0, 2 ).equals( ''978'' ){

          pubNr = isbn.substring( 6, 10 );
    }
    else{

          pubNr = isbn.substring( 8, 12 );
    }
    ...
}
                          ISBN is NOT a String !!!
public interface Isbn {
      public Region getRegion(){ ... }
      public Integer getPublisherNumber(){ ... }
      public Integer getTitelNumber(){ ... }
      public Integer getChecksum(){ ... }
      public boolean isValid(){ ... }
}


        ISBN is a concept in its own right !!!

    public reorderBook( Isbn isbn ){
       ...
       isbn.getPublisherNumber();
       ...
    }
Conture
          &   Boundary
public boolean isValidLaufzeit( Vertrag vertrag ){

     GregorianCalendar start = vertrag.getStart();
     GregorianCalendar end = vertrag.getEnd();

     int tagesdifferenz = 0;
     if (start != null && end != null) {
           int startJahr = start.get(Calendar.YEAR);
           int endJahr = end.get(Calendar.YEAR);
           int tageImStartJahr = start.get(Calendar.DAY_OF_YEAR);
           int tageImEndJahr = end.get(Calendar.DAY_OF_YEAR);
           int aktuellesJahr = startJahr;

          while (aktuellesJahr <= endJahr) {
              if (aktuellesJahr == startJahr) {
                    if (aktuellesJahr == endJahr) {
                          tagesdifferenz += tageImEndJahr - tageImStartJahr;
                    } else {
                          tagesdifferenz += start.isLeapYear(startJahr) ?
                                (366 - tageImStartJahr) : (365 - tageImStartJahr);
                    }
              } else if (aktuellesJahr == endJahr) {
                    tagesdifferenz += tageImEndJahr;
              } else {
                    tagesdifferenz += start.isLeapYear(aktuellesJahr) ? 366 : 365;
              }
              aktuellesJahr++;
          }
     }
     return tagesdifferenz > 365 && tagesdifferenz < 999;
}
public void createOrder( int itemId, Date shippingDate ){

    Date today = new Date();

    long start = today.getTime();
    long end = shippingDate.getTime();

    BigDecimal diff = new BigDecimal( start - end );

    int days = diff.divideToIntegralValue(
                        new BigDecimal( 1000 * 60 * 60 * 24 ) ).intValue();

    if( days > 14 ) rejectOrder();

    // ...
}
Don't repeat yourself
Single Source of Truth
public boolean isValidLaufzeit( Vertrag vertrag ){

    TimeInterval interval = vertrag.getLaufzeit();

    return
        interval.toDuration().inYears() > ONE_YEAR
        &&
        interval.toDuration().inYears() < THREE_YEARS;
}
public void createOrder( int ItemId, Date shippingDate ){

    Duration duration = new Duration( today(), shippingDate );

    if( duration.inDays() > 14 ) rejectOrder();

    // ...
}
Tell ! Don't ask
String separator ='' '';
String query = ''select '';
if( ... ) query += '' name '';
if( ... ) query = query + separator + '' alter '', separator = '', '';
query += '' from person '';
if( existFilter ){
      query += '' where ''
      if( ... ) query += '' stadt = '' + stadt; separator = '' and '';
      else{
           query += '' stadt in ( '';
          for( String stadt : staedte )
             query += stadt + inSeparator; inSeparator = '', '';
          query += '' ); separator = '' and ''
      }
...
String separator ='' '';
String query = ''select '';
if( ... ) query += '' name '';
if( ... ) query = query + separator + '' alter '', separator = '', '';
query += '' from person '';
                                      Do you see the core idea ?
if( existFilter ){
                                     (Hint: it's NOT about String Handling)
      query += '' where ''
      if( ... ) query += '' stadt = '' + stadt; separator = '' and '';
      else{
           query += '' stadt in ( '';
          for( String stadt : staedte )
             query += stadt + inSeparator; inSeparator = '', '';
          query += '' ); separator = '' and ''
      }
...
String separator ='' '';
String query = ''select '';
if( ... ) query += '' name '';
if( ... ) query = query + separator + '' alter '', separator = '', '';
query += '' from person '';
                                      Building SQL-Statements ...
if( existFilter ){
                                        … is NOT about String Handling
      query += '' where ''
      if( ... ) query += '' stadt = '' + stadt; separator = '' and '';
      else{
           query += '' stadt in ( '';
          for( String stadt : staedte )
             query += stadt + inSeparator; inSeparator = '', '';
          query += '' ); separator = '' and ''
      }
...
Encapsulation
Query personQuery = Query.onTable( ''Person'' )

personQuery.select( ''name'' )
personQuery.select( ''alter '' )

personQuery.add( criteria( ''stadt'' ).equals( stadt ) );

personQuery.add( criteria( ''stadt'' ).in( staedte ) );

...
PIE Principle
SEP Principle
String separator ='' '';                          … by the way ...
String query = ''select '';
if( ... ) query += '' name '';
if( ... ) query = query + separator + '' alter '', separator = '', '';
query += '' from person '';
if( existFilter ){
      query += '' where ''
      if( ... ) query += '' stadt = '' + stadt; separator = '' and '';
      else{
           query += '' stadt in ( '';
          for( String stadt : staedte )
             query += stadt + inSeparator; inSeparator = '', '';
          query += '' ); separator = '' and ''
      }
...
String separator ='' '';                    … anybody missed that ?
String query = ''select '';
if( ... ){ query += '' name ''; separator = '', ''; }
if( ... ) query = query + separator + '' alter '', separator = '', '';
query += '' from person '';
if( existFilter ){
      query += '' where ''
      if( ... ) query += '' stadt = '' + stadt; separator = '' and '';
      else{
           query += '' stadt in ( '';
          for( String stadt : staedte )
             query += stadt + inSeparator; inSeparator = '', '';
          query += '' ); separator = '' and ''
      }
...
Abstraction
''Look, a Composite ...'


                    Directory              ''delete'




   File              File                         Directory          ''delete'

''delete'          ''delete'


                                  File                           File

                               ''delete'                      ''delete'
''Look, another Composite ...''


              UI Panel             ''draw'




UI Text      UI Input                  UI Panel         ''draw'

''draw'       ''draw'


                        UI Text              UI Selection
                         ''draw'                  ''draw'
AbstractComposite

         operation()
         add( Composite)
         remove( Composite )
         childs() : List<Comp.>




  Node                    Composite

operation()          operation()
                     add( Composite)
                     remove( Composite )
                     childs() : List<Comp.>
Is this a Composite ?


                     AtLeastOneAuthProvider            ''authenticate'




LdapAuthProvider           DatabaseAuth.           UnanimousAuthProvider
   ''authenticate'            ''authenticate'


                                  CertificateAuth.              AccessAuth.
                                     ''authenticate'             ''authenticate'
... and this ?


             CEO               ''salary'



Employee     Employee                      CIO

''salary'    ''salary'

                    Employee               Employee
                   ''salary'               ''salary'
Collection


        generalization


                                List       Set   Bag



Queue                           Stack
         < discrimination >


   FIFO                  LIFO
public static Integer sum( Stack<Integer> vals ){
    int sum = 0;
    for( int val : vals ) sum += val;
    return sum;
}
public static Integer sum( Stack<Integer> vals ){
    int sum = 0;
    for( int val : vals ) sum += val;
    return sum;
}


sum( new Stack<Integer>(){{ push(1); push(2); push(3); }};

sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }};
public static Integer sum( List<Integer> vals ){
    int sum = 0;
    for( int val : vals ) sum += val;
    return sum;
}


sum( new Stack<Integer>(){{ push(1); push(2); push(3); }};

sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }};

sum( new HashSet<Integer>(){{ add(1); add(2); add(3) }};
public static Integer sum( Collection<Integer> vals ){
    int sum = 0;
    for( int val : vals ) sum += val;
    return sum;
}


sum( new Stack<Integer>(){{ push(1); push(2); push(3); }};

sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }};

sum( new HashSet<Integer>(){{ add(1); add(2); add(3) }};
Adaption
public class QueueTest extends TestCase {

    private Queue<Integer> queue = null;
    public void setUp() throws Exception{
        queue = new ...
        queue.add( 10 );
        queue.add( 3 );
        queue.add( 7 );
        queue.add( 5 );
    }

    public testQueuePolling{
        assertEquals(   ? , queue.poll() );
        assertEquals(   ?? , queue.poll() );
        assertEquals(   ??? , queue.poll() );
        assertEquals(   ???? , queue.poll() );
    }
}
public class QueueTest extends TestCase {

    private Queue<Integer> queue = null;
    public void setUp() throws Exception{
        queue = new ArrayBlockingQueue<Integer>();
        queue.add( 10 );
        queue.add( 3 );
        queue.add( 7 );
        queue.add( 5 );
    }

    public testQueuePolling{
        assertEquals(   10 , queue.poll() );
        assertEquals(   3 , queue.poll() );
        assertEquals(   7 , queue.poll() );
        assertEquals(   5 , queue.poll() );
    }
}
public class QueueTest extends TestCase {

    private Queue<Integer> queue = null;
    public void setUp() throws Exception{
        queue = new PriorityQueue<Integer>();
        queue.add( 10 );
        queue.add( 3 );
        queue.add( 7 );
        queue.add( 5 );
    }

    public testQueuePolling{
        assertEquals(   3 , queue.poll() );
        assertEquals(   5 , queue.poll() );
        assertEquals(   7 , queue.poll() );
        assertEquals(   10 , queue.poll() );
    }
}
Accomodation
Collection


            generalization


                                   List       Set   Bag

   Queue

                                  Stack



PriorityQueue          ArrayQueue

HPFO       < discrimination >
                                FIFO
Appropriateness
public static List<Integer> multiplesOf( int factor, int limit ){

    List<Integer> collect = new ArrayList<Integer>();

    for( int i = 1; i * factor <= limit; i++ ){
        collect.add( i * factor );
    }
    return collect;
}
                                 vs.

public static Set<Integer> multiplesOf( int factor, int limit ){

    Set<Integer> collect = new HashSet<Integer>();

    for( int i = 1; i * factor <= limit; i++ ){
        collect.add( i * factor );
    }
    return collect;
}
public static List<Integer> multiplesOf( int[] factors, int limit ){

    List<Integer> collect = new ArrayList<Integer>();

    for( int factor : factors ){

       for( int i = 1; i * factor <= limit; i++ ){

           collect.add( i * factor );
       }
    }
    return collect;
}
public static Set<Integer> multiplesOf( int[] factors, int limit ){

    Set<Integer> collect = new HashSet<Integer>();

    for( int factor : factors ){

       for( int i = 1; i * factor <= limit; i++ ){

           collect.add( i * factor );
       }
    }
    return collect;
}
Re - Cognition
Distinction

public boolean isGoodDeal(     BigDecimal initialCosts,
                               BigDecimal runCosts ){

    BigDecimal totalCost = initialCost.add( runCost );

    BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) );

    BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN );

    return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1;
}
Distinction

public boolean isGoodDeal(     BigDecimal initialCosts,
                               BigDecimal runCosts ){

    BigDecimal totalCost = initialCost.add( runCost );

    BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) );
                                        BigDecimal as Money
    BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN );

    return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1;
}
Distinction

public boolean isGoodDeal(     BigDecimal initialCosts,
                               BigDecimal runCosts ){
                                      BigDecimal as Percent
    BigDecimal totalCost = initialCost.add( runCost );

    BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) );

    BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN );

    return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1;
}
Distinction

public boolean isGoodDeal(     BigDecimal initialCosts,
                               BigDecimal runCosts ){

    BigDecimal totalCost = initialCost.add( runCost );

    BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) );

    BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN );

    return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1;
}

                          What's the result 'type' of
                       combining 'Money' with 'Percent'
Distinction

public boolean isGoodDeal(     BigDecimal initialCosts,
                               BigDecimal runCosts ){

    BigDecimal totalCost = initialCost.add( runCost );

    BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) );

    BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN );

    return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1;
}

                      Which combinations are allowed -
                               which not ?
LiM Principle
Distinction

public boolean isGoodDeal( Money initialCosts, Money runCosts ){

    Money totalCost = initialCosts.sum( runCosts );

    Percent proportionRunCosts = totalCost.proportionOf( runCost )

    return proportionRunCosts.isGreaterThan( Percent.FIFTY )
}
Single Responsibility Principle
Mental Distance
  Mental Distance
... do you recognize the underlying concept ?




         interface Stepper<T>{

             public boolean isExhausted();

             public void step();

             public T getCurrent()
         }
... do you recognize the underlying concept ?




         interface ElementSupplier<T>{

             public boolean hasMoreElements();

             T nextElement();
         }
... do you recognize the underlying concept ?




       interface ElementConsumer{

           public void observe( BigElement e );

           public void calculate( AnotherElement e );

           public void extract( YetAnotherElement );
       }
... do you recognize the underlying concept ?




       interface ElementInspector{

           public void inspect( BigElement e );

           public void inspect( AnotherElement e );

           public void inspect( YetAnotherElement );
       }
... do you recognize the underlying concept ?




       interface ElementVisitor{

           public void visit( BigElement e );

           public void visit( AnotherElement e );

           public void visit( YetAnotherElement );
       }
Language


       date.compareTo( otherDate ) < 0


                      vs.


           date.isBefore( otherDate )
Code
slicing
L
o
c
a
l
i
t
y
Trust
Verifiable Specifications
Stack stack = is(
             new DescriptionOf <Stack>(){
                 public Stack isDescribedAs(){
                      Stack<String> stack = new Stack<String>();
                      stack.push( foo );
                      stack.push( bar );
                      return stack; } } );

       it( "should contain foo" );
       state( stack ).should( contain( foo ) );

       it( "should contain bar" );
       state( stack ).should( contain( bar ) );

       it( "should return bar when calling pop the first time" );
       state( stack.pop() ).should( returning( bar ) );

       it( "should return foo when calling pop the second time" );
       stack.pop();
       state( stack.pop() ).should( returning( foo ) );

       it( "should be empty after popping the two elements" );
       stack.pop();
       stack.pop();
       state( stack ).should( be ( empty() ) );
Design by Contract
@Invariant( "this.size >= 0 and this.size <= this.capazity" )
public interface Stack { ... }
    @Postcondition( "return > 0" )
    public int getCapacity();

    public int getSize();

    @Precondition( "elem not null and this.size < this.capacity" )
    @Postcondition( "elem == this.top and this.size == old:this.size + 1" )
    public void push( Object elem );

    @Postcondition( "this.top == old:this.top ) " )
    public Object getTop();

    @Postcondition(
     "(old:this.size>0) ==> (return == old:this.top and this.size == old:this.size - 1)")
    public Object pop();

    ...
}
Liskovsubtype of T, then objects of type T in a
  ''if S is a
              Substitution Principle
   program may be replaced with objects of type S
   without altering any of the desirable properties''
Open Closed Principle
Principle of least astonishment
Symmetry & balance
...

void writeToFile( Output outout ){

      openFile();

      writeToFile( output );

}
void process{

    input();

    count++;

    output();
}
One level of abstraction
Dependency Inversion Principle
                                                declarative
                                                    vs
    Intention Revealing Interfaces              imperative



                                     Functional Programming
   Yagni                   Immutability
                                         side effects

       Expressiveness


                                 Domain Driven Design
 Consistence
If there are three things to keep in mind ...
… it's not only ''developers! developers! developers!'' ...
… but

 Empathy!

   Empathy!

        Empathy!
Now stop hacking code
          for machines


 start writing programs
              for humans




… and the rest will follow ...
Empathic Programming - How to write comprehensible code

Contenu connexe

Tendances

Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. ExperienceMike Fogus
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.Mike Fogus
 
Kotlin collections
Kotlin collectionsKotlin collections
Kotlin collectionsMyeongin Woo
 
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...Johannes Schildgen
 
Programming Java - Lection 04 - Generics and Lambdas - Lavrentyev Fedor
Programming Java - Lection 04 - Generics and Lambdas - Lavrentyev FedorProgramming Java - Lection 04 - Generics and Lambdas - Lavrentyev Fedor
Programming Java - Lection 04 - Generics and Lambdas - Lavrentyev FedorFedor Lavrentyev
 
About java
About javaAbout java
About javaJay Xu
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureMike Fogus
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Codestasimus
 
Python 내장 함수
Python 내장 함수Python 내장 함수
Python 내장 함수용 최
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friendThe Software House
 
Coffee script
Coffee scriptCoffee script
Coffee scripttimourian
 

Tendances (20)

Kotlin standard
Kotlin standardKotlin standard
Kotlin standard
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.
 
Hammurabi
HammurabiHammurabi
Hammurabi
 
Kotlin collections
Kotlin collectionsKotlin collections
Kotlin collections
 
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
Marimba - A MapReduce-based Programming Model for Self-maintainable Aggregate...
 
Kotlin class
Kotlin classKotlin class
Kotlin class
 
Programming Java - Lection 04 - Generics and Lambdas - Lavrentyev Fedor
Programming Java - Lection 04 - Generics and Lambdas - Lavrentyev FedorProgramming Java - Lection 04 - Generics and Lambdas - Lavrentyev Fedor
Programming Java - Lection 04 - Generics and Lambdas - Lavrentyev Fedor
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
About java
About javaAbout java
About java
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of Clojure
 
Google Guava
Google GuavaGoogle Guava
Google Guava
 
The Groovy Way
The Groovy WayThe Groovy Way
The Groovy Way
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 
Python 내장 함수
Python 내장 함수Python 내장 함수
Python 내장 함수
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
 
ddd+scala
ddd+scaladdd+scala
ddd+scala
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
 
Coffee script
Coffee scriptCoffee script
Coffee script
 

En vedette

Ur Domain Haz Monoids DDDx NYC 2014
Ur Domain Haz Monoids DDDx NYC 2014Ur Domain Haz Monoids DDDx NYC 2014
Ur Domain Haz Monoids DDDx NYC 2014Cyrille Martraire
 
Redis training for java software engineers
Redis training for java software engineersRedis training for java software engineers
Redis training for java software engineersMoshe Kaplan
 
Clean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionClean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionKent Huang
 
Clean Code - How to write comprehensible code regarding cognitive abilities o...
Clean Code - How to write comprehensible code regarding cognitive abilities o...Clean Code - How to write comprehensible code regarding cognitive abilities o...
Clean Code - How to write comprehensible code regarding cognitive abilities o...Mario Gleichmann
 
Writing beautiful code with Java 8
Writing beautiful code with Java 8Writing beautiful code with Java 8
Writing beautiful code with Java 8Sergiu Mircea Indrie
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code DevelopmentPeter Gfader
 
Clean Code (Presentacion interna en Virtual Software)
Clean Code (Presentacion interna en Virtual Software)Clean Code (Presentacion interna en Virtual Software)
Clean Code (Presentacion interna en Virtual Software)jmiguel rodriguez
 
Java data structures powered by Redis. Introduction to Redisson @ Redis Light...
Java data structures powered by Redis. Introduction to Redisson @ Redis Light...Java data structures powered by Redis. Introduction to Redisson @ Redis Light...
Java data structures powered by Redis. Introduction to Redisson @ Redis Light...Nikita Koksharov
 
Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best PracticesTheo Jungeblut
 
[DevoxxFr] Savoir faire le deuil de son code
[DevoxxFr] Savoir faire le deuil de son code[DevoxxFr] Savoir faire le deuil de son code
[DevoxxFr] Savoir faire le deuil de son codeElleneDijoux
 

En vedette (15)

Ur Domain Haz Monoids DDDx NYC 2014
Ur Domain Haz Monoids DDDx NYC 2014Ur Domain Haz Monoids DDDx NYC 2014
Ur Domain Haz Monoids DDDx NYC 2014
 
Redis training for java software engineers
Redis training for java software engineersRedis training for java software engineers
Redis training for java software engineers
 
Clean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionClean Code: Chapter 3 Function
Clean Code: Chapter 3 Function
 
Clean Code - How to write comprehensible code regarding cognitive abilities o...
Clean Code - How to write comprehensible code regarding cognitive abilities o...Clean Code - How to write comprehensible code regarding cognitive abilities o...
Clean Code - How to write comprehensible code regarding cognitive abilities o...
 
Writing beautiful code with Java 8
Writing beautiful code with Java 8Writing beautiful code with Java 8
Writing beautiful code with Java 8
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
Clean Code (Presentacion interna en Virtual Software)
Clean Code (Presentacion interna en Virtual Software)Clean Code (Presentacion interna en Virtual Software)
Clean Code (Presentacion interna en Virtual Software)
 
Clean Code
Clean CodeClean Code
Clean Code
 
OOP Basics
OOP BasicsOOP Basics
OOP Basics
 
CDI: How do I ?
CDI: How do I ?CDI: How do I ?
CDI: How do I ?
 
Java data structures powered by Redis. Introduction to Redisson @ Redis Light...
Java data structures powered by Redis. Introduction to Redisson @ Redis Light...Java data structures powered by Redis. Introduction to Redisson @ Redis Light...
Java data structures powered by Redis. Introduction to Redisson @ Redis Light...
 
Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best Practices
 
Clean code
Clean codeClean code
Clean code
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
[DevoxxFr] Savoir faire le deuil de son code
[DevoxxFr] Savoir faire le deuil de son code[DevoxxFr] Savoir faire le deuil de son code
[DevoxxFr] Savoir faire le deuil de son code
 

Similaire à Empathic Programming - How to write comprehensible code

Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?Adam Dudczak
 
Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#Mark Needham
 
ES6 patterns in the wild
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wildJoe Morgan
 
Apache PIG - User Defined Functions
Apache PIG - User Defined FunctionsApache PIG - User Defined Functions
Apache PIG - User Defined FunctionsChristoph Bauer
 
Introduction to Kotlin.pptx
Introduction to Kotlin.pptxIntroduction to Kotlin.pptx
Introduction to Kotlin.pptxAzharFauzan9
 
01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptxIvanZawPhyo
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Juan Pablo
 
Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7Paulo Morgado
 
Google Guava for cleaner code
Google Guava for cleaner codeGoogle Guava for cleaner code
Google Guava for cleaner codeMite Mitreski
 
C# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewC# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewPaulo Morgado
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In JavaAndrei Solntsev
 
In this lab, you will be given a simple code for a min Heap, and you.pdf
In this lab, you will be given a simple code for a min Heap, and you.pdfIn this lab, you will be given a simple code for a min Heap, and you.pdf
In this lab, you will be given a simple code for a min Heap, and you.pdfcharanjit1717
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldBTI360
 
Paradigmas de Linguagens de Programacao - Aula #4
Paradigmas de Linguagens de Programacao - Aula #4Paradigmas de Linguagens de Programacao - Aula #4
Paradigmas de Linguagens de Programacao - Aula #4Ismar Silveira
 

Similaire à Empathic Programming - How to write comprehensible code (20)

Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?
 
Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#
 
ES6 patterns in the wild
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wild
 
Apache PIG - User Defined Functions
Apache PIG - User Defined FunctionsApache PIG - User Defined Functions
Apache PIG - User Defined Functions
 
Introduction to Kotlin.pptx
Introduction to Kotlin.pptxIntroduction to Kotlin.pptx
Introduction to Kotlin.pptx
 
01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx
 
Lezione03
Lezione03Lezione03
Lezione03
 
Lezione03
Lezione03Lezione03
Lezione03
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7
 
Kpi driven-java-development-fn conf
Kpi driven-java-development-fn confKpi driven-java-development-fn conf
Kpi driven-java-development-fn conf
 
Google Guava for cleaner code
Google Guava for cleaner codeGoogle Guava for cleaner code
Google Guava for cleaner code
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
C# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewC# 6.0 - April 2014 preview
C# 6.0 - April 2014 preview
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In Java
 
mobl
moblmobl
mobl
 
In this lab, you will be given a simple code for a min Heap, and you.pdf
In this lab, you will be given a simple code for a min Heap, and you.pdfIn this lab, you will be given a simple code for a min Heap, and you.pdf
In this lab, you will be given a simple code for a min Heap, and you.pdf
 
Miracle of std lib
Miracle of std libMiracle of std lib
Miracle of std lib
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 World
 
Paradigmas de Linguagens de Programacao - Aula #4
Paradigmas de Linguagens de Programacao - Aula #4Paradigmas de Linguagens de Programacao - Aula #4
Paradigmas de Linguagens de Programacao - Aula #4
 

Dernier

A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 

Dernier (20)

A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 

Empathic Programming - How to write comprehensible code

  • 1. Clean Code How to write comprehensible Code regarding cognitive abilities of human mind 01.03.2011 XPUG Rhein / Main Mario Gleichmann
  • 2. Mario Gleichmann twitter: @mariogleichmann blog: gleichmann.wordpress.com (brain driven development) site: www.mg-informatik.de mail: mario.gleichmann@mg-informatik.de
  • 3.
  • 4.
  • 5. The cost of Software Development
  • 6. Intellectual Complexity ''Making changes is generally easy if you exactly know what needs to be changed''
  • 7. Programming is a cognitive process
  • 10. Communication 'existing code is much more read than new code is written'
  • 11. Fear
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 21.
  • 22.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 42. What's the goal ? def find( start :Char, end :Char, pths :List[ (Char,Char) ] ) :List[ (Char,Char) ] = { var rout = (start,start) :: Nil var dends :List[(Char,Char)] = Nil while( !rout.isEmpty && rout.head._2 != end ){ var conts = from( rout.head._2, pths ) .filter( pth => !dends.contains( pth ) && !rout.contains( pth ) ) if( conts.isEmpty && !rout.isEmpty ) { dends = rout.head :: de rout = rout.tail } else{ rout = conts.iterator.next :: rte } } rout.reverse.tail }
  • 45. Goals & sub-goals
  • 48. 'G' 'F' 'I' 'B' 'C' 'A' 'H' 'D' 'G' 'E'
  • 49. What's the goal ? def findRoute( start :WayPoint, target :WayPoint, map :Set[Path] ) :Sequence[Path] = { var route = new Stack[Path] var deadEnds :Set[Path] = new HashSet[Path] route push Path( start, start ) while( !route.isEmpty && route.top.endPoint != target ){ var continuingPaths = pathsFrom( route.top.endPoint, map ) .without( deadEnds ).without( route ) if( continuingPaths.isEmpty && !route.isEmpty ) { deadEnds += route.pop } else{ route push continuingPaths.first } } route.reverse }
  • 50. Hypothesis & Verification
  • 52. public class PrimeGenerator { static int[] sieveUpTo( int maxValue ){ if( maxValue < 2 ) return new int[0]; boolean[] grid = new boolean[maxValue + 1]; for( int i = 0; i <= maxValue; i++ ){ grid[i] = true; } grid[0] = grid[1] = false; for( int i = 2; i < Math.sqrt( maxValue + 1 ) + 1; i++ ){ if( grid[i] ){ for( int j = 2*i; j <= maxValue; j += i ){ grid[j] = false; } } } … }
  • 56. Concepts Push Pop Stack
  • 57. Concepts Store Push Pop Stack
  • 58. Concepts Not Store 'lose' Push Elements Pop Stack
  • 59. Concepts Not Store 'lose' Push Elements Pop Collection Stack
  • 60. Concepts Not Store 'lose' Push Elements Pop Collection Stack Add Remove Iterate Elements Elements Elements
  • 61. Concepts Store Push Pop Stack LIFO
  • 62. Concepts Store Push Pop Stack LIFO FIFO
  • 63. Concepts Store Push Pop Stack LIFO Queue FIFO FIFO
  • 64. Concepts Store Push Pop Collection Stack LIFO AddAddAdd Elements Elements Elements Queue FIFO FIFO
  • 66. public class Folding { public static <T> T fold( List<T> list, Monoid<T> monoid ){ return list.isEmpty() ? monoid.unit() : monoid.conjunct( head( list ), fold( tail( list ), monoid ) ); } private static <T> T head( List<T> list ){ return list.isEmpty() ? null : list.get( 0 ); } private static <T> List<T> tail( List<T> list ){ return list.size() >= 2 ? list.subList( 1, list.size() ) : EMPTY_LIST; } }
  • 67. public interface Monoid<T> { public T unit(); public T conjunct( T t1, T t2 ); }
  • 68. public class MonoidInstanceTest extends TestCase{ ... public void testStringAsMonoid(){ assertEquals( "helloworld", stringMonoid.conjunct( "hello", "world" ) ); assertEquals( "hollamundo", stringMonoid.conjunct( "hola", "mundo" ) ); assertEquals( "hola", stringMonoid.conjunct( "hola", stringMonoid.unit() ) ); assertEquals( "hola", stringMonoid.conjunct( stringMonoid.unit(), "hola" ) ); } public void testIntegerAsMonoid(){ assertEquals( 6, poductIntMonoid.conjunct( 2, 3 ) ); assertEquals( 42 , productIntMonoid.conjunct( 7, 6 ) ); assertEquals( 11, productIntMonoid.conjunct( 11, productIntMonoid.unit() ) ); assertEquals( 11, productIntMonoid.conjunct( productIntMonoid.unit(), 11 ) ); } ... }
  • 69. public class MonoidTest extends TestCase{ ... private static <T> void assertAssociativity( Monoid<T> monoid, T t1, T t2, T t3 ){ assertEquals( monoid.conjunct( t1, monoid.conjunct( t2, t3 ) ), monoid.conjunct( monoid.conjunct( t1, t2 ), t3 ) ); } private static <T> void assertNeutrality( Monoid<T> monoid, T value ){ assertEquals( monoid.conjunct( value, monoid.unit() ), value ); assertEquals( monoid.conjunct( monoid.unit(), value ), value ); } public void testMonoidInstances(){ assertAssociativity( stringMonoid, "s1", "s2", "s3" ); assertNeutrality( stringMonoid, "s1" ); ... assertAssociativity( productSumMonoid, 1, 2, 3 ); assertNeutrality( productSumMonoid, 1 ); } }
  • 70. public class Monoids { public static Monoid<String> stringMonoid = new Monoid<String>(){ public String unit() { return ""; } public String conjunct(String t1, String t2) { return t1 + t2; } }; public static Monoid<Integer> productIntMonoid = new Monoid<Integer>(){ public Integer unit() { return 1; } public Integer conjunct(Integer t1, Integer t2) { return t1 * t2; } }; ...
  • 71. public class Monoids { ... public static Monoid<Integer> sumIntMonoid = new Monoid<Integer>(){ public Integer unit() { return 0; } public Integer conjunct(Integer t1, Integer t2) { return t1 + t2; } }; ...
  • 72. public class FoldTest extends TestCase{ public void testStringConcat(){ assertEquals( "Hello world !!!", fold( asList( "Hello", " ", "world" + " " + "!!!" ), stringMonoid ) ); } public void testSum(){ assertEquals( 15, fold( asList( 1, 2, 3, 4, 5 ), sumIntMonoid ).intValue() ); } public void testProduct(){ assertEquals( 120, fold( asList( 1, 2, 3, 4, 5 ), productIntMonoid ).intValue() ); } ...
  • 73.
  • 74. public reorderBook( String isbn ){ ... if( isbn.substring( 0, 2 ).equals( ''978'' ){ pubNr = isbn.substring( 6, 10 ); } else{ pubNr = isbn.substring( 8, 12 ); } ... }
  • 75. public reorderBook( String isbn ){ ... if( isbn.substring( 0, 2 ).equals( ''978'' ){ pubNr = isbn.substring( 6, 10 ); } else{ pubNr = isbn.substring( 8, 12 ); } ... } ISBN is NOT a String !!!
  • 76. public interface Isbn { public Region getRegion(){ ... } public Integer getPublisherNumber(){ ... } public Integer getTitelNumber(){ ... } public Integer getChecksum(){ ... } public boolean isValid(){ ... } } ISBN is a concept in its own right !!! public reorderBook( Isbn isbn ){ ... isbn.getPublisherNumber(); ... }
  • 77. Conture & Boundary
  • 78. public boolean isValidLaufzeit( Vertrag vertrag ){ GregorianCalendar start = vertrag.getStart(); GregorianCalendar end = vertrag.getEnd(); int tagesdifferenz = 0; if (start != null && end != null) { int startJahr = start.get(Calendar.YEAR); int endJahr = end.get(Calendar.YEAR); int tageImStartJahr = start.get(Calendar.DAY_OF_YEAR); int tageImEndJahr = end.get(Calendar.DAY_OF_YEAR); int aktuellesJahr = startJahr; while (aktuellesJahr <= endJahr) { if (aktuellesJahr == startJahr) { if (aktuellesJahr == endJahr) { tagesdifferenz += tageImEndJahr - tageImStartJahr; } else { tagesdifferenz += start.isLeapYear(startJahr) ? (366 - tageImStartJahr) : (365 - tageImStartJahr); } } else if (aktuellesJahr == endJahr) { tagesdifferenz += tageImEndJahr; } else { tagesdifferenz += start.isLeapYear(aktuellesJahr) ? 366 : 365; } aktuellesJahr++; } } return tagesdifferenz > 365 && tagesdifferenz < 999; }
  • 79. public void createOrder( int itemId, Date shippingDate ){ Date today = new Date(); long start = today.getTime(); long end = shippingDate.getTime(); BigDecimal diff = new BigDecimal( start - end ); int days = diff.divideToIntegralValue( new BigDecimal( 1000 * 60 * 60 * 24 ) ).intValue(); if( days > 14 ) rejectOrder(); // ... }
  • 82. public boolean isValidLaufzeit( Vertrag vertrag ){ TimeInterval interval = vertrag.getLaufzeit(); return interval.toDuration().inYears() > ONE_YEAR && interval.toDuration().inYears() < THREE_YEARS; }
  • 83. public void createOrder( int ItemId, Date shippingDate ){ Duration duration = new Duration( today(), shippingDate ); if( duration.inDays() > 14 ) rejectOrder(); // ... }
  • 85. String separator ='' ''; String query = ''select ''; if( ... ) query += '' name ''; if( ... ) query = query + separator + '' alter '', separator = '', ''; query += '' from person ''; if( existFilter ){ query += '' where '' if( ... ) query += '' stadt = '' + stadt; separator = '' and ''; else{ query += '' stadt in ( ''; for( String stadt : staedte ) query += stadt + inSeparator; inSeparator = '', ''; query += '' ); separator = '' and '' } ...
  • 86. String separator ='' ''; String query = ''select ''; if( ... ) query += '' name ''; if( ... ) query = query + separator + '' alter '', separator = '', ''; query += '' from person ''; Do you see the core idea ? if( existFilter ){ (Hint: it's NOT about String Handling) query += '' where '' if( ... ) query += '' stadt = '' + stadt; separator = '' and ''; else{ query += '' stadt in ( ''; for( String stadt : staedte ) query += stadt + inSeparator; inSeparator = '', ''; query += '' ); separator = '' and '' } ...
  • 87. String separator ='' ''; String query = ''select ''; if( ... ) query += '' name ''; if( ... ) query = query + separator + '' alter '', separator = '', ''; query += '' from person ''; Building SQL-Statements ... if( existFilter ){ … is NOT about String Handling query += '' where '' if( ... ) query += '' stadt = '' + stadt; separator = '' and ''; else{ query += '' stadt in ( ''; for( String stadt : staedte ) query += stadt + inSeparator; inSeparator = '', ''; query += '' ); separator = '' and '' } ...
  • 89. Query personQuery = Query.onTable( ''Person'' ) personQuery.select( ''name'' ) personQuery.select( ''alter '' ) personQuery.add( criteria( ''stadt'' ).equals( stadt ) ); personQuery.add( criteria( ''stadt'' ).in( staedte ) ); ...
  • 92. String separator ='' ''; … by the way ... String query = ''select ''; if( ... ) query += '' name ''; if( ... ) query = query + separator + '' alter '', separator = '', ''; query += '' from person ''; if( existFilter ){ query += '' where '' if( ... ) query += '' stadt = '' + stadt; separator = '' and ''; else{ query += '' stadt in ( ''; for( String stadt : staedte ) query += stadt + inSeparator; inSeparator = '', ''; query += '' ); separator = '' and '' } ...
  • 93. String separator ='' ''; … anybody missed that ? String query = ''select ''; if( ... ){ query += '' name ''; separator = '', ''; } if( ... ) query = query + separator + '' alter '', separator = '', ''; query += '' from person ''; if( existFilter ){ query += '' where '' if( ... ) query += '' stadt = '' + stadt; separator = '' and ''; else{ query += '' stadt in ( ''; for( String stadt : staedte ) query += stadt + inSeparator; inSeparator = '', ''; query += '' ); separator = '' and '' } ...
  • 95. ''Look, a Composite ...' Directory ''delete' File File Directory ''delete' ''delete' ''delete' File File ''delete' ''delete'
  • 96. ''Look, another Composite ...'' UI Panel ''draw' UI Text UI Input UI Panel ''draw' ''draw' ''draw' UI Text UI Selection ''draw' ''draw'
  • 97. AbstractComposite operation() add( Composite) remove( Composite ) childs() : List<Comp.> Node Composite operation() operation() add( Composite) remove( Composite ) childs() : List<Comp.>
  • 98. Is this a Composite ? AtLeastOneAuthProvider ''authenticate' LdapAuthProvider DatabaseAuth. UnanimousAuthProvider ''authenticate' ''authenticate' CertificateAuth. AccessAuth. ''authenticate' ''authenticate'
  • 99. ... and this ? CEO ''salary' Employee Employee CIO ''salary' ''salary' Employee Employee ''salary' ''salary'
  • 100.
  • 101. Collection generalization List Set Bag Queue Stack < discrimination > FIFO LIFO
  • 102. public static Integer sum( Stack<Integer> vals ){ int sum = 0; for( int val : vals ) sum += val; return sum; }
  • 103. public static Integer sum( Stack<Integer> vals ){ int sum = 0; for( int val : vals ) sum += val; return sum; } sum( new Stack<Integer>(){{ push(1); push(2); push(3); }}; sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }};
  • 104. public static Integer sum( List<Integer> vals ){ int sum = 0; for( int val : vals ) sum += val; return sum; } sum( new Stack<Integer>(){{ push(1); push(2); push(3); }}; sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }}; sum( new HashSet<Integer>(){{ add(1); add(2); add(3) }};
  • 105. public static Integer sum( Collection<Integer> vals ){ int sum = 0; for( int val : vals ) sum += val; return sum; } sum( new Stack<Integer>(){{ push(1); push(2); push(3); }}; sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }}; sum( new HashSet<Integer>(){{ add(1); add(2); add(3) }};
  • 107. public class QueueTest extends TestCase { private Queue<Integer> queue = null; public void setUp() throws Exception{ queue = new ... queue.add( 10 ); queue.add( 3 ); queue.add( 7 ); queue.add( 5 ); } public testQueuePolling{ assertEquals( ? , queue.poll() ); assertEquals( ?? , queue.poll() ); assertEquals( ??? , queue.poll() ); assertEquals( ???? , queue.poll() ); } }
  • 108. public class QueueTest extends TestCase { private Queue<Integer> queue = null; public void setUp() throws Exception{ queue = new ArrayBlockingQueue<Integer>(); queue.add( 10 ); queue.add( 3 ); queue.add( 7 ); queue.add( 5 ); } public testQueuePolling{ assertEquals( 10 , queue.poll() ); assertEquals( 3 , queue.poll() ); assertEquals( 7 , queue.poll() ); assertEquals( 5 , queue.poll() ); } }
  • 109. public class QueueTest extends TestCase { private Queue<Integer> queue = null; public void setUp() throws Exception{ queue = new PriorityQueue<Integer>(); queue.add( 10 ); queue.add( 3 ); queue.add( 7 ); queue.add( 5 ); } public testQueuePolling{ assertEquals( 3 , queue.poll() ); assertEquals( 5 , queue.poll() ); assertEquals( 7 , queue.poll() ); assertEquals( 10 , queue.poll() ); } }
  • 111. Collection generalization List Set Bag Queue Stack PriorityQueue ArrayQueue HPFO < discrimination > FIFO
  • 113. public static List<Integer> multiplesOf( int factor, int limit ){ List<Integer> collect = new ArrayList<Integer>(); for( int i = 1; i * factor <= limit; i++ ){ collect.add( i * factor ); } return collect; } vs. public static Set<Integer> multiplesOf( int factor, int limit ){ Set<Integer> collect = new HashSet<Integer>(); for( int i = 1; i * factor <= limit; i++ ){ collect.add( i * factor ); } return collect; }
  • 114. public static List<Integer> multiplesOf( int[] factors, int limit ){ List<Integer> collect = new ArrayList<Integer>(); for( int factor : factors ){ for( int i = 1; i * factor <= limit; i++ ){ collect.add( i * factor ); } } return collect; }
  • 115. public static Set<Integer> multiplesOf( int[] factors, int limit ){ Set<Integer> collect = new HashSet<Integer>(); for( int factor : factors ){ for( int i = 1; i * factor <= limit; i++ ){ collect.add( i * factor ); } } return collect; }
  • 117. Distinction public boolean isGoodDeal( BigDecimal initialCosts, BigDecimal runCosts ){ BigDecimal totalCost = initialCost.add( runCost ); BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) ); BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN ); return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1; }
  • 118. Distinction public boolean isGoodDeal( BigDecimal initialCosts, BigDecimal runCosts ){ BigDecimal totalCost = initialCost.add( runCost ); BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) ); BigDecimal as Money BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN ); return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1; }
  • 119. Distinction public boolean isGoodDeal( BigDecimal initialCosts, BigDecimal runCosts ){ BigDecimal as Percent BigDecimal totalCost = initialCost.add( runCost ); BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) ); BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN ); return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1; }
  • 120. Distinction public boolean isGoodDeal( BigDecimal initialCosts, BigDecimal runCosts ){ BigDecimal totalCost = initialCost.add( runCost ); BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) ); BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN ); return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1; } What's the result 'type' of combining 'Money' with 'Percent'
  • 121. Distinction public boolean isGoodDeal( BigDecimal initialCosts, BigDecimal runCosts ){ BigDecimal totalCost = initialCost.add( runCost ); BigDecimal oneP = totalCost.divide( new BigDecimal( 100 ) ); BigDecimal propRunCosts = wk.divide( oneP, 2, DOWN ); return ! propRunCosts.compareTo( new BigDecimal( 50 ) ) > 1; } Which combinations are allowed - which not ?
  • 123. Distinction public boolean isGoodDeal( Money initialCosts, Money runCosts ){ Money totalCost = initialCosts.sum( runCosts ); Percent proportionRunCosts = totalCost.proportionOf( runCost ) return proportionRunCosts.isGreaterThan( Percent.FIFTY ) }
  • 125.
  • 126. Mental Distance Mental Distance
  • 127. ... do you recognize the underlying concept ? interface Stepper<T>{ public boolean isExhausted(); public void step(); public T getCurrent() }
  • 128. ... do you recognize the underlying concept ? interface ElementSupplier<T>{ public boolean hasMoreElements(); T nextElement(); }
  • 129. ... do you recognize the underlying concept ? interface ElementConsumer{ public void observe( BigElement e ); public void calculate( AnotherElement e ); public void extract( YetAnotherElement ); }
  • 130. ... do you recognize the underlying concept ? interface ElementInspector{ public void inspect( BigElement e ); public void inspect( AnotherElement e ); public void inspect( YetAnotherElement ); }
  • 131. ... do you recognize the underlying concept ? interface ElementVisitor{ public void visit( BigElement e ); public void visit( AnotherElement e ); public void visit( YetAnotherElement ); }
  • 132. Language date.compareTo( otherDate ) < 0 vs. date.isBefore( otherDate )
  • 135. Trust
  • 136. Verifiable Specifications Stack stack = is( new DescriptionOf <Stack>(){ public Stack isDescribedAs(){ Stack<String> stack = new Stack<String>(); stack.push( foo ); stack.push( bar ); return stack; } } ); it( "should contain foo" ); state( stack ).should( contain( foo ) ); it( "should contain bar" ); state( stack ).should( contain( bar ) ); it( "should return bar when calling pop the first time" ); state( stack.pop() ).should( returning( bar ) ); it( "should return foo when calling pop the second time" ); stack.pop(); state( stack.pop() ).should( returning( foo ) ); it( "should be empty after popping the two elements" ); stack.pop(); stack.pop(); state( stack ).should( be ( empty() ) );
  • 137. Design by Contract @Invariant( "this.size >= 0 and this.size <= this.capazity" ) public interface Stack { ... } @Postcondition( "return > 0" ) public int getCapacity(); public int getSize(); @Precondition( "elem not null and this.size < this.capacity" ) @Postcondition( "elem == this.top and this.size == old:this.size + 1" ) public void push( Object elem ); @Postcondition( "this.top == old:this.top ) " ) public Object getTop(); @Postcondition( "(old:this.size>0) ==> (return == old:this.top and this.size == old:this.size - 1)") public Object pop(); ... }
  • 138. Liskovsubtype of T, then objects of type T in a ''if S is a Substitution Principle program may be replaced with objects of type S without altering any of the desirable properties''
  • 140. Principle of least astonishment
  • 142. ... void writeToFile( Output outout ){ openFile(); writeToFile( output ); }
  • 143. void process{ input(); count++; output(); }
  • 144. One level of abstraction
  • 145. Dependency Inversion Principle declarative vs Intention Revealing Interfaces imperative Functional Programming Yagni Immutability side effects Expressiveness Domain Driven Design Consistence
  • 146. If there are three things to keep in mind ...
  • 147. … it's not only ''developers! developers! developers!'' ...
  • 148. … but Empathy! Empathy! Empathy!
  • 149. Now stop hacking code for machines start writing programs for humans … and the rest will follow ...