Slide 1

Slide 1 text

Rails from “good” to fast How to get the view rendering from ~600ms to ~60ms

Slide 2

Slide 2 text

What’s the slowest part in Rails? • Request Handling (ActionDispatch) • NO! • Database Queries (ActiveRecord) • NO, just a bit! • Rendering (ActionView, HAML, JBuilder) • YES!

Slide 3

Slide 3 text

Let’s build a Blog github.com/timoschilling/YetAnotherBlog Why ~5ms?

Slide 4

Slide 4 text

Asset Overhead Prod Dev 1 Asset Dev 100 Assets

Slide 5

Slide 5 text

Fix Asset Overhead How? Dev 1 Asset Dev 100 Assets

Slide 6

Slide 6 text

Even Faster?

Slide 7

Slide 7 text

The Code

Slide 8

Slide 8 text

Render a Index with 100 Items

Slide 9

Slide 9 text

Side Note:
 Every Query is a lie! 0.3ms + 0.4ms + 4.4ms +0.6ms = 5.7ms 5.7ms != 6.1ms

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Why 5.7ms != 6.1ms? ActiveRecord show only the query time! Not the real amount of each operation!

Slide 12

Slide 12 text

How to get a real value? Before: (0.3ms) SELECT COUNT(*)…
 Post Load (0.4ms) …
 User Load (0.4ms) …
 Comment Load (4.4ms) …
 User Load (0.6ms) … 
 
 Completed in 568ms
 (Views: 561.9ms |
 ActiveRecord: 6.1ms) After: (0.3ms) SELECT COUNT(*)…
 Post Load (0.4ms) …
 User Load (0.4ms) …
 Comment Load (4.4ms) …
 User Load (0.6ms) …
 
 DB Queries: 78.85ms
 
 Completed in 568ms
 (Views: 489,1ms |
 ActiveRecord: 6.1ms)

Slide 13

Slide 13 text

Hint! If you use Trailblazer:
 You will get this kind of measurement for free, in the future.

Slide 14

Slide 14 text

How to make it faster? Cache!?

Slide 15

Slide 15 text

Russian Doll Caching from 570ms to 677ms ???

Slide 16

Slide 16 text

Russian Doll Caching It helps only if you have slow views! This view has the same render time as a view without `sleep` with Russian Doll Caching

Slide 17

Slide 17 text

good old Rails.cache.fetch It’s fast!
 But now I need to manage the cache!
 :( 85ms

Slide 18

Slide 18 text

tl;dr Rails caching sucks!

Slide 19

Slide 19 text

Again: How to make it faster? Don’t use ActionView! But how? Use Cells!

Slide 20

Slide 20 text

Cells? A gem for ViewModel’s,
 written by this awesome guy:

Slide 21

Slide 21 text

Demo

Slide 22

Slide 22 text

Status:
 ~650ms -> ~150ms

Slide 23

Slide 23 text

Where is the Time? • 150ms Request • DB: 70ms • ActiveRecord: 6.1ms • ActionView: 78.1ms • Cells: 71.4ms

Slide 24

Slide 24 text

Next Step: remove index (action)view (demo)

Slide 25

Slide 25 text

Where is the Time? • 145ms Request • DB: 70ms • ActiveRecord: 6.1ms • ActionView: 74.1ms • Cells: 71.4ms

Slide 26

Slide 26 text

Next Step: remove layout (action)view (demo)

Slide 27

Slide 27 text

Where is the Time? • 145ms Request • DB: 70ms • ActiveRecord: 6.1ms • Cells: 71.4ms

Slide 28

Slide 28 text

How does tempting works?

Slide 29

Slide 29 text

Why need that ~70ms? • 1 Layout • Index List • 100 Post • + 1 User • + 1 Comment • + 1 User • = 404 Renderings • 404 Renderings • each rendering needs 100 method call (theoretical assumption)

Slide 30

Slide 30 text

70ms vs. 4ms Where the time goes by? Tilt!

Slide 31

Slide 31 text

What does Tilt do? • one time • compile the template • build a method • cache this method • per rendering • bind the method to the context • call the method • unbind the method from context • one time • compile the template • build a method • cache this method • per rendering • bind the method to the context • call the method • unbind the method from context

Slide 32

Slide 32 text

Solution: Hand build tilt replacement

Slide 33

Slide 33 text

Where is the Time? • 91ms Request • DB: 70ms • ActiveRecord: 6.1ms • Cells: 17.4ms

Slide 34

Slide 34 text

ActiveSupport::Notifications • Nice • But slow • One event costs ~0.05ms

Slide 35

Slide 35 text

Path helpers • post_path(model) # => f***ing slow • post_path(id: model.id) # => slow • “/posts/#{id}” # => fast • brings up to 4ms (50%)

Slide 36

Slide 36 text

Cell::Mailer

Slide 37

Slide 37 text

Real World App

Slide 38

Slide 38 text

Jbuilder

Slide 39

Slide 39 text

Faster? How? A gem JSON/XML Object Mapper,
 written by this awesome guy: Representable

Slide 40

Slide 40 text

Representable

Slide 41

Slide 41 text

Jbuilder
 vs.
 Representable from ~230ms to ~80ms

Slide 42

Slide 42 text

Form’s SimpleForm

Slide 43

Slide 43 text

Faster? How? A form builder gem,
 written by this awesome guy: Formular

Slide 44

Slide 44 text

Formular SimpleForm 11ms vs. Formular 0.6ms

Slide 45

Slide 45 text

Disclamer I’m an apotonick fanboy!

Slide 46

Slide 46 text

The End

Slide 47

Slide 47 text

Tanks!

Slide 48

Slide 48 text

Questions?

Slide 49

Slide 49 text

Links • github.com/timoschilling/YetAnotherBlog • github.com/apotonick/cells • github.com/apotonick/representable