pnezis
We are currently in the process of restructuring our codebase. Till now we follow the monolith way (well structured though) but we have started facing scaling issues (especially on CI pipelines). Umbrella is not an option since we have multiple applications and we wish to split the configuration as well.
The main goals of this restructuring are:
- Speed up CI pipelines - by splitting the codebase into multiple packages we can build, lint test only the affected parts of the codebase
- Code organization and clear separation of concerns
- Better development experience - a developer working on the API does not need to compile dozens of
Broadwaypipelines orLiveViewapplications
A Ponzo like project with path dependencies seems as the best option:
- Maximize code resue
- Consistent tooling, code guidelines, CI pipelines
- No internal dependencies nightmare
On the other hand there are some caveats, the most important of which is:
- Each project will have each own
lockfile,depsand_buildpaths making CI configuration more complex (e.g. deps caching) and introducing incompatibilities between external dependencies
Since custom paths for lockfile, dependencies and build paths are supported for umbrella projects I was thinking the possibility of solving this issue by having a shared artifacts folder for all packages/applications ( something like rust workspaces with a common lockfile and output directory for all packages). Imagine a folder structure like the following:
project
├── .artifacts
│ ├── _build
│ └── deps
├── applications
│ ├── admin_ui
│ │ └── mix.exs
│ ├── api
│ │ └── mix.exs
│ └── data_pipelines
│ └── mix.exs
├── mix.lock
└── packages
├── package_a
│ └── mix.exs
├── package_b
│ └── mix.exs
└── package_c
└── mix.exs
Where each mix.exs will have deps_path, lockfile and build_path properly defined:
def project do
...
deps_path: deps_path(),
lockfile: lockfile_path(),
build_path: build_path()
end
...
I have tested this on a sample project and it seems to work fine. The documentation of build_path though suggests avoiding overriding this variable:
This option is intended only for child apps within a larger umbrella application so that each child
app can use the common _build directory of the parent umbrella. In a non-umbrella context,
configuring this has undesirable side-effects (such as skipping some compiler checks) and should be avoided.
What are these side effects? Does anybody has experience with elixir mono-repos? Any advice / alarms on the aforementioned structure?
Thanks! ![]()
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #ai
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
BradS2S
Agreed that diverging config by app under a umbrella project is an anti-pattern.
Functional Web Development with Elixir, OTP, and Phoenix starts by building the business logic as a separate application, without Phoenix. Might be worth thinking about breaking out your app as separate applications that are added as dependencies to the main app.
D4no0
I don’t think it is wise what you are trying to do, from what I understood you want a single runtime, but multiple independent codebases. This will require all the codebase to be compiled at the end of the day, because you will want at some point to start a part of the application on dev.
Instead of making this abomination, just take a step back and think how can you refactor it in a smart and easy to use way:
While all of this sounds more complicated than the solution you provided, this approach will ensure total separation, making it much easier to monitor, deploy and debug of the applications.
pnezis
You misunderstood, I want the exact opposite - multiple runtimes from a single codebase. I want to avoid compiling the complete codebase since it includes multiple applications that should be separated. But I want a single code-base, mono-repo style in order to have everything under a single git repository. The CI would then build, lint and test only the affected packages based on the dependencies graph and the modified files.
The application even in the current monolithic state is already well separated in multiple layers, including business domains, helper libraries and applications (presentation layer). So no actual refactoring is needed only a
mvof some folders to some new mix projects under the same git repo.What I want to avoid is to have multiple deps/_build folders per internal package. Umbrella projects support it already and I am wondering if this will work on the suggested approach as well.
D4no0
Is that only because of CI build time or there is another reason behind keeping the code in a single git repository?
pnezis
Totally agree, thanks for the reference I have already read through it. The application is already well structured. The business logic, presentation layers (API, UI) and the data layers are completely separated with boundaries enforced. This is the plan to split it into multiple applications but I don’t want to go the umbrella way for multiple reasons, one of which is the application config, the other being that the codebase includes completely independent applications.
pnezis
I want to keep the code in a single repository for multiple reasons:
BradS2S
What are the upsides of this? It seems like having it split up means less opportunities to break things or have two people work on the same file, etc. Also as your team scales, you have a natural demarcation of what different teams should support. Just my two cents.
Yes, this is the main benefit cited when considering whether go with an umbrella project.
BradS2S
Source: https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-projects.html#umbrella-projects
D4no0
If the packages are truly standalone this shouldn’t be the case.
This is true, however having 2 people work on the same file is not better.
I would never want to have all my codebase in a single place, it should be the rule of giving the minimal privileges, you don’t want to give to a new employee all your codebase on a platter.
Can be achieved by referencing the script from a common source.
This is a valid point, however taking in consideration multiple runtimes I don’t think it will be any easier than having separate applications.
From my personal experience, umbrella projects are more trouble than they are worth, I find it as a good tool when it comes to refactoring from a monolith application to services, after that they become a mess starting from management of dependencies and ending with release of application. I wasted a lot of time at a few projects having to deal with that and ended either refactoring to a monolithic application or migrating to services. If you don’t need services at this stage of your product, I would recommend to leave things the way they are, if developers are organized there will never be a mix of concerns in your code, as for compilation, everything is cached so they compile all the project only once.
pnezis
From the same page:
This is our case, the codebase is very big (thousands of elixir files) handling fully decoupled applications with multiple domains and the split is necessary for scaling.