December 29, 2015

Designing Your Code

By Drew Barontini

For me, organizing is second nature. It weaves itself through all facets of my life. And this includes the code that I write. No matter the language, I “design” my code to optimize readability. I’m biased, but I think it looks better, too.

So let’s talk about some techniques and ways that we can design and organize our code.

I’d like to point out that this is highly opinionated, so you might not agree with all, or any, of it. However, I hope we can all agree that conventions are vital. Establish them and stick to them, whatever they may be. At the very least, this could get you thinking about your own conventions.

Spacing

The first, and easiest, thing to do is provide spacing to your code.

class Animal {
  constructor() {
    // ...
  }
}

I like to use spacing, and in this case, newlines, to clearly distinguish the different parts of the code:

class Animal {
  constructor() {
    // ...
  }
}

Alright. That feels better. Let’s keep building out our class:

class Animal {
  constructor(name) {
    this.name = name;

    this._sayHello();
  }

  _sayHello() {
    return `Hello, my name is ${this.name}`;
  }
}

Again, we use spacing to differentiate the parts of the code:

  • We add a single space inside the parenthesis around the argument.
  • We separate the instance variable assignment and the method call by a newline.
  • We add a single space inside the string interpolation ${}.
class Animal {

  constructor( name, type, attributes = {} ) {
    this._name       = name;
    this._type       = type;
    this._attributes = attributes;

    this._sayHello();
  }

  getAttributes() {
    return this._attributes.
  }

  getAttribute( key ) {
    return this._attributes[ key ];
  }

  getName() {
    return this._name;
  }

  getType() {
    return this._type;
  }

  _sayHello() {
    return `Hello, my name is ${ this.getName() }. I am a ${ this.getType() }`;
  }

}

We have a few more things going on now, but we apply the same spacing conventions. Additionally, we line up the equals = sign for the variable assignment in the constructor. This is a personal preference, but I like the design of the code when assignments line up.

let person = {
  name: 'Drew Barontini',
  occupation: 'Front-end Developer',
  company: 'Code School',
};

It also works well with object keys and values.

I don’t recommend doing this manually. Your editor should have a way to automate it for you.

Comments

Next, let’s talk about applying comments to our code. Why are they so important, anyway?

  • They document the functionality of the code.
  • They provide better maintainability to future authors of the code (including yourself).
  • They help distinguish the individual parts of the code.

In all the various languages I write in, I generally use four main levels of comments:

  1. Heading comment for the introduction of the code.
  2. Large comment for secondary blocks.
  3. Small comment for tertiary blocks.
  4. Normal comment for the lowest level.

Heading

// *************************************
//
//   Title
//   -> Description
//
// *************************************

The heading comment contains a simple Title and Description. Additionally, it can hold further information about the file/component, such as parameters, usage, etc.

// *************************************
//
//   Animal Class
//   -> Creation of Animal objects
//
// *************************************

class Animal {
  // ...
}

Large

// -------------------------------------
//   Comment
// -------------------------------------

The large comment breaks up the code into its sections. In our class example, it would exist above each method:

class Animal {
  // -------------------------------------
  //   Constructor
  // -------------------------------------

  constructor(name, type, attributes = {}) {
    // ...
  }
}

And since we have arguments to pass into the constructor, this is a good place to document what the method is expecting:

class Animal {
  // -------------------------------------
  //   Constructor
  // -------------------------------------
  //
  // @param name       { string } Name of the animal
  // @param type       { string } Type of animal
  // @param attributes { object } Additional custom attributes
  //
  // -------------------------------------

  constructor(name, type, attributes = {}) {
    // ...
  }
}

Small

And here is the small comment that’s used at the tertiary level:

class Animal {
  constructor(name, type, attributes = {}) {
    // ----- Instance Variables ----- //

    this._name = name;
    this._type = type;
    this._attributes = attributes;

    // ----- Initialization ----- //

    this._sayHello();
  }
}

Normal

// Comment

And finally, the normal comment. This will vary from language to language, but it’s // in JavaScript. This is great for notes, todos, and general comments about the code:

class Animal {
  constructor(name, type, attributes = {}) {
    // ----- Instance Variables ----- //

    this._name = name;
    this._type = type;
    this._attributes = attributes;

    // ----- Initialization ----- //

    // TODO: Make this a public method that isn't called when
    //       a new object is instantiated.
    this._sayHello();
  }
}

Putting it all together

// *************************************
//
//   Animal Class
//   -> Creation of Animal objects
//
// *************************************

class Animal {
  // -------------------------------------
  //   Constructor
  // -------------------------------------
  //
  // @param name       { string } Name of the animal
  // @param type       { string } Type of animal
  // @param attributes { object } Additional custom attributes
  //
  // -------------------------------------

  constructor(name, type, attributes = {}) {
    // ----- Instance Variables ----- //

    this._name = name;
    this._type = type;
    this._attributes = attributes;

    // ----- Initialization ----- //

    // TODO: Make this a public method that isn't called when
    //       a new object is instantiated.
    this._sayHello();
  }

  // -------------------------------------
  //   Get Attributes
  // -------------------------------------
  //
  // @return { object } Attributes
  //
  // -------------------------------------

  getAttributes() {
    return this._attributes;
  }

  // -------------------------------------
  //   Get Attribute
  // -------------------------------------
  //
  // @param  key { string } Attribute key
  // @return     { string } Attribute value
  //
  // -------------------------------------

  getAttribute(key) {
    return this._attributes[key];
  }

  // -------------------------------------
  //   Get Name
  // -------------------------------------
  //
  // @return { string } Name of the animal
  //
  // -------------------------------------

  getName() {
    return this._name;
  }

  // -------------------------------------
  //   Get Type
  // -------------------------------------
  //
  // @return { string } Type of animal
  //
  // -------------------------------------

  getType() {
    return this._type;
  }

  // -------------------------------------
  //   Say Hello
  // -------------------------------------
  //
  // @return { string } Greeting
  //
  // -------------------------------------

  _sayHello() {
    return `Hello, my name is ${this.getName()}. I am a ${this.getType()}`;
  }
}

// -------------------------------------
//   Usage
// -------------------------------------
//
// let dog = new Animal( 'dog', 'Maddox');
// let dog = new Animal( 'dog', 'Maddox', { age : 8 } );
//
// -------------------------------------

That’s All, Folks

With minimal effort, we can add spacing and comments to make our code readable, maintainable, and pleasing to look at it. I hope this helps you develop your own conventions and standards for “designing” your code.

© 2019 Drew Barontini — Building products under Drewbio, LLC