The words "Using Akka and Scala" super-imposed over the photo of a laptop

Using Akka and Scala for CQRS and Event Sourcing

In the past, we covered using Lagom to implement Java microservices using the event sourcing and CQRS patterns that framework relies on. Today, we’ll be revisiting our blog microservice example using the Scala programming language and Akka, one of the main components underlying Lagom.

Event Sourcing

First, let’s take a quick review of what event sourcing and CQRS are along with the general design patterns to use to implement these ideas. Event sourcing is an architectural pattern where all activity in a system is captured by immutable event objects, and these events are stored and published in a sequential log. The state of a system at a given time can therefore be derived from the sequence of events prior to the state.

For example, most SQL databases are implemented using this sort of architecture where all data mutation operations are stored as events in a write-ahead log. This pattern works very well with the physical storage underlying these devices as they tend to be based on magnetic disks which can work very fast in sequential access but become a lot slower in random access.

Using the concept of event sourcing, Command Query Responsibility Segregation is an architectural pattern that is rather self-describing: the responsibility of a system to handle commands and queries are separated rather than intertwined as in typical applications. Commands are used to update state while queries are used to inspect state.

The separation of these two concerns allows for much greater scalability in distributed systems than traditional approaches such as a single backing database for both reading and writing data. While CQRS is not required in order to implement a write-side and read-side pair of databases, it does offer a strong pattern to follow to do so.

For example, an application like Twitter may wish to store all tweets in a distributed database such as Cassandra, but in order to effectively search those tweets, it would be useful to copy written data into Elasticsearch for later querying. Provided that we follow an event sourcing pattern, then the source streams of data are well defined and make it much simpler to implement this responsibility segregation.

In CQRS, we can issue a command to a system to update its state. This command, after validation, will create an immutable event that is appended to the event log. After persisting this event, the state of the system can be updated in response. By doing this, the system can always be brought back to any given state by replaying the events in the event log. For performance reasons, the state of a system is periodically snapshotted and persisted so that less events from the main event log need to be replayed when restarting the system.

The state obtained from the event log can be as simple as the denormalized representation of entities, or it could be more complex views of the event stream which can be further combined down the line. It’s important to note that following this pattern means we need to manually reimplement some things we take for granted in a normal RDBMS such as transactions, indexing, joins, constraints, and triggers.

Ideally, these sorts of things can be abstracted well enough to be provided mostly through libraries or frameworks, but some things such as transactions are still application-specific in how to make compensating transactions to roll back erroneous data.

Actor Model and Akka

The actor model is essentially a model of distributed systems where processes are modeled as “actors”, things that have an inbox for receiving messages that are processed asynchronously. Actors can only communicate with other actors via messages, and this allows actors to be scaled outward into fully distributed systems.

A simple way to think of an actor is as a thread that cannot directly access the state of any other thread and must pass immutable message objects to other threads to coordinate anything. This avoids the use of synchronization, locks, and all the extremely difficult to debug concurrency issues that plague typical concurrent code.

Actors are lightweight and can be spawned and restarted many times with very little overhead (far less than an actual thread). Thus, following the ideals of programming languages like Erlang, actors are small enough to allow for a more robust form of error handling known as “let it crash”. Forming a suitable hierarchy of actors, parent actors can automatically restart child actors when errors occur or perform other fallback strategies.

This is particularly useful for long-running systems where either a full restart is infeasible or the cost of resources to double up the system for blue green deployments is prohibitive. It may also be the case that recovering the full state of the system would take too long, so being able to selectively restart only single components without affecting the rest of the system is very useful.

Akka is an implementation of this actor model inspired by Erlang. Akka is written in Scala and provides both a Scala and Java API for actors, clustering, persistence, distributed data, reactive streams, HTTP, and integration with various external systems.

All code samples in this post are from my GitHub repository. We’ll be using Scala 2.12 which requires Java 8. Note, if you’re still stuck on Java 6 or 7, Scala 2.10 and 2.11 both only require Java 6. Code samples may be adaptable to previous releases of Scala with little or no modifications. Let’s jump in to using Scala!

