Identifying states when using state machine to validate a form field

  softwareengineering

Scenario is simple, a password field with few validation rules.

The states I came up with are

  • default ( when the form loads or reset button is pressed)
  • filled ( should this even be a state ?)
  • valid ( date is present with all rules satisfied)
  • invalid (data is there but not satisfying the rule set )

Error message is displayed based on the current state.

For example,

  • default state, user didn’t enter any data yet, so logical it is an invalid state (assuming the field is required) but we do not want to show errors to the user right away after opening the form (that will be horrible ux, right ?) so I added the default state specifically for that purpose.

Secondly, there seems to be arbitrary states Like

  • validating
  • submitting

They look like states to me but are they?

Lastly, can we say

  • submitted is also a state ?
  • invalid after submitted due to error in API call ( maybe API team added a new rule we didn’t know).

Million dollar questions are,

Am I even thinking in the right direction to implement validation this way?
Is there any states I am missing or overdoing?
Is this right? Can it be further simplified?

P.s. (this question is about how to infer states from a problem and not about how to actually implementing it in code. I know and have used xstate lib).

I think you are overthinking this. If you are trying to express the authentication flow as a state machine then it can obviously have many odd states depending on the flow, “too many password attempts”, “user locked”, “already logged in” etc

If you want to validate a single field then its simple, “unknown”, “valid” or invalid with a list of validation fails.

In general

Before jumping into a complex state-machine design, you need to first separate concerns at stake.

You can think of each of these separate concerns as having a separate state machines. It can be simple one such as a boolean flag, or it can be very complex table driven state machines with complex behavior via state pattern. Or it can be anything else in-between these extreme cases.

Your example

If you’re apparently working on an UI design. You seem to merge different concerns:

  • The states Empty and NotEmpty can make sense if you want to deactivate or activate some other UI elements (e.g. keep button “Submit” deactivated as long aa mandatory field is empty).
  • The states Compliant and NonCompliant can make sense if you want to put a green or red indicator next to your field for immediate visual feedback while the user is typing (e.g. the indicator stays red until the password is sufficiently long and has all the expected categories).
  • The states Submitted, Valid and Invalid make sense if you try to follow the status of the field against the server feed-back (I hate those long address forms where I get an error message that one of the field is invalid, but I cannot figure out which field among the 12).

You may want to merge some of these state machines if it helps to keep your design simpler:

  • Emptyness and compliance seem to be strongly related, Empty being always NonCompliant, NonEmpty can be either Compliant or NonCompliant. You may want to merge them into a single set of states (Empty, NonCompliant and Compliant).
  • You may want to go further and harmonize the behaviors (e.g. “Submit” button deactivated not only if it’s empty but also if the content is non compliant). In this case, you could just drop Empty/NonEmpty and consider emptynes as a special case of non-compliance.
  • Lastly, the validity of the field according to the API call seems independent of the compliance of its content with basic rules. You may then keep separate state machines with separate states.
  • But you may want for the sake of UI consistence, merge both machines anyway (for example if the red light next to the field is to be red for both invalid or non compliant values). In this case, you may create composite states, for example CompliantSubmitted, CompliantValid, CompliantInvalid, NonCompliant, Compliant (not submitted), Empty.

As you see, there are many ways to conceive state machines for the same problem. So the question is really what your design intents are.
Keep in mind that combining state machines make them more complex. Simpler is always better (when simpler is possible).

LEAVE A COMMENT