Sunday, April 17, 2016

Does software architecture matter?



Short answer, of course it matters! It is in fact crucial, and not just for us geeks. Software houses seem to agree, and a strong indication is that ‘software architects’ and related job titles are paid handsomely. What I doubt is how the software architecture is communicated, if it is considered important from all the involved stakeholders (do they even know they have “stakes” on it?) and how ‘honest’ the developed software application is to its envisioned architecture.


Here would be a good place for a definition of software architecture, but which one to choose from the numerous that are out there? For me all of them are probably correct from the perspective and the context they were produced. From IEEE’s “fundamental concepts or properties of a system in its environment embodied in its elements, relationships, and in the principles of its design and evolution” to Mr. Martin Fowler’s “things that are hard to change” and everything between (or beyond).


For the point I want to get across the one that seems to fit the best is that a software architecture provides a common (enough) understanding of the system and allows us to reason about it, decide on the trade-offs and keep us on the right track while developing.


I said common enough, because as Mr. Fowler has mentioned “software diagrams are an imperfect representation of a shared understanding between stakeholders”. Imperfect yes, but good enough. And in fact, for different stakeholders, different diagrams or more accurately different abstractions of the software architecture must be used for reasoning based on this common understanding.


Let’s back up a bit and discuss about how I believe most software architectures are defined and used in practice at different companies*. The software architect has a vision of how the application should be, it presents it to management, they don’t understand much but they agree as long as it will be realized in their preferred timeframe and then the architecture is presented to the development team. Software is developed aiming to realize this architecture. A year later the codebase looks nothing like the architecture, the architect probably already left and the architecture found its best use in the least sexy slide of the marketing team for the project. Sounds familiar?


It does not have to be like that. With some discipline, good communication and to be honest a bit more time up-front, software architecture can be really something that matters. And in the long run be both what will make a software application a success and a force for economy of resources when maintaining the application.


So how to go about defining the software architecture? And who should be involved? My concern is how the architecture will be represented and how it will be communicated to different groups. And it is not only the resulted architecture that matters, but the process of generating the software architecture. Dwight D. Eisenhower said “plans are useless but planning is indispensable”. In software, architecture is certainly not useless but its process is equally important, if not more. It brings together the assumptions, expectations and agreed trade-offs of all stakeholders in a software product from the business to the nitty-gritty code monkeys (or artists/scientists/Gods in our own perspective!).


The best approach in my opinion, is to produce different abstraction levels** of the architecture which will be mapped to the interests and technical depth of the involved stakeholders. This will serve the purpose of the architecture which is to give a common understanding between the stakeholders, about which they can reason.
I will attempt to show the value of the architecture (and the process of its definition) by providing a few examples. Let’s consider different scenarios where a good software architecture description can be proved golden.


A new developer joins the dev team:
Lots of legacy code, many decisions and trade-offs were made (shortcuts were taken) while developing as it always happens. The developers that are currently present may never touched parts of the codebase. How are we going to help the new dev get on board? How long will it take to become productive? With a good description of the architecture, it is (relatively) easy. Few UML sequence diagrams for the main control flows of the application, a picture with the layers of the application and mapping of the “diagram shapes” to the part of the code (e.g., packages) will help with understanding how the application works, where to search in the codebase and even what scenarios to run for a given issue. Of course it is extremely important to make sure that the code is sticking to the architecture or that the architecture is evolved during development.


Communicating with non-tech stakeholders:
How to discuss the development decisions with not so technical people? How to decide on the trade-offs? Mr. Bob Martin says that the architecture of an application should “scream what the application does”. And I see the merit in it. The decisions that shaped the architecture show what is important for the application. For example an application having a glitch when putting things on the “bag” of an e-commerce shop might be an acceptable choice, but having a glitch while helping a space vehicle to land, not so much. Use cases, pictures, UML diagrams, metaphors are invaluable tools during the architecture discussions and decisions - for me they are as a unit the architecture, not only some diagrams! These decisions must be agreed and communicated to the developers.


