Optimization Techniques by Benchmark Winners
Tags: ruby, optimization, benchmark
Published: 2020-02-26 02:44:55

This post is based on [Jeremy Evans]‘s Optimization Techniques Used by the Benchmark Winners presentation. [Slides](https://code.jeremyevans.net/presentations/rubykaigi2019/) | [YouTube](https://www.youtube.com/watch?v=RuGZCcEL2F8) at Ruby Kaigi 2019. It‘s better to watch his fabulous presentation, but you can come back here for written references. These techniques coming from maintaining [Sequel] and [Roda]. These two gems have always been 0 issues. It‘s probably the best maintained gems. Sequel and Roda are the leaders for Ruby in [TechEmpower] benchmark results. Let‘s see what lessons can we learn to optimize Ruby.

These techniques may not be the best to write at application code level but good when building libraries, optimize critical path of your application. The ideas and principles are universally applicable.

## Avoid processing

[2:24](https://youtu.be/RuGZCcEL2F8?t=144)

> No code is faster than no code
> -- Merb Motto

Fastest code does the least. Execute less code. Run code once instead of many times, once is better than many. In big-o terms: `O(1) > O(n)`.

Take initialize model instance as example, the Sequel is definitely faster than Active Record because it does much less things.

Active Record:

```ruby
# https://github.com/rails/rails/blob/8ae8e19a33f4749e529b1649f4f0ace1dbb37285/activerecord/lib/active_record/core.rb#L357-L369
def init_with_attributes(attributes, new_record = false) # :nodoc:
  @new_record = new_record
  @attributes = attributes

  init_internals

  yield self if block_given?

  _run_find_callbacks
  _run_initialize_callbacks

  self
end
```

Sequel:

```ruby
# https://github.com/jeremyevans/sequel/blob/4a146796f273ce14e121954ad4e7f3134209386d/lib/sequel/model/base.rb#L221
def call(values)
  o = allocate
  o.instance_variable_set(:@values, values)
  o
end
```


## Delay Computations

For web app, it means to do at initialization time is better than doing at Runtime. See Hound applies this for putting [environment variables into constants](https://github.com/houndci/hound/blob/f308b0cb3ef328a533043e144042f5c29044add5/config/initializers/constants.rb).

**Example: Active Record & Sequel Callbacks**

Active Record runs find and initialize callbacks during initialization. Even when there are no callbacks defined on the model, so it slows down:

```ruby
# lib/active_record/core.rb
def init_with_attributes(attributes, new_record = false)
  ...

  _run_find_callbacks
  _run_initialize_callbacks

  ...
end
```

Sequel does this by having a [Plugin System](http://sequel.jeremyevans.net/plugins.html)[^1]. In Sequel, if you need callbacks, add `plugin :after_initialize` to your model. Nothing gets run if you‘re not using callbacks.

**Inheritance gives every subclass things that they may not need.** Prefer Composition over Inheritance. Plugins give all subclass a chance to only take what they need. Sequel and Roda use plugins for most features so they are faster.

## Reduce Object Allocations

[10:28](https://youtu.be/RuGZCcEL2F8?t=628)

The `init_internals` in Active Record set few instance variables to `nil`:

```ruby
def init_internals
  @primary_key              = self.class.primary_key
  @readonly                 = false
  @destroyed                = false
  @marked_for_destruction   = false
  @destroyed_by_association = nil
  @_start_transaction_state = nil
  @transaction_state        = nil

  self.class.define_attribute_methods
end
```

Jeremy found [avoid `@instance_variable = nil` resulted in 150% faster](https://youtu.be/RuGZCcEL2F8?t=267) in Sequel and Roda. This is controversial because only in verbose mode, using instance variable without define first will emit warnings. Emit warnings makes it slower. He made a patch to remove such warnings but got rejected for backward compatibility.

You can find another example of delay allocation of instance variables in [this commit from rails/rails](https://github.com/rails/rails/commit/b1458218c95d85c4ce911dd3e99da5ae7cf7aeee). Delay setting instance variable to hash by setting it to `nil` first.

Another common place to reduce object allocations is string. Before Ruby 2.3, we need to call `freeze` on strings. Since 2.3, we can add a frozen string literal in a file and by default all strings in that file are frozen.

### Reduce String Allocations

Before frozen string literal (Ruby < 2.3), introduce a constant for common places of strings `SELECT = 'SELECT'.freeze` was okay:

```ruby
SELECT = 'SELECT'.freeze
SPACE = ' '.freeze
FROM = 'FROM'.freeze

def select_sql
  sql = String.new
  sql ‌<< SELECT ‌<< SPACE
  sql ‌<< literal(columns)
  sql ‌<< SPACE <<‌ FROM <<‌ SPACE
  sql ‌<< literal(table)
end
```

Since Ruby 2.3:

```ruby
# frozen-string-literal: true

def select_sql
  sql = String.new
  sql << "SELECT "
  sql << literal(columns)
  sql << " FROM "
  sql << literal(table)
end
```

It‘s simpler and easier to understand. Avoids string allocations in the meantime with less operations (`<<`), hence faster.

### Reduce Hash allocations

Avoid default hash in method definition:

```ruby
class Sequel::Dataset
  def union(dataset, opts={})
    compound_clone(:union, dataset, opts)
  end
end
```

Introduce an empty frozen hash constant:

```ruby
class Sequel::Dataset
  OPTS = {}.freeze

  # 100% faster than `opts={}`.
  def union(dataset, opts=OPTS)
    compound_clone(:union, dataset, opts)
  end

  # Keyword argument is slower than Optimal hash constant.
  def union(dataset, **opts)
    compound_clone(:union, dataset, opts)
  end
end
```

Right now double splat keyword arguments are slower (2.7) than above empty frozen hash constant technique. Keyword arguments also have maintenance barriers the method caller and callee all need to change when keyword changes.

### Reduce Proc Allocation

[15:03](https://youtu.be/RuGZCcEL2F8?t=903)

For proc does not depend on something else or any runtime state:

```ruby
def indifferent_params
  Hash.new { |h, k| h[k.to_s] if k.is_a?(Symbol) }
end
```

can extract into a constant:

```ruby
IND = proc { |h, k| h[k.to_s] if k.is_a?(Symbol) }
def indifferent_params2
  Hash.new(&IND)
end
```

About 300%+ faster.

```ruby
Benchmark.ips do |x|
  x.report("inline proc") { indifferent_params }
  x.report("constant proc") { indifferent_params2 }
  x.compare!
end

Comparison:
       constant proc:  5645873.6 i/s
         inline proc:  1469374.7 i/s - 3.84x  slower
```

### Reduce Array Allocation

This is not from the presentation but I think it‘s great to also include an example here.

Use `transform_values` when modifying hashes. See [this commit](https://github.com/rails/rails/commit/df81f2e5f5df46c9c1db27530bbd301b6e23c4a7) from rails/rails:

```diff
    def escape(params)
-     Hash[params.map { |k, v| [k, Rack::Utils.escape(v)] }]
+     params.transform_values { |v| Rack::Utils.escape(v) }
    end
```

## Minimize Indirection

Say a common operation in our app is to convert a string into Integer. We could have a `lambda`, a kernel method, a dedicated object with `call` to do so, or an object that aliased `call` to `Integer()`:

```ruby
string = "42"

using_lambda = lambda { |str| Integer(str) }
using_kernel = Kernel.method(:Integer)
using_object = Object.new
def using_object.call(str); Integer(str); end
no_indirection_object = Object.new
class << no_indirection_object
  alias call Integer
  public :call
end

Benchmark.ips do |x|
  x.report("lambda") { using_lambda.call(string) }
  x.report("Kernel") { using_kernel.call(string) }
  x.report("Object") { using_object.call(string) }
  x.report("Object v2") { no_indirection_object.call(string) }
  x.compare!
end
```

```text
Comparison:
  Object v2:  6258404.2 i/s
  Object:     5674514.7 i/s - same-ish: difference falls within error
  lambda:     5199998.6 i/s - 1.20x  slower
  Kernel:     5130274.6 i/s - 1.22x  slower
```

We see using `Kernel.method` is slowest here. A lambda is slightly faster than that. Define a method on an object is faster than calling a lambda. Avoid indirection (by alias `call` to `Integer`) further makes it `~10%` faster. The benchmark example above aligns with Jeremy‘s observations on benchmarking Sequel from the presentation. A [similar observation][calling-func] is also found from graphql-ruby land that they‘re now in favor of [method call instead of using procs](https://rmosolgo.github.io/blog/2018/03/25/why-a-new-schema-definition-api/).

### Defining Methods

[19:02](https://youtu.be/RuGZCcEL2F8?t=1142)

```ruby
def foo
  1
end

# 50% slower than `def foo; 1; end`
define_method(:foo) do
  1
end
```

So we always want to define method with `def`. Sometimes we want to define at runtime. Take Sequel as example, it needs to dynamically define model columns‘s setters and getters, can achieve with `class_eval` + `def`.

```ruby
# def_column
columns.each do |column|
  class_eval("def #{column}; @values[:#{column}]; end")
  class_eval("def #{column}=(v); @values[:#{column}] = v; end")
end
```

This works for column name without spaces `"name"`, with space `"employee name"` it does not work. We need to use `define_method`:

```ruby
columns.each do |column|
  column = column.to_sym
  define_method(column) do
    @values[column]
  end

  define_method(:"#{column}=") do |v|
    @values[column] = v
  end
end
```

which is slower than using `class_eval + def`.

These columns with "bad" names are not the majority of the case but changing the implementation to this hurts performance. Here comes another general optimization principle.

## Separate Common from Uncommon

[21:18](https://youtu.be/RuGZCcEL2F8?t=1278)

We usually have a fast approach for the simple cases but it fails in more complex cases. Assume the simple cases are more common, we can speed up by separating the two cases. Sequel separates the common from the uncommon, to have the best of both worlds. Below are simplified from Sequel‘s [column definitions](https://github.com/jeremyevans/sequel/blob/cc5c1612fb4c42e7cbf6db6b0572001fd5bf6b58/lib/sequel/model/base.rb#L778-L788):

```ruby
def def_column_accessor(*columns)
  columns, bad_columns = columns.partition { |x| /\A[A-Za-z_][A-Za-z0-9_]*\z/.match(x.to_s) }

  bad_columns.each{|x| def_bad_column_accessor(x)} # define_method
  columns.each do |column|
    # faster with `def`
  end
end
```

In general `def` > `define_method`, but there is one case where `define_method` is preferred for performance. Let‘s see an example:

```ruby
class Def
  def self.def_numbers(first, last)
    class_eval("def numbers; (#{first}..#{last}).to_a.freeze; end")
  end

  def self.def_numbers2(first, last)
    array = (first..last).to_a.freeze
    define_method(:numbers2) do
      array
    end
  end
end
```

```ruby
Benchmark.ips do |x|
  x.report("def") { Def.def_numbers(1, 10) }
  x.report("define_method") { Def.def_numbers2(1, 10) }
  x.compare!
end

Comparison:
       define_method:   542551.0 i/s
                 def:    62085.7 i/s - 8.74x  slower
```

So prefer `def` over `define_method` unless you can access local variables from surrounding scope to avoid computations, only then `define_method` > `def`.

Related to this. If we need to accept blocks and store blocks, and use `instance_exec` to execute these blocks. Let‘s implement a before hook to demonstrate this idea.

```ruby
def self.before(&block)
  before_hooks << block
end

def before
  # execute all blocks passed to self.before
  self.class.before_hooks.each { |block| instance_exec(&block) }
end
```

This works but `instance_exec` creates singelton class for the instance, it‘s faster to use methods. We can define before hooks methods by naming them based on their position in the array, then we pass to `define_method`:

```ruby
def self.before(&block)
  meth = :"_before_hook_#{before_hooks.length}"
  define_method(meth, &block)
  before_hooks << meth
end

def before
  self.class.before_hooks.each { |m| send(m) }
end
```

Execute these before hooks could be a `send` which is faster. This is good but we can do better. Since we know which methods will be executed, we can define the `before` to execute these before hook methods by:

```ruby
def self.before(&block)
  # ...

  class_eval("def before; #{before_hooks.join(';')}; end")
end
```

This is faster because it avoids the need to call each on before hooks array and each method invoked directly instead of one indirection `send`. But we can still do better.

```ruby
def self.before(&block)
  # ...

  if before_hooks.length > 1
    class_eval("def before; #{before_hooks.join(';')}; end")
  else
    class_eval("alias before #{before_hooks.first}")
  end
end
```

If there is only a single before hook, we can alias to that method hence minimized indirection.

This approach to implementing before hooks compare to using `define_method`, is about 200% faster because it avoids a lot of internal indirections. One caveat of this approach is that it does not work with `before { |x| }`. But we can fix this by:

```ruby
unless block.arity == 0 || block.arity == -1
  b = block
  block = lambda { instance_exec(&b) }
end
```

## Optimize Inner Loops

[26:16](https://youtu.be/RuGZCcEL2F8?t=1576)

Another best place to start optimizing is inside any inner loops. Let‘s see an example from Sequel‘s Anywhere adapter:

```ruby
# https://github.com/jeremyevans/sequel/blob/ae50b5e98efb3ad902fb37f370cbf237644a12d3/lib/sequel/adapters/sqlanywhere.rb#L157-L187
while db.api.sqlany_fetch_next(rs) == 1
  max_cols = db.api.sqlany_num_cols(rs)
  h2 = {}
  max_cols.times do |cols|
    h2[col_map[db.api.sqlany_get_column_info(rs, cols)[2]]||db.api.sqlany_get_column_info(rs, cols)[2]] =
      cps[db.api.sqlany_get_column_info(rs, cols)[4]].nil? ?
          db.api.sqlany_get_column(rs, cols)[1] :
            db.api.sqlany_get_column_info(rs, cols)[4] != 500 ?
              cps[db.api.sqlany_get_column_info(rs, cols)[4]].call(db.api.sqlany_get_column(rs, cols)[1]) :
                convert ? cps[db.api.sqlany_get_column_info(rs, cols)[4]].call(db.api.sqlany_get_column(rs, cols)[1]) :
                  db.api.sqlany_get_column(rs, cols)[1]
  end
  yield h2
end unless rs.nil?
```

And there are some hidden ternary operators without parentheses...So this is complex, but not the reason why it‘s slow. It‘s slow because:

`db.api.sqlany_get_column_info(rs, cols)` repeated 5 times with same arguments in the inner loop. Another one is `db.api.sqlany_get_column(rs, cols)[1]` repeated 4 times. After a serious refactoring, now we arrive at:

```ruby
def fetch_rows(sql)
  db = @db
  cps = db.conversion_procs
  api = db.api
  execute(sql) do |rs|
    convert = convert_smallint_to_bool
    col_infos = []
    api.sqlany_num_cols(rs).times do |i|
      _, _, name, _, type = api.sqlany_get_column_info(rs, i)
      cp = if type == 500
        cps[500] if convert
      else
        cps[type]
      end
      col_infos << [output_identifier(name), cp]
    end

    self.columns = col_infos.map(&:first)
    max = col_infos.length

    if rs
      while api.sqlany_fetch_next(rs) == 1
        i = -1
        h = {}
        while (i+=1) < max
          name, cp = col_infos[i]
          v = api.sqlany_get_column(rs, i)[1]
          h[name] = cp && v ? cp.call(v) : v
        end
        yield h
      end
    end
  end
  self
end
```

The inner loop now becomes much simpler:

```ruby
while (i+=1) < max
  name, cp = col_infos[i]
  v = api.sqlany_get_column(rs, i)[1]
  h[name] = cp && v ? cp.call(v) : v
end
```

All operations inside are stored on local variables. This seems not a big deal but if you are retrieving 100,000 rows with each row of 10 columns, this makes a big difference. By define local variables, this saves millions of method calls. This is another general optimization principle.

### Prefer Local Variables

[29:02](https://youtu.be/RuGZCcEL2F8?t=1742)

Prefer local variables whenever possible especially in inner loop as demostrated above.

Local variables > Instance variables
[Local variables > Constant](https://github.com/rails/rails/commit/58df9a452fa75f10365849775292dcf0ae79a6f2)
Local variables > Method Calls

local variables are faster because it minimize the number of indirections.

**while v.s. each**

Let‘s go back to the above refactoring example. The deliberate use of `while` in the inner loop:

```ruby
while (i+=1) < max
  name, cp = col_infos[i]
  v = api.sqlany_get_column(rs, i)[1]
  h[name] = cp && v ? cp.call(v) : v
end
```
Inner loop like this is one of the few places that make sense to use `while` instead of `each` because using `each` for inner loops can hurt performance, because it requires a seperate a stackframe to push and pop for each iteration.

## Choose Faster Algorithms

[31:07](https://youtu.be/RuGZCcEL2F8?t=1867)

Sinatra routes (by pattern) v.s. [Roda‘s routing tree]

Given thousands of routes. Sinatra will be busy matching against all routes. `O(N)` Roda‘s routing tree would take route segments. Filter out the segment to the right tree. `O(log(N))`

```ruby
Roda.route do |r|
  r.on "foo" do
    # /foo ...
  end
  r.on "bar" do
    # /bar ...
  end
end
```

But the worst case is still `O(N)` and Jeremy does not accept the worst case being `O(n)`... Here comes multi route:

```ruby
Roda.plugin :multi_route

Roda.route("foo") { |r| # /foo... }
Roda.route("bar") { |r| # /bar... }

Roda.route { |r| r.multi_route }
```

Multi route builds a regexp to match initialial segment (`/foo`, `/bar`, ...) then dispatch:

```ruby
Roda.route { |r| r.multi_route }
```

which brings the performance back to `O(log(n))`. But he wants `O(1)`...

```ruby
Roda.plugin :static_routing

Roda.static_get("foo") { |r| # /foo... }
Roda.static_get("bar") { |r| # /bar... }

Roda.route { |r| }
```

But `O(1)` gives up many advantages. In the end, he created `hash_routes` plugin to have the best of both worlds:

```ruby
Roda.plugin :hash_routes

Roda.hash_routes do
  on("foo") do |r|
    r.hash_routes
  end
  is("foo/bar") do |r|

  end

Roda.route do |r|
  r.hash_routes
end
```

## Cache when Possible

[39:40](https://youtu.be/RuGZCcEL2F8?t=2380)

Introduce cache is the highest ratio of the following formula:

```text
  % Increase in Performance
-----------------------------
    Lines of Code Changed
```

Maximum performance increase over minimum lines of code changed.

**Use case: Sequel Symbol Literalization**

[40:00](https://youtu.be/RuGZCcEL2F8)

```ruby
:column_name
# => '"column_name"'
```

```ruby
def self.split_symbol(sym)
  v = case s = sym.to_s
  when /\A((?:(?!__).)+)__((?:(?!___).)+)___(.+)\z/
    [$1.freeze, $2.freeze, $3.freeze].freeze
  when /\A((?:(?!___).)+)___(.+)\z/
    [nil, $1.freeze, $2.freeze].freeze
  when /\A((?:(?!__).)+)__(.+)\z/
    [$1.freeze, $2.freeze, nil].freeze
  else
    [nil, s.freeze, nil].freeze
  end

  v
end
```

Introduce symbol cache:

```ruby
SPLIT_SYMBOL_CACHE = {}

def self.split_symbol(sym)
  unless v = Sequel.synchronize { SPLIT_SYMBOL_CACHE[sym] }
    v = case s = sym.to_s
    when /\A((?:(?!__).)+)__((?:(?!___).)+)___(.+)\z/
      [$1.freeze, $2.freeze, $3.freeze].freeze
    when /\A((?:(?!___).)+)___(.+)\z/
      [nil, $1.freeze, $2.freeze].freeze
    when /\A((?:(?!__).)+)__(.+)\z/
      [$1.freeze, $2.freeze, nil].freeze
    else
      [nil, s.freeze, nil].freeze
    end
    Sequel.synchronize { SPLIT_SYMBOL_CACHE[sym] = v }
  end
  v
end
```

This is over 1000% faster after introduced this cache.

### Globally Frozen, Locally Mutable

[41:50](https://youtu.be/RuGZCcEL2F8?t=2510)

Freeze global state like classes, objects that is accessed by multiple threads. Local objects instantiated per request remain mutable for ease of use (cache). This approach is mainly to improve reliability (thread safe). This also improves performance because frozen object means it is easy to cache them.

Note that Frozen is not the same as Immutable. Frozen means Immutable State + Mutable Cache.

```ruby
# https://github.com/jeremyevans/sequel/blob/cc5c1612fb4c42e7cbf6db6b0572001fd5bf6b58/lib/sequel/dataset/misc.rb#L25-L30
OPTS = {}
def initialize(db)
  @db = db
  @opts = OPTS # state in frozen hash
  cache = {} # <-- mutable cache
  freeze # <-- freeze this object
end
```

Make sure access to mutable cache is protected by Mutex for thread safety.

## Optimization Through Metaprogramming

[46:11](https://youtu.be/RuGZCcEL2F8?t=2771)

```ruby
class Album < Sequel::Model
  dataset_module do
    def by_name
      order(:name)
    end

    def released
      where(released: true)
    end
  end
end

# Album.where(released: true).order(:name).first
# => Album.released.by_name.first
```

This is good to DRY up code but does not improve performance. Jeremy introduced metaprogramming for users to define like following and speed up by introduced dataset cache to these metaprogramming generated methods:

```ruby
class Album < Sequel::Model
  dataset_module do
    order :by_name, :name # def by_name
                          #   cache { order(:name) }
                          # end

    where :released, released: true
    # def released
    #   cache { where(released: true) }
    # end
  end
end
```

**Example: Roda String Matching**

[48:41](https://youtu.be/RuGZCcEL2F8?t=2921)

Roda was forked from Cuba. The matching of routing segment was:

```ruby
def match_string(str)
  consume(Regexp.escape(str))
end

# https://github.com/soveran/cuba/blob/1dce54d0926c5d6e5daab033a8e9685c6faa4227/lib/cuba.rb#L214-L226
def consume(pattern)
  matchdata = env[Rack::PATH_INFO].match(/\A\/(#{pattern})(\/|\z)/)

  return false unless matchdata

  path, *vars = matchdata.captures

  env[Rack::SCRIPT_NAME] += "/#{path}"
  env[Rack::PATH_INFO] = "#{vars.pop}#{matchdata.post_match}"

  captures.push(*vars)
end
private :consume
```

This code looks perfectly fine. But let‘s see how Jeremy optimized it. First is to avoid allocations. The first change was to include the proceeding slash in the first capture to avoid extra array allocation for the captures:

```diff
- /\A\/(#{pattern})(\/|\z)/
+ /\A(\/(#{pattern}))(\/|\z)/

...

- path, *vars = matchdata.captures
+ vars = matchdata.captures

- env[Rack::SCRIPT_NAME] += "/#{path}"
+ env[Rack::SCRIPT_NAME] += vars.shift
```

Next is to use a regular expression feature, positive lookahead assertion instead of a capture:

```diff
- /\A(\/(#{pattern}))(\/|\z)/
+ /\A(\/(#{pattern}))(?=\/|\z)/
```

So we no longer need to pop the last element of capture variables (`vars`):

```diff
- env[Rack::PATH_INFO] = "#{vars.pop}#{matchdata.post_match}"
+ env[Rack::PATH_INFO] = matchdata.post_match
```

Also avoid the allocation of additional string by using post match directly.

He then profile and found generating a new regular expression every time `consume` was called takes a large portion of time. Then he introduced cached matcher:

```diff
   def match_string(str)
-    consume(Regexp.escape(str))
+    consume(self.class.cached_matcher(str) { Regexp.escape(str) })
   end
```

This change is possible because `consume` was a private method. Another optimizations technique is to keep most methods private.

## Keep Most Methods Private

Only makes a method public if it needs to be public. When method is private, you are free to change its API to improve performance. Public methods have limit options to optimize.

### Prefer String operations over Regexp operations

In Roda 3.0, the matching of string segment changed to use string operations instead of regular expression matching:

```ruby
def match_string(str)
  rp = @remaining_path
  if rp.start_with?("/#{str}") # <----
    last = str.length + 1
    case = rp[last] # <----
    when "/"
      @remaining_path = rp[last, rp.length] # <----
    when nil
      @remaining_path = ""
    end
  end
end
```

But still, there are two String allocations: `rp.start_with?("/#{str}")` and `rp[last]`.

### Prefer Integer operations over String operations

Iterating by index and checking if first character of string is 47 (`47` is ascii code of `/`):

```ruby
def _match_string(str)
  rp = @remaining_path
  length = str.length

  match = case rp.rindex(str, length) # <------
  when nil
    return
  when 1
    rp.getbyte(0) == 47 # <--- start_with?("/")
  else
    length == 0 && rp.getbyte(0) == 47 # <--- start_with?("/")
  end

  if match
    length += 1
    case rp.getbyte(length)
    when 47
      @remaining_path = rp[length, 100000000]
    when nil
      @remaining_path = ""
    end
  end
end
```

The most common failure case `when nil` also moved up because it happens more often. Another trick is to use a large number that is larger than any reasonable path length: `rp[length, 100000000]`.

Finally...

> Remember that optimizations come last.
> First make it work, then make it correct.
> After you make it fun, then you can make it fast.
> —Jeremy Evans

[Profile] to find where to optimize. Then [Benchmark] your change.

That‘s all from Jeremy‘s presentation.

<hr>

There is no silver bullet. It depends on the context. We must try ourselves. Verify it‘s faster than the other instead of directly quoting anything here.

 The faults are probably mine. I‘m happy to fix if you would [let me know]. You can reach out to him on twitter for more questions: [@jeremyevans0][Jeremy Evans] or [GitHub] to see more of his work.

Thanks for reading!

*Originally published on [juanitofatas.com](https://juanitofatas.com/optimization_techniques_by_benchmark_winners) on January 27th, 2020.*

[sequel]: https://github.com/jeremyevans/sequel
[roda]: https://github.com/jeremyevans/roda
[Profile]: https://github.com/JuanitoFatas/ruby-performance-tools#profiling
[Benchmark]: https://github.com/JuanitoFatas/ruby-performance-tools#benchmark
[Jeremy Evans]: https://twitter.com/jeremyevans0
[TechEmpower]: https://www.techempower.com/benchmarks/
[GitHub]: https://github.com/jeremyevans
[let me know]: https://twitter.com/JuanitoFatas
[Roda‘s routing tree]: https://www.youtube.com/watch?v=W8zglFFFRMM
[calling-func]: https://gist.github.com/rmosolgo/6c6a7d787e0f1666f4c6d858c8402a01#gistcomment-1843329

[^1]: Learn more about [the plugin system of Sequel and Roda](https://twin.github.io/the-plugin-system-of-sequel-and-roda/) from [Janko Marohnić](https://twin.github.io/).