Evo Image

Reflections as a Former Student at the Art Institute of Seattle

The Art Institutes

Although I never did finish my degree at the Art Institute of Seattle, I acquired a lot of invaluable knowledge about design fundamentals including how to create and implement typographical font faces, how to work with some sort of grid system for use on projects such as magazine layouts and website interfaces, how to utilize the pen tool in Adobe Illustrator to effectively create computer vector illustrations, but most importantly how to brainstorm ideas in such a way as to capture them for use as thumbnails and drafts that are then fine-tuned into a finished brand for a product.

Quote of the Day

Devolution

“The good thing about science is that it's true whether or not you believe in it.”

Neil Degrasse Tyson, Real Time with Bill Maher, 2011

Quote of the Day

Devolution

“You might not think that programmers are artists, but programming is an extremely creative profession. It's logic-based creativity.”

John Romero, Co-founder of id Software

The Last Jedi Movie Review

Star Wars: Episode VIII: The Last Jedi

I highly recommend seeing this picture if you haven't already. Next to “Baby Driver”, it was the most fun I had at the theater all year.

Overall Impression: ★★★★☆ (4/5)

Quote of the Day

Devolution

“Solutions nearly always come from the direction you least expect, which means there's no point trying to look in that direction because it won't be coming from there.”

Douglas Adams, The Salmon of Doubt

Refactoring JavaScript

JavaScript Logo

Refactoring is a controlled technique for improving the design of an existing code base. Its essence is applying a series of small behavior-preserving transformations, each of which "too small to be worth doing". However the cumulative effect of each of these transformations is quite significant. By doing them in small steps you reduce the risk of introducing errors. You also avoid having the system broken while you are carrying out the restructuring - which allows you to gradually refactor a system over an extended period of time.”

Martin Fowler, Refactoring: Improving the Design of Existing Code

Here are some good examples of refactoring JavaScript code. Take this rather complex if-else statement:

            
ul.addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const button = e.target;
    const li = button.parentNode;
    const ul = li.parentNode;
    if (button.textContent === 'remove') {
      ul.removeChild(li);
    } else if (button.textContent === 'edit') {
      const span = li.firstElementChild;
      const input = document.createElement('input');
      input.type = 'text';
      input.value = span.textContent;
      li.insertBefore(input, span);
      li.removeChild(span);
      button.textContent = 'save';
    } else if (button.textContent === 'save') {
      const input = li.firstElementChild;
      const span = document.createElement('span');
      span.textContent = input.value;
      li.insertBefore(span, input);
      li.removeChild(input);
      button.textContent = 'edit';
    }
  }
});
            
          

All of which can be refactored into:

            
ul.addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const button = e.target;
    const li = button.parentNode;
    const ul = li.parentNode;
    const action = button.textContent;
    const nameActions = {
      remove: () => {
        ul.removeChild( li );
      },
      edit: () => {
        const span = li.firstElementChild;
        const input = document.createElement('input');
        input.type = 'text';
        input.value = span.textContent;
        li.insertBefore(input, span);
        li.removeChild(span);
        button.textContent = 'save';
      },
      save: () => {
        const input = li.firstElementChild;
        const span = document.createElement('span');
        span.textContent = input.value;
        li.insertBefore(span, input);
        li.removeChild(input);
        button.textContent = 'edit';
      }
    };
    nameActions[action]();
  }
});
            
          

Let’s break this down step-by-step.

Step 1

Put each branch of the if-else block into its own function in order to see them more clearly. First, we'll take the contents of the first branch...

            
ul.addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const button = e.target;
    const li = button.parentNode;
    const ul = li.parentNode;
    if (button.textContent === 'remove') {
      ul.removeChild(li); // Cut this statement out
    } else if (button.textContent === 'edit') {
      const span = li.firstElementChild;
      const input = document.createElement('input');
      input.type = 'text';
      input.value = span.textContent;
      li.insertBefore(input, span);
      li.removeChild(span);
      button.textContent = 'save';
    } else if (button.textContent === 'save') {
      const input = li.firstElementChild;
      const span = document.createElement('span');
      span.textContent = input.value;
      li.insertBefore(span, input);
      li.removeChild(input);
      button.textContent = 'edit';
    }
  }
});
            
          

...and replace it with a call to the function removeName.

            
ul.addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const button = e.target;
    const li = button.parentNode;
    const ul = li.parentNode;
    function removeName() { // Creates removeName function
      ul.removeChild(li); // Content of removeName function
    }
    if (button.textContent === 'remove') {
      removeName(); // Calls the removeName function
    } else if (button.textContent === 'edit') {
      const span = li.firstElementChild;
      const input = document.createElement('input');
      input.type = 'text';
      input.value = span.textContent;
      li.insertBefore(input, span);
      li.removeChild(span);
      button.textContent = 'save';
    } else if (button.textContent === 'save') {
      const input = li.firstElementChild;
      const span = document.createElement('span');
      span.textContent = input.value;
      li.insertBefore(span, input);
      li.removeChild(input);
      button.textContent = 'edit';
    }
  }
});
            
          

At this point, this isn’t necessarily an improvement. However, with the next branches we will see a considerable clean up in the following if-else statement.

Step 2

Repeat previous refactoring method with the following else-if branches:

            
ul.addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const button = e.target;
    const li = button.parentNode;
    const ul = li.parentNode;
    function removeName() {                           
      ul.removeChild(li);                            
    }
    function editName() { // Creates editName function
      const span = li.firstElementChild; // Contents of editName function
      const input = document.createElement('input');
      input.type = 'text';
      input.value = span.textContent;
      li.insertBefore(input, span);
      li.removeChild(span);
      button.textContent = 'save';
    }
    function saveName() {
      const input = li.firstElementChild;
      const span = document.createElement('span');
      span.textContent = input.value;
      li.insertBefore(span, input);
      li.removeChild(input);
      button.textContent = 'edit';
    }
    if (button.textContent === 'remove') {
      removeName();                                
    } else if (button.textContent === 'edit') {
      editName();
    } else if (button.textContent === 'save') {
      saveName();
    }
  }
});
            
          

At this point, it almost reads like plain English, “If the removeButton is clicked, remove a name, if the editButton is clicked, edit the name, and if the saveButton is clicked, save the name.” In fact, you could leave your code this way and it would be a significant improvement. But we can do better, we can simplify the code even further.

Step 3

Store the three functions in an object.

            
ul.addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const button = e.target;
    const li = button.parentNode;
    const ul = li.parentNode;
    const action = button.textContent;
    const nameActions = { // Creates nameActions object
      remove: () => {
        ul.removeChild( li );
      },
      edit: () => { // Creates an object property called edit
        const span = li.firstElementChild;
        const input = document.createElement('input');
        input.type = 'text';
        input.value = span.textContent;
        li.insertBefore(input, span);
        li.removeChild(span);
        button.textContent = 'save';
      },
      save: () => { // Creates an object property called save
        const input = li.firstElementChild;
        const span = document.createElement('span');
        span.textContent = input.value;
        li.insertBefore(span, input);
        li.removeChild(input);
        button.textContent = 'edit';
      }
    };
    nameActions[action]();
  }
});
            
          

This new object notation is a bit easier to read. And we’re done!