KISSing It: On Revisiting Old Code

EJ Mitchell

My journey as a programmer began in college when, in my numerical methods course, I was introduced to Matlab and Python. Unfortunately, that class was in my senior year. So after working for a year after that, I had the pleasure of joining Launch Academy in 2017, where I was treated to a deep dive in web development in a bootcamp-style learning environment.

(It was also where I first learned about thoughtbot.)

Fastforward to now, it’s been three years since I’ve graduated, and a little over a year since I’ve started at thoughtbot. Though it’s been a relatively short while, I feel like I’ve learned enough from my colleagues to fill lifetimes.

However, I realized there’s one person I hadn’t learned from yet: myself.

Looking back at old code, like looking back at old writing, can be cringeworthy. But, it can be extremely valuable, even if you get a cold chill going down your spine when revisiting it.

My first solo project at Launch was a tour-de-force of everything I learned while there. It tried to use every tool I had come across, every framework, every bell and whistle I could think of to make myself look valuable to potential employers. As a result, it was a bloated and showy React-on-Rails app.

Don’t even ask how long it took to load on Heroku.

From the description, you can see how this was prime for refactoring. What I was in for was quite different than I expected.


New Rails, New You

For one thing, I was on Rails 5 for the original app. That meant, if I wanted to do anything with React, I had to configure Webpacker. I wanted to cry when, after running rails new for the refactored app, I saw Webpacker was already configured for me. I remembered the hours my fellow Launchers and I had gone through, each of us whooping in victory when we finally managed to get Webpacker to work. Or groan when something failed.

(Mostly, it was groaning.)

Too bad that, in my bid for simplification, I didn’t need Webpacker. Everything I was going to do for the refactored version of this app was going to be in Rails 6. The reason for this was my recent exploration of sustainable web design and development.

You can have beautiful, functional websites while keeping things simple. Of course, having a website like this doesn’t necessarily absolve you from polluting the Earth, as fellow co-worker Eric Bailey discusses, but it definitely contributes to harm reduction.

That reason aside, there are a lot of really neat changes going from Rails 5 to Rails 6, if you haven’t already discovered them. Though it wasn’t necessary in the refactored app I’m working on, I definitely benefited from it in client work. Namely, using the new create_or_find_by method, which addresses a race condition I’d been faced with before. As someone who works primarily in the backend for clients, I also took advantage of insert_all and upsert_all.

In addition to the shiny features of Rails 6, I also applied some of my own new knowledge to make my life easier when working with model relationships across the application. One of these things was writing class methods for scopes instead of using the scope syntax.

In fact, class methods and scopes were something new to me altogether. Once I started digging into more complex codebases after Launch, I started seeing syntax for both rather frequently. Here is an example from my refactor:

class BusinessEvent < ApplicationRecord
  belongs_to :business
  belongs_to :event

  validates :business, presence: true
  validates :event, presence: true

  def self.for_business(business)
    where(business: business)

  def self.for_event(event)
    where(event: event)

  def self.user_events(user)
    where(business: user.businesses)

In the refactored version of my app, a user can own many businesses, and these businesses can indicate their attendance at events. However, there are places where I would like to list businesses that are attending an event (e.g., the event#show page). There are also places where I would like to list events that a business is attending (business#show page). In addition, a user (whose profile is visible only to them) might want a list of all of the events their businesses are going to.

Writing a class method for each of these on the BusinessEvent model allows this to be so. Now, learning about scope, I found that the preference was for writing them in the above class method notation vs. using scope itself. There seem to be a few reasons for this, one of them being intent and readability, the other being simply historical as Rails evolved over time.

Even though I had learned about scopes and class methods long before refactoring my app, I was able to see the utility for them in real time, which was a moment of pride for me. I learned something!

Keep It Simple, Stupid (KISS It)

Keeping it simple came about in two different ways. The first is that I was giving myself a shortened timeline to come up with an MVP. The first time around, I was panicking and throwing around as many ideas as possible in two weeks. Instead, I learned from past-me’s mistakes and came up with a roadmap for 5 work days.

To implement the roadmap, I used GitHub issues with labels to keep track of what I wanted to do. If something changed, I put a comment in the issue. Instead of merging everything to main right away, I opened up PRs and linked them to the issues.

Being at thoughtbot for over a year now, I had seen colleagues work on quite a few MVP and rapid validation projects that had benefited greatly from a streamlined sense of organization like this.

Also, in seeing these projects going through our pipeline, I learned the value of only having a few core features in the first release as opposed to as many as possible from the original idea.

This is a powerful switch in thought process:

During the first iteration of this app, I was looking for my first job in the field. I felt like I needed to prove myself - throw everything at the wall and hope it stuck.

This time, I was not doing this for someone else to accept me. I was doing it to apply my new experiences and understand how far I had come in the last three years.

In the first iteration, the user could sign up, attend/create events, have products, and create orders.

In this new iteration, a user could sign up, create businesses, create events, and attend events.

That’s it. The products and orders from the first iteration would come later.

Now, the only new thing in this MVP compared to the original was adding the concept of businesses. Observing local shop owners over the course of the pandemic created this new piece of business intel. Many restaurants in the area were owned by the same family, often under one name.

Evolution of the MVP aside, another simplification came in the form of the design. What I discovered was that 90s nostalgia can not only be friendly in terms of sustainability, but it can also be quick to set up and quite pretty in its own way.

I will admit that my pitfall here was spending a little too much time on styling. In the end, I was not pleased with the naming conventions I chose in my stylesheet.

(Time management was clearly another lesson here.)

In future iterations, I’d like to spend time organizing my design, because I’ve quickly learned that organized stylesheets make life easier. Observing the work of thoughtbot designers and how they organized stylesheets on our apps only made this clearer to me.

There’s Always More to Learn

While there were many takeaways from refactoring my application, I know there’s more that I could be learning. During my investment time, I came up with a plan for future enhancements - not necessarily features here, but knowledge enhancements.

One enhancement is to take the newly refactored app and take the test coverage from “zero to hero”. 🦸🏻 Here, my plan is to set up CI and configure the test suite on my own. (In past projects, I’ve come in after the MVP had been built or configuration had already been established.)

When you’re working with your own code, you can shuffle the order of things as you see fit - which is a huge benefit if you want to focus on growing one or two skills at a time.

Another possible knowledge enhancement is adding Sorbet to the codebase. Since the codebase is so small, this would be great to do earlier on before I go beyond the MVP features. I haven’t used Sorbet yet, but have grown to know and love the power of typed languages thanks to my first project at thoughtbot using Scala and Elm.

This enhancement is less about strengthening current skills and about cultivating a new one with a tool that interests me.

This is another benefit to revisiting your old code - you can see what’s changed in the last several years and try things that have come out since you’ve last worked on it.

Parting Thoughts

As much as you might want to avoid it, returning to old code has a ton of benefits. It might not be something you use to make the next Fortune 500 company, but it can be personally affirming and deeply satisfying.

In a world where we’re constantly trying to keep up with one another, and beating ourselves up if we perceive we’re not “making the cut”, taking the time to remind yourself about how far you’ve come is immensely important.