Freitag, 17. Juni 2011

Let it flow...

The Object Modeling Technique (OMT) introduced by James Rumbaugh defines for the analysis phase (OOA) three modeling types. Starting at the object level, defining an object model, the dynamic modeling is following for the core parts of the business logic mainly to visualize state changes. Object models and dynamic models covered through state diagrams are present in the UML today. The functional modeling, also known as data flow models, are not part of the UML. The reason might be the functional background of data flows, not recognized as an important modeling technique in the object-oriented world.

For my computer science degree I designed with OMT and developed a multimedia system in the programming language C which is a portable solution for Microsoft Windows NT and IBM OS/2. I designed  in the object-oriented style and used the functional programming language C to implement the model, that was possible with some tricks and effort. I remember one important point during modeling the multimedia system. I had some problems with the object model relationships and sometimes problems to define the dynamic model in detail. The data flow modeling was easier for me, more natural and rather fluent. 

Data Flow Diagram
At that time I thought the problem is my weak experience in modeling complex object-oriented systems. Later in my career I learned object-oriented modeling starting with the domain layer (DDD). I learned to visualize the software model in class and component diagrams using stereotypes and the power of UML diagrams. This power is in some cases weak when it touches the implementation and the differences in the model and the implementation occur. Continuous rework for the improvement of the models are necessary to avoid this weakness. Modeling on an appropriate level with appropriate details is not simple and some lessons are necessary to learn modeling on the right level. My advice is to try the Java EE architect certification as an opportunity to find this level.

During last weeks, I followed the discussion about Event Based Components (EBC) which is a technique to develop software flow-oriented. Ralf Westphal defined principles and patterns for the flow-oriented programming. I read some of his blog articles and listened to the discussions in the clean code developer forum. It seems to me that the .NET community is very eager in the field of flow-oriented programming. Later, I found a website from a developer whose aim is to bring EBC to the Java platform. Impressed of the flow-oriented modeling which again seems natural and fluent, usable on different levels and in line with the implementation, I was inspired to find a Flow Pattern

Therefore it was obvious to start Eclipse to do some TDD practice to dive into the flow. I admit that my knowledge about flow-oriented programming is weak and I rather think in object-oriented structures. This is what I have learned over the years developing software on the Java platform. Usually it is a worse starting position developing software in a field with weak domain knowledge, but it’s still a training  session. Starting with this background programming flows leading to a solution for a simple pattern for flow-oriented programming. Do not expect the "killer pattern" for a wide range of scenarios and problem solutions covered by this flow pattern.

The pattern is following the principle of the “input-process-output” model. It is usable in isolation or in chained scenarios. The use case for the pattern is a simple calculator board adding and subtracting values encapsulated in assemblies. The following discusses the flow pattern that is first documented with UML.

Flow Pattern

The “FlowChain” is an inspiration of the ChainOfResponsibility pattern. The ChainOfResponsibility pattern loosely couples assemblies and let the assemblies decide whether to process a value or not. The core of the pattern is based on Template Method by overriding the flow method to chain assemblies. The benefit of this pattern is to chain in the overriden flow method which is well encapsulated. The drawback is that you can only test assemblies covering their relationships, chained in the flow method. It’s not possible to test assemblies in isolation, that might be a drawback for some use cases.

The interface of the flow pattern is simple by calling the process method of an assembly instance which extends the flow pattern. The process method expects an input pin and returns an output pin as the result of the processing task. It’s not possible to build the chaining outside of the assemblies which is flexible but on the other side a slightly more complex programming interface.

The “FlowWire” is weaker coupled than the “FlowChain” with the possibility for outside wiring and testing of assemblies in isolation. In the flow pattern implementation the "FlowWire" extends the “FlowChain” with a wire method for outside wiring. The pattern consists of small super classes as the base for boards or assemblies of the boards using pins to fulfill the requirements of the “input-process-output” model.

