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

2 Likes

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.

4 Likes

Hey thanks for detailed reply

Yeah deploy previews are a feature of modern tools like Vercel, Cloudflare, Netlify, STT. They are very helpful and really tricky to setup it for other platforms

I was wondering what approaches taken by the industry to smoothen the workflow with LV across a team and thanks for the detailed insight

In this case, I think it’s a question of mindset. I understand that previews are convenient and provide some “security” to the developer, but they are not the only way to achieve this. CI is another well-known practice to achieve this, even in environments like the backend.

Even in the case where you want to “isolate” the UI from the backend, you can use umbrella applications. This allows you to release only the “_web” app without having to release the application that connects to the database.

This is not the case for the different teams I have worked with or for other companies using LiveView like Cars.com or PepsiCo.

It would be like saying that applications based on any fullstack framework (such as Laravel Livewire or Rails HotWire, etc.) would not be viable to be developed by teams, which of course is not the case.

1 Like

We use Render as our host and generate a preview environment on PRs. We used to do it every PR, now we do it based on a PR title ([render preview]). Every PR gets the same environment we use for production, just much smaller. It’s just a smaller database and a smaller API box, etc. We have a seed process that prepopulates with test data, and QA can get a link right on the PR for sign off.

We don’t separate front end and back end PRs (we did that a litte before with Rails and Ember, we still deployed QA environments on all PRs but to AWS and rolled that ourselves).

Any PR can be deployed to a QA box if there’s a reason for manual QA. All deploys run the full test suite automatically in Github actions etc.

I think you’re potentially overcomplicating it. We do this with 3 small teams working on the same app, often with 5-7 open PRs, typically with 3-4 deploys (sometimes many more) to production per day.

3 Likes

Thanks for spending your first post on this splendid comment! Hi :wave:

Great idea to have something in the PR title to indicate whether a preview is required.

From your explanation I guess you’re at Felt? If not, they seem to do something similar.

Nope— Allovue, which was acquired by PowerSchool a little less than a year ago. We used to do skip render instead of render preview but started a practice of opening PRs as draft early and often, which has had many advantages but a disadvantage was creeping cost on PR preview environments.

2 Likes

Yeah we make extensive use of preview environments at Felt. They’re really quite essential to get thorough testing of changes (especially any UI changes) before code hits production. We actually also generate some AWS resources for each PR in addition to our elixir instance and database which are hosted on Render.

We talk about it a bit in a post: Deploying more, stressing less: how Felt achieves 15+ daily releases

2 Likes

Our process is nearly identical to this, including the data seeding, merge queues, etc. I haven’t timed it, but other than potentially the whole Xcode build tools install, I definitely think we’re sub 25 mins from git clone to mix phx.server. That comes from things like asdf working great and having a comprehensive mix setup script that includes the data seeding we use for PRs.

The magic links for different roles on a PR is super cool and I hadn’t considered that before so it’s getting added to the list.

3 Likes

Are the setup seeds regular exs scripts that use Ecto schemas? Or do you have other ways to maintain a representative dataset?

It all uses our actual code-- so we have a lot of data onboarding uploads and for some data we read CSVs we check in and process it through the uploads. For other data, we have hard coded arrays of maps that call our create/update functions for the data module. It was a bit of work to setup and is a big thing to maintain-- we require PRs update seed data for new features or to exercise a bug or new condition when it comes up just like we require tests-- but it has absolutely been worth it.

priv/repo/seeds.exs basically just calls a module we have defined in utils called Seeds to run/manage the process.

thanks, this looks promising

1 Like