Selecting tools and frameworks:
This is a tricky one. Mr. Martin advocates that we should separate the architecture from the technologies and tools. It has to do with the reversibility, which is desired of course, since requirements seem to change, assumptions could be proved to be wrong and decisions sometimes are not that great. Selecting tools and frameworks often makes things less reversible or costly to reverse which in turn may increase the complexity of the system. So when Mr. Martin says "the purpose of a good architecture is to delay decisions, because then you can make decisions with more information" is pretty good advice. However, technologies to a certain extent shape the architecture. For example the different nature of NoSQL databases compared to relational, have effect in the architecture of the application. Isn't the selection of the database model closely related to the nature of the application? And is it not this choice affecting the architecture? And how these decisions will be made? During the crucial process of defining the architecture. So delay the selections of tools, sure, but the selection is very much part of the architecture. Even for the business the selection of technologies plays a big role. Try convincing a car or plane manufacturer to use things other than Excel sheets to hold their data and you will understand what I mean!

Here is another definition for software architecture: Mr. Fowler stated that “Architecture is about the important stuff. Whatever that is.” As I understand it, in its essence is a statement about communication, the important stuff need to be communicated between involved parties. From business and sales all the way to devs and ops, architecture in different abstraction levels, shapes, and forms gets people to discuss, decide and implement what is expected by all stakeholders. It is figuring out what are the important stuff, communicating the important stuff and building while having in mind the important stuff. And when it is done like this, the architecture really matters.

* Based on what I see and read in different blogs, books and portals
** Defining a software architecture on different abstraction levels is a concept proposed by few people and one of them (most recent to my memory) is Mr. Simon Brown. I rather enjoyed one of his presentations I viewed in youtube Software Architecture vs. Code in GOTO conference.

Sunday, March 6, 2016

The State design pattern

I love it when my next post subject comes from a 'real' life situation I am in. Recently I was working on a piece of code in which there was a class with a huge method. In this method there was a long switch block and based on the value of a property in the class, it performed some logic. This code was extended and edited by multiple developers over time. This is a common  code smell and a clear refactoring case, so I was a bit surprised that none took the time to improve the code by using the state design pattern. And just like that, I had the theme and motivation for my next design pattern tutorial!

The state design pattern is of the behavioral family and allows objects to alter their behavior depending on their internal state. For example, people should not talk much to me in the morning before I have a coffee! The state pattern is ideal for cases where the state of objects can change at runtime and the behavior for each state has to change as well. Many times, as was the case I saw, new states and behaviors are added and this requires changes in the class which violates the open/closed principle. Using the state pattern, we can remove long and difficult to follow switch blocks and have a clear, modularized and extendable piece of code.

To showcase how the state design pattern can be used, lets consider a coffee machine. Our coffee machine makes great coffee but it only does this when it has coffee and it has water. Based on its state, meaning it has water and it has coffee will either make us a cup of coffee or guide us to take it to the right state. The UML diagram of the components that we will build is presented below:


We start by creating the State inteface, which defines the behaviors that will be adjusted based on the state of the object. Our coffee machine can insert coffee, insert water and make coffee.

package com.tasosmartidis.design_patterns_tutorial.state;

public interface State {

    public void insertCoffee();
    
    public void insertWater();
    
    public void makeCoffee();
}

Next, we will define the different states a coffee machine can be in. It can be empty, which means that it contains neither water, nor coffee and thus it cannot make coffee. In cases that someone inserts coffee, then it will print the appropriate message and  change the state of the coffee machine to 'has coffee'. Similar for inserting water.

package com.tasosmartidis.design_patterns_tutorial.state;

public class IsEmpty implements State {

    private CoffeeMachine coffeeMachine;

    public IsEmpty(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }
    