The flow assemblies are based on classes whose instances are chained. It’s also possible to see flows as a chain of method calls which is finally more fine grained. The flow pattern covers simple use cases, not supporting complex routings and broadcasts.

FlowChain (stronger coupling)

public abstract class FlowChain<T> {
               
    public FlowPin<T> process(final FlowPin<T> inPin) {

        return flow(inPin);
    }
   
    protected abstract FlowPin<T> flow(final FlowPin<T> inPin);
}

 FlowWire (weaker coupling)

public abstract class FlowWire<T> extends FlowChain<T> {
   
    public FlowPin<T> wire(final FlowWire<T> assembly,
                                      final FlowPin<T> inPin) {
               
        return assembly.process(inPin);
    }
}

FlowPin

public class FlowPin<T> {

    private final T value;
   
    public FlowPin() {
       
        this(null);
    }
   
    public FlowPin(final T value) {
       
        this.value = value;
    }
   
    public T value() {
       
        return value;
    }

    @Override
    public int hashCode() {

        final int prime = 31;
        int result = 1;
        result = prime * result + ((value == null) ? 0 : value.hashCode());
       
        return result;
    }

    @Override
    public boolean equals(Object obj) {
       
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;              
        final FlowPin<T> other = (FlowPin<T>) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
       
        return true;
    }
}

FlowChainTest

import static org.junit.Assert.assertEquals;
import org.ccd.flow.pattern.api.FlowChain;
import org.ccd.flow.pattern.api.FlowPin;
import org.junit.Test;

public class FlowChainTest {

    @Test
    public void testSubtractAssembly() {
      
        final FlowChain<Integer> subtractAssembly = new SubtractAssembly();      
        assertEquals(new FlowPin<Integer>(7), subtractAssembly.process(new FlowPin<Integer>(12)));
    }
  
    @Test
    public void testAddAssembly() {
      
        final FlowChain<Integer> addAssembly = new AddAssembly();      
        assertEquals(new FlowPin<Integer>(17), addAssembly.process(new FlowPin<Integer>(12)));
    }
  
    @Test
    public void testCalculatorBoard() {
      
        final FlowChain<Integer> calculatorBoard = new CalculatorBoard();      
        assertEquals(new FlowPin<Integer>(7), calculatorBoard.process(new FlowPin<Integer>(2)));
    }
  
    private class CalculatorBoard extends FlowChain<Integer> {

        @Override
        protected FlowPin<Integer> flow(final FlowPin<Integer> inPin) {
              
            final AddAssembly add = new AddAssembly();
          
            return add.process(inPin);
        }
    }
  
    private class AddAssembly extends FlowChain<Integer> {

        @Override
        protected FlowPin<Integer> flow(final FlowPin<Integer> inPin) {
              
            final Integer value = addValue(inPin.value());
            final SubtractAssembly subtract = new SubtractAssembly();                      
                      
            return subtract.process(new FlowPin<Integer>(value));
        }

        private Integer addValue(final Integer value) {
          
            return value + 10;
        }
    }
  
    private class SubtractAssembly extends FlowChain<Integer> {

        @Override
        protected FlowPin<Integer> flow(final FlowPin<Integer> inPin) {
              
            Integer value = substractValue(inPin.value());          
              
            return new FlowPin<Integer>(value);
        }
      
        private Integer substractValue(final Integer value) {
                              
            return value - 5;
        }
    }
}

FlowWireTest

import static org.junit.Assert.assertEquals;
import org.ccd.flow.pattern.api.FlowPin;
import org.ccd.flow.pattern.api.FlowWire;
import org.junit.Test;

public class FlowWireTest {

    @Test
    public void testSubtractAssembly() {
      
        final FlowWire<Integer> subtractAssembly = new SubtractAssembly();      
        assertEquals(new FlowPin<Integer>(7), subtractAssembly.process(new FlowPin<Integer>(12)));
    }
  
    @Test
    public void testAddAssembly() {
      
        final FlowWire<Integer> addAssembly = new AddAssembly();      
        assertEquals(new FlowPin<Integer>(22), addAssembly.process(new FlowPin<Integer>(12)));
    }
  
    @Test
    public void testCalculatorBoard() {
      
        final FlowWire<Integer> calculatorBoard = new CalculatorBoard();      
        assertEquals(new FlowPin<Integer>(7), calculatorBoard.process(new FlowPin<Integer>(2)));
    }
  
    private class CalculatorBoard extends FlowWire<Integer> {

        @Override
        protected FlowPin<Integer> flow(final FlowPin<Integer> inPin) {
          
            final FlowWire<Integer> add = new AddAssembly();  
            final FlowPin<Integer> outPin = wire(add,inPin);
          
            final FlowWire<Integer> subtract = new SubtractAssembly();          
            return add.wire(subtract,outPin);
        }
    }
  
    private class AddAssembly extends FlowWire<Integer> {

        @Override
        protected FlowPin<Integer> flow(final FlowPin<Integer> inPin) {
              
            final Integer value = addValue(inPin.value());
                                                  
            return new FlowPin<Integer>(value);
        }

        private Integer addValue(final Integer value) {

            return value + 10;
        }
    }
  
    private class SubtractAssembly extends FlowWire<Integer> {

        @Override
        protected FlowPin<Integer> flow(final FlowPin<Integer> inPin) {
              
            final Integer value = substractValue(inPin.value());          
              
            return new FlowPin<Integer>(value);
        }
      
        private Integer substractValue(final Integer value) {

            return value - 5;
        }
    }
}

The flow pattern is developed in an object-oriented manner to support the programming of flows. Their is usually a border between object-oriented and flow-oriented programming. But listen: "This border is in your mind". You see it's possible to mix different styles to find a solution. The Flow Pattern is object-oriented and the implemented flows in the test cases are a mixture of the flow-oriented and object-oriented style.Using the power of both styles is appropriate to define a solution that fullfils the criteria of "input-process-output", encapsulation, isolation, loose coupling (coupling happens only on the board) and high cohesion to develop small assemblies and wire them to build a bigger assembly named as board. Wire boards and build a bigger solution that I call the flow-oriented application.You see, let it flow...to cross the border.


Der Rechtshinweis des Java Blog für Clean Code Developer ist bei der Verwendung und Weiterentwicklung des Quellcodes des Blogeintrages zu beachten.

Montag, 13. Juni 2011

Code of Conduct

There is no doubt that Robert C. Martin is an experienced programmer who gives the community of programmers a framework to write clean code. Robert published a lot of articles about principles to improve software quality which flows in his book “Clean Code: A Handbook of Agile Software Craftsmanship”. This book is rather technique centric, viewing code smells, guidelines how to refactor smells, explaining best practices for writing clean code and testing. The mission of the book is to sharpen programmer skills and learn how to reflect the daily written code using the boy scout rule for continuous improvements.

In Germany, Ralf Westphal and Stefan Lieser founded the clean code developer community launching a website which summarizes the principles and practices of clean code. In technical discussion the community understands the principles of clean code knowing that there must be more than technical terms. Proposals were made to missing principles, new ideas came up and the constructive critique boosted the understanding of clean code principles. Discussions about object-oriented principles, testing, agile models, programming language specifics followed along with the discussions in the clean code community. Code katas, to show how to write clean code, were used to view the benefits of clean code for discussion in the community. There is still some critique regarding code bloat, doubts about some principles in detail and how to handle the development lifecycle (e.g. TDD "yes or no" or how and when to do the design for modeling the software).