Blog API

Our API to implement today will be the same as in my Lagom tutorial. As such, we’ll have a blog data type consisting of three fields: title, author, and body. Blog posts are identified by UUIDs. The REST API will consist of a GET, POST, and PUT endpoint for looking up, creating, and updating blog posts respectively. The first thing to implement, then will be our blog data type.

final case class PostContent(title: String, author: String, body: String)

You may note that there isn’t much to it, and you’re right! Let’s review the syntax here. First of all, we don’t need to define things as public in Scala as they’re all assumed to be public by default. In fact, public is not even a keyword in Scala. After a class name comes its parameters which can be thought of as the parameters to its constructor.

A class can still have multiple constructors by defining methods named this within the class, but we have no need for that here. Parameters and variables are declared in the opposite order as Java; in Java, we would say String foo, whereas in Scala we would say foo: String. The other keywords used here are final which makes the class final as in Java, and case which makes this a “case class”.

Recall that in Java, we can use Lombok to automatically create an all-args constructor, getters for all fields, equals, toString, and hashCode, builders, withers, and other boilerplate code. In Scala, we can simply add case to a class to get a lot of that for free. A case class makes all its class parameters (fields) available with something similar to getters, adds sensible equals, hashCode, and toString method implementations, and handles some other Scala-specific features we’ll cover later. Essentially, a case class can be thought of as a data value class, and we’ll be using it as such.

Next, we’ll define a post id class instead of directly using UUID.

class PostId(val id: UUID) extends AnyVal {
  override def toString: String = id.toString
}

object PostId {
  def apply(): PostId = new PostId(UUID.randomUUID())

  def apply(id: UUID): PostId = new PostId(id)

  implicit val postIdDecoder: Decoder[PostId] =
    Decoder.decodeUUID.map(PostId(_))
  implicit val postIdEncoder: Encoder[PostId] =
    Encoder.encodeUUID.contramap(_.id)
}

We have several new keywords to discuss here. First, by adding val to the id class parameter, this will add a Scala-style getter for id by providing a way to access the id field directly. Classes use the extends keyword to extend other classes or implement traits (interfaces). This AnyVal class is a special class in Scala that works essentially as a boxed value type. This value class can only contain a single public field, and at compile time, the compiler will attempt to remove all indirect access of that field and replace it with direct access. Thus, we can create a wrapper type for UUID without sacrificing performance at runtime.

The override keyword is used just like the @Override annotation in Java: while not required, if the keyword is present but the method doesn’t actually override anything, this will cause a compiler error. This can be useful for catching typos or unknown API changes. The def keyword is used for defining methods. When a method has zero arguments, the parenthesis are optional. The conventional style here is that parentheses are omitted in pure functions while they remain in side-effecting functions. As with variables, the types of parameters and method return values come afterwards.

The object keyword here defines what is essentially a singleton instance of a class of the same name. Scala does not have static, but these objects provide an equivalent feature. When an object is named the same as a class, it is called the class’s “companion object”. A class and its companion object have equal access to internals of each other similar to how static and non-static members work in Java.

The apply methods here are used as factory methods to create PostId instances. The apply method has special meaning in Scala: we can omit the name of the method when calling it. For example, PostId.apply() is the same as calling just PostId(). As can be seen here, the return keyword is optional when the last line of executing code of a method is the return value.

The implicit keyword is used for a lot of things in Scala, and in this case, an implicit variable is one that is available for implicit parameters to methods that take them. We’ll be using it here to fill in custom encoder and decoder implementations for our PostId class to ensure that the JSON marshaller and unmarshaller do not think that this is a complex object.

The square bracket syntax, Decoder[PostId], is Scala’s generic type parameter syntax. The equivalent in Java would be Decoder<PostId>. Finally, these codecs are derived from existing UUID codecs, so we map and contramap them using some lambda functions. Both of these lambda functions use anonymous parameter syntax, both of which can be expanded to:

