Haseeb Annadamban

Navigating the Maze: How to Start Working on a Legacy Rails Codebase

ยท 1661 words ยท 8 minutes to read

Working on a legacy Rails codebase can be challenging. But you can start navigating and working on it effectively with a good strategy. This blog post discusses common steps when working in a legacy codebase. This article does not talk about optimizing the codebase; it is only about understanding and navigating it. Because it does not make any assumptions.

Understanding The Project ๐Ÿ”—

Each and every project will be unique. There will be project specific decisions taken and it will be reflected all over the codebase. This section is about understanding the project from a technical perspective.

Checking The Documentation ๐Ÿ”—

Begin by searching for any existing documentation. This could include

  • README files
  • Wiki pages
  • API documentation
  • Deployment guides

The bad news is, Sometimes I find these very outdated in legacy projects. I have also seen very freshly updated documentation though. But still, It can provide really valuable and important information.

What to do if the information is outdated and I am stuck due to that?

There is one important source of documentation you should use if available, The other employees who are already working on this codebase. Or maybe the founders/CTO, etc. Make sure to ask when you are stuck.

Analyzing The Codebase ๐Ÿ”—

Gemfile ๐Ÿ”—

The Gemfile is a treasure trove of information about the project’s dependencies. It includes information like The Rails version, key gems and their versions, custom gems, and forks. This analysis will give you an idea of the project’s effective age and the technologies it relies on. Google or search in RubyGems for the name of the gems you have no idea what it is. It will be very helpful later.

If your project does not have Gemfile, Congratulations. You are now privileged to work on a really old project before Rails 3 (Not Ruby 3). In this case, check the config/environment.rbfile. It will have information like RAILS_GEM_VERSION which is the Rails version and look for config.gem calls, which were used to specify gem dependencies in Rails 2.x.

.ruby-version File ๐Ÿ”—

It will include exactly what you expect in it. The version of Ruby used. If this file is missing there are other options.

  1. Open the Gemfile and look for a ruby directive. It might look like this:
ruby '2.3.1'
  1. The Gemfile.lock file often contains the Ruby version used when the dependencies were last updated. Look for a line like this at the end:
RUBY VERSION
 ruby 2.3.1p112
  1. Check the git log for hints:
git log -p -- .ruby-version
git log --grep="ruby"

Check DB Schema ๐Ÿ”—

You can start with config/database.yml. Other than the DB adapter, There can be information about read replicas, other environment-specific configurations, Where DB is located in production, pool size, encoding, timeout, etc.

Review the schema.rb or structure.sql file to understand the data model. If it is a structure.sql most probably there can be stuff that can not handled with regular rails migration. You can check what it is. By the way, You can stop and come back to this step after running the app for the first time. Check if it has a large number of tables, the structure of tables, and the relationship between major models, Index, and constraints.

Skim through the db/seeds.rb to find important data. Sometimes it misses critical data. In this scenario of understanding a legacy application, it is fine.

Check The Routes ๐Ÿ”—

Routes provide a high-level overview of the application’s structure. Seriously at this stage, it can be all confusing. But coming back to it after running the application and/or demo will help to understand a lot.

At the moment mainly check if the routes are well structured and does they use resourceful routing complex and messy routing or simple and look for keywords like mount and nonstandard stuff like devise_for to understand those components hooking the routes. Looking here you can identify if this app has an API using Rails or something like Grape.

Application Structure ๐Ÿ”—

You can the app/ directory to see some important information like if it uses services, finders, etc, and some nonstandard stuff can be there. Sometimes some projects even have a module structure where there can be directories for each model.

Check the lib/ directory to find some library code. Some teams use it to store domain objects. Also, you can check lib/tasks it can sometimes give some surprising information like doing standard stuff in a nonstandard way or code that is used for old rails versions and there is a better alternative now.

The config/initializers will have important information about some external services used.

Run The App ๐Ÿ”—

You have to run the app. If you are lucky there will be some information in README on how to get started.

Getting hands-on experience with the application functionality is crucial. It gives important context on what you want to achieve.Let’s try to make the app run in your local environment.

Running Old Versions of Ruby ๐Ÿ”—

I recommend using rbenv for managing multiple versions of Ruby. Many people use asdf too due to its ability to manage multiple languages at once. Both are fine in my opinion.

If you are on an M1 Mac. You might have to follow some extra steps to get the ruby working.

Steps for M1+ Macs in case you can’t get Ruby installed ๐Ÿ”—

We will try to install the old Ruby version you need. And if that doesn’t work we will try to use Rosetta. First, let’s do it in a simple way. Replace X.X.X with your required version:

RUBY_CFLAGS="-Wno-error=implicit-function-declaration" rbenv install X.X.X

If that doesn’t work try this.

First, install Install Rosetta:

software update --install-rosetta

Then use Rosetta to install Ruby.

RUBY_CFLAGS="-Wno-error=implicit-function-declaration" RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl)" arch -x86_64 rbenv install X.X.X

This command does a few important things:

  • RUBY_CFLAGS="-Wno-error=implicit-function-declaration": Ignores certain warnings that might prevent compilation.
  • RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl)": Points to the Homebrew-installed OpenSSL.
  • arch -x86_64: Forces the installation to use x86_64 architecture via Rosetta 2.

What if Ruby and Rails are too old and it’s not working? ๐Ÿ”—

A usual rescue when it comes to running old software that is not working in our latest generation machine is virtualization and containerization. I recommend going with Ubuntu for running legacy Rails. The easiest option in this case is to use Docker to run the app using the ubuntu base image. Another option is to use MultiPass, It is the official Ubuntu VM. If you prefer using Vmware etc, you can go for that too.

Getting Access ๐Ÿ”—

You will definitely need access to credentials, messaging systems, Git repos, and documentation. Many teams won’t have this info readily available. The main thing you have to do is ask around when you need information. Don’t sound harsh. Be professional. Not everyone knows everything. Each person might have a specific area of expertise. And sometimes you might have to delegate communication. For example, if one specific secret key is missing and you find out the person who worked on it who has left the company has it. Make sure to delegate this to the right person.

About Tests ๐Ÿ”—

This is a legacy app or an app with the legacy part you are supposed to work on. Usually, the legacy part won’t have many tests which are up to date. You can check which test suite framework do they use, minitest or Rspec, etc? Based on the task why you are here. You will have to update the tests accordingly IF NEEDED. Here is why that part is in caps. Some teams don’t want you to write tests. For example, you are a consultant here to meet the compliance deadline as quickly as possible or to make sure the features to show in an important investor demo are simply working as expected. This does not look perfect or satisfying. But it is how it is. On the other hand If you can write tests make sure to write it well.

Understanding The App ๐Ÿ”—

First, try to navigate the app. It is very common in applications with legacy codebase to be domain-specific and not easy to navigate. Try to get a demo from another person who is experienced in the app.

Understanding The Existing Team ๐Ÿ”—

You may wonder why this sub-section is here or why this is a sub-section of understanding the app. We got hired as a developer to work on the app. This information will be helpful.

  • Who are the people you have to contact for different issues?
  • What is the business model, How new customers are on-boarded, and How many customers do they have (estimate)?
  • What is the current culture: How do they work, How do they communicate, How to collaborate, Is Timezones involved, How much async or sync are they?

Getting Demo ๐Ÿ”—

If possible, pair program with someone familiar with the app. Walk through key features together, asking questions about design choices and business logic.

Discuss The Issues You Are Facing With The Team ๐Ÿ”—

This is not a bad thing. When running the app you might find many silly stuff and mistakes. Start conversations about these. Sometimes this will bring in important tribal knowledge you need to know. The legacy code might be built on old concepts. There can be misunderstandings in your understanding of the app. The issue you might be facing is due to that “age difference” or “domain difference”. If you bring up this other developers can help you in clearing your understanding and aligning you with the app. Or may be you will be able to fix the issue.

Be Prepared Before Meetings ๐Ÿ”—

Before going to meetings, be prepared with questions to ask, Important issues you want to discuss, what you want to convey, and What not to discuss.

Conclusion ๐Ÿ”—

Legacy projects have varying levels of difficulty based on various factors. But it is not impossible to navigate. Here I intentionally skipped Javascript and possible optimizations. It is to make it make it Rails specific and on topic. I hope it is fine with you. I hope you are able to navigate legacy Rails projects using the ideas I seeded here.

Your Feedback Matters!

I'd love to hear your thoughts on this. Connect with me on LinkedIn Or Twitter