The Clean Coder
One fact was completely missing: The attitude of a professional programmer. First, I was doubtful about the new book of Robert which defines a code of conduct for professional programmers describing the attitude of a professional in detail. Personally, I don’t like books which advice behavior, how to handle schedules, conflicts and pressure. On the other hand, I like Robert’s style of writing books, explaining daily work scenarios and true experience of his craftsmanship career. The introduction of the book includes the excerpt: "I’ am a programmer, too. I’ve been a programmer for 42 years (don’t panic); and in that time - let me tell you – I’ve seen it all…". Robert has definitively a strong voice which is based on his experience leading to his brilliant reputation. But no one is born which such a voice, it’s still hard work to get every day a little bit better following the principles of clean code.

His message is to work clean (QA should find nothing), to have a work ethic, to know your field and domain, to learn continuously, to practice frequently, to collaborate with colleagues and to mentor junior developers as well as identification with your company and customers to mention the primarily subjects. Diving deeper into the subjects explains when to say “yes” or “no”, how to say it and what it really means. Some subjects are already known in the agile community like the “definition of done” (Scrum) and the commitment (the contract for agreement) to deliver features.

The book is easy to read and full of real life experience of a programmer with brilliant reputation. I have also experience working in different teams using different models and programming languages (mainly C/C++ and Java) for software development. I found a lot of experience written in this book which I have also made in my career. Leading to the simple principle to work clean, to avoid high pressure, conflicts and overtime. In Robert's words the best technical programmer could be fired when he has no professional attitude and his work is like a mess. We all know that pressure, conflicts and overtime could lead to bad code quality. But all this reasons are not acceptable as an excuse for bad code quality. Therefore, avoid pressure by clear communication and commitments which are reachable. Work clean to avoid overtime, and if overtime is necessary, the overtime should happen only in a defined time frame. Resolve conflicts like a professional and when this is not possible resolve it with a sense of humor (laugh may help). It’s also natural to have a wall in front of you, sitting on the keyboard and nothing happens. You may solve this situation by asking for a pair partner or simply accept the situation trying to resolve by going to the window to get some fresh air.

Interesting for me is Robert's opinion according the Flow Zone. For an experienced programmer the Zone is usually like a vacuum, working in a closed room with high speed producing large pieces of source code. I compare the Zone with a mountain bike trail having the power to cycle without hurts forgetting all sorrows in a perfect manner. It’s a nice feeling which could on the other hand be exhausting, if you cycle too far away from your home, it could be a problem to get back. Robert has the same opinion. Avoid the Zone although you write more code with higher speed. But the danger is to lose the big picture not getting the way back home. His advice is to enter the Zone only during practicing a training kata.

I could write even more about the book: “The Clean Coder – A Code of Conduct for Professional Programmers" but I might leave it up to you to participate in a valuable publication which completes the craftsmanship series with useful hints to work clean in the software development lifecycle with the appropriate attitude and responsibility to get things done.

Samstag, 11. Juni 2011

Vertical separation

Die vertikale Trennung schreibt die Definition von Variablen und Methoden nahe bei ihrer Verwendung vor. Verbunden mit der vertikalen Trennung ist die Kohäsion von Methoden. Eine kohäsive Methode ist klein und erfüllt genau eine Aufgabe. Das Band zwischen der vertikalen Trennung und kohäsiven Methoden wird durch die Lesefolge gebunden. Ausgehend von einer öffentlichen Methode werden die privaten Methoden, welche in der öffentlichen Methode verwendet werden, unterhalb der öffentlichen Methode im Quellcode geschrieben. Der vertikale Abstand zwischen den kohäsiven Methoden soll gering sein.

