The Modular Monolith: Elixir Architecture

There has been a hype about microservices: start every project with a microservice structure! But I always believe we should build a well organized monolith first, then consider extracting submodules into microservices one by one. And there are some people who think the same (or I learned this idea from them).

First, I was quite curious about how to build a modular monolith with Ruby on Rails due to my Rails background. I found this article which gives a great answer:

  • First focus on making our app modular
    • Our goal was to identify good architectural boundaries before we extracted code out into independent services
    • This would set us up to be able to migrate to microservices in the future, by having the code structured in a way to make a smooth transition.
  • Effectively, we're using a monorepo.
    • We don't have an app/ directory in our Rails project. All of our code is either in gems/ or engines/.

      Dir.glob(File.expand_path("../engines/*", __FILE__)).each do |path|
        gem File.basename(path), :path => path
      end
      
      Dir.glob(File.expand_path("../gems/*", __FILE__)).each do |path|
        gem File.basename(path), :path => path
      end
      
    • First Steps Towards Implementing a Modular Monolith
      • A great place to start (three engines)

        +----------+      +------------+
        |  Admin   |      |    API     |
        +--+-------+      +---------+--+
           |                        |
           |                        |
           |     +-------------+    |
           +---> |   Domain    | <--+
                 +-------------+
        
        1. Admin
        2. API
        3. Domain
      • breaking up the domain logic
      • putting third-party dependencies in context

-- from The Modular Monolith: Rails Architecture – Dan Manges – Medium

But this article reminds me more of Elixir than Rails. Here is why:

  1. Using relative path to extract code as gems into separate directories is almost the same as the way Elixir organize Umbrella apps.
  2. Breaking up the domain logic into three gems=/=apps (like Admin, API, Domain) is a typical use case for Umbrella apps.

If you want to learn more about Umbrella apps, you can check the official documents. And I also explained how to build an Elixir app from a monolith to a microservice before. Hopefully this can help you somehow. :)