Improving performance with Presenter and Eager Load of a big Rails app

Wellington Santos
3 min readMar 18, 2020

--

When I landed on this new job position at EBANX one of my very first tasks was to get the top 10 issues of a Ruby on Rails app used all over the World, with around 4 million requests every month, using data provided by a monitoring tool which I had never worked with (Datadog).

Throughout the analysis I have found that 7 out of 10 issues pointed out by DataDog were related to views. Looking for what was going on in those views I found:

  • Several N + 1 queries;
  • Too much logic in the views;
  • Unnecessary DB hits;

Here I will describe how I and my teammates solved these problems, improved the codebase quality, decreased DB hits to almost 90% and decreased around 200% p99 latency when the server was under several requests.

Presenter Design Pattern

We have chosen to use an adaptation of the Presenter Design Pattern. In a few words it simply creates a layer responsible to hold all logic regarding views and remove controller’s unrelated logic (lean controllers please).

Lets see how it works

We are going to create a simple project with Posts and Comments

First the models:

models

Some dummy data:

seeds.rb

The controller:

posts_controller.rb

And finally the view:

index.html.erb

So what is the problem with our index view?

Lets see what the index view is doing:

  • It hits the DB counting the number of Post registers;
  • It loads all Posts;
  • It counts Comments for each Post;
  • It loads Comments for each Post;

That is a total of 22 hits!

And of course we can remove logic from it :)

Let’s do this with the Presenter Pattern. We are going to change only the controller, the view and create the post_presenter.rb file.

post_presenter.rb
index.html.erb updated
posts_controller.rb updated

With the Presenter Pattern we have decreased from 22 hits to only 2 hits on the DB, removed logic from the view layer, we could as well remove from controller, and our code became more clean and readable :)

We use .load method to eager load into memory the query result.

Instead of using .count method we use .size which does not query the DB again if we already have it in memory.

And we use .includes method to avoid the N + 1 query for Comments.

Benefits

Despite the Presenter Pattern simplicity, the benefits are remarkable:

  • We don’t need to write a lot of views tests hence decreasing the test suite run time. View tests are painful.
  • Our views are more concerned with Frontend code, thus lean.
  • We pass only one instance variable from the controller and use only that variable.
  • We could change to a Frontend framework with ease.
  • We decrease tests regarding controllers and keep controllers lean.
  • We know that all logic is in the Presenter.

Moreover in the Presenter class we can easily spot unnecessary DB hits and N + 1 queries.

After the improvements we have made, these are the charts we got from DataDog:

Overall P99 Latency

DB Hits

Conclusion

The Presenter Pattern is a good option for an application which has a rich information view. It is very easy to test and modify and decrease complexity of controllers and views.

--

--