Tsoobame

software, japanese, kyudo and more

Ports and adapters architecture and functional programming (part 1)

Last week I was seeing a video about functional architecture and how it could help projects to be more maintainable:

Functional architecture - The pits of success - Mark Seemann


Although I did not agree on some of the statements and some of the examples on C#, I got curious (even more) about the topic. 

In my project we are starting to use RabbitMQ as message broker for our business events, both for services communication and for analytics.  For example, we want to make our logger to publish events in case of a message that is above some configured threshold (error by default).

When explaining these ideas to my team, one of my team members was worried about it, since the logger that was already performing side effects (but more or less safe) would start emitting events. He proposed to detach the functionality from the side effects. So again, functional programming was knocking to my door. 

Functional Programming

I started reading about functional programming and found some posts very interesting about applying functional programming in javascript. I am not an expert on functional programming but there are some basic concepts that are key to make software that is testable and less prone to errors. Before learning more about the complex concepts (monads, functors, etc) I want to understand the basic ones and try to apply them to a vanilla javascript project. 

Side Effects

A side effect is any change or any action performed out of the boundaries of a given function. By definition modifying a global variable, writing to the database, sending an event through an event bus, writing to a log file, changing the DOM, etc. is a side effect. Any of those things could produce a failure or an unexpected change and therefore any function performing any of those actions becomes non-deterministic and more difficult to test (more on this to come). 


Pure vs Impure functions

A pure function is a deterministic function that will always return the same value when getting the same input and that does not perform any side effects. So basically the pure function gets some values, performs some calculations and return a result: always the same one given the same parameters.

As you might suppose then, an impure function is any function that has performs side effects, so it is not deterministic. Its output, success or failure, etc would depend on external factors.

As a result, testing a pure function is easy and testing an impure function not so much; depending on the number or nature of the side effects they can become very complex to test.



Ports and adapters architecture

Ports and adapters or Hexagonal architecture tries so separate the core of the application from all the external elements it needs to connect to. An application will need to access to the Database, send emails, send events through a message broker, receive http requests, write log messages to files, etc.



It proposes four different types of elements:

- Application: the core, the functionality that models the domain behaviours and data. 

- Ports: entry (or exit) points to the application. The public interface to the application. What methods it provides for inputting information and what methods it needs to send resulting data to external services.

- Adapters: they are the elements responsible for getting or sending data to specific external elements. For example a module to access to the Database, a module to send events to an event bus, a logger to write the messages to disk, etc.

 - External elements: these are elements that are not part of out system but we need to interact with them to be able to perform the complete functionality. These are UI, Database, message brokers, etc.


Combining everything

Adding all together, it is easy to map the concepts from functional programming and from ports and adapters to have an idea on how nicely they fit and how natural it should be to create a functional application with ports and adapters architecture.

- Application shall be composed by only pure functions. It will provide the predictability and testability we need for the most important part of the system and we can reason about it more easily due to its deterministic nature.

- Adapters shall contain all the functions that will access the external systems, i.e. that will perform side effects. So the impure (non-deterministic) functions will be enclosed in the boundaries of the application.


Conclusion

The idea of joining functional programming with ports and adapters seems very reasonable and logic, but still without a clear/real example the concepts cannot be tested.

In my next posts I will create an application in three different flavours so we can materialise these ideas and find out if they really make sense. The application will be a service based on nodejs performing accesses to a database, writing log messages and sending business events to an event broker (all the external systems will be simulated). The flavours will be:

- Layered architecture: HTTP layer will call service layer that will call the repository and the event bus.

- Ports and adapters - Object Oriented: the core application will contain the domain logic and will get the adapters by dependency injections.

- Ports and adapters - Functional: the core application will contain only pure functions, the side effects will be performed by the adapters.

All will contain Unit Tests since I can foresee that in this regard we will see a lot of differences.


Do you  have any experience on working with functional programming? What are your thoughts about it?


Event sourcing: introduction by Greg Young

Some days ago I watched a video about event sourcing and cqrs where Greg Young was introducing the concepts in a very nice way.

I remember once in a project where we had to record every action that every user was performing in the system, so we had the usual database with the current state of the system that included a historical table with all the actions performed.

Event sourcing is about assuming that all the information that a system holds is based on the events that produced changes in that system. So they worth being stored. Instead of focusing on the current state of the data, it focus in the process that lead to the current state. For regulated enviroments it is a must to have all this events stored so it can naturally fall into the event sourcing pattern, but many other business can take a lot of benefit on using event sourcing.

This way of working is not new. Banks, lawyers, human resources, etc. have been working in this way since long time ago (before information was managed by something called software). The current state of your account is just the result of executing all the events/actions that affected it. No one would like to know their savings by having a table with the current state and not all the movements on the account. 

It has a lot of advantatges, like being able to go back in time and see how the system was in a given point of time, or calculate the evolution of a system, and also to be able to analyze the data in a deeper way than just having the current state. So for business intelligence reports and dashboards it is very useful.

It has also some ugly disadvantatges. Since you focus on storing the changes that are made to your system, you need to execute all the events in order to calculate the current state of the system. It is not very performant if you need to show this information to your users in a reasonable time. To minimize this you can create snapshots, so you only need to execute the events from the latest snapshot to the end, but still it would be too expensive to query data to show it on the screens. That is why event sourcing cannot work without CQRS.

I will talk about CQRS in a new post, but there is also a small introduction to it in the attached video.If you want to know more about event sourcing and to learn from someone more acknowledgeable, here you have the video:

Greg Young - CQRS and Event Sourcing - Code on the Beach 2014



Are you using event sourcing in your companies? Did you find any problems difficult to solve?