0Pricing
Ruby Academy · Lesson

Common Bottlenecks

Speed up Ruby code.

Common Bottlenecks is a free Ruby Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Ruby Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Recognizing Bottlenecks

Most Ruby slowdowns come from a few recurring patterns. Knowing them lets you fix code quickly.

  • Wrong data structure for the job
  • Repeated work that could be cached
  • N+1 queries and nested loops

This lesson covers the most common offenders.

puts 'Speeding up Ruby starts with knowing the usual suspects'

Array#include? vs Set

Checking membership with Array#include? is O(n). A Set (or hash) gives O(1) lookups.

  • For repeated membership checks, build a Set once
  • Huge speedup on large collections
require 'set'

allowed = Set.new(['a', 'b', 'c'])
puts allowed.include?('b')
puts allowed.include?('z')

Nested Loops (O(n squared))

Comparing every pair of elements is quadratic and explodes with size.

  • Replace inner loops with a hash lookup
  • Turns O(n squared) into O(n)
a = [1, 2, 3, 4]
b = [3, 4, 5]
set_b = b.to_set rescue require('set') || b.to_set
common = a.select { |x| set_b.include?(x) }
puts common.inspect

The N+1 Pattern

Fetching related data inside a loop causes N+1 operations.

  • 1 query for the list, then 1 per item
  • Batch the lookups instead with a single grouped fetch
# Bad: lookup inside loop
orders = [1, 2, 3]
prices = { 1 => 10, 2 => 20, 3 => 30 }
# Good: one preloaded hash, O(1) per item
total = orders.sum { |id| prices[id] }
puts total

Memoization

Recomputing the same expensive value wastes time. Memoize it with ||=.

  • Cache the result after first computation
  • Subsequent calls return instantly
class Report
  def total
    @total ||= begin
      puts 'computing...'
      (1..1000).sum
    end
  end
end

r = Report.new
puts r.total
puts r.total

Choosing the Right Method

Some Enumerable methods are far faster than chains.

  • sum beats inject(:+)
  • any? short circuits, unlike select.empty?
  • find stops at the first match
nums = (1..1_000_000)
puts nums.any? { |n| n > 5 }
puts nums.find { |n| n > 5 }

Avoiding Repeated Sorting

Sorting inside a loop or repeatedly is costly. Sort once and reuse.

  • Sorting is O(n log n)
  • Cache the sorted result if the data is stable
data = [5, 2, 8, 1, 9]
sorted = data.sort
puts sorted.first
puts sorted.last

Hash Grouping

group_by and tally aggregate in one pass instead of repeated scans.

  • tally counts occurrences efficiently
  • Avoids manual counting loops
words = ['a', 'b', 'a', 'c', 'b', 'a']
puts words.tally.inspect

String Building Cost

Joining with join is faster than repeated concatenation for collections.

  • Build an array, then join once
  • Avoids many intermediate strings
parts = (1..5).map { |i| "item#{i}" }
puts parts.join(', ')

Regex Compilation

Defining a regex literal inside a hot loop recompiles it implicitly. Hoist it to a constant.

  • Compile once, match many times
  • Use match? when you only need a boolean
EMAIL = /\A[^@\s]+@[^@\s]+\z/

inputs = ['a@b.com', 'nope', 'x@y.org']
valid = inputs.select { |s| EMAIL.match?(s) }
puts valid.inspect

Lazy Loading Work

Do not compute what you may never use. Defer with lazy evaluation or guards.

  • Return early when possible
  • Compute heavy values only on demand
def describe(items)
  return 'empty' if items.empty?
  "#{items.size} items, first is #{items.first}"
end

puts describe([])
puts describe([10, 20])

Quick Check

Test your bottleneck knowledge.

Recap

You learned to fix common bottlenecks:

  • Use Set or hash for fast membership instead of include?
  • Eliminate nested loops and N+1 patterns with preloaded hashes
  • Memoize expensive computations with ||=
  • Pick efficient methods (sum, any?, tally) and hoist regexes
  • Defer or skip work you may never need

Always measure before and after to confirm the gain.

Frequently asked questions

Is the “Common Bottlenecks” lesson free?

Yes — the full text of “Common Bottlenecks” is free to read here on the web, and the Ruby Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Ruby Academy course, upgrade to CoddyKit PRO.

What will I learn in “Common Bottlenecks”?

Speed up Ruby code. You practise Ruby Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Ruby Academy?

No prior experience is required. Ruby Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Common Bottlenecks” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Ruby Academy lesson?

Yes. Every Ruby Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Measuring Performance
  2. Profiling Tools
  3. Memory Optimization
  4. Common Bottlenecks
← Back to Ruby Academy