Decoder.decodeUUID.map(id => PostId(id))
Encoder.encodeUUID.contramap(postId => postId.id)

Next, let’s stub out a service interface. We’ll fill in the details later.

trait BlogService {
  def getPost(id: PostId)
  def addPost(content: PostContent)
  def updatePost(id: PostId, content: PostContent)
}

The trait keyword is very similar to an interface in Java. In fact, as written, this trait will compile directly into an interface. Traits are far more powerful than Java interfaces, so this isn’t always possible, but Java has started making interfaces more powerful starting with default methods in Java 8, so these two concepts may converge one day. The main difference between a trait and a class in Scala is that a trait cannot have its own parameters, but a class can extend (or mix in) multiple traits. So far, this is still very similar to Java. However, traits can contain fields, private and protected members, default implementations, and even constraints on what the concrete implementing class must conform to. We’ll omit the return types of the methods for now, but we’ll return to add them later once we’ve defined them.

Blog Entity

Next, let’s dive down to the entity level. Recall that in Lagom, a persistence entity is associated with three related things: commands, events, and state. Following a similar pattern here, we’ll implement a BlogEntity class by first defining our commands, events, and state classes.

object BlogEntity {

  sealed trait BlogCommand

  final case class GetPost(id: PostId)
    extends BlogCommand

  final case class AddPost(content: PostContent)
    extends BlogCommand

  final case class UpdatePost(id: PostId, content: PostContent)
    extends BlogCommand

  sealed trait BlogEvent {
    val id: PostId
    val content: PostContent
  }

  final case class PostAdded(id: PostId, content: PostContent)
    extends BlogEvent

  final case class PostUpdated(id: PostId, content: PostContent)
    extends BlogEvent

  final case class PostNotFound(id: PostId)
    extends RuntimeException(s"Blog post not found with id $id")

  type MaybePost[+A] = Either[PostNotFound, A]

  final case class BlogState(posts: Map[PostId, PostContent]) {
    def apply(id: PostId): MaybePost[PostContent] =
      posts.get(id).toRight(PostNotFound(id))

    def +(event: BlogEvent): BlogState =
      BlogState(posts.updated(event.id, event.content))
  }

  object BlogState {
    def apply(): BlogState =
      BlogState(Map.empty)
  }

}

The first new thing of note here is the sealed keyword. A trait or class marked sealed indicates that all subclasses of that trait or class must be contained in the same file. This makes pattern matching on these types of classes easier as it aids the compiler in detecting missing patterns checked by the programmer and can help prevent certain classes of bugs.

We have three types of commands: GetPost, AddPost, and UpdatePost. These are all rather trivial and mirror the same commands from the Lagom version of this microservice.

Next, we defined a sealed trait BlogEvent which contains two public values. The val keyword is similar to marking a variable as final in Java, while the var keyword is similar to a normal variable in Java. When defining aval or var on a class, this is technically creating a field in the class along with a getter-style method (named the same as the field) and a setter-style method if using var. What this effectively does is allows the variable to be accessed as if it were a public field of the class. Note that by not giving a val or var an initial value, this makes them abstract. It may be worth noting here that semicolons are optional in Scala and tend to be omitted; otherwise, this would have been our first usage of them.

For our events, we only care about commands, not queries (in the CQRS sense of the words, not a BlogCommand type of command), so we defined two events: PostAdded and PostUpdated.

Next, we abuse the case class feature to implement our own exception class, PostNotFound, to obtain some handy features for free. This demonstrates the syntax to call the constructor of a superclass as well. There is one other nifty feature in use here: interpolated strings. Scala provides an extensible feature to make interpolated strings which are expanded out and filled in at compile time. The syntax s"Hello, $foo!" would be essentially the same as "Hello, " + foo + "!" at compile time. We could use more advanced expressions inside the string by wrapping the variable name in curly braces, so for instance, we could say s"Hello, ${foo.capitalize}!".

