DEV Community

Cover image for Writing Code for Others to Read
José Muñoz
José Muñoz

Posted on

Writing Code for Others to Read

Most software engineers primarily focus on becoming great at writing code. And this makes perfect sense. This is an essential step to become a great engineer within a reasonably sized team.

Successful companies, however, grow continuously. Sooner or later, the software engineering team will be beyond a few dozen people, where everyone can easily talk with everyone else. People will be split across different floors. New offices in different locations will be opened. Face-to-face communication starts to be insufficient. Channels like email, chat or video calls become more important. The pace of which this growth happens varies by company: for some, it takes years. For some of the really successful companies, it happens much more rapidly.

-Gergely Orosz

When you get your first gig as a developer you will inevitably be reading, understanding, and maintaining other people's code. Coding is an expression of one's logical abilities, and every mind is a world of its own, so as you gain experience, you will learn to identify people by their coding style. On a small team, this is no biggie, but as people come and go this starts to become an issue.

In the ideal situation, the organization maintains a style-guide and this helps to keep the code-base homogeneous, if this isn't your case, your code should express intent, tell a story, this will make bugs easier to identify and locate. there are a few of things that we can do to keep our code clean. The following observations are my personal, over-simplified take on The Clean Code book series by Robert C. Martin with just the right amount of empiric bias.

Use Meaningful Names

Variable names should express intent, be explicit on what that variable is going to be used for. Don't be afraid of using long names, just make sure you're following the language's casing convention. Variables should be named within their context, loosely-coupled logic rarely has several resources doing the same thing, so naming things within context allows you to re-use variable names that make sense in another file. Function names should be thought of as verbs, a reaction to an event. when naming a function think about what is the function going to be used for.

Instead of writing this:

 button.onclick = () => {
  const anchor = document.createElement('a')
  anchor.download = 'my download.pdf'
  anchor.src = '/some/resource/url'
  anchor.click()
 }
Enter fullscreen mode Exit fullscreen mode

you could write this:

const downloadPdf = // some implementation
button.onclick = downloadPdf
Enter fullscreen mode Exit fullscreen mode

Currying is your friend

Currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument. Curried functions are particularly useful in the context of function composition, which allows us to create specialized higher-order functions that can provide more semantic sense.

Instead of writing this:

const SomeComponent = props => {
  return (
    <Button
      onClick={() => props.navigate('somewhere-else')}
    />
  )
}
Enter fullscreen mode Exit fullscreen mode

you could write this:

const SomeComponent = props => {
  const goTo = route => () => props.navigate(route)

  return (
    <Button
      onClick={goTo('somewhere-else')}
    />
  )
}
Enter fullscreen mode Exit fullscreen mode

Comments can be functions too!

If you're writing a large portion of logic you may feel like you need to explain what that code does, it is natural to think about leaving a comment for another collaborator to read when working around that file. Every time you find yourself writing a comment to explain the reasoning behind a portion of code, think about it as an opportunity to refactor that portion of code into its own function with a meaningful name. This doesn't mean that comments are bad, there are valid cases for comments where legacy code can't be refactored or notes for things that need to be revisited like //#TODO: vacuum cat

Instead of writing this:

const myBigImperativeFunction = async () => {

 if(isCold){
   const clothes = await fetch('/api/clothes')
   if(clothes.sweater){
     if(clothes.sweater.thickness > 3){
       clothes.sweater = await fetch('/api/sweaters?thickness=4')
     }
   } else {
      clothes.sweater = await fetch('/api/sweater')
   }

   const coffee = await fetch('/api/beverages/coffee')
   this. energy += cofee;
 }
}
Enter fullscreen mode Exit fullscreen mode

you could write this:

const wearWarmSweater = //some implementation
const getSomeCoffee = //some implementation

if(isCold){
  await wearWarmSweater()
  await getSomeCoffee()
}
Enter fullscreen mode Exit fullscreen mode

Keep things DRY

Logical reduction is one of the most powerful tools on any developer's belt. The thing about code with lots of flow control is that, it is hard to detect duplicate efforts but now that your code is explicitly expressing its intent, it is easier to spot things that can be reduced and re-used.

Instead of writing this:

const rightIcon = {
  size: 16,
  name: 'plus',
  color: '#0064D2',
}


const leftIcon = {
  size: 16,
  name: 'minus',
  color: '#0064D2',
}

Enter fullscreen mode Exit fullscreen mode

you could write this:

const smallCeruleanSign = name => ({
  name,
  size: 16,
  color: '#0064D2',
})

const rightIcon = smallCeruleanSign('plus')
const leftIcon = smallCeruleanSign('minus')
Enter fullscreen mode Exit fullscreen mode

Conclusion

Writing clean code makes everyone's life easier, your users will benefit of the increased productivity that having readable and understandable code will provide. Even on a personal level, clean code allows us to understand our projects 6 months down the line, it allows teams to onboard new engineers faster, and it helps spot efforts that could be optimized in a granular fashion. Let me know what you do to keep your code clean, I would love to learn a couple of tricks from the comment section.

Top comments (0)