Codacy Background Image

Strongly typed actors in a loosely coupled architecture

This is a blog post of our Code Reading Wednesdays from Codacy (http://www.codacy.com): we make code reviews easier and automatic.

Being a code centered company, one thing we are consistently focused is on keeping code with high cohesion and low coupling.
As we previously mentioned, Codacy is built using Scala and Play, both of which have proved to be great decisions.
While building Codacy, to keep the code clean and logically contained, we decided to break our play application into several specialized components. This is a small glimpse of how our architecture is structured.

Components

A component is no more than a cohesive set of functionality that can be developed and compiled independently of other components.
We then let each component transmit a public API which will become the only coupling to the outside world (the remaining components).
To accomplish this, we used the sbt sub-project functionality and configured play to depend on these subprojects.

This is great for various reasons:

  • It makes for self-tested and smaller bundles of features
  • It reduces the amount of class dependencies hence reducing the compilation time
  • It creates greater organization and we can easily point out where to head next or what needs to be improved

 

Component Architecture

This is an example diagram of the component driven architecture (with some examples taken from our own architecture):

Note: The PlayWebsite component has a dependency on all components, not shown here for simplicity’s sake

We can see several components that are dependent of each other and connect to other outside sub systems (in this case Git and our DB).

The Git system represents our 3rd party execution of binaries (since we rely on it heavily to communicate with our users’ repositories).

Each project components was only responsible for one system task, relying on the framework for utilities like logging and system configuration settings, injected directly from the PlayWebsite configuration.

Unfortunately, as the project grew, we found the need to add more components, sometimes having inter-dependencies.

To solve this, we implemented a simple factory, that all components could depend on for object creation. (As a side note, the reason why we steered away from standard and vanilla Dependency Injection is enough for a new blog post by itself).
We wanted however to make this simple factory to be configurable and as non-binding as possible to our code.
Hence we created a register based dependency injection where components ask our ComponentFactory for instances of a type. This factory, in turn, returns the registered implementation for the requested type.

This is a final view of how this simple structure ended up impacting the architecture.

Implementation

Since we use Scala, we’re providing our Scala implementation (that depends somehow on Play 2).

To start, all components should first implement a trait that would be used for requesting a object creation.
As an example, let’s create an Engine class that extends an IEngine trait:

class Engine extends IEngine 

To request an instance of the engine, a component would simply call:

val engine = ComponentFactory.getComponent[IEngine]

In order to work, all required components would need to be registered on application start. We started by configuring and registering all components (Play2 specific):

object Global extends GlobalSettings {
  override def onStart(app: Application) {
      ...
      ComponentFactory.setComponent[IEngine](classTag[Engine])
      ...
  }
}

Because we wanted to have different types of registered components for different executing environments (such as development, debug and production), we started setting the components by reading the registrations from a config file:

codacy.components.IEngine.interface="codacy.framework.component.IEngine"
codacy.components.IEngine.class="codacy.Engine"

This allowed us to quickly change the implementing classes without having to restart or recompile the application, only having to deploy a new jar and changing the configuration to use the new class.
Furthermore, this structure allows us to have the benefits of dependency injection without having to pollute our injected classes with cross concerning code (subcut).

Although this system worked for a development environment, we had to make sure the website would not have the blocked waiting for a component to finish some operation, especially as some I/O operations could potentially take a long time (eg, reading from a remote hosting provider). Hence we came with the idea of creating actors that were responsible for each component. So, we started using Akka and its actor system.
This is also the main reason why we didn’t choose guice: we wanted greater control on the execution and distribution of our components.

Actors with Type safety

Because we wanted our interface to be completely type checked, we used Typed Actors.
This way we achieve a truly object oriented approach which transforms message passing to method invocations and we use the compiler as much as possible.

For this, we extended the ComponentFactory to, instead of instantiating simple classes that implemented those interfaces, create them as strongly typed akka actors that implemented the exact same interface but performing these actions with all the features and safety that akka actors provide. So, instead of a simple class factory:

def getComponent[T <: AnyRef](implicit m: Manifest[T]): T = {
  val className = this.classCache.get(m.runtimeClass.getName)
  Class.forName(className)
       .getConstructor()
       .newInstance()
       .asInstanceOf[T]
}

We started providing strongly typed actors:

private[dependencyBuilder] def getComponentActor[T <: AnyRef](implicit m: Manifest[T]): T = {
  val className = this.classCache.get(m.runtimeClass.getName)
  TypedActor(system).typedActorOf(
      TypedProps(Reflect(system).actorClassFor(className.get)
  )
}  

classCache is a simple SynchronizedMap holding class names for all configured traits Note: If trying to use this code snipped, be sure to check this Stackoverflow answer.

However intimidating at first, this code is quite clever and concise.
While this required absolutely no code changes in the rest of the application, we started having a system that worked on the shoulders of the awesome Akka toolkit. Pretty cool!

With this, we have a system that is fully message driven, with non blocking calls.

Next step is to have several instances of each component, with messages being delivered with the help of a Router.
That’ll be the subject of my next blog post.

Thanks for reading. Reach me on Twitter for more on this.

By João (https://twitter.com/caxaria)


Brought to you by the makers of Codacy (http://www.codacy.com): an automated code review tool focused on giving you code analysis results that matter.
We simplify and save time of your code reviews and pull requests.

Follow us at https://twitter.com/codacy