    public void insertCoffee() {
        System.out.println("Inserting coffee..."); 
        coffeeMachine.setMachineState(coffeeMachine.getHasCoffeeState());
    }
 
    public void insertWater() {
        System.out.println("Inserting water..."); 
        coffeeMachine.setMachineState(coffeeMachine.getHasWaterState());
    }
 
    public void makeCoffee() {
        System.out.println("Cannot make coffee, there is no water or coffee!");     
    }
}

So lets now create a state where coffee is already inserted. It still cannot make coffee and will not accept more coffee since it has already. But it will certainly accept water to be inserted, print appropriate message and set the state to has water and coffee since then it will have both.
package com.tasosmartidis.design_patterns_tutorial.state;

public class HasCoffee implements State{
    
    private CoffeeMachine coffeeMachine;

    public HasCoffee(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }

    public void insertCoffee() {
        System.out.println("Cannot insert coffee, it is already full!");         
    }
 
    public void insertWater() {
        System.out.println("Inserting water...");
        coffeeMachine.setMachineState(coffeeMachine.getHasCoffeeAndWaterState());
    }
 
    public void makeCoffee() {
        System.out.println("Cannot make coffee, it has coffee but no water!");      
    }
}

In the case that water has been inserted to the coffee machine, its state change to 'has water'.
package com.tasosmartidis.design_patterns_tutorial.state;

public class HasWater implements State {
     
    private CoffeeMachine coffeeMachine;

    public HasWater(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }
    
    public void insertCoffee() {
        System.out.println("Inserting coffee..."); 
        coffeeMachine.setMachineState(coffeeMachine.getHasCoffeeAndWaterState());
    }
 
    public void insertWater() {
        System.out.println("Cannot insert water, it is already full!");
    }
 
    public void makeCoffee() {
        System.out.println("Cannot make coffee, it only has water!");       
    }

}

Of course inserting water does not always change state to 'has water'. The change of the state depends also in the current state of the machine. For example, when a machine is in state 'has water' and coffee is inserted, its state changes to 'has coffee and water'. Let's define this state:
package com.tasosmartidis.design_patterns_tutorial.state;

public class HasCoffeeAndWater implements State {

    private CoffeeMachine coffeeMachine;

    public HasCoffeeAndWater(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }

    public void insertCoffee() {
        System.out.println("Cannot insert coffee, it is already full!");         
    }
 
    public void insertWater() {
        System.out.println("Cannot insert coffee, it is already full!");    
    }
 
    public void makeCoffee() {
        System.out.println("Making coffee...");
        coffeeMachine.setMachineState(coffeeMachine.getMakingCoffeeState());
    }
}

Finally, when the machine has both coffee and water, it is ready to make us a nice cup. This is an additional state, and while it is making coffee, it cannot perform anything else, like adding coffee or water. When making coffee is finished, its state returns back to 'is empty'.
package com.tasosmartidis.design_patterns_tutorial.state;

public class MakingCoffee implements State {
     
    private CoffeeMachine coffeeMachine;

    public MakingCoffee(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;   
    }
    
    public void insertCoffee() {
        System.out.println("Cannot insert coffee while making coffe!"); 
    }
 
    public void insertWater() {
        System.out.println("Cannot insert water while making coffee!"); 
    }
 
    public void makeCoffee() {
        System.out.println("Cannot make coffee its busy!"); 
        coffeeMachine.setMachineState(coffeeMachine.getIsEmptyState());         
    }

}

Great! So now all the possible states of our coffee machine and their behavior are defined. Next we will define the coffee machine. Our coffee machine will have its current state, which we can set and the behaviors which change based on the state, for inserting coffee, water and making coffee. I also define all possible states in the object with getters, which they will help moving the current state of the machine to the desired one based on thegiven action. Basicallly you can see what I mean if you look at the makeCoffeemethod of the HasCoffeeAndWater class. When the machine starts making coffee, it prints the appropriate message and sets the current state of the machine, using the getter of the machine for the state we want to set it to. An alternative would be to create a new state object in the set method, e.g., "coffeeMachine.setMachineState(new MakingCoffeeState())", but I do not want to create a new object every time the state changes. The coffee machine source is shown below:
package com.tasosmartidis.design_patterns_tutorial.state;

public class CoffeeMachine {

    private State machineState;
    private State isEmpty;
    private State hasCoffee;
    private State hasWater;
    private State hasCoffeeAndWater;
    private State makingCoffee; 
    
    
    public CoffeeMachine() {
        this.machineState = new IsEmpty(this);
        
        this.isEmpty = new IsEmpty(this);
        this.hasCoffee = new HasCoffee(this);
        this.hasWater = new HasWater(this);
        this.hasCoffeeAndWater = new HasCoffeeAndWater(this);
        this.makingCoffee = new MakingCoffee(this);
    }
    
    public void setMachineState(State newState) {
        this.machineState = newState;
    }
    
    public void insertCoffee() {
        machineState.insertCoffee(); 
    }
 
    public void insertWater() {
        machineState.insertWater();
    }

    public void makeCoffee() {
        machineState.makeCoffee();
        
    }
    
    public State getIsEmptyState() { return isEmpty; }
    public State getHasCoffeeState() { return hasCoffee; }
    public State getHasWaterState() { return hasWater; }
    public State getHasCoffeeAndWaterState() { return hasCoffeeAndWater; }


Now let's see our coffee machine in action! We will test how the coffee machine works based on its state and the actions requested from the machine.
package com.tasosmartidis.design_patterns_tutorial.state;

public class CoffeeMachineDemo {

    public static void main(String[] args) {
        
        CoffeeMachine coffeeMachine = new CoffeeMachine();

        coffeeMachine.makeCoffee();
        coffeeMachine.insertCoffee();
        coffeeMachine.makeCoffee();
        coffeeMachine.insertWater();
        coffeeMachine.makeCoffee();
        coffeeMachine.makeCoffee();
        coffeeMachine.makeCoffee();     
    }
}

The main method above, has some simple commands and flow. Let's break down what we expect:

  1. A new coffee machine object is created - its state is empty
  2. Ask to make coffee - it shouldn't be able to
  3. We insert coffee - change state to has coffee
  4. Ask to make coffee - still water is missing
  5. We insert water - now machine has both coffee and water
  6. Ask to make coffee - makes us coffee and change state to making coffee
  7. Ask to make coffee again - it cannot, it is busy making coffee and changes state to empty
  8. Ask to make coffe last time - it cannot, machine is empty
And when we run the program, we get the following output:
















It worked as expected! So this brief tutorial presented the state design pattern and when it can be useful. It should be stressed however, that the state pattern can get quite complicated. The states used above are not many, but if we kept extending with more states and behaviors there is complexity from having to keep track of how to move from one state to the other and how to behave in each state. It is a useful design but must be applied with care. 

As always, the code is available in github.

Sunday, February 21, 2016

The Chain of Responsibility design pattern

It has been some time since my last post. Life get's busy I guess! So to pick things up a bit, I will add another design pattern in the series of tutorials (see previous posts such as Facade or Adapter and more).

The chain of responsibility design pattern is of the behavioral family and implements an approach where a sender/originator of a request can be served by any in a number of receiver objects. Each receiver object contains a reference to other receiver objects and the sender’s request is passed from receiver to receiver, till the request is served or all the receivers in the chain are traversed.

The main motivation of the pattern is to detach the request from a specific receiver. The use of the chain pattern allows to be decided at runtime, which object will serve a request, from a set of object that are able to do so. In the chain of responsibility pattern, it is possible that the request will not be served.

To showcase the pattern, lets consider a customer support center where clients can be served by English or Dutch speaking employees. Also, as probably you would have guessed, an employee that is already busy with a client, cannot serve another support request.

The followin UML class diagram provides an overview of the components of the tutorial:





















We start with an abstract class, named CustommerSupportEmployee. Usually an interface is used for the chain pattern and in general interfaces are preferable than extending a class (because you can only extend one) but I want to use a method across all receivers of our example. The source code, is shown below:
package com.tasosmartidis.design_patterns_tutorial.chain;

public abstract class CustomerSupportEmployee {
    private CustomerSupportEmployee nextInChain;
    private boolean employeeBusy = false;
    
