Reactive Clean Architecture with Vert.x

I have recently written about Clean Architecture and provided an implementation example by Uncle Bob himself. This time, we’ll look at the implementation from a bit different angle i.e. is it possible to implement a Clean Architecture and still take advantage of modern, reactive frameworks like Vert.x? Here it comes!

What Was That Clean Architecture, Again?

Clean Architecture divides our code into 4 conceptual circles – Enterprise Business Rules, Application Business Rules, Interface Adapters and Frameworks & Drivers. Between these circles, there is a strong dependency rule – dependencies can only flow inwards (see picture below). One of the rule’s implications is that the code in the inner part should have no knowledge of the frameworks being used, in our case these will be Vert.x and Guice. In general, you should be able to switch UI technologies, databases and frameworks without impacting the two inner circles.

If you want to read more about the theory behind Clean Architecture, make sure to check out my previous post and Uncle Bob’s upcoming book.

Reference Implementation

When working towards my reactive implementation, I used Uncle Bob’s repository as a reference:

One could go crazy with all the types of objects in the codecastSummaries use case package above. To make sure we’ll all on the same page, let me explain how I understand the role of each of them:

  • Controller – handles input e.g. web requests and orchestrates the work between the use caseview, and presenter
  • Input Boundary – an interface to the use case, a clear indication where the Interface Adapters circle ends and Use Cases circle begins
  • Output Boundary – an interface to the present the use case output, a clear indication where the use case ends processing and presentation begins
  • Use Case – orchestrates entities and other classes (e.g. external services) to satisfy a user’s goal
  • Response Model – a “stupid” representation of the use case results – we don’t want any business logic to leak through the output boundary
  • Presenter – converts data to a presentable form and presents them using a view
  • View Model – a presentable form of data. It’s usually similar to response model, with the only difference being that the response model does not care about being presentation-friendly
  • View – an object that handles actual displaying on the screen e.g. rendering an HTML page

It’s good to think about those objects as useful roles instead of obligatory parts of the architecture. Sometimes common sense suggests skipping some of them or making one object play multiple roles and we shouldn’t constrain ourselves too much.

Problem Domain

Despite using it as a reference, I didn’t want to code up the same thing as in Uncle Bob’s repository. I set out to implement something extremely simple – displaying a list of activities, in which, for now, an activity consists only of a name. I wanted to put as close to 100% focus on the architecture and as close to 0% focus on the domain itself. Hence, my Activity entity ended up looking like this:

The Entity base class looks almost the same, with the difference that it contains an id field instead of name.

The Use Case

As I already mentioned, the use case is really simple. All it needs to do is retrieve the data from a database and pass it through the output boundary:

As the response model would consist of a single field, we’re passing a collection of ActivityDetails directly through the boundary. This could be considered short-sighted, as any new field in the response model would force us to wrap it in a class and change the output boundary, but saves us some brain cycles analyzing the code for some time.

Don’t Call Us, We’ll Call You

Since in the reactive approach the thread responsible for processing our request should not wait for the results of a use case and catch exceptions, we need a way to process these asynchronously. The easiest way to deal with this is by using callbacks. But since we don’t want to couple our code to the framework, we need to use our own piece of code, instead of Vert.x’s  Handler and  AsyncResult. That’s why I created the  Callback interface:

As you can see, it contains two methods, success for asynchronously returning a result and failure for asynchronous indication of an exception. You can see the class in action in the use case implementation above. The use case invokes a database query which can take a long time and thus was implemented in a non-blocking manner using callbacks:

The Output Boundary

The output boundary of our use case is responsible only for presenting activities and communicating a failure if necessary. Hence, I made it extend the Callback interface directly:

Since there’s no need for a special view model and a presenter of the use case would only pass the result straight to the view, I decided to skip it and let the view play the role of an output boundary instead. Hence, the view was implemented like this:

Since the view implementation is part of the UI, it can contain direct references to the Vert.x framework i.e. the RoutingContext.

Binding Things Together

Now, that we have all the pieces of our use case, we can bind them together and expose via the web. Binding is done using a simple Guice module:

And exposing via the web is done using Vert.x Web  Router mechanism:

Wrap Up

That’s it. The final code structure looks like this:

As you can see, newest frameworks like Vert.x and Clean Architecture are not mutually exclusive. What’s more, there’s not much extra coding that you need to do to prevent the framework from spreading all over your codebase.

You can find all the code from this article here.

About the Author Grzegorz Ziemoński

King of Tidy Java, nerd that thinks about producing perfect software all the time and proud owner of 2 cats.

follow me on: