DEV Community

Samantha Ming
Samantha Ming

Posted on • Originally published at samanthaming.com

Code Smell: No AND in Function name

CodeTidbit by SamanthaMing.com

Function should adhere to the Single Responsibility Principle - meaning it should do one thing and one thing only. So if your function name includes "AND", it means you're doing too much. Solution? Remove the "AND" and split it into separate functions ๐Ÿ‘

// โŒ Bad
function teaAndSugar () {}

// โœ… Better
function tea () {}
function sugar () {}
Enter fullscreen mode Exit fullscreen mode

Single Responsibility Principle (SRP)

Every module should have one single responsibility. This means two separate concerns/responsibilities/tasks should always be implemented in separate modules.

Principles Wiki: SRP

And the Rationale behind is:

When this rule is not adhered to, one module has several tasks. If one of these tasks changes, there is the risk that this also has an effect on the other task that normally should be independent. Thus unrelated functionality may break.

When you follow the Single Responsibility Principle, you create a code base that is more flexible and modular.

SRP Benefits in Non Dev Terms

Let's try to explain this in non-dev terms. Let's say you're a chef and you're trying to order ingredients for your kitchen. Two sellers approach you with their options. Seller A tells you, we have all the ingredients you need and everything is mixed for you. Seller B tells you, we have all the ingredients you need and will sell them to you separately. Which one would you buy? Sure Seller A option is pretty good because everything is pre-mixed. BUT the recipes you can make is very limited because you're confined to recipes that require all 3 ingredients. However, with Seller B, the recipes you make are endless. You can make desserts and savory recipes ๐Ÿ‘ฉโ€๐Ÿณ

Seller A:

Buying pre-mixed ingredients limit you to recipes that require ALL 3 items.

function flourAndSugarAndEgg () {}
Enter fullscreen mode Exit fullscreen mode

Seller B:

Buying individual ingredients removes the limitation and allows you to create far more recipes ๐Ÿ†

function flour () {}

function sugar () {}

function egg () {}
Enter fullscreen mode Exit fullscreen mode

Maintainability Benefit

Another great thing with sticking with this rule is maintainability. When you just start out, sure it may seem a lot easier just to put everything together. But I guarantee you that over time, as you add more functionality or make changes, one singular function that does everything becomes very messy to maintain.

Explained in Non-Dev Terms

Let's explain this with another non-dev term explanation. Let's say you're a big Lego builder and you bought yourself a brand new Lego set. You're super excited you open the new set and dump all the pieces into a container. Unfortunately, you have a final exam the next week so you have no time to build it yet. A few weeks later, your rich aunt buys a few more Lego sets. I mentioned your aunt is rich because we all know Lego sets are ridiculously expensive ๐Ÿ˜‚. Again you open the new set and dump them in the same container, thinking that it's no big deal. Not to be outdone by your rich aunt, your rich grandma also wants to win your love, so she buys more Lego sets for you. Again, you didn't think it'd be a big deal, you open everything and dump them all in the same container. Okay, a few weeks have passed and now you're ready to build your Lego sets. Guess what happened? You're now knocking your head against the wall. Because all the pieces are mixed into one single container and you don't know which is which. However, if you had kept all the Lego sets in its own container, you wouldn't have this problem ๐Ÿ’ฉ

That's why one function should do one thing and one thing only. When it's doing more than one thing. It may not seem like it now, but over time and with changing requirements, this function will become bloated and it will become extremely difficult to maintain.

Community Input

  • @Skateside: Another pro tip: start the function names with a verb. This makes your intentions clearer and easier to explain - "this one makes tea, that one adds sugar."
function makeTea() {}
function addSugar() {}
Enter fullscreen mode Exit fullscreen mode
  • @sunnysingh.io: Generic functions like getData() ๐Ÿ˜ Um... what type of data? Unless it's a top-level utility, I like being specific like getUser(), getPost(), etc.

  • @Mouadovicc: I prefer to use drinkTea and drinkSugar by replacing AND by a unified word in this case is drink

Resources


Thanks for reading โค
Say Hello! Instagram | Twitter | Facebook | Medium | Blog

Top comments (16)

Collapse
 
n1ru4l profile image
Laurin Quast

Great article!

Especially when doing database operations I quickly find myself naming my methods/functions something like this: findPostRecordsWhereUserIdAndStatus({ userId, status }).

This obviously becomes worse with more parameters involved in a query. For me, it is always a trade-off between exactly knowing what the method/function does and having an awfully long name.

I am curious how you and other devs deal with such things, let me know!

Collapse
 
briwa profile image
briwa

I might be missing the obvious, but couldn't you just do:

findPostRecords({ userId, status })

If you're using Typescript/Flow (or Eslint to some degree, but I have to check), the arguments would be shown in your IDE so that you would know them when you type them, without having the need to be part of the function name.

Collapse
 
n1ru4l profile image
Laurin Quast • Edited

That works well when you always have the same criteria for finding post records. However, once you have to fetch post records under different conditions you need to overload (which is messy is not so cool in js).

Nevertheless, I can see how your approach could work for projects that are not too big!

Thread Thread
 
andrejnaumovski profile image
Andrej Naumovski

You don't need to overload. Just make the function take a single object as an argument with optional properties, then filter out the undefined ones at the start.

Thread Thread
 
n1ru4l profile image
Laurin Quast

This becomes a mess when only certain object properties should be used together.

Thread Thread
 
seanmclem profile image
Seanmclem

If it takes a standard query object for what to filter by

Collapse
 
napicella profile image
Nicola Apicella

Hi! Thanks for sharing.

SRP seems so easy to understand, but in fact it is not.
Toy examples are good to make a point, but hardly match the complexity of a real system.
So even in your example, the function which makes the breakfast is gonna call all three the function you defined (eggs, tea, flour).
Does that respect the SRP? It depends on the context.

Alrought having 'And' in a function name is a smell, what about the same one renamed without the 'And'?

The definition of SRP itself causes these kind of conflicts, which is why I use a different one, which takes into account what is the effect of SRP:
Functions X respects SRP if it has only one reason to change.

Collapse
 
prahladyeri profile image
Prahlad Yeri

Nice article ๐Ÿ‘

Though you should be wary of carrying the idea of single responsibility too far. Otherwise, you'll end up in the JavaScript/NPM world of is-odd, is-even and left-pad all managing their own single responsibilities!

Collapse
 
samanthaming profile image
Samantha Ming

Fair point, thanks for noting that ๐Ÿ‘

Collapse
 
jdforsythe profile image
Jeremy Forsythe

Sounds like a great idea for a custom tslint/eslint rule

Collapse
 
samanthaming profile image
Samantha Ming

It totally could be ๐Ÿคฉ

Collapse
 
vlasales profile image
Vlastimil Pospichal

I use method names: drink(), add(), find(), insert(), update(), delete(), etc.

Collapse
 
seanmclem profile image
Seanmclem

In the example of 2 functions, makeTea and addSugar, what would you name a function that eventually needs to call both functions?

Collapse
 
jbristow profile image
Jon Bristow • Edited

You have a new function...


addSugar :: Tea -> Tea
makeTea :: TeaLeaves -> Water -> Tea

makeSugaryTea :: TeaLeaves -> Water -> Tea
makeSugaryTea = addSugar . makeTea

-- pointfree equivalent of
makeSugaryTea t w = addSugar(makeTea t w)
Collapse
 
danjconn profile image
Dan Conn

This was a really nice way of explaining this important topic! Thanks :)

Collapse
 
samanthaming profile image
Samantha Ming

Awesome, glad it helped! ๐Ÿ˜Š