Approaching Rails Legacy Systems – Chapter 1: Project Anatomy

Reading Time: 6 minutes

This is the chapter 1 of a series of blog posts about some pieces of advice, tools, and tips you can consider when you arrive to a Rails project considered as Legacy.

Imagine that you landed in a "new" project (new for you, but it’s actually an 8-year-old project). Suddenly you find yourself into a lot of spaghetti code and a monolithic application (which is not bad at all). You can also tell that a small battalion of software engineers has marched through the project.

Has something like this happened to you before? Does it sound familiar?

No worries. In this Approaching Rails Legacy Systems series I'm going to give you hints for when you arrive in a Rails project that can be considered as Legacy.

In this chapter, we take a look at the Project Anatomy. So, it's important for you to understand your project structure, type of files, and more.


What's a Legacy System?

Wikipedia definition:

In computing, a legacy system is an old method, technology, computer system, or application program, "of, relating to, or being a previous or outdated computer system," yet still in use. Often referencing a system as "legacy" means that it paved the way for the standards that would follow it. This can also imply that the system is out of date or in need of replacement.

Project Anatomy

Check your domain knowledge

Use ls to look for clues on what the domain knowledge looks like:

$ ls
Brewfile                Rakefile                engines
Capfile                 app                     lib
Dockerfile              bin                     log   circle.yml              package.json
Gemfile                 client                  public
Gemfile.lock            config                  script
Guardfile                    spec
Procfile                db                      tmp
Procfile_no_npm         doc                     vendor               dump.rdb                webpack.config.babel.js

As you can see above, we found a Gemfile. Did you see it? Awesome! Looks like this is a Rails Application, right? Well, then you can see that there is a spec folder.

Woohoo! There might even be something to test the project. At this point, we are getting some good signs about this "new" app. So. it's time to take a look inside our app folder and see which other patterns we need to take into consideration or worry about in the future.

$ ls app/
assets       mailers      pdfs         serializers  views
controllers  models       presenters   services     workers
helpers      overrides    repositories uploaders

Oh, I see!, presenters, services, serializers, uploaders, repositories, overrides, so interesting. More things to consider 🤔🤓. I expect you to be taking notes already.

presenter - acts upon the model and the view. It retrieves data from repositories (the model) and formats it for display in the view.

services - service objects that talks to external entities.

Martin Fowler describes a repository as follows:

repositories - A repository performs the tasks of an intermediary between the domain model layers and data mapping, acting in a similar way to a set of domain objects in memory. Client objects declaratively build queries and send them to the repositories for answers. Conceptually, a repository encapsulates a set of objects stored in the database and operations that can be performed on them, providing a way that is closer to the persistence layer. Repositories, also, support the purpose of separating, clearly and in one direction, the dependency between the work domain and the data allocation or mapping.

uploaders - 😱 Something we’ll need to take care in the future.

overrides - 😨 Another pattern that we’ll have to consider later in the future.

It feels like we understand our project better now 🤓, right?

How much of what?

Use ag to have a quick search and wc (short for word count) to check how much Ruby code do we have.

So far it looks like Rails and Ruby are the core of this app, but how much Ruby? Let's see:

$ ag -l 'class|module' --ruby | wc
    1873    1873   96753

How much Ruby in our lib and app?:

$ ag -l 'class|module' --ruby  app lib |wc
    1104    1104   48996

Wait a minute, why is this important? Details matter, right? But also the big picture is important, so I think is adequate to have in mind this kind of information to have a general idea of the size of your project.

What else?

Now, let's see. How many file types are there?

$ find . -type f \
>     | sed -e 's/.*\.//' \
>     | sed -e 's/.*\///' \
>     | sort | uniq -c | sort -rn| wc
    1768    3536   74117

Amazing, so many files to deal with! 🏃 Let's use find, sort, sed, uniq, head to get the top counts per file type:

$ find . -type f \
>     | sed -e 's/.*\.//' \
>     | sed -e 's/.*\///' \
>     | sort | uniq -c | sort -rn
4687 cache
1544 rb
 593 erb
 477 png
 440 jpg
 199 js
 180 scss
 145 html
 124 deface
  72 yml
  59 svg
  53 rake
  46 coffee
  36 gif
  13 pack
  13 idx
  11 ttf
  11 rabl
  11 csv
  11 css
  10 sample
  10 prawn
  10 ejs
   9 woff
   9 markdown

There are 1544 rb files. 💫💥 And if we look closely, there are 477 png files... Maybe, just maybe, we could consider using an S3 bucket and CDN to solve this. 🍻 Remember, performance is king!!!

Project structure

Let's use tree to look deeper:

$ tree lib/
├── 3d_coupon_updater.rb
├── 3d_importer.rb
├── assets
├── data_warehouse
│   └── order_field_converter.rb
├── devise
│   └── custom_failure.rb
├── errors_app.rb
├── google_tag_manager_data_layer.rb
├── kmts.rb

14 directories, 109 files

The Rails guide says:

app/ - Contains the controllers, models, views, helpers, mailers, channels, jobs and assets for your application. You'll focus on this folder for the remainder of this guide.
lib/ - Extended modules for your application.

Understand your boundaries

One way to help you understand the architecture is to understand the boundaries. Let's start with your Gemfile

$ cat Gemfile

source ''

gem 'rails', '~> 4.0.13'

group :assets do
  gem 'sass-rails'
  gem 'coffee-rails', '~> 4.0.1' # TODO: remove all .coffee + this gem
  gem 'uglifier', '~> 2.5.0'

# Assets
gem 'active_model_serializers', '~> 0.9.0.alpha1' # 0.10 introduces breaking changes
gem 'autoprefixer-rails', '~> 6.0.3'
gem 'bootstrap-sass'
gem 'bourbon', '~> 3.2.1'
gem 'fancybox2-rails', '~> 0.2.8'
gem 'mustache', '~> 0.99.5'
gem 'sass-mediaqueries-rails'
gem 'ui-rails'

gem 'paper_trail', '~> 4.0.0'

gem 'css_splitter', github: 'madebymade/css_splitter', branch: 'use-railtie'

gem 'route_downcaser'
gem 'stringjs-rails', '~> 2.1.0' # small util, mostly for unescapeHTML in cards
gem 'jbuilder' # what is this can we remove?

gem 'ahoy_matey'
gem 'kmts', '~> 2.0.0'
gem 'activeuuid', '~> 0.5.0'
gem 'ga_cookie_parser'
gem 'google-tag-manager-rails'
gem 'savon', '~> 2.11.1'
gem 'netsuite', '~> 0.4.0'
gem 'sift', '~> 1.1.7'

I recommend checking every dependency you don't know much about, look at the documentation of those you don't understand what the hell are doing, and at this point you should have the big picture of your boundaries. Remember your notes.

  • Draw how the boundaries look like. Yes, take your notebook and draw:

diagram legacy

  • You don't need to follow a specific methodology, just draw.

Let's try Rubrowser

Rubrowser is a visualizer for ruby code (rails or otherwise), it analyze your code and extract the modules definitions and used classes/modules and render all these information as a directed force graph using D3. The idea is that the project opens every .rb file and parse it with parser gem then list all modules and classes definitions, and all constants that are listed inside this module/class and link them together.

rubrowser legacy

There are a lot of tools that I enjoy using it. For example, let’s try rails-erd

This creates a quick entity-relationship diagram of your models, but you can also use the database manager of your choice.

erd legacy

So far we have looked at the anatomy of this project, but we still need to go far and beyond!

I hope you find this blogpost useful somehow. In the following chapter, we are going to use GIT as a tool to approach legacy systems and a couple of tools around this distributed version-control system that you might not be aware of.

Thanks for reading!

Oh, before saying goodbye, please share this on Twitter so your peers will know about this Approaching Rails Legacy Systems series:

Take a peek at some pieces of advice, tools, and tips you can consider when you arrive to a Rails project considered as Legacy. Click To Tweet

@VíctorVelázquez, Director Of Engineering at MagmaLabs

You May Also Like