DEV Community

Cover image for Don't stop Mutating

Don't stop Mutating

Stephan Meijer on December 16, 2020

I recently came across a tweet by Simon Hรธiberg that basically forbids you to use delete. The reason for this? "You don't want to mutate the existi...
Collapse
 
jackmellis profile image
Jack

I think this is quite a dangerous thing to encourage. In your example, fetchUsers could be bringing the data in from anywhere, it could be caching the result, it could be returning a hard-coded value, etc.

If you mutate the resulting users, what if another part of your code is also using it in order to get a list of ages? This would completely break it.

Immutability for the purpose of avoiding bugs is so much more important than readability or performance.

The real readability problem in your examples is that there's no natively elegant way to omit a property. Wouldn't you agree this looks nicer with a basic helper method?

const users = fetchUsers(100).map(user => omit(user, 'age'));
Enter fullscreen mode Exit fullscreen mode
Collapse
 
smeijer profile image
Stephan Meijer

Sure, helpers help. Please understand, my examples are contrived examples. I assume that fetchUsers fetches data from a remote origin. An API call so to say. Should I have mentioned that in the article?

Your comment is valid. But that does not make my article invalid. I also don't want to encourage mutating data. I want to encourage people to see that there is a valid scenario for both ways. I wish people to stopped banning half the language, simply because they:

  • find it hard to grasp
  • think it's prone to bugs
  • think the new way is better

Immutability for the purpose of avoiding bugs is so much more important than readability or performance.

That can definitely be a good argument to make something immutable. And honestly, when working on the frontend, it often is. On the other hand, I'm also working on the backend, with geospatial data (geojson). When I run geospatial operations, such as geometry simplifications, mutating objects is WAY faster. It has a noticeable impact, that we confirmed by profiling real requests. When someone submits a form to my backend, and I just normalize/simplify that data before I send it to the database, it makes zero sense to do it in an immutable way.

My goal with articles like this isn't to encourage anything else than to open the readers eyes. "There is a valid use case for each and every function.". A lot of articles push readers in a specific direction. And (junior?) developers are very sensitive to that and start refactoring stuff right away. Only to come back to it years later.

Collapse
 
jackmellis profile image
Jack

I 100% agree that the developer community is sometimes too opinionated and that everybody should be doing things a certain way. And there are of course instances where mutability is fine, even preferable, usually when you're writing internal code where you fully understand the implications of mutating data.

Your snippets have a good example of this. You're mutating an array by pushing to it, but you also created that array yourself directly before, so you have confidence that mutation won't cause any bugs.

For me I tend to do immutability-first and then think "what benefit would this have if I made it mutable?"

Collapse
 
bravemaster619 profile image
bravemaster619

You shouldn't have included projects attribute in the first place.

Anyways, deleting something somewhere in your code will cause unpredictable behavior in the long run.

You better leave original object as it is, because mutating objects WILL affect other parts of your code.

I agree on the second example (Unpredictable behavior) but the first one is kinda misleading. I would say.. Readability vs Maintainability

I will definitely choose this way:

const users = fetchUsers(100);
const newUsers = [];

for (let i = 0; i < users.length; i++) {
  const { age, ...newUser } = users[i];
  newUsers.push(newUser);
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
smeijer profile image
Stephan Meijer

Yes, in the perfect world, projects wouldn't have been there in the first place. Unfortunately, we don't live in the perfect world. Sometimes we use external API's, and get more data than we need. Sometimes, we fetch data from MongoDB, and deleting a bit of data is easier done on the backend than it is through aggregation piplelines.

You better leave original object as it is, because mutating objects WILL affect other parts of your code.

No, it doesn't have to. If the mutation is abstracted away, there is no issue (my getUsersWithoutProjects example). And that's the point of the article. It really isn't that black and white.

I will definitely choose this way:

And that's okay. Everyone has their own preference. The fact that you choose this style, doesn't make someone choosing the other wrong.

Collapse
 
bravemaster619 profile image
bravemaster619

Sometimes, we fetch data from MongoDB, and deleting a bit of data is easier done on the backend than it is through aggregation piplelines.

Yeah, maybe it's easier to do in frontend. BUT you need to do in BACKEND. For the sake of security and performance. Right?

If the mutation is abstracted away, there is no issue (my getUsersWithoutProjects example)

I already said that I agree on getUsersWithoutProjects.

The problem lies in this one:

const users = fetchUsers(100);

for (let i = 0; i < users.length; i++) {
  delete users[i].age;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
smeijer profile image
Stephan Meijer

THANK YOU! It's truly nice to see that some people get it.

I'm not here promoting mutability or immutability patterns. I'm here to open eyes and make developers understand that they have to make a choice on a case by case basis.

Collapse
 
tbm206 profile image
Taha Ben Masaud

If readability is the main concern of this article, I'd simply wrap the non mutating code in a delete function. Many libraries, such as lodash, provide this.

Collapse
 
smeijer profile image
Stephan Meijer

It's not. The main concern of this article is that too many of us (/other articles) lack nuance, and try to push developers in a single direction. While development isn't that black and white.

The TLDR is in the last paragraph:

Programming isn't black and white. We can't just ban half the keywords or native functions because they "feel wrong". There is a valid use case for each and every function

Collapse
 
tbm206 profile image
Taha Ben Masaud

That is quite a statement. I'm not aware of any credible advice out there where the reasoning revolves around "feel wrong".

Mutation is definitely bad from my experience. While I understand where you come from, the advice in this post does not offer credible proof that promoting different styles is more important than actually following best practices.

Thread Thread
 
smeijer profile image
Stephan Meijer

Mutation is definitely bad from my experience.

Expressions like that are the reason I wrote this article. Mutating data is not "definitely bad". There are very valid scenarios where you want to avoid immutable patterns. And that's what I tried to explain in this post.

It's unfortunate that I didn't get this message expressed more clearly.

Thread Thread
 
tbm206 profile image
Taha Ben Masaud

Mutation can only be beneficial because of machine code and computer architecture.

In an ideal world, e.g. higher level language, mutation should be avoided unless the developer really enjoys debugging.

It's clear you're stubbornly convinced that the wider community is at fault for sharing best practices; that I can do little to change.

Thread Thread
 
smeijer profile image
Stephan Meijer

It's clear you're stubbornly convinced that the wider community is at fault for sharing best practices;

Thank you for the kind words.

I like to think that I'm stubbornly convinced that I'm slighly frustrated by the unnuanced "best practices" I find on the web, that are blindly followed as the "only truth" by a bit too many developers.

Collapse
 
thorstenhirsch profile image
Thorsten Hirsch

I agree with you in all your examples. But in general I think "don't mutate" is a good advice (it doesn't say "never mutate").

Collapse
 
smeijer profile image
Stephan Meijer

Ooh, I definitely agree. Most of the time, immutable code is fine. Maybe even preferred. I simply try to make a sound against the unnuanced pushing that starts to take overhand on the web. I hope to make especially junior developers realize that they have to make decisions. And that banning half the language because it's "the old way" isn't the solution.

Collapse
 
jacobmgevans profile image
Jacob Evans

I really appreciate the "this article isn't telling you what to do" feel you make sure to emphasize while still making a sound argument for your perspective on the issue!

Collapse
 
smeijer profile image
Stephan Meijer

Thanks, Jacob! ๐Ÿ˜Š