After that, we define a type alias named MaybePost[+A]. There are a few things going on in this, so let’s break it down. First of all, Scala allows us to define type aliases which can be used to alias a larger type into something more readable, or it can even be used simply to rename types. In the generic type parameter, the +A bit indicates that, if B is a subclass of A, then MaybePost[B] is a subclass of MaybePost[A]. This is called a covariant type parameter. If we omitted the plus, we’d have an invariant type parameter which means that regardless of how A and B are related, Foo[A] and Foo[B] would not be related.

There is a third type of variance available called contravariant type parameters which use -A and imply the opposite subclass relationship between Foo[A] and Foo[B] from Aand B. We alias this MaybePost from the Either[A, B] type from the Scala standard library which is a type that can be either a Left or Right value containing a type A or B respectively. This class is normally used as a more powerful form of Option (Optional in Java) where the left side type is an exception type and the right side type is the success value type.

Finally, we come to the BlogState class and companion object. We have some strange names chosen here for methods: apply and +. Wait, +? Yup! In Scala, you can name a method pretty much anything you like. Scala will translate the names into valid Java identifiers at compile time. As explained above, the apply method is treated specially by allowing the word apply to be omitted when calling the method. There are several other special method names that allow for syntax features in Scala such as update, unapply, map, flatMap, filter, withFilter, foreach, and methods named after mathematical operators such as +, -, and *. We will not be covering most of them, but it’s worth noting their names. One other thing to note here is that the default Map[K, V] type used here is an immutable hash map, and in keeping with the spirit of immutability, we will be updating our BlogState by returning a new BlogState with a new Map which contains the old map plus an additional item. Thus, the use of posts.updated(key, value) returns a new map with the addition or modification of the provided key value mapping.

With all that out of the way, let’s move on to the entity implementation.

class BlogEntity extends PersistentActor {

  import BlogEntity._
  import context._

  private var state = BlogState()

  override def persistenceId: String = "blog"

  override def receiveCommand: Receive = {
    case GetPost(id) =>
      sender() ! state(id)
    case AddPost(content) =>
      handleEvent(PostAdded(PostId(), content)) pipeTo sender()
      ()
    case UpdatePost(id, content) =>
      state(id) match {
        case response @ Left(_) => sender() ! response
        case Right(_) =>
          handleEvent(PostUpdated(id, content)) pipeTo sender()
          ()
      }
  }

  private def handleEvent[E <: BlogEvent](e: => E): Future[E] = {
    val p = Promise[E]
    persist(e) { event =>
      p.success(event)
      state += event
      system.eventStream.publish(event)
      if (lastSequenceNr != 0 && lastSequenceNr % 1000 == 0)
        saveSnapshot(state)
    }
    p.future
  }

  override def receiveRecover: Receive = {
    case event: BlogEvent =>
      state += event
    case SnapshotOffer(_, snapshot: BlogState) =>
      state = snapshot
  }

}

Note that we need to extend PersistentActor to use akka-persistence, the mechanism we’ll be using to save blog events to disk. This class is dense with syntax we haven’t covered yet, so let’s go over it all. First of all, note how we imported all the members of the BlogEntity object. The _ in the import is equivalent to using * in Java (Scala doesn’t use * here because * is a valid class and method name in Scala). Note that we don’t ever use an import static like in Java as Scala does not have static things (though it can import static things from Java without having to specify it’s a static import).

Since BlogEntity is already in scope, we did not have to specify the full package name preceding it in the import. We also import the members of the context variable, which is defined in a superclass. We do this to gain access to some implicitly available variables used in the asynchronous code below.

Next, note that we were able to construct a BlogState object by omitting the keyword new because we defined a method named apply. Thus, we are actually calling BlogState.apply() here. In the next line, we override an abstract method to identify this aggregate root for persistence purposes. An alternative name here may be the fully qualified class name.

