Ruby Performance
What actually costs in MRI: object allocation, frozen and deduplicated strings, symbol keys, array and string growth, lazy enumerators, and the generational collector. Every claim is one you can measure with GC.stat rather than guess at.
Who it is for
Has never measured anything.
For someone confident in the language who wants the traps, the edge cases and the interview questions.
You will get the most out of it if you have written Ruby recently enough to read it without effort, and have been surprised by it at least once. If you are picking the language up for the first time, start with Ruby Essentials and come back to this one.
It is also built for interview preparation: the questions are the ones that get asked because they separate people who have read the documentation from people who have hit the behaviour in production.
How long it takes
90 graded questions at roughly 45 seconds each is about 68 minutes of answering in total.
At the default five questions a day, and because the session mixes in your other courses, expect around 18 days — call it 3 weeks — to see everything once, plus a few weeks of thinning reviews after that before it is all mastered.
A question is mastered on the third correct answer, once the gap between reviews has grown past a week — so a course cannot be finished in a weekend however long you sit with it.
Question mix
- 60 multiple choice
- 10 concept cards
- 10 predict the output
- 10 put it in order
- 10 matching questions
Syllabus
What you will be asked about
-
01
What Actually Allocates
Count the objects a line of Ruby creates and name the values that cost nothing.
-
02
frozen_string_literal
Predict which strings the magic comment freezes and reach for + or - when you need the other kind.
-
03
Symbols versus Strings as Keys
Explain what a Hash does to a String key and why a Symbol key costs nothing.
-
04
The Cost of Dynamic Dispatch
Choose between method_missing and define_method by what each one costs per call.
-
05
Growing an Array
Tell mutation apart from rebinding and pick the form that does not allocate per iteration.
-
06
each versus map
Choose between each, map and map! by what each one returns and what it allocates.
-
07
Lazy Enumerators
Use lazy to skip work rather than to skip allocations, and say when it is not worth it.
-
08
The Garbage Collector
Describe generational collection well enough to predict what retains memory and what does not.
-
09
Memoization and its nil Pitfall
Write a memo that caches a falsy result and say what ||= actually expands to.
-
10
What Is Worth Optimising
Rank a change by the share of the total it can affect rather than by how clever it looks.
8 more topics, and all 90 questions
Ruby Performance is a Pro course. One subscription opens it and every other course in the catalogue, including the ones still being written.
A question from this course
What Actually Allocates
What does this print?
def alloc
a = GC.stat(:total_allocated_objects)
yield
GC.stat(:total_allocated_objects) - a
end
s = alloc { 1000.times { "x" } }
y = alloc { 1000.times { :x } }
p [s >= 1000, y < 10]
Show the answer
D [true, true]
Identical string literals look interchangeable, so people assume Ruby caches them the way it interns symbols. It does not: a plain literal is a constructor, and a thousand evaluations build a thousand mutable Strings. The symbol is interned once and every later :x is the same object, so the counter barely moves.
The rest of the track
Ruby at every depth
Ruby Essentials
The behaviour underneath the friendly syntax. Only nil and false are falsy, symbols are not strings, string literals are mutable, and a method returns its last expression whether or not you meant it to.
Ruby Core
Where Ruby trips people who use it daily. Blocks against procs against lambdas, the ancestor chain and method lookup, the three kinds of equality, and what happens when two names point at the same object.
Ruby Data & Collections
Array, Hash, Set and Enumerable in earnest. Bang methods that return nil, Hash defaults that share one object between every key, fetch against [], grouping and tally, and lazy enumerators that are not always cheaper.
Ruby Errors & Edge Cases
Exceptions and their edges. Rescue ordering, StandardError against Exception, what an ensure does to a return value, retry, and the difference between catch/throw and raising at all.
Ruby Standard Library
The library people reimplement by hand: Struct and Data, Set, the Comparable and Enumerable mixins, Forwardable, JSON, Digest and BigDecimal. Ten places where a built-in already does the job, and one behaviour in each that is not what you assumed.
Ruby Idioms & Pitfalls
The Ruby people write out of habit that is wrong or merely un-Ruby: for loops that leak their variable, and versus &&, unless with an else, ||= on a false value, map followed by compact, and rescuing Exception. Ten habits, and the behaviour that punishes each one.
Ruby Advanced
The metaprogramming that still catches experienced Rubyists: singleton classes, method_missing, refinements, prepend, and the two searches behind constant lookup. Every snippet is one you could be handed in a code review.
Ruby Testing
What a test actually asserts, and where that claim is weaker than it looks. Argument order and failure messages, the three kinds of equality, exceptions, isolation between examples, and the difference between a failure and an error.
Ruby Interview Questions
The Ruby questions interviewers actually ask, and the answers that need a reason attached. Proc and lambda return semantics, the ancestor chain, mixins, duck typing, shared references, symbols, method_missing, memoisation and Enumerable built by hand.
Start Ruby Performance
in tomorrow’s session.
Enrol and this course joins your daily five, mixed in with everything else you are studying — 90 questions spread over about 18 days rather than dropped on you at once.
Browse the catalogue