article cover

Code Quality

A refactoring happy story

~ 12 minute read

Mihaela Derevlean
Software Engineer

02 Jul 2024

A refactoring happy story

Hi, I’m Miha and it’s been 5 minutes since I last refactored some code.

We're all too familiar with the dilemma: drowning in tech debt and code chaos while juggling a dozen other priorities. But here's the twist: in my case, tackling the refactoring wasn't just about cleaning up code—it was about waving goodbye to a hefty invoice and saving some serious money. Yey!

This was no ordinary refactoring, we had to revamp the authorization system in the process (the money-saving hero of the story). So, we started writing up a proposal, documenting and mapping out every step of the journey before diving in.

First things first: documentation. Just kidding, that's not what this article is about. Surprisingly (or not), the documentation turned out to be our secret weapon for speed. We implemented a POC while documenting, smoothing our path through the spaghetti code later on.

‘Ok Miha, but what did you refactor?’ Well, it’s not just about adding the new functionality and calling it a day. I saw an opportunity and I grabbed it. Leaving messy, unorganized code untouched would’ve been a recipe for disaster. Trust me, spending a little extra time tidying up saved us from a world of bugs during implementation.

Oh, by the way, this is a front-end—React app. Now let’s get our hands dirty!

How do I tackle refactoring across the entire project? I go from top to bottom and not the other way around.

1. Tests (from 0 to 80%)

First I looked at the tests. What tests do we have, what kind, and what about coverage?

What I found:

- snapshot testing on a few components.

- coverage: 17%

- tests written: 20

- failing tests: 19

What should I do? Easy! Remove everything and start anew. While snapshot testing can be useful, I believe more in unit tests and testing actual functionality.

What I left:

- unit tests on all components & hooks

- 80% code coverage

- Tests passing - mandatory for merging your PR in main

2. Architecture

I started looking at how the files are arranged and organized. Needless to say, we find ourselves in the Broken windows theory (https://www.britannica.com/topic/broken-windows-theory). How do I like to approach this? I don’t care about code logic at this point, we just create new files, new folders where page components sit, a folder for hooks, and a service folder for all the endpoints. We split the code.

What I found:

- React Components everywhere

- 3 or more components inside the same file

- The entire communication with the backend in the same file → hard to find and read.

What I left:

- Folders that tell you what they have inside

- Consistency across components, hooks, helper functions, etc.

- Easy to find code & logic

3. NPM packages

Always check if all the packages are used. It’s easy to end up with functionality that changed but the packages remained there.

What I found:

- 3 packages were not used anymore

- 2 packages are used in pages that are not actually used in production

- 4 ui & theming libraries

What I left:

- Only packages that are used

- 2 ui & theming libraries (but for this code had to be changed & adapted). Why 2? The client's custom UI library doesn’t accommodate complex tables, so we needed something in that area.

4. UI libraries

I don’t know how it got to this, but things were not great. I would put this into “We don’t have that much time, that library has it, let’s use it”. But when you are using your own design system, and then you add MUI 4 and MUI 5 it kind of bloats the app.

What I found:

- Semantic UI

- MUI 4

- MUI 5

- Our own design system based on Chakra UI

What I left:

- Our own design system

- MUI 5 (we are in need of a complex table which our own DS didn’t have)

5. Unused code

I manually tested the app, covering all use cases (luckily it is a small app). I found unused components living in our app rent-free. Simple solution: OFF WITH THEIR HEAD. Even if you later realize that the code is needed, you always have the git history.

What I found:

- Components that were not used

- Functions that were not used

- CSS that was not needed

What I left:

- Nothing that was not needed

6. Logic & code standard

Ok, now it’s time to dive deeper into the refactoring process. While ECMAScript has evolved over the years, our code hasn’t kept pace. Our unfair advantage was having SonarCloud at our disposal, screaming at us all the problems in need of fixing. But fear not, even if you don’t have such a tool, try to pay attention to the logic, try to look at the code and act like a debugger, see if you can reach each return if there are irrelevant conditions, etc.

What I found:

- Logic that was never reached

- Conditions that were checking if the objects have properties in a very hard-to-read way

- Components with different styles, imports all over the place, function components, class components, you get the idea

What I left:

- Removed the code that was not used

- Brought JS code up to the latest ECMAScript standards

- Transformed all components into function components, and now they all look the same

7. Code duplication

The part I was most proud of. Code duplication. Looooots of it. Even if Axios was used to facilitate communication with the backend, the project didn’t use interceptors ending up in adding headers on each function. The same logic is used in multiple functions or components.

What I found:

- Don’t have the exact number but had like 18 functions with at least 3 lines of code that were repeating itself

What I left:

- Clean code, easy to change if needed in the future, modularized

This was my experience, and I don’t think it’s perfect (I don’t believe in perfection… if after one month you are still happy with your code, it means you didn’t grow), but for sure I left the project in a better state than it was before.

Happy refactoring :)

Written by

Mihaela Derevlean

Software Engineer

Share this article on

We create value through AI and digital software engineering in a culture of empowerment that enables new perspective and innovation.

OFFICE

24 George Barițiu street, 400027, Cluj-Napoca, Cluj, Romania

39 Sfântul Andrei street, Palas Campus, B1 block, 5th floor, 700032, Iasi, Iasi, Romania