What is this about?

Newly generated Phoenix (v1.7) applications come with a lib directory that is split into two subdirectories:

  • myapp for application code
  • myapp_web for web code (HTTP endpoint, router, controller, views, etc.)

It looks like this:

myapp
├── application.ex
├── mailer.ex
└── repo.ex
myapp_web
├── components
├── controllers
├── endpoint.ex
├── gettext.ex
├── router.ex
└── telemetry.ex

When the application grows and more and more modules are added you might end up with a long list of files in the lib/myapp directory that looks similar to this:

myapp
├── accounts
├── accounts.ex
├── admin
├── application.ex
├── auth.ex
├── bililng.ex
├── billing
├── cache.ex
├── documents
├── documents.ex
├── ecto_types
├── ev.ex
├── file.ex
├── format.ex
├── icu.ex
├── logger.ex
├── mailer.ex
├── pricing
├── pricing.ex
├── repo.ex
├── startup.ex
└── vault.ex
myapp_web
├── components
├── controllers
├── endpoint.ex
├── live
├── gettext.ex
├── plugs
├── router.ex
└── telemetry.ex

Due to lack of a better place, the lib/myapp directory now contains a mix of business logic (context) modules and supporting infrastructure code. This makes it harder to find the code you are looking for and it also makes it harder to reason about the application’s purpose.

How to?

Since in Elixir module names do not have to strictly match file names, we can move the infrastructure code to a separate directory without changing any module names. My personal preference is to call this directory lib/myapp_sys to keep it short. The lib/myapp directory then contains only business logic modules.

Here’s the same list of files as before now split into three directories:

  • myapp for business logic code
  • myapp_sys for supporting infrastructure code
  • myapp_web for web code (HTTP endpoint, router, controller, views, etc.)

And it looks like this:

myapp
├── accounts
├── accounts.ex
├── admin
├── auth.ex
├── bililng.ex
├── billing
├── documents
├── documents.ex
├── pricing
└── pricing.ex
myapp_sys
├── application.ex
├── cache.ex
├── ecto_types
├── ev.ex
├── file.ex
├── format.ex
├── icu.ex
├── logger.ex
├── mailer.ex
├── repo.ex
├── startup.ex
└── vault.ex
myapp_web
├── components
├── controllers
├── endpoint.ex
├── live
├── gettext.ex
├── plugs
├── router.ex
└── telemetry.ex