Eugene Zhulenev

Engineering Machine Learning and Audience Modeling at Collective

Seamless Migration From Monolithic Application to Finagle Services (Part 1/2)

| Comments

Synopsis

The code & sample app can be found on Github

Distributed micro-services architecture is hot trend right now, it’s widely adopted by Twitter, LinkedIn and Gilt. However it can be difficult if data model is already defined, and services accessed via existing API throughout all your code. I’ll show how it’s possible to split monoliths app into standalone services built with Finagle and SBinary for custom communication protocol.

I’m going to show it on example of small Fancy Movie Database application.

[Part 1] Fancy Movie Database application

Go to Part 2 where fancy movie database application is divided into server and client using Finagle.

Data model

Let’s start with application data model definition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sealed trait Genre

object Genre {
  case object Action      extends Genre
  case object Adventure   extends Genre
  case object Animation   extends Genre
  case object Biography   extends Genre
  case object Comedy      extends Genre
  case object Crime       extends Genre
  case object Documentary extends Genre
  case object Drama       extends Genre
  case object Thriller    extends Genre
  case object Western     extends Genre
}

case class Person(firstName: String, secondName: String, born: LocalDate)

case class Cast(person: Person, as: String)

case class Movie(title: String,
                 genre: Genre,
                 year: Int,
                 directedBy: Person,
                 cast: Vector[Cast])

Services definition

And services that we want to provide:

1
2
3
4
5
6
7
8
9
10
11
12
13
trait PeopleService {
  def people(): Future[Vector[Person]]
}

trait MoviesService {
  def movies(): Future[Vector[Movie]]

  def movies(year: Int): Future[Vector[Movie]]

  def movies(genre: Genre): Future[Vector[Movie]]

  def movies(person: Person): Future[Vector[Movie]]
}

Mock data access layer

In real application we probably would have SQL database or some other type of storage with movies data. Let’s assume that this storage is blocking resource, and quite expensive to access. However for this example application I will use small in-memory mock implementation of access layer with only two movies directed by Quentin Tarantino: Django Unchained, and Inglourious Basterds

Source code for access layer on Github: MovieDatabaseAccess.scala

Let’s be reactive

I hope we all agree that applications needs to be reactive, that’s why I’m wrapping blocking calls into scala.concurrent.future.

Straightforward services layer implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package object monolithic {
trait PeopleServiceImpl extends PeopleService {
  override def people() =
       future { MovieDatabaseAccess.people() }
}

trait MoviesServiceImpl extends MoviesService {
  override def movies(person: Person) =
       future { MovieDatabaseAccess.movies(person) }

  override def movies(genre: Genre) =
       future { MovieDatabaseAccess.movies(genre) }

  override def movies(year: Int) =
       future { MovieDatabaseAccess.movies(year) }

  override def movies() =
       future { MovieDatabaseAccess.movies() }
}

Let’s combine it together

After model and services are defined, and basic implementation is provided we can build simple application for querying Fancy Movies Database.

Let’s find all movies with Leonardo DiCaprio:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
object MonolithicExample extends App {

  // Lets create services
  object Services extends PeopleServiceImpl with MoviesServiceImpl

  // Lets' get all movies for Leonardo DiCaprio
  val leo = Await.
    result(Services.people(), 1.second).find(_.firstName == "Leonardo").get

  val leoMovies = Await.
    result(Services.movies(leo), 1.second)

  println(s"Movies with ${leo.firstName} ${leo.secondName}:")
  leoMovies.map(m => s" - ${m.title}, ${m.year}").foreach(println)

  // Shutdown
  System.exit(0)
}
Output
1
2
Movies with Leonardo DiCaprio:
 - Django Unchained, 2012

Next step

In next part I’m going to divide this application into server and client preserving existing API, such that migration from monolithic application to distributed is completely seamless for service clients.

»> Go to Part 2

Comments