Ruby Academy · Lesson

Common Bottlenecks

Speed up Ruby code.

Lesson 4 of 413 steps

Common Bottlenecks is a free Ruby Academy lesson on CoddyKit. This is lesson 4 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Ruby Academy learning path, and your progress syncs across the web and the CoddyKit app. The Ruby Academy course includes 4 lessons in total.

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.

Free to start

Learn Ruby with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
29
Lessons
109

Frequently Asked Questions

Is the “Common Bottlenecks” lesson free?

Yes — any 3 lessons of the Ruby Academy learning path, including “Common Bottlenecks”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Ruby Academy course includes 4 lessons in total.

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, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.

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