How to build a survey app the Phoenix way?

Hola Elixir community.

We are currently thinking about switching to Elixir and Phoenix (with Liveview) at our company. Currently we are heavily using Next.js and Laravel. One question that is still open is how we would implement the data layer for our survey app. We have different kind of question types like simple select questions, grid/matrix questions, open input questions and more complex questions like a shopping simulator. Each of those question types have different kinds of properties, ui views and response types. Each survey as many questions while each question can be a different type of question.

In next.js we would just store the question information in a json field and work with interfaces and types in the frontend.
With Laravel we would probably choose something like table inheritance.

What would be the “Phoenix way” of solving this problem? I know there are probably more than one solution, but what is your experience with existing Phoenix apps?

4 Likes

Survey app is a quite complex product, so it is hard to suggest a silver bullet.
I think about survey definition as a single document which may have multiple versions, so responses of the survey belong to the version, and I’d probably use a single JSON field. That’s regardless of programming language/web framework.

3 Likes

Welcome @tombraul! One thing about Ecto, which is Elixir’s default tool for integrating with databases, is that it tries to stay close to the database. Therefore, your question can be generalized to “what is the best way to model my problem at the database level”.

If you haven’t done this before, it may require getting used to, but it is totally worth it as you won’t have impedance mismatch between your app and the database in the long term.

10 Likes

A package that can help with this kind of approach is polymorphic_embed - it can provide some structure beyond just “a JSON field”.

5 Likes

I’ve been looking for this library for long. :blush:

Thanks for mentioning it here!

2 Likes

Welcome from someone that’s also pretty familiar with Laravel :facepunch:. Polymorphic embeds will give you dynamic JSON types if those interfaces change frequently. You can likely create a static embed if you can abstract field names and if there’s a chance they may change infrequently. Table inheritance can be an option I believe through another package I’m forgetting but your data model may not really require it.

Data migrations could get a little messy using either scenario and you may want to experiment on what your team can live with. Working backward from there could help guide your approach.

Are you planning on migrating and using the existing database, which may be possible to a degree, or are you looking to implement this version from scratch? It’d likely be easier to start over because there are some major paradigm shifts but there can be some middle ground depending on your needs, like wiring up Next.js to an API.

What about databases? Planning on using mysql/mariadb or move to Postgres?

I realize I’m asking way more questions but some of the answers can help narrow down the scope a little bit. I’m also personally curious as someone also moving from Laravel, I’m interested in the paths others take in their transition. I wonder if you run into the same pain points trying to shed “Laravel-isms” or coming from heavy OOP to FP as I have.

2 Likes

I know this is a VERY old question/thread but I came here with the same one. I’m noticing from the comments that the focus seems to be on how to model the data. I’m wondering more about how to structure/model the user experience. Are surveys resources? Are pages, groups, questions nested resources? Is a question a function component/form element that decides how to render itself based on information that was added to the conn via plugs? Admittedly, I’m BRAND new to Elixir and Phoenix and and and. But, I would love to hear the community’s thoughts.

From my experience the biggest thing people struggle with when building survey services is the differenciation between a survey and a survey response.

When rendering the form for creating a survey response a survey record defines what fields appear in the form, but you wouldn’t use a Survey changeset with the form. It would need to be a SurveyResponse changeset, because that’s what is getting created (or updated). The survey record might also be an input for a SurveyResponse changeset to validate any submitted inputs.

So for the survey response form handling a survey record will be a parameter, but the form is not about the survey record.

Generally I’d suggest starting without a survey record, hardcoding the markup for an example survey. Then hardcode details about a survey for that route, but dynamically rendering the markup based on that hardcoded data and from there it should be simple to use a survey record loaded from the db instead of hardcoded data.

6 Likes

Only tangentially related but you guys should check out the form and workflow framework that the company where I work at developed: GitHub - projectcaluma/caluma: A collaborative form editing service

Yeah, it’s python but a lot of the ideas are transferable.