Search code examples
javaarchitecturebackend

What is the correct way to create multi-step forms on the server side?


I have an Application entity that includes other entities. In pseudo code that is not specific to a particular programming language, it would be described like this:

public class Application {
    public Client client = null;
    public Address address address = null;
    public House house house = null;
    public float price = 0;
    public boolean hasMortgage = false;
}

The validation of each entity is a separate step and is performed by the server, not the client

I see two options and want to know which one is used on real projects.

a) Each individual step:

1. User enters entity data
2. On the server the entity is validated in the controller of this entity
3. A record of the entity is created in the database
4. The id of the created record is returned to the user

When all steps are completed, the ApplicationController creates the Application entity, assigns the existing Address, House entities by their id and saves the Application entity record to the database.

b) At each individual step:

1. The user enters the entity data
2. On the server, the entity is validated in the controller of this entity
3. The user receives a response "Yes, you can go to the next step".

When all steps are passed, the ApplicationController creates the Application entity, creates the Address, House entities, assigns them to the Application entity, and only then saves records about all entities into the database.


Solution

  • There's no wrong or right architecture to do this. It just depends on your requirements and what your software is supposed to do. Obviously from the 2 choices you described there are pros and cons to each model. Here is what I see those being:

    Persist at Each Step Model:

    Pros

    • Strict control over the process for the server
    • If the user refreshes the page nothing is lost
    • The user can resume the flow at a later date
    • Enables easier troubleshooting user problems with flow.

    Cons

    • Could create a lot of trash or abandoned records in the DB, will require clean up of those situations
    • More work involved to persist each step
    • Changing the flow would mean more rework of the backend
    • too much control exerted by the server could create unnecessary coupling

    Persist At the End Model

    Pros

    • Minimal work to validate at each step
    • Only completed records are kept in the DB
    • Changes in the front end flow don't have to affect the backend (or maybe less of an effect)

    Cons

    • Front end will loose the flow if the user refreshes the page (local storage)
    • Won't be able to resume a flow some point later
    • Some other option to troubleshoot user flow issues.
    • Control of the overall process may be too loose

    How the client fits into this is going to impact these two solutions. Is this a SPA-style frontend or server side rendering? So the answer to the question is going to depend on not just the technology involved on the server, but could have implications for the client as well.

    The pros and cons of each solution can be mitigated with other solutions being introduced. For example, a clean up procedure on the backend or staging tables to hold the users entries before they finish the wizard flow, use of local storage in the browser to temporarily hold onto flows that were abandoned by the user - no backend clean up needed, or Google analytics style tracking on the front end for troubleshooting UX issues. To some degree each solution can be made palatable by introducing other solutions to dampen the cons.

    So it sometimes comes down to which is going to involve more supporting solutions to make up for the issues. If it's a lot of them then maybe the other way is better for you. Maybe you can tolerate some cons, or other pros are more important to you.

    I would add though that storing the state in the server memory is something you want to avoid. Keeping the server stateless should be the goal. Of course if you kept the state in something like Redis or an external cache that would fine, but it's a more complex architecture. But you definitely don't want it stored in server memory. That is one design that is definitely inferior.

    Hopefully this has given you some ideas of pros and cons of your own.