Workflows for LiveView in a team environment?

Hi all,

We are currently building applications with API and Frontend separation. Frontends are often written in React/Vue(Next/Nuxt) for example. In our current workflow we are creating deploy previews for frontend applications with Vercel/Cloudflare before it gets merged into the main branch and then into production environment. This involves QAs signing off a PR before it gets merged into main and helps us eliminate most of the issues beforehand

Now I’ve seen LiveView as a good select for a Solo Developer to quickly prototype applications(and i agree with this), but how exactly it can be adapted with a team environment where multiple roles like developers/QAs involved?

  • How are the changes propagated? for example do you allow UI + Core Logic updates in same PR?
  • Do you provision entire infrastructure stack for the previews(for example imagine the PR has a migration, so you need an isolated snapshot of the staging database to run it, it has more components probably an instance of everything)

This has been bothering me for sometime, would like to hear about Workflows created for tackling the mentioned problems

1 Like

If I understand correctly, you’re trying to mimic a flow where there are previews of your application (at least the UI)?

Certainly in any fullstack application regardless of the technology (rails, laravel, etc) where the same application handles the UI and the server would have the same inconvenience vs a separate application for the UI.

While that specific use case of having previews is easier to handle in a client-side javascript-only app that doesn’t require additional pieces like a database, you face other challenges like contract compatibility between the API and the client, synchronization of deploys, etc.

From a workflow point of view for teams, it would have the same inconvenience with any backend. The feedback loops are longer and more expensive using previews.

These types of problems are what practices like CI/CD try to solve: frequent integrations, incremental and iterative development, automated testing, etc. In short, speeding up feedback loops.

Imagine 5 open PRs with their respective previews - that’s a lot of resources, even if it’s just the frontend and requires more resources if the team grows. Instead of making previews that require infrastructure for each open PR, each integration generates a deployable artifact (like a docker image). This artifact can be deployed and promoted to the downstream environments (DEV, QA, UAT, etc.). If everything works correctly it can be promoted to production, if not it is replaced by a new artifact.

Other tools like feature flags are very useful to keep under control functionality that you don’t want to show to the public yet, without stopping the integration speed and feedback cycles for the rest of the work.

3 Likes

Hi @SergioV

Thanks for detailed answer, the main point i wanted to clarify is this.

In a Backend/Frontend separation(backend is in Node and FE is in React) we clearly know which PRs affect which parts of the app easily.

PRs against the Backend wont get any previews as they can be costly(mostly these services have lot of other components such as DBs, Queues etc) and often not useful. Instead we can push the approved PR changes to a staging env for testing APIs. Often this wont break the frontend thanks to API versioning etc.

PRs against FE are a different case, in a modern environment we can easily do a deploy preview to see how the UI looks like and eliminate any issues before code get merge to main. Often we use feature flags to ship unfinished stuff that way.

The workflow is very clear and scales well within a team environment and its working really well. As you mentioned in the answer this is sort of promoting artifacts between environments

The problem with LiveView for me is how to set this boundary within a team env, you can change both backend and frontend at once and we wont be able to preview the changes unless we provision set of infra and add a preview deployment(which can be costly). By preview deployment here im talking about building a docker image based on PR to main branch and getting it running to see the changes.

Yeah its completely ok to skip previews and keep pushing code to the different envs for people to check, but we have found having PR previews on FE is extremely useful to double check the functionality and deploy more confidently keeping codebases more cleaner.

From lot of online talks i saw, LiveView stays as a tool for a Solo Dev(a solo dev can ship Y in Z amount of time), but im wondering how this can be adapted into a team environment or how people actually do it

Try generating an “umbrella” project.

See here for details: mix phx.new — Phoenix v1.7.18

TL;DR
Tailscale, Massdriver, and maybe some DB branching tech like Supabase/Neon/Planetscale offer.

FE + BE separated apps aren’t “easier” to scale though, Vercel is just doing a lot of the heavy lifting.


Please skip if this isn’t useful

I have found, as far as “how” people work together in LV, it’s very fairly standard. Things can be abstracted to components, slots. The components can be “higher order”, stateful, or lower-level and just display oriented.

The testing tooling is quite nice though. It’s generally much easier to modify/refactor a LiveView without even needing a manual QA step, because the tests are able to programmatically cover what might be too difficult to test in another approach, or would require more “waiting” statements.

To the meat of your question. What about previews, or when you just need to update the visuals, but not the rest of it.
I don’t know of a way to resolve this except with infrastructure or tools. But if you think about it, that’s what Vercel is doing for you.

Thankfully there are options/approaches though that don’t require you to go “Full Terraform/OpenTofu”

For local development tooling: My last place we started using tailscale for parts of it, and were able to set some things up that made collaborative pairing very nice.
We could be in a vscode liveshare, or a tmate connection, but then using tailscale to each be connected to the app running on someone’s laptop/devcontainer. And we’d both get all the benefits as if it were just running locally for each of us. It was fantastic. Then you could tell your PM or whomever to go to your tailscale address (e.g. peter.mysillytailnetname.ts.net) and they could give feedback on an actual running instance. I miss it daily

For middle-ish size teams on a budget: you need a little bit of infrastructure, but it’s not too bad. If you wanted you could define preview environments that connect to a shared database, and just only generate a preview if there’s no database migrations.

Ultimately though, you at some point, have to consider the need for either “database branches” features, like on Supabase, Neon, or PlanetScale, etc, or some other functionality for segregating your PR preview environments.

For larger teams:
You probably want preview environments stood up for each PR, and reasonably robust seeds. For a QA environment, you probably want an environment similar to the preview env, but w/ a recent restore.
These aren’t that difficult. You’d need something like a docker-compose for the preview environments, and some terraform, and a way to run that terraform on GitHub triggers (probably massdriver or something if you don’t have something already).
Recent restores for QA is probably more difficult, but not by much.

Maybe there’s an equivalent of Vercel for Elixir preview environments. I’m not sure. Database branching is the main tricky bit, assuming you need it.

All in all though even if this were a FE-only app, you’re still interacting with an API that’s capable of making changes, and if your preview is making POST calls based on bad data, or causing changes in a shared DB, you either have to be okay with those not being cleaned up, or you need a way to set it back to a clean state.

In my experience though, the same way a bad FE change doesn’t mean the backend is going to allow it to propagate, a bad/messy LiveView doesn’t mean it’s going propagate past the Context, or wherever you’re defining your interface.

You still have an API, it’s just in 2 modules/files instead of 2 apps.

2 Likes