Refactoring the Hyper terminal
Published: 2023-01-08 21:22:06

## Greetings!
Hi, Hello! My name is Mārtiņš and I am a 2nd year ICT student. Today I have decided to challenge myself and try to refactor part of an already existing codebase.

In order to decide which codebase I would like to try and refactor, I decided to 

> look within myself
 
(I think that's what Albert Einstein said once, right?) by searching through my computer for programs that I use or have used in the past. The reason I did that was to maybe find that one of these programs are open-source.

And guess what? One of them was! This time I am talking about the [Hyper terminal](https://hyper.is/) developed by Vercel. The repository can be found [here](https://github.com/vercel/hyper).

## But why am I even writing this, when there are much smarter developers that you can listen to?
Well, maybe you, dear reader, will find it interesting to see how a beginner developer refactors code in a large codebase. Maybe my way of thinking will entertain you.

## What is Hyper?
Hyper is an Electron-based terminal that is built on Web technologies (HTML, CSS, JS). The terminal supports plugins, meaning that you can customize it to whatever level you feel like. The reason I had it on my computer was because I had a phase in my "developer lifecycle" where I wanted my default terminal application to look as nice as possible.

<img width="100%" style="width:100%" src="https://media.giphy.com/media/35OOkbcHtrFr8cQD7E/giphy.gif">


## What tools did I use?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mq7x67z54wu1kpyfdupf.png)

In order to find a code smell I used [SonarQube](https://www.sonarsource.com/products/sonarqube/). It is an open-source platform developed for continuous inspection of code quality to perform automatic reviews and static analysis of code. The tool works by scanning the source code and comparing it against a set of rules that define what is considered good code quality. It can detect issues such as coding style violations, potential bugs, security vulnerabilities, and other problems that can impact the quality and maintainability of the code.

<img width="100%" style="width:100%" src="https://www.freecodecamp.org/news/content/images/2021/08/vscode.png">

We all know and love Visual Studio Code...right?
<img width="100%" style="width:100%" src="https://media1.giphy.com/media/LRVnPYqM8DLag/giphy.gif?cid=ecf05e4789ydr18opzn8p8g6vlekszcbb0kvxder1ac03sz7&rid=giphy.gif&ct=g">
...right?

## The actual refactoring process
Since the Hyper codebase is quite large, I used the aforementioned SonarQube tool to find code smells. In order to avoid refactoring something insignificant like a regex expression (gross, right?), I looked through the ones marked as **Critical**. Upon looking at the method at first, I was quite scared, honestly. Because (according to GitHub) this code was written 6 years ago, which means it is quite outdated. The function itself falls under the [_Long Method_](https://refactoring.guru/smells/long-method) category, as it contains lots of **if** statements, is quite long and is definitely hard to read.

So, what code smells were detected by SonarQube?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v3t2i038m5mv3q6ku501.png)

<img width="100%" style="width:100%" src="https://media3.giphy.com/media/BqLnHVdrW1UQpBJBwV/giphy.gif?cid=ecf05e47hcsbsd097kf639p07hpcuzh5479key8pqasq8aax&rid=giphy.gif&ct=g">

_Cognitive Complexity_ is a measure of how difficult a unit of code is to intuitively understand.

You can read more about cognitive complexity [here](https://docs.codeclimate.com/docs/cognitive-complexity#:~:text=Cognitive%20Complexity%20is%20a%20measure,be%20to%20read%20and%20understand.)

## Before

Here's what the code looked like prior to my refactoring:

```
function range(a, b, str) {
  var begs, beg, left, right, result;
  var ai = str.indexOf(a);
  var bi = str.indexOf(b, ai + 1);
  var i = ai;

  if (ai >= 0 && bi > 0) {
    begs = [];
    left = str.length;

    while (i >= 0 && !result) {
      if (i == ai) {
        begs.push(i);
        ai = str.indexOf(a, i + 1);
      } else if (begs.length == 1) {
        result = [ begs.pop(), bi ];
      } else {
        beg = begs.pop();
        if (beg < left) {
          left = beg;
          right = bi;
        }

        bi = str.indexOf(b, i + 1);
      }

      i = ai < bi && ai >= 0 ? ai : bi;
    }

    if (begs.length) {
      result = [ left, right ];
    }
  }

  return result;
}
```

Mystical variable names, hard to read and **var**??
Unacceptable.

Okay, so this is a function that helps you find special letters or symbols in a word or sentence. It has three parts, `a`, `b`, and `str`. `a` and `b` are the special letters or symbols that you want to find, and `str` is the word or sentence that you want to look in.

The function first looks for the first special letter `a` in `str`, and then looks for the first special letter `b` after `a`. Then, it starts a loop that keeps going until it finds the special letters that go together or until it can't find any more special letters.

If it finds the special letters that go together, it returns an array with their positions. If it doesn't find any, it returns `undefined`.

## After
And now, let's have a look at the refactored code...

<img width="100%" style="width:100%" src="https://media3.giphy.com/media/3o7TKNTYGvBRDvq67S/giphy.gif?cid=ecf05e47r9ikeze3tjcjzb8u8k87c34vq6kburmg4qaq0vqy&rid=giphy.gif&ct=g">

```
function getRange(startChar, endChar, string) {
  let startIndices = [];
  let startIndex = string.indexOf(startChar);
  let endIndex = string.indexOf(endChar, startIndex + 1);
  let currentIndex = startIndex;
  let result;

  if (startIndex >= 0 && endIndex > 0) {
    let leftmostStartIndex = string.length;
    while (currentIndex >= 0 && !result) {
      if (currentIndex == startIndex) {
        startIndices.push(currentIndex);
        startIndex = string.indexOf(startChar, currentIndex + 1);
      } else if (startIndices.length == 1) {
        result = [startIndices.pop(), endIndex];
      } else {
        let start = startIndices.pop();
        if (start < leftmostStartIndex) {
          leftmostStartIndex = start;
        }
        endIndex = string.indexOf(endChar, currentIndex + 1);
      }
      currentIndex = startIndex < endIndex && startIndex >= 0 ? startIndex : endIndex;
    }
    if (startIndices.length) {
      result = [leftmostStartIndex, endIndex];
    }
  }
  return result;
}
```
In my humble opinion, this is much better.

1. No more var's 
2. Variables like `a` and `b` are renamed to more "easy-to-read" names

## Final thoughts / conclusion
In conclusion, refactoring code can be a challenging but rewarding task. It allows you to improve the readability and maintainability of the code, as well as fix any potential issues that may have been overlooked in the past. In this blog post, I walked through my process of refactoring a function in the Hyper terminal codebase, using tools like SonarQube to identify areas that needed improvement and implementing changes to make the code easier to understand and work with. Whether you are a beginner or an experienced developer, there is always room to improve and learn, and refactoring existing code is a great way to do so.


Thank you very much for reading my post!
Until next time :)
<img width="100%" style="width:100%" src="https://media3.giphy.com/media/m9eG1qVjvN56H0MXt8/giphy.gif?cid=ecf05e47dc66wcec1b3f9kx17c9nzpwr14dbd00mvh8bxa5z&rid=giphy.gif&ct=g">