Another neat syntax to note here is that in Scala, a zero-arg method can omit its parenthesis. This feature allows a val to override an arg-less def in the parent class. Our next method,receiveCommand, returns an Akka type called Receive, which is a type alias for a lambda function that takes a single parameter of type Any and returns nothing. This warrants a quick overview of some of the standard Scala types.

The Any class is the root class, and from there are AnyVal and AnyRef. The AnyVal class is for types like Int, Boolean, Double, etc., along with user-defined value classes as explained in the PostId description, while AnyRefis equivalent to Object in Java. There is also the Unit class, which is equivalent to void in Java. The difference is that technically, all methods must return a value in Scala. So for an empty return type, Unit can be used, which has only one possible value: ().

There are also two bottom-most types in Scala: Nothing and Null. The Nothing type is generally used as a return value for a method that does not actually return (e.g., it always throws an exception). The Null type is the type of the null reference, which is a subtype of everything. Try not to confuse these with the None type of an empty Option or the Nil instance of an empty List.

The receive method of an actor tends to be implemented as a pattern match expression. A pattern match takes the form of foo match { case a => ...; case b => ...; ... }, and this is a very powerful feature used pervasively in Scala. In our use case here, we can omit the foo match part to create a lambda function that matches an anonymous value. In our cases, we’ll be looking for messages that match our command types. Since our commands are all case classes, Scala has generated an unapply method for each which makes the classes destructurable so to say within pattern match expressions. For example, the expression case GetPost(id) => will match when the matched object is an instance of GetPost, and it will subsequently bind its one field to the new variable named id. We can use nested patterns here if we wanted, but that is a more advanced feature.

In the GetPost example, we already have a handy BlogState.apply(id) method available as a lookup to find the content for a given id. This returns our MaybePost[PostContent] type which can be used to determine whether or not we got the content. Using the sender() method, we can send a message back to the actor that sent the initial message. The ! method used here is an alias for the tell method. Note that we omitted the dot and parenthesis here by using the infix notatation syntax of calling methods. This syntax allows, for example, the method call 1.+(1)to be written as 1 + 1. This is particularly useful for methods that have an operator syntax like +, but it can also be useful in functional programming contexts as well. Thus, our line of code is equivalent to sender().!(state.apply(id)) when expanded out.

Next, to handle the AddPost command, we create a PostAdded event with a new id and its content. The result of handling the event is a Future[PostAdded], so we use the pipeTo pattern in Akka to send the result of that future back to the sender. As mentioned for the infix method call syntax, this line can be equivalently written as handleEvent(PostAdded(PostId(), content)).pipeTo(sender()). We’ll be reusing the event handling logic in UpdatePost, so we’ll come back to that. The next line contains a Unit to return explicitly. We do this because we are using a set of strict compiler flags which would make discarding a return value an error otherwise. Note that this is not required in the default Scala compiler settings, but we’re trying to stick to high quality Scala code.

The UpdatePost command requires a bit more work than AddPost did. This is to validate that the id provided already exists. Thus, first we look up in our state for an existing post. If it does not exist, we’ll get a Left(error) value with some exception error; if it does exist, we’ll get a Right(content) value with content being the PostContentvalue. Thus, we combine this with a pattern match to check for both types. The syntax, case response @ Left(_), uses two pattern types concurrently: binding the matched expression to the new variable named response, and matching that it is a Left type with any content (the _ is a wildcard match in this context as a throwaway variable). If the post doesn’t exist, we send back the error. Otherwise, we create a PostUpdated event, handle it, and send it back.

Next, we look at handling the event. Let’s break down the new syntax. The [E <: BlogEvent] bit is a generic method type parameter, where <: is equivalent to extends in a Java generic method. Conversely, the >: generic syntax would be equivalent to super in Java. For example, this method may be written in Java as private <E extends BlogEvent> Future<E> handleEvent(E event). The other syntax of note here is the e: => E parameter. This is similar to a zero-arg lambda function, but when called as such, does not require being wrapped in a lambda. Had we used e: () => E as the parameter instead, then we would have had to call the method as handleEvent(() => PostAdded(...)) instead.

