Skip to content

Proposal: change mutation name style #1733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Proposal: change mutation name style #1733

wants to merge 2 commits into from

Conversation

galvez
Copy link

@galvez galvez commented Jul 31, 2018

The original text uses REMOVE_TODO (uppercase constant style, reminiscent of React and Redux) as mutation name in an example. I propose that it changes to todoRemoved, a style that will match the rest of the code, while maintaining a clear distinction from related actions.

@chrisvfritz
Copy link
Contributor

We're actually inconsistent about this in our current examples - sometimes using UPPER_CASE, sometimes camelCase. We're discussing it internally and right now, are leaning towards consolidating on camelCase for mutation names, which is more generally the standard for function names in JavaScript.

@galvez
Copy link
Author

galvez commented Aug 3, 2018

@chrisvfritz awesome, very glad to hear! -- should I keep this PR open then? :)

@chrisvfritz
Copy link
Contributor

Up to you, if you want to get contribution credit. 🙂 Once we have a clear consensus, I'll be going through and updating all our examples, in all repos. Here are the specific conventions we're leaning towards though:

  • camelCase for actions and mutations
  • imperative-style verbs for anything callable, like actions, mutations, and methods (e.g. closeModal, sendMessage)
  • intent-based verbs for actions (e.g. addTodo, updateTodo, removeTodo)
  • implementation-based verbs for mutations (e.g. pushTodo, mergeTodo, deleteTodo)

@galvez
Copy link
Author

galvez commented Aug 3, 2018

@chrisvfritz I'll insist then on my proposal for past-tense mutations then. I think having both deleteTodo and removeTodo would be weird and would contribute to confusion. Having past-tense mutations (todoRemoved) offers a clear and easy distinction between mutations and actions. We've adopted this standard in a number of projects at work and it's been pretty manageable.

I'll leave the PR open if this suggestion stands a chance of consideration.

@chrisvfritz
Copy link
Contributor

@galvez I think the chances are relatively low, but it's not impossible at this point. Personally, if I see something called todoRemoved, I'd think it was either a boolean to tell me whether or not a todo was removed, or an event to log that the todo was removed. In the context of commit('todoRemoved', todoId), the todo is not technically removed yet, so we're calling the function to make that happen rather than reporting that it was already done.

Also more generally in JavaScript, imperative-style verbs are almost universally used for called functions, so we'd be breaking a big convention of the larger ecosystem.

Does that make sense? Also, I'd love to hear more about the confusions that the past-tense convention resolved for you. I'm wondering if there may be a 3rd option or additional convention that could resolve all our concerns. 🙂

@galvez
Copy link
Author

galvez commented Aug 3, 2018

we'd be breaking a big convention of the larger ecosystem.

That's a valid point. Adopting past tense for mutations also required creating the notion that mutations are really special functions. Since their purpose is to provoke actual state change, past tense simply created a way to identify them by interpreting them in a what happened after this ran narrative. It made sense enough to me, but I understand it may confuse some. Other ideas that come to mind would involve even more complex and redundant semantics.

@galvez
Copy link
Author

galvez commented Aug 3, 2018

One small thing: the past-tense narrative also encourages data wrangling logic to happen outside the mutation, keeping them pure.

@chrisvfritz
Copy link
Contributor

Since their purpose is to provoke actual state change, past tense simply created a way to identify them by interpreting them in a what happened after this ran narrative.

That makes sense. 🙂 It's what I was attempting to achieve with the suggestion to describe the specific nature of the mutation, but it sounds like it's not quite sufficient to avoid confusion. 😅 Do you think it would help to define an exhaustive list of verbs to recommend that all mutations begin with?

Browsing through my own apps, I believe every mutation could begin with one of the verbs below:

  • push: when using Array.prototype.push.

  • pop: when using Array.prototype.pop.

  • unshift: when using Array.prototype.unshift.

  • shift: when using Array.prototype.shift.

  • reverse: when using Array.prototype.reverse.

  • copyWithin: when using Array.prototype.copyWithin.

  • fill: when using Array.prototype.fill or otherwise setting static or non-deterministic values for 2 or more items in an array.

  • sort: when using Array.prototype.sort or otherwise sorting the items in an array (e.g. with lodash's sortBy or orderBy).

  • delete: when removing 1 or more items from an array or object, whether using Array.prototype.splice, Array.prototype.filter, Vue.delete, or some other strategy.

  • set: for all other cases using = to set a new value for an existing property, or Vue.set to create/set a property.

As a bonus, this strategy would also help people limit the scope of their mutations, keeping all business logic in actions where it belongs. In the apps I have access to, I did notice some cases where none of the above verbs were appropriate - but in every case, the mutation was doing much more than it should have.

And as another bonus, this convention could speed up development with snippets and we might even be able to automate its enforcement in eslint-plugin-vue! 😻 (@michalsnik, do you think that might be feasible?)

What are your thoughts? In the teams you've worked with, do you think this would clarify the responsibilities of mutations for and reduce the cognitive overhead of naming them?

@galvez
Copy link
Author

galvez commented Aug 4, 2018

@chrisvfritz No reason we can't do both, I guess?

How about we add a paragraph as follow to the docs:

@galvez
Copy link
Author

galvez commented Aug 4, 2018

When naming mutations, a good strategy is to mimic the list operations the mutation mainly performs, e.g., pushUser, unshiftUser. If that is too limiting an approach, you can also adopt a past-tense narrative style, where a mutation is named after the changes it provokes, e.g., userAdded, userRemoved. Either way promotes keeping mutations pure, with data wrangling logic best kept in actions.

I added it to the bottom of style-guide/index.md, but feel free to edit and relocate it if you think it's a good idea.

@michalsnik
Copy link
Member

I like this idea @chrisvfritz !

However in terms of eslint rule that might check it - I'm not so sure. Depending on a person or team, structure of the vuex module might differ drastically. Some might keep it in store folder, some not. One team prefers to have single file modules, other not. Same with keeping mutation names as constants in a separate file. I don't see how - except explicit comments detect whether given mutation is indeed a mutation using just an AST and filename from the context. In the end it might probably introduce too many false positives as well as false negatives.

I think that this kind of rule might be feasible but only per-project case as a team's internal agreement, so as from our plugin's perspective I must say: no, it's not feasible, unless I missed something.

@TheAlexLichter
Copy link
Contributor

Maybe we should move this to https://github.com/vuejs/vuex? 🤔

Copy link

@tatoon187 tatoon187 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

http-push

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants