The 3Ms of Coding Practices


In the world of programming, there are many lists of dos and don'ts. Some are universally liked, and some are personal preferences from one programmer to another. I want to take a step back and instead introduce 3 concepts you should use. This article is not a styling guide for any particular language, though I'll use JavaScript for my demos. 

The 3Ms

Let me introduce the 3Ms first before (in no particular order) diving into each one separately:

  • Minimize "imports"
  • Maximize "const"
  • Minimize "nesting"

Minimize "imports"

The first M is to structure your files so that you minimize/shorten the import statements. For example, take a look at the following:

import http from './utils/http';
import logger from './utils/logger';
import Button from './components/button/ButtonContainer';

This corresponds to a project structure that looks something like this:

src/
  utils/
    http.js
    logger.js
  components/
    button/
      ButtonComponent.jsx
      ButtonContainer.jsx
  app.js

 

Let's restructure this to minimize imports:

src/
  utils/
    http.js
    logger.js
    index.js
  components/
    button/
      ButtonComponent.jsx
      ButtonContainer.jsx
      index.js
  app.js

The two new files index.js just import and export the files within each folder:

// utils/index.js
export { default as http } from './http';
export { default as logger } from './logger';

// components/button/index.js
import ButtonContainer from './ButtonContainer';

export { default as ButtonComponent } from './ButtonComponent';
export { ButtonContainer };
export default ButtonContainer;

With this refactor, now let's see how our original file with the imports looks like:

import { http, logger } from './utils';
import Button from './components/button';

Now at this point, you might ask, "so what? This is just a coding preference". Well, this refactoring is giving us the following: simpler imports and internal files are abstracted out.

Simpler imports

You no longer need to dive into the structure of a file to import something.

Internal Files are Abstracted Out

Each directory may have internal files that are not intended to be used by any other file. For example, if you are familiar with React, the button directory has a component and a container file. When you want to use the Button component, you only need to use the container - the component is an internal file that a user of the Button component should not care about. In the original structure, this was not obvious - you had to know which of the two files to import. We will export the main (i.e. the "default") class with the new structure.

Maximize "const"

The next M is to maximize your constants/finals - that is, to define all your variables are final so they cannot be overwritten. There are many reasons why one should do this, but for me, the three primary reasons are:

  • No accidental overwrite
  • Breaks your code into smaller functional ones (help with readability and testability)
  • Reduces the if/else statements

Let's take a look at an example:

const onClick = async () => {
  let user = null;
  
  if (userExists) {
    const option = { /* some parameter */ };
    user = await findUser(option);
  } else {
    const option = { /* some parameter */ };
    user = await createUser(option);
  }

  // Now use user
}

The code above does not have the  user as final since it needs to be fetched from different locations based on certain conditions. This has led to an if/else statement. Furthermore, you may accidentally overwrite the user in some future line. Now let's refactor it:

const onClick = async () => {
  const user = await getUser(userExists);

  // Now use user
}

const getUser = async (userExists) => {
  if (userExists) {
    const option = { /* some parameter */ };
    return findUser(option);
  }

  const option = { /* some parameter */ };
  return createUser(option);
}

The if/else statement logic has now moved to its function and the variable user is currently a final. Not only is this more readable code, but it is also less nestedness (there is no else statement), and the code is easier to test.

Minimize "nesting"

The final M is to minimize nesting. This is all in favour of making your code easier to read and understand. There are 3 primary strategies here:

  • Use async/await instead of Promise
  • Return fast
  • Reduce if/else statement

Use async/await Instead of Promise

Take a look at this code:

const handleClick = () => {
  return getData()
    .then(data => {
      const req = { id: data.id };
      return getUser(req)
        .then(user => {
          this.setState({ user, action: data.action });
        });
    });
}

The code above is five levels nested! If you replace this Promise with async/await, things simply dramatically:

const handleClick = async () => {
  const data = await getData();
  const req = { id: data.id };
  const user = await getUser(req);
  this.setState({ user, action: data.action });
}

From a level 5 to a single level of nesting! 

Return Fast

Return fast refers to quickly returning/breaking in your function as soon as a particular condition is met. This can sometimes be achieved by reversing the if/else condition check you are performing. I've also seen people unnecessarily continuing to use an else statement when there is no need. Let's take a look at an example:

const getUser = async () => {
  if (someCondition) {
    const options = { /* some parameters */ };
    const config = await getConfiguration(options);
    if (config.id) {
      return getUserFromConfiguration(config.id);
    } else {
      return createUser();
    }
  } else {
    return defaultUser();
  }
}

There are two observations in the code above:

  • All the else blocks are unnecessary
  • If you reverse the first if statement, you can achieve the so-called "return fast."

Let's take a look: 

const getUser = async () => {
  if (!someCondition) {
    return defaultUser();
  }
    
  const options = { /* some parameters */ };
  const config = await getConfiguration(options);
  if (config.id) {
    return getUserFromConfiguration(config.id);
  }
  
  return createUser();
}

That's It!

I hope you enjoyed this article. My goal was to show you three simple principles you can use to clean up your coding style, make it more legible, make it more testable, and reduce the potential for bugs.

How do you rate this article?


4

0


k88.io Presents: Programming
k88.io Presents: Programming

Just another blog about programming, tricks and tutorials.

Send a $0.01 microtip in crypto to the author, and earn yourself as you read!

20% to author / 80% to me.
We pay the tips from our rewards pool.