Die vertikale Trennung wird oft mit dem Lesen einer Tageszeitung gleichgesetzt. In einer Tageszeitung werden bewusst hervorgehobene Überschriften (Headlines) genutzt, denen ein Artikel folgt. Das Single Level of Abstraction (SLA) Prinzip gibt vor, dass in Klassen und Methoden möglichst nur ein Abstraktionsniveau verwendet werden soll. Teil dieses Prinzips ist, dass vorzugsweise mit lokalen Variablen in Methoden anstelle von Attributen einer Klasse gearbeiten wird. Die Nutzung lokaler Variablen vermeidet Seiteneffekte und beugt Problemen, die durch Nebenläufigkeit entstehen können vor. Quellcode, der dem SLA Prinzip folgt, ist gut zu lesen und zu verstehen. Der Leser erkennt durch die saubere Anordnung des Quellcodes sehr viel leichter essentielle Abschnitte ohne sich dabei in Details zu verfangen. Die vertikale Trennung und Bildung kleiner kohäsiver Methoden ist eine essentielle Praktik bei der Refaktorisierung durch Anwendung der Pfadfinderregel.

Die vertikale Trennung erhöht aber nicht nur die Lesbarkeit von Quellcode, sondern ist partiell nötig, um Kompilierprobleme zu Gunsten eines klaren Methodendesigns zu beseitigen.

Beispiel „Wildcard Capture“:

public static void reverse(List<?> list);
public static <T> void reverse(List<T> list);

Die Methodensignatur der “reverse” Methode kann auf Basis eines Wildcards oder mit einem Typparameter beschrieben werden. Die Wildcard Methodensignatur ist kürzer und lesbarer, bringt aber die Problematik mit sich, dass die übergebene Liste per Definition nicht mit neuen Elementen erweitert werden darf. Ein Kompilierfehler zeigt dieses Problem an. Das Problem ist durch eine zusätzliche Methode, die der vertikalen Trennung genügt, lösbar.

Quellcode einer einfachen ListHelper-Klasse:
 
public class ListHelper {

    public static void reverse(final List<?> list) {
       
        assertNotNull(list);       
        assertNotEmpty(list);
       
        reverseOperation(list);
    }
   
    private static void assertNotNull(final List<?> list) {
       
        if(null == list) {
           
            throw new NullPointerException("List argument is null!");
        }
    }

    private static void assertNotEmpty(final List<?> list) {
       
        if(list.isEmpty()) {
           
            throw new IllegalArgumentException("List contains no elements!");
        }
    }
   
    private static <T> void reverseOperation(final List<T> list) {
       
        final List<T> tmpList = new ArrayList<T>(list);
        final int maxPositions = list.size() - 1;
        int readPosition = 0;
       
        for(int writePosition = 0; writePosition <= maxPositions; writePosition++) {
           
            readPosition = maxPositions - writePosition;
            list.set(writePosition, tmpList.get((readPosition)));
        }
    }
}

In der Methode "reverseOperation" hat der Typparameter den Wildcard erfasst (captured).

Testfälle der ListHelper-Klasse:

@RunWith(value=Parameterized.class)
public class TestListHelper {
   
    private final List<String> original;
    private final List<String> reversed;
   
    public TestListHelper(final String[] original,
                                   final String[] reversed) {
       
        this.original = Arrays.asList(original);
        this.reversed = Arrays.asList(reversed);
    }
   
    @Parameters
    public static Collection<String[][]> getTestParameters() {
       
        return Arrays.asList(new String[][][]{
               
                {{"one", "two", "three"},{"three", "two", "one"}},
                {{"1", "2", "3"},{"3", "2", "1"}}});
    }
   
    @Test
    public void testReverse() {
                    
        ListHelper.reverse(original);       
        assertEquals(reversed, original);
    }
}

public class TestListHelperExceptions {

    @Test(expected=NullPointerException.class)
    public void testReverseWithNullPointerException() {
                    
        ListHelper.reverse(null);
    }
   
    @Test(expected=IllegalArgumentException.class)
    public void testReverseWithIllegalArgumentException() {
                    
        ListHelper.reverse(new ArrayList<String>());
    }   
}


Der Rechtshinweis des Java Blog für Clean Code Developer ist bei der Verwendung und Weiterentwicklung des Quellcodes des Blogeintrages zu beachten.