DEV Community

loading...

Prefer duplication over code that depends on if-else

Ahmad khattab
Be humble, unusual, there's power in those. Lead Product Engineer.
・3 min read

Back in 2018, when i had just begun coding, it was during the rise of JavaScript frameworks like React, Vue, and others like them. Those frameworks redefined frontend code and development as we know of, from the days of jquery.

One thing that stood out to me and really liked was the idea Components, the idea that you can nest some html code into a component and reuse it anywhere you liked, it stood out to me, i really liked to keep my code DRY. Not knowing of the other SOLID principle, the SRP(Single Responsibility principle) which states, an object, class, file, code needs to do one thing, and it needs to do it well. I was so fascinated by components that i tricked myself into violating the SRP while i was creating my components.

How? well, a component's purpose is to encapsulate some code and behaviour, and to be used on a location/s.

Let's illustrate that with an example, consider this Card component

import React from "react"

const card = (props) => {
  // return some html code here
}

export default card;
Enter fullscreen mode Exit fullscreen mode

now this is really handy, we can use this in our Profile page by simply doing these two lines

import Card from "./components/card"

<Card ...props />
Enter fullscreen mode Exit fullscreen mode

Now, all logic and UI design of a card is enacpsulated in one single source of truth(file), which allows us to change only in one place and all Card elements will be changed, really powerful, or is it?

Now, requirement's change, we need to display some UI from card depending on a state of it's Consumer(the place where it's rendered). We want to show an admin badge next to the user icon if they are an admin, pretty easy to add, let's update the code

const card = (props) => {

  if(props.isAdmin) {
    // render admin badge here
    // other elements for admin
  }
  // return some html code here
}

export default card;
Enter fullscreen mode Exit fullscreen mode

and we can simply pass it to the component where we need it

<Card isAdmin={admin value} />
Enter fullscreen mode Exit fullscreen mode

Now, requirements change again, aside from supporting admin elements like badge, we need to set the border of the element based if the user has been a long time user (they have been created more than one month ago). Let's update the code once more

const card = (props) => {

  if(props.isAdmin) {
    // render admin badge here
    // other elements for admin
  }

  if(props.isUserActive) {
     // change border of the card element
  }

   // return some html code here
}

export default card;
Enter fullscreen mode Exit fullscreen mode

Yet again, requirement change, we need to render a different icon for a user type moderator, let's update the code once more

const card = (props) => {

  if(props.isAdmin) {
    // render admin badge here
    // other elements for admin
  }

  if(props.isModerator) {
     // update UI elements for moderator
     // a border and specific icon
  }

  if(props.isUserActive) {
     // change border of the card element
  }

   // return some html code here
}

export default card;
Enter fullscreen mode Exit fullscreen mode

Now, you can see the pattern. whenever we want the card to support a specific use-case we need to add another if statement. I've been guilty of this, i've had components perform multiple checks and multiple control props just to determine how i'm going to render the component.

Solution

you can break the if statements by placing each if in it's own file, we would end up with three components

//components/cards/admin.js

import React from "react"

const adminCard = (props) => {
  // all admin properties 
  // admin icon
  // admin badge

  // returns html for an admin card.
}

export default adminCard;
Enter fullscreen mode Exit fullscreen mode
//components/cards/moderator.js

import React from "react"

const moderatorCard = (props) => {
  // all moderator properties 
  // moderator icon
  // moderator badge

  // returns html for an moderator card.
}

export default moderatorCard;
Enter fullscreen mode Exit fullscreen mode
//components/cards/activeUser.js

import React from "react"

const activeUserCard = (props) => {
  // all active user properties 
  // active user icon
  // active user badge

  // returns html for an moderator card.
}

export default activeUserCard;
Enter fullscreen mode Exit fullscreen mode

what did we do

we breaked the file into multiple files each with it's own properties, now we have three different card elements

<AdminCard isAdmin={admin value} />

<ActiveUserCard ...props />

<ModeratorCard ...props />
Enter fullscreen mode Exit fullscreen mode

However, we have some code duplication here, some code from all three files are duplicated, it's all a matter of trade-offs here, we removed if controlled code into a file with standalone purpose, but we ended up copy-pasting the code into three different files.

It's okay for a component to have a couple of if related code there, but if you see yourself passing more and more control variables, this is usually a sign that your component is attempting to do a-lot of stuff at once, your solution would be dividing the code into separated files.

Happy coding!.

Related links:

Building Resilient Frontend Architecture by Monica Lent

SOLID

Discussion (0)