DEV Community

Nimmo
Nimmo

Posted on

State transitions (i.e. Elm messages/React actions etc.): Past or imperative tense?

Do you have an opinion over which helps either you or your colleagues reason about your applications better?

Past tense: DetailsUpdated
Imperative tense: UpdateDetails

Personally I'd always gone with imperative, but I thought about it recently and realised that whenever I'm looking at a list of state transitions things felt a little strange. For example:

A list of state transitions, all in imperative tense: StartGame, ChangeUrl, ChangeRoom, ExamineRoom, ToggleInventory

Whilst this is easy enough to follow, it's hard to describe it without reverting to past tense anyway: The user started the game, the URL changed, the user changed rooms, the user toggled the inventory...

But this isn't the same when you're writing the code: "When a user opts to start the game, I want the game to start" etc.

So I'm interested: what do you use?

Top comments (16)

Collapse
 
skaterdad profile image
Mike • Edited

I personally use the imperative tense.

Since messages in Elm are a declarative, I feel it makes sense to name the action according to what it will do. It would feel strange seeing a past-tense name when reading the code which actually triggers an action.

 [ button [ onClick StartGame ] [ text "Start Game" ]

vs

 [ button [ onClick GameStarted ] [ text "Start Game" ]
Collapse
 
nimmo profile image
Nimmo

The string passed to text in the second example would still be "Start Game" of course. But yes, that in itself is a good example of the trade-off being made if you're using past-tense for messages.

Collapse
 
skaterdad profile image
Mike

Thanks for catching that. Fixed the code block.

Thread Thread
 
nimmo profile image
Nimmo

I feel the same re: naming the action according to what it will do, for what it's worth. I'm just starting to wonder if perhaps it makes more sense to name them based on how they're used, you know what I mean?

By the time the application is processing the message, the message in question has already been sent by the user; so when you look at it in the debugging tools (in debug mode of course), it feels like it makes more sense to be in past tense. Hmm...

Thread Thread
 
skaterdad profile image
Mike

I get your point, but it's only in the dev tools or logs where that comes up.

Most of my time is spent reading the source code, so I optimize for that.

If a new person from your team reads your .elm file for the first time, the imperative message names make the intention of the code more clear.

What might be neat is if the dev tools could accept a function that lets you translate Msg names to a "display name". Then you get the best of both styles.

Thread Thread
 
nimmo profile image
Nimmo

I'm really thinking out loud here btw, rather than actively trying to convince you (or me) that this is a change worth making.

Thread Thread
 
drbearhands profile image
DrBearhands

I'd say name things for what they are. Use imperative if the message will trigger an action when passed to update. Use past if they are notifications of an action having occurred. The two cases usually overlap and it's mostly a matter of emphasis. E.g. with the start game button:

"StartGame" because the message will start the game, "StartGameButtonPressed" because it is a notification that the button was pressed.

"GameStarted" is wrong though, because the logic that handles the message has not completed yet and may even need Cmds.

Thread Thread
 
nimmo profile image
Nimmo

That's an interesting point re mixing tense - perhaps messages should generally be imperative and commands should generally be past, since for the most part a message is something a user has intentionally requested happen where a command is something that has happened without them realising.

Thread Thread
 
drbearhands profile image
DrBearhands

If you're talking about commands as in Cmd msg, I disagree. Commands are imperative by definition.
For messages caused by a Sub msg, that does make a degree of sense.
For messages pushed by the execution of some command, maybe. You could say (a) firstCmd |> Cmd.map doSecondCmd or (b) someCmd |> Cmd.map firstCmdDone. (a) communicates intent directly in the execution of the command, (b) does not communicate intent directly, but elsewhere the update function. Considering update is supposed to handle and react to messages (b) seems to be "correct" most often, but in cases where the handling of the message logic is shared by multiple commands, (a) might be a better fit.

Thread Thread
 
nimmo profile image
Nimmo • Edited

I was thinking specifically with the example I posted initially to be honest:

StartGame, ChangedUrl, ChangeRoom

Now you can see what effects the user intentionally chose, and which one was a side-effect of something that they chose to do.

Thread Thread
 
nimmo profile image
Nimmo

Of course, the inverse of that is that the user can in fact change the URL for themselves, so I guess this hasn't actually helped anything at all. D'oh.

Thread Thread
 
drbearhands profile image
DrBearhands

It depends on what those messages are.

GameMsg ToggleInventory, will it, when passed to update, create a new Model that when passed to view will show an inventory? Then imperative makes sense.

If you'd use the name InventoryToggled to denote that the user has e.g. pressed the ToggleInventory button, I'd say you're naming things incorrectly because the inventory wasn't toggled, as the message has not been processed by update yet.

ChangedUrl on the other hand denotes something that definitely did happen. It is more similar to ToggleInventoryButtonPressed.

Thread Thread
 
nimmo profile image
Nimmo

Yeah, the more I think about it the more I think mixed tense (but intentionally so, rather than accidentally so) feels like the way forward here.

Appreciate your input, this has been a useful conversation.

Thread Thread
 
drbearhands profile image
DrBearhands

Glad it was of use to you

Collapse
 
tamcarre profile image
Tam CARRE • Edited

My approach:

button [ onClick StartGameClicked ] [ text "Start Game" ]
Enter fullscreen mode Exit fullscreen mode

GameStarted is a lie, and StartGame implies that the view is somehow responsible for telling the update what to do. I prefer the view to be a pure description of the UI with messages describing what has happened. The view dispatches a StartGameClicked event, which is purely factual, and the update is free to create a new model based on this in whatever way it wants to.

Collapse
 
dwayne profile image
Dwayne Crooks

I like the advice given in this talk,

and/or in this comment.