crenwick

crenwick

How do we organize our project

Hey yall, I have a project organization question:

We are building two internal elixir apps (i’ll call them “local_app” and “cloud_app”), which share a ton of code so we decided to go with a monorepo strat.

Here are all the elixir projects under the repo. (Note: only the _app projects are elixir applications. the other projects are simply changesets and functions.)

home
├──local_app
├──cloud_app
├──shared_models
├──local_models_api
└──cloud_models_api

Basically, what happens is that the we needed both the local_app and cloud_app to know what a shared_model is, so we abstracted away those schemas and changesets to the “shared_models” project, which both _app’s declare as a dependency using the path: ../shared_models option.

We need both apps to know how to read those models, however only one app should have right access to a specific model. For example, we might have a SharedModel.Note schema, which both apps will know how to read, and the API to get the notes might live there too (SharedModels.Notes.list_notes/0). However, we only want the local_app to have write privileges to those notes—this is so important that we don’t even want the write functions available to cloud_app at compile time—so we made a local_models_api project that exposes functions like LocalModelsAPI.Notes.create_note/1 and only the local_app uses that as a dependency.

(The reason we needed that code to live in a separate local_models_api project and not just live in the local_app project is because we needed to write test helpers for the cloud_app test suite that writes a handful of those models in order to test some other behaviors, so we have cloud_app declaring local_models_api and a test only dependency.)

Vis-versa, we only have some models that we want write access to via the cloud_app, so we created the cloud_models_api project.

This leads to messy alias APIs in our application code, for example, its really common for a server_app controller to have

use LocalWeb, :controller

alias LocalModelsAPI.Notes
alias SharedModels.Notes.Note

and we use the defdelegate pattern at the bottom of the LocalModelsAPI.Notes module to bring in all the SharedModels.Notes functions into the LocalModelsAPI.Notes namespace (which leads to compile time warnings that functions don’t exist, but we ignore those).

It also leads us to have a messy test pattern. For example, we want to test our LocalModelsAPI logic in our local_models_api project, but because it doesn’t have its own stand alone application, it cannot run a DB. So instead, we added the "../local_models_api/test" to the test_paths list in our LocalApp mix file. (Which then leads to doubling our tests for the SharedModels project, but that’s fine.)

Is there a simpler way?

To recap, the problems we need to solve:

  • Have a shared library of models
  • Have some APIs of those models only available to specific projects
  • Have all those APIs available to all the projects test helpers

First Post!

hauleth

hauleth

Seems like you wanna do synchronisation and communication via DB. In that case I have only one answer for you - don’t.

Last Post!

crenwick

crenwick

lol, good guess but no. We just already have another application taking care of syncing (just not via the DB).

Where Next?

Popular in Questions Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44139 214
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42533 114
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

We're in Beta

About us Mission Statement