    public abstract void serveCustomer(CustomerServiceRequest csRequest);
    
    void passRequestToNextInChain(CustomerServiceRequest csRequest, String noNextEmployeeMessage){
        if(nextInChain!=null)
            nextInChain.serveCustomer(csRequest);
        else
            System.out.println(noNextEmployeeMessage);
    }
        
    public void setNextInChain(CustomerSupportEmployee nextInChain){
        this.nextInChain = nextInChain;
    }

    public boolean isEmployeeBusy() {
        return employeeBusy;
    }

    public void setEmployeeBusy(boolean employeeBusy) {
        this.employeeBusy = employeeBusy;
    }   
}

The serveCustomer is the importnt one for the receiver objects. We use a boolean for checking if a customer support employee is busy which will help us with the workflow when showing the pattern. Simply put, if an employee (receiver) is busy, then passes the request to the next in chain. And passing to the next in chain is a helper method for doing that.

Next, we create two classes, a Dutch and an English customer support employee. Objects of these classes will be used as receivers of requests in the chain pattern demo. The code for these classes looks something like this:

package com.tasosmartidis.design_patterns_tutorial.chain;

public class CustomerSupportDutch extends CustomerSupportEmployee{
    private String name;
    
    public CustomerSupportDutch(String name) {
        this.name = name;
    }

    public void serveCustomer(CustomerServiceRequest csRequest) {
        if(!this.isEmployeeBusy()) {
            
            if(csRequest.getLanguage().equals("NL"))
                System.out.println("Client receives service by Dutch CS representative: " + name); 
            else
                passRequestToNextInChain(csRequest, "We provide customer service for EN and NL only");
        }else {
            passRequestToNextInChain(csRequest, "Sorry, all support employees are busy at the moment! Please try again later!");
        }
    }
}

And the English speaking customer support employee:
package com.tasosmartidis.design_patterns_tutorial.chain;

public class CustomerSupportEnglish extends CustomerSupportEmployee { 
    private String name;
    
    public CustomerSupportEnglish(String name) {
        this.name = name;
    }

    public void serveCustomer(CustomerServiceRequest csRequest) {
        if(!this.isEmployeeBusy()) {
            
            if(csRequest.getLanguage().equals("EN"))
                System.out.println("Client receives service by English CS representative: " + name); 
            else
                passRequestToNextInChain(csRequest, "We provide customer service for EN and NL only");
        }else {
            passRequestToNextInChain(csRequest, "Sorry, all support employees are busy at the moment! Please try again later!");
        }
    }           
}

I am showcasing the chain pattern here and focus only in it, but I would prefer to have the factory pattern for selecting between Dutch and English customer support employee and use the chain for passing the request if a receiver (employee) is busy.

Let's now create a requester class, for the objects that require customer support. The requester will have a name and the language in which they wish to be "supported".
package com.tasosmartidis.design_patterns_tutorial.chain;

public class CustomerServiceRequest {

    private String clientName;
    private String language;
    
    public CustomerServiceRequest(String clientName, String language) {
        this.clientName = clientName;
        this.language = language;
    }
    
    public String getClientName() {
        return clientName;
    }
    public void setClientName(String clientName) {
        this.clientName = clientName;
    }
    public String getLanguage() {
        return language;
    }
    public void setLanguage(String language) {
        this.language = language;
    }
}

We are almost there! Let's create a demo scenario, where a customer will request support and the request will be passed in the chain to the appropriate receiver that is currently not busy.
package com.tasosmartidis.design_patterns_tutorial.chain;

public class CustomerSupportDemo {

    public static void main(String[] args) {
        CustomerServiceRequest supportClient = new CustomerServiceRequest("Tasos", "EN");
        
        // Create a few customer support employees
        CustomerSupportEmployee englishSpeaker1 = new CustomerSupportEnglish("Joe");
        CustomerSupportEmployee englishSpeaker2 = new CustomerSupportEnglish("Jane");
        CustomerSupportEmployee dutchSpeaker1 = new CustomerSupportDutch("Anne");
        CustomerSupportEmployee dutchSpeaker2 = new CustomerSupportDutch("Tessa");
        
        // Define the chain of command
        dutchSpeaker1.setNextInChain(dutchSpeaker2);
        dutchSpeaker2.setNextInChain(englishSpeaker1);
        englishSpeaker1.setNextInChain(englishSpeaker2);
        
        // Make first in chain English speaking employee busy so he has to pass the request
        englishSpeaker1.setEmployeeBusy(true);
        
        dutchSpeaker1.serveCustomer(supportClient);
    }
}

All setup, and for the scenario we setup in the demo class above, the request should pass the dutch speaking employees in the chain (Anne, Tessa), and the busy English speaker ("Joe") to be served by the available one ("Jane"). Let's see if it works as expected!


It worked! And this concludes the tutorial on the chain design pattern. The code as always, is available on github.

Wednesday, January 20, 2016

What makes teams great?

Great teams beat great individuals (almost) every time. Most of us have been members of a team at some point or another. The lucky of us who  happened to be members of great teams (or at least felt that way) probably achieved our goals, grew our skills and enjoyed every minute of it. I have been member of teams from early on and still find great pleasure in working within teams. It started with football at my young age and continues in my professional life as a software engineer. Many times I contemplated on what makes a great team and I think that both in football and in software development, the traits of great teams are essentially the same - or can be abstracted to seem like that. In this post I provide my take in what makes great teams.


It all starts with skills. Good teams are made of people that are very skilled in their domain. They constantly work to develop their skills even further and interact with teammates in a manner that improves each other’s skills (i.e., knowledge exchange, motivation, mentoring, etc.). Teams must have big goals and like it or not, certain level of skills are required to reach such goals.


Next, and closely related to the first trait, is the variety of skills. Different members should be experts in different skills so that teammates complement each other’s skills and achieve mutual growth. A software project for example, involves many aspects, such as the user experience, the architecture, performance & security, front-end and back-end development and the clear business value it brings. It is not common for single individuals to be highly skilled in all aspects. But put together people with variety of exceptional skills and with the right process and attitude you will eventually have a team of people who are jack of all trades and master of many. Moreover, discussions between people that approach a given issue from a different point of view, usually brings great results.


Another important trait of good teams is the respect of teammates for each other’s skills. In my opinion, most people involved in software engineering have quite an ego problem. It makes some sense, since designs, solutions and trade-off decisions are not always binary - right or wrong way to do it. People feel very emotional about the things they “give birth to” and are quick to jump and dismiss the opinion of others if they do not respect their skills and knowledge. Many times I heard sentences from fellow geeks such as “he doesn’t know how to test my application right” or “he is not able to write a code of line, he can’t talk to me about architecture”. These things I believe would be avoided and the discussions would be much more constructive if there is mutual respect on the skills of teammates.

The three traits mentioned above, I believe are enough to make a good and efficient team. But what separates good teams from great teams? In great teams, teammates like each other!
It is very important dynamic and changes a great deal of things. I will list the three most important effects it has in the team:

  1. It greatly enhances communication, because every comment or discussion is perceived with good intentions behind it
  2. It creates a fun environment to work in and I believe this does wonders on the team productivity
  3. There is not a “not my f@cking job” mentality and teammates are truly willing to help each other

Hopefully most of us are working within great teams! What are the traits you believe make a great team?