ream88

ream88

Sharing code across apps

Hi everyone,

I’m working on a well-established Phoenix application that has grown quite a bit, and I now need to create a separate Phoenix app to act as a back office for managing the data and operations of the main app. The existing app has a lot of schemas and helper functions that I’d like to reuse in this new back office application to avoid duplicating code.

What I’m trying to achieve:

• Set up a new Phoenix app for back office functionality.
Reuse existing schema files (and some helper functions) from the main app in this new app.
• I don’t want to create an umbrella app or move things into a standalone library.
• I’m considering using git sparse-checkout to manage only the parts of the codebase I need in the back office app, but I’m not sure if this is the best approach. I know that mix has support for it, however while testing my back office app wasn’t able to find modules defined in the other app.

What is the best approach here?

Most Liked

al2o3cr

al2o3cr

More like “didn’t particularly pay attention to”. You can find folks who’ll decry the use of ANYTHING - even if statements! - and I wasted waaaaaaay too much time arguing with that sort in Rails-land.


I’ve seen an umbrella solve OP’s specific problem very efficiently - the system was one that coordinated delivery companies (+ drivers) and stores. The key problem the umbrella solved was keeping UIs for different audiences entirely separated; apps were roughly like:

  • core: giant ball of DB schemas + business logic
  • store_web: UI for stores to use to submit & track delivery requests
  • driver_web: UI for drivers to use when making deliveries. Mobile-first, designed to tolerate drivers losing network connectivity intermittenttly
  • dispatcher_web: UI for the dispatchers to manage their driver’s work and check status

We didn’t do anything fancy for deployment like splitting subparts (for instance, deploying core + store_web separately) but the built-in boundary checking means we could.

This setup really showed its benefit when Bigco asked us for a new interface that would let Bigco management admin all of their stores. It found a straightforward home as a new bigco_admin_web, with a separate asset pipeline so BigCo could have their logo plastered on everything.

Another nice momement was when we needed to add SAML as a login option, but only for stores. This involved “splitting” the login form to ask for email first, and then either prompt for password or redirect to the IdP. Since each audience has its own _web, it was straightforward to modify only the one for stores.

None of these are strictly “only umbrella could do this”; a team with sufficient organization and discipline could accomplish the same thing all wedged into one Phoenix app, the same way a team like that could make a well-factored Rails monolith. Here in the real world, IMO the umbrella helped us keep things organized despite the hectic schedule of a startup.

D4no0

D4no0

I don’t know if you want to introduce complexity from git into your codebase, I personally wouldn’t consider this as a viable option.

Depending on how your projects are organized, I would recommend to have the shared code separated in a library, but in the same repo (a monorepo that hosts both the projects and the library). In this way you can use the option of local dependency and not worry about maintaining separate variants for the library codebase and version them:

defp deps do
  [
    {:local_dependency, path: "path/to/local_dependency"}
  ]
end
LostKobrakai

LostKobrakai

If it’s for a sunday afternoon hackathron then copy/paste will likely just work.

The unit of composition for dependencies is not modules, but it’s (otp) applications. Therefore the tools (like mix) for working with dependencies are built for that model. This is not done for lolz as well, given that has always been the unit of how dependencies are resolved within the beam VM and releases (see e.g. *.app files in _build or start scripts in releases). Each app declares it’s dependencies, so if ecto e.g. depends on decimal the vm makes sure to start decimal before ecto.

E.g. if your shared/file.ex depends on ecto, but your new app doesn’t have ecto (or decimal) around things will just blow up. These kinds of dependencies are not tracked on a per module level.

As you’ve figured out – or by using my suggestion of copy/paste – you can always forego proper dependency tracking if you want to. I however wouldn’t call that a good idea nor something that should be encouraged or be made simpler to do. All the primitives to do that exist and can be used, but you want to actively opt in to the fact that you’re sideloading modules and not depending on a third party (otp) application.

Last Post!

axelson

axelson

Scenic Core Team

You can have a Phoenix app that has multiple endpoints. I don’t think there’s anything “special” that you need to do that, just a bunch of configuration that you need to duplicate for the new endpoint.

If you have two endpoints then they’ll be running on two different ports. If you want to access them through the same port instead then you’d want to use something like main_proxy (like @cblavier mentioned).

Where Next?

Popular in Questions Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

Other popular topics Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
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
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

We're in Beta

About us Mission Statement