Clean code exercises - part 1
Tags: cleancode, javascript, programming
Published: 2020-11-19 05:37:31

---
title: Clean code exercises - part 1
published: true
tags: ["cleancode", "javascript", "programming"]
series: "Clean code exercises"
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/7jzmzrulahgas589rj1g.png
canonical_url: https://ederdiaz.dev/blog/clean-code-exercises-part-1
description: A series of scenarios to practice clean code theory
---

_Illustration by <a href="https://dribbble.com/Ivan_Haidutski">Ivan Haidutski</a> from <a href="https://icons8.com/">Icons8</a>_

You've probably read and listen a lot about Clean Code and probably you're tired of acronyms like YAGNI, DRY and KISS. All of this usually goes directly to your brain's recycle bin because you don't practice it enough. 

After years of reading other people's code in code reviews, I've developed an 'eye' to catch bad code, and I think you can develop it too by reading the scenarios I've designed.

The following examples aren't necessarily flawed code, I mean, imagine they don't have any bugs and they do the job, but the aren't as maintainable as they could be. Read each example, try to identify the problem and imagine what would you do to solve it. 

## Scenario 1
```javascript
function canBuyBeer(age, money) {
  if(age >= 21 && money >= 20) {
    return true
  }
  return false
}
```

### What's the problem? 
(don't read until you are done with above's code)

The problem in this example is the arbitrary numbers that are being used in the if statement. Because of the method context you might infer that `21` is the legal age to drink and `20` is the beer price, but this isn't too straight forward at first sight. These are usually called `magic numbers`.

### Solution
One way to solve this is creating named constants for the numbers. This makes it easier to read. 
```javascript
function canBuyBeer(age, money) {
  const legalDrinkingAge = 21
  const beerPrice = 20
  if(age >= legalDrinkingAge && money >= beerPrice) {
    return true
  }
  return false
}
```
Also if in the future something changes, like the beer price, it will be less prone to error by changing the constant value instead of finding and replacing the appearances of `20`.


## Scenario 2
```javascript
function shouldShowImage(itemIndex, article, showAllImages) {
  return [0, 1, 2].includes(itemIndex)
    ? !!article.imageUrl
    : showAllImages
      ? !!article.imageUrl
      :false
}
```

### What's the problem?
(Remember to try to identify this by yourself first)
There's too many things happening in that return statement. The person that wrote this might thing is clever to use idiomatic features to solve things in a line or a couple of lines of code, that's why this is called `clever code`.

### Solution
Just be explicit on what is the intended behavior and make it easy to read, even if that means splitting the code into more lines.

```javascript
function shouldShowImage(itemIndex, article, showAllImages) {
  if(!article.imageUrl) {
    return false
  }
  if(showAllImages) {
    return true
  }
  const isItemOneTwoOrThree = [0,1,2].includes(itemIndex)
  if(isItemOneTwoOrThree) {
    return true
  }

  return false
}
```
There were many refactoring steps between the example and the solution, but I assure you that both have the same behavior.

If a peer defends their clever code by saying that the solution is making the application become larger, that's likely not true, most modern languages when compiled or minified will be smaller than any clever code created by a human.

## Scenario 3
```javascript
function getArea(shape, width, height, radius) {
  if(shape === 'circle'){
    return Math.PI * radius * radius
  } else if(shape === 'square') {
    return width * width
  } else if(shape === 'rectangle') {
    return width * height
  }
}
```
### What's the problem?
This method has too many responsibilities. Whenever someone adds a new shape also a new `if/else` statement will need to be created. Also in this case the area calculations are one liners but if they become more complex, for example to validate the inputs, this method would become huge.

### Solution
Separate them into strategies with their own method, this way if they grow in size they'll be easier to maintain.

```javascript
const circleStrategy = (shape) => Math.PI * shape.radius * shape.radius

const squareStrategy = (shape) => shape.width * shape.width

const rectangleStrategy = (shape) => shape.width * shape.height

const areaStrategies = {
  circle: circleStrategy,
  square: squareStrategy,
  rectangle: rectangleStrategy
}

function getArea (shapeName, width, height, radius) {
  const shapeObject = { width, height, radius }
  const strategy = areaStrategies[shapeName]
  return strategy(shapeObject)
}
```
Notice we also improved the mechanism to choose a strategy by using a dictionary instead of the multiple `if/else` statements.

Well, that's it for today's practice, I hope it helps you to get your spider sense tingle in the next code review you do.

I'll follow up soon with more examples in a future post, if you have ideas for more scenarios put them in the comments section.

Also you can check the part 2 of this series [here](https://dev.to/ederchrono/clean-code-exercises-part-2-3ee3).