In order to create a Future here, we’re using the Promise class. A Scala Promise works rather similarly to promises in JavaScript and other languages. To handle the event, we call the persist method defined in the PersistentActorsuperclass. We use another new syntax here where a method with a single lambda function parameter can be replaced with curly braces.

A lambda function can always be surrounded in curly braces, so this syntax is taking advantage of some infix method call syntax features. This syntax is rather similar to how Closures work in Groovy. The lambda provided to persist here is called after the event has been successfully persisted. In this, we complete our promise, which is returned as a Future to the caller.

After that, we call state += event. Since we never defined a method called += on BlogState, Scala sees that state is a var, so it can rewrite that expression into state = state + event. Since we do in fact have such a method available, the whole expression is equivalent to calling state = state.+(event). After that, we publish the event to the system event stream which can be used as an application-wide event bus. Finally, we add in a periodic call to saveSnapshot every 1000 events which will allow us to restart and recover the state a lot faster than rereading the entire event log.

The last bit of code we needed to implement in this actor was the receiveRecover method, used to recover the latest snapshot on startup if available. We can populate this actor’s state directly from the snapshot, and then subsequently handle all the events that weren’t included in that snapshot. The only new syntax used here is the case event: BlogEvent pattern match syntax which matches when the object is an instance of BlogEvent and binds it to the new variable event.

Blog Service

Now that we’ve written our entity actor, we can fill in the stub BlogService trait defined earlier.

trait BlogService extends AkkaConfiguration {

  import BlogEntity._

  private val blogEntity = actorRefFactory.actorOf(Props[BlogEntity])

  def getPost(id: PostId): Future[MaybePost[PostContent]] =
    (blogEntity ? GetPost(id)).mapTo[MaybePost[PostContent]]

  def addPost(content: PostContent): Future[PostAdded] =
    (blogEntity ? AddPost(content)).mapTo[PostAdded]

  def updatePost(id: PostId, content: PostContent): Future[MaybePost[PostUpdated]] =
    (blogEntity ? UpdatePost(id, content)).mapTo[MaybePost[PostUpdated]]

}

The AkkaConfiguration trait we mix in here is a trait we defined for easy access to Akka-related objects such as an ActorRefFactory to create actors, a Materializer which is used to run Akka Streams, an ExecutionContext which is used for coordinating Futures and other asynchronous functionality, and a Timeout which is used for a default timeout value when making request/reply-style ask calls to actors.

As noted before, we can import all the members of the BlogEntity companion object here. It’s also worth noting that Scala allows you to import things to whatever scope you want, so we can limit our imports to the closest spot it is actually used.

To use our BlogEntity actor, we need to spawn it first. Using our ActorRefFactory, we can spawn a BlogEntityusing the default Props of a BlogEntity. Spawning the actor will create it and start it asynchronously, returning an ActorRef instance, which can be used to interact with the actor. Since actors can be restarted, replaced, or even located on completely different processes or machines, we never directly access an actor’s instance and instead use its ActorRef to send messages, watch it, etc. Since actors are written in a rather type-unsafe fashion, we’re wrapping the actor’s messaging API into a typesafe trait.

In order to receive responses from our actor when sending a message, we must do so asynchronously. Thus, our API returns futures. We utilize the ask pattern to send a message to the actor and wait for a response message. Since actors are not typed, the message response comes back as a Future[Any], so we use the mapTo[A] method on Future to verify it matches our expected type and cast it. Other than that, this trait is rather self-explanatory based on our BlogEntity.

Blog REST API

Next up is defining our REST API. We’ll be using the high level Akka HTTP route DSL for this. Using our BlogServicetrait, we’ll mix that in to another trait to define our API.

