Hello, Hexagonal Architecture

Hello Hexagonal Architecture


While developing a software we always craving for Architecture because we want our software adopts future changes easily.

So, Architecture stepped in for maintainability. Here maintainability mean how easily we can incorporate changes without disturbing old.

Every feature addition in a software comes with a Risk, Risk of breaking old,maintainability,rigidity,dependencies etc, There are many shades of risks
we called it Technical debt.


Technical debt has an inverse relationship of maintainability, using Architectural style we want to decrease the risk or I can say make it constant while adding new features.

We experienced that when we start writing code at that time it is easy to add features and gradually it becomes hard unless we do not use proper architecture for that software.


Hexagonal Architecture:

We will discuss Hexagonal Architecture here, in one word Hexagonal Architecture says.

Core business logic talks to other through a contract.

The core business logic means your software development logic should talk to others means Database or any JMS Queues or any Flat files or HTTP request or FTP , NOSQL etc through a contract or in Java language we can say interface.

The benefits of above type of design is whatever the input or output channels that boil down to the contract so every channel has to implement that contract/interface to talking with our software, So for our software perspective all are same as all implement the same contract so our software can deal with any types of input and output channel .

Benefits:

1, Easily incorporates any channel like Flat file,RDBMS, NoSQL, Http,Ftp,JMS etc.
2. Our software can be easily tested because it is easy to create a mock as just need to implement the contracts.

3. Adding new requirements means plugging it, or implementing the contracts.
4. Proper separation of concern.
5. Maintains IOC as Higher level and lower level talking through contract.


Sometimes we called Hexagonal architecture as Port and Adapter or Onion architecture.

As in this architecture, we have a port for each channel say for Database

The tasks we have to perform

To implement the contract to talk with our software.
As database API say JDBC is itself a contract or Hibernate is itself a framework so we need to create an adaptor GOF adapter pattern where we have to implement a strategy which converts JDBC related operation to our contract related operation.
Then plug this adaptor into our port to talk with this channel.



Outline of the design

Software Contract

package com.example.architecture.hexagonal;

public interface IPersists<T,TCOMMAND> {
   
   public void save(T t,TCOMMAND commandObject);    
   public void delete(T t,TCOMMAND commandObject);
   

}

This is the general contract for talking with our software, any output channel like File channel, RDBMS,NoSQL should implement that contract.


Here I take an example How it can talk to JPA entity which saves that data in Database.

DataBaseChannelAdapter.java
package com.example.architecture.hexagonal;

public class DataBaseChannelAdapter implements IPersists<EmployeeDomainObject,EmployeeCommand>{

   public void save(EmployeeDomainObject t, EmployeeCommand commandObject) {
     
       String underLyingJPAEntity = commandObject.getEntityClass();
       System.out.println("call save on " + underLyingJPAEntity);
     
   }

   public void delete(EmployeeDomainObject t, EmployeeCommand commandObject) {
       String underLyingJPAEntity = commandObject.getEntityClass();
       System.out.println("call delete on " + underLyingJPAEntity);
     
   }

}


As JPA Entity use some JPA related annotation so I did not include this JPA entity as part of our Domain, I use JPA framework as an Outside Channel of our software domain and DataBaseChannelAdapter takes our core domain Employee Object and takes a Command Object which tells Adapter to Which JPA entity to call and call the same.


EmployeeDomainObject

package com.example.architecture.hexagonal;

public class EmployeeDomainObject {
   
   public String name;
   public String address;
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getAddress() {
      return address;
   }
   public void setAddress(String address) {
      this.address = address;
   }
   @Override
   public String toString() {
      return "EmployeeDomainObject [name=" + name + ", address=" + address
              + "]";
   }
   
   

}


Our core Domain Employee Object it does not dependent on any Framework so I can plug any framework with it through Adapter like I can easily change DatabaseAdapter to FileAdepter to save our core domain object in File.




EmployeeCommand.java

package com.example.architecture.hexagonal;

public class EmployeeCommand{
   
   public String entityClass;

   
   
   public String getEntityClass() {
      return entityClass;
   }

   public void setEntityClass(String entityClass) {
      this.entityClass = entityClass;
   }

   @Override
   public String toString() {
      return "EmployeeCommand [entityClass=" + entityClass + "]";
   }

   
   

}





This Command object is nothing but help Adapter to convert Core Domain Object to Underlying Output channel (Database or File)

EmployeeDomainDao.java

package com.example.architecture.hexagonal;

public class EmployeeDomainDao<T,TCommand>{
   
   IPersists<T,TCommand> adapter;
   
   
   public void save(T t,TCommand commandObject)
   {
      adapter.save(t, commandObject);
   }
   
   public void delete(T t,TCommand commandObject)
   {
      adapter.delete(t, commandObject);
   }

   public IPersists<T, TCommand> getAdapter() {
      return adapter;
   }

   public void setAdapter(IPersists<T, TCommand> adapter) {
      this.adapter = adapter;
   }
   
   
   

}
This is our Core Domain Persist layer here I use the adapter as Strategy based on the Adapter it will call exact output channel and persist our Domain Object.





Now Time to Test our Software design


Main.java

package com.example.architecture.hexagonal;

public class Main {
   
   public static void main(String[] args) {
      EmployeeDomainDao<EmployeeDomainObject,EmployeeCommand> dao = new EmployeeDomainDao<EmployeeDomainObject,EmployeeCommand>();
      IPersists<EmployeeDomainObject,EmployeeCommand> adapter= new DataBaseChannelAdapter();
      dao.setAdapter(adapter);
      EmployeeDomainObject emp = new EmployeeDomainObject();
      emp.setName("Shamik Mitra");
      emp.setAddress("India,Kolkata");
     
      EmployeeCommand command = new EmployeeCommand();
      command.setEntityClass("com.employeemanagement.entity.EmployeeJpaEntity");
     
      dao.save(emp, command);
      dao.delete(emp, command);
   }

}








Output:

Object StateEmployeeDomainObject [name=Shamik Mitra, address=India,Kolkata]
call save on com.employeemanagement.entity.EmployeeJpaEntity
Object StateEmployeeDomainObject [name=Shamik Mitra, address=India,Kolkata]
call delete on com.employeemanagement.entity.EmployeeJpaEntity





Hexagonal Layers :






Hexagonal architecture,port & adapter architecture,onion Arhitechture

Picture courtesy Google



Application Domain: As I said earlier it is the software where all software related business logic, validation goes on, this is the inside module every outside module talks with it through contract.

Application/Mediation Layer:  Kind of services layer it adopts the Framework layer or ut’s outside layer and make necessary changes according to domain layer contract to talks with Domain layer or in the same way return back the result from Domain to Framework layer.
It sits between Framework and Domain layer.


Framework Layer: This layer as to input/output channel or we can say the outside world and use an adaptor to adapt the data and transform it according to our  software contract.




Reveal the Programing to an Interface Design principles in java.



Programming to an Interface    

I think it will better to discuss design principals in java based on which design patterns are created.

The very first principal is “Programming to an Interface” what does it mean?

Let try to understand the principal in details.

In general, scenario, if you look at any problem statement or business solution you can find two parts.

1.    Fixed part.
2.    Variable

The fixed part is some kind boilerplate code. But when we design we take care of the variable part.
All the design patterns are discovered to maintain this variable parts. Because they are ever-changing. If your code is not flexible with future enhancement, then your code is not up to the mark.

The question is in java How you can maintain your variable parts?
To drill down to answer let magnify the statement "maintain variable parts". we know same will perform an operation but we don’t know How we can achieve this  operation . Specifically, we know the type of the operation but don’t know details of the implementation moreover client needs can be changed so operation implementation  change in future.

Let’s, take an Example A computer monitor is design for display purpose. So I can say if Computer is a product and Computer monitor is a part of computer product.,then Computer monitor is responsible for display operation.

Now, later on, client needs is changed ,now they want to display by Projector

So If our solution is not capable of welcome this needs it will be nothing but a waste product.

According to new needs what we can analyse is, it will perform same action display but the module should change from Computer monitor to Projector.

So display module in Computer product should be flexible so we can change it easily. Or we can change it dynamically(runtime). We can say display module is like a strategy  and client change the strategy now.

So our java solution is like following.

interface displayModule
{
 public void display();
}

public class Monitor implements displayModule
{
public void display()
{
s.o.p(“Display through Monitor”);
}



public class Projector implements displayModule
{
public void display()
{
s.o.p(“Display through projector”);
}


public class Computer
{
 displayModule dm;

public void setDisplayModule(displayModule dm)
{
this.dm=dm;
}

public void display()
{
 dm.display();
}


public static void main(String args[])
{
Computer cm =new Computer();
displayModule dm = new Monitor();
displayModule dm1 = new Projector();
cm. setDisplayModule(dm);
cm. display();
cm. setDisplayModule(dm1);
cm. display();


}                                                                                                    


}

Look the solution, we know Display Module should be flexible, and we know the operation of the display module is "display" but according to the client it may be changed later, but in a computer, there should always be a display module but we don’t know what will that equipment. It’s may be monitor or projector or any other.


So we create an interface and every Display parts should implement that and provide the own definition of the display.

Look the computer class here I create HAS-A relation call display-module because we know display module change frequently as per client needs so we always make display module as abstract
So we can change it runtime with actual implementation.

Remember always code through an interface so you can change your strategy run-time with actual implementation.
The interface means here java interface or abstract class.
Make the variable parts as an interface or abstract class as you know the operation which is never changes but it implementation or the implement module can change.