trait BlogRestApi extends RestApi with BlogService {
  override def route: Route =
    pathPrefix("api" / "blog") {
      (pathEndOrSingleSlash & post) {
        // POST /api/blog/
        entity(as[PostContent]) { content =>
          onSuccess(addPost(content)) { added =>
            complete((StatusCodes.Created, added))
          }
        }
      } ~
      pathPrefix(JavaUUID.map(PostId(_))) { id =>
        pathEndOrSingleSlash {
          get {
            // GET /api/blog/:id
            onSuccess(getPost(id)) {
              case Right(content) => complete((StatusCodes.OK, content))
              case Left(error) => complete((StatusCodes.NotFound, error))
            }
          } ~
          put {
            // PUT /api/blog/:id
            entity(as[PostContent]) { content =>
              onSuccess(updatePost(id, content)) {
                case Right(updated) => complete((StatusCodes.OK, updated))
                case Left(error) => complete((StatusCodes.NotFound, error))
              }
            }
          }
        }
      }
    }
}

There are a couple new syntax features here along with many DSL-specific things going on. First of all, this introduces the keyword with which is used when extending multiple traits. The RestApi trait is one we made that mixes in the Akka HTTP route DSL along with support for marshalling and unmarshalling our case classes and primitive types into JSON.

The only other new syntax here is the tuple syntax. A tuple is an abstraction of an ordered pair. A tuple can have two or more values that do not have to be the same type. They are contained in parenthesis and separated by commas. Due to syntax ambiguity, when sending an inline tuple to a method, we need to double up on the parenthesis to avoid it being interpreted as a call to a method with multiple parameters.

All other syntax in this trait are features of the route DSL. For example, URI paths can be matched using implicit conversions from strings into URI patterns, and those patterns can be composed with / which matches a slash in the URI. Segments of the path can be extracted into parameters in the lambda function provided after. We can easily unmarshal request bodies using the entity(as[A]) { a: A => ... } DSL. Using our service mixin, we can forward these requests and get response which can be chained back into the HTTP response. Finally, the ~ function is used to chain two routes together into a single route. Far more comprehensive information about the routing DSL can be found in the Akka documentation.

In order to run this code, we still need to create our HTTP server and set up Akka in general. That code is not very interesting in itself and is included in the code samples. While this post only scratches the surface of Scala, it provides a broad overview of various Scala-specific syntax features that really differentiate it from Java. There is one other feature that has only been mentioned by name so far, and that is implicits. Implicits are a powerful feature specific to Scala that helps reduce boilerplate typing in various scenarios. Implicits can generally be used for a few different things:

  • Implicit values can be used to provide parameters to functions or class constructors without being explicitly written as long as it’s in scope. This is useful for passing around parameters that are needed by tons of methods such as the ExecutionContext object mentioned above.
  • Implicit parameters can be used to automatically be filled in by an implicit value that is in scope so that the parameter doesn’t have to be typed out over and over again.
  • Implicit methods can be used to convert from one type to another when the original type is not compatible where it is used. For example, this feature is used to automatically convert an Int to a Long when passed to a method parameter that takes a Long. This can be a very dangerous feature when misused.
  • Implicit classes can be used to provide extension methods to an existing API. This is used to add methods to java.lang.String, for example, which cannot normally be done as String is a final class that cannot be extended. Extension methods provide a compositional way to extend APIs in a type safe fashion without having to explicitly wrap the API everywhere an extension method is desired.
  • Implicits can be used to provide type classes to Scala, a feature common to functional programming languages. Type classes are used very seldomly in object oriented programming languages. An example of a simple type class in Java is the Comparable<T> or Enum<E> interface.

Overall, Scala is a fantastic programming language with a simple core set of features and tons of extensibility. Staying true to the “scalable language” concept behind its name, Scala works well in small scripts all the way up to large distributed applications. The Akka framework provides the building blocks for writing distributed systems using event sourcing and CQRS, while Scala itself enables much more concise, readable DSLs and removal of verbose boilerplate common to many Java frameworks. Akka is far more flexible than its opinionated cousin, Lagom, and it works well with various technologies common to event sourced systems like Kafka and Cassandra.

Tags> , , ,

Matt Sicker

Matt Sicker is a Senior Consultant in the Custom Development - Open Source Practice at SPR.