Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

You Know Too Much Now (What to Do With It)

You started this book knowing how to use Ruby web frameworks. You end it knowing what they are.

The gap between "knowing how to use" and "knowing what it is" is the difference between operating a tool and understanding it. Both are useful. The second makes you significantly more capable with the first.

Let's account for what actually changed.

What You Now Know

HTTP is text with a defined format. A request is a method, a path, headers, and an optional body — all ASCII text over a TCP socket. A response is a status code, headers, and a body. You've built both from raw sockets. This means you can debug HTTP problems at the wire level, read network traces, and understand error messages that previously seemed cryptic.

Rack is a contract. The Rack spec defines one thing: your application receives a hash, it returns a three-element array. That contract is what makes every Ruby web framework interoperable. Rails, Sinatra, and Roda all honor it. You've read the spec, built conforming applications, built a conforming server, and written middleware. The contract is no longer abstract.

Middleware is function composition. An object that wraps another object and delegates to it, with behavior added before or after. That's it. You've written several middlewares. You can now read any middleware in any framework and understand exactly what it does, because they all use the same pattern.

Routing is pattern matching. A router maintains a list (or tree) of (method, pattern, handler) tuples. When a request arrives, it's matched against the list. You've built a flat router. You've used Roda's tree router. You understand why tree routing has better performance characteristics and better structural properties for large applications.

Frameworks are solutions to repeated problems. Rails solves the problem of building database-backed web applications with HTML views at scale. Sinatra solves the problem of writing small web services without a lot of boilerplate. Roda solves the problem of routing and opt-in features for applications that need both correctness and performance. None of them are magic. You've built a mini-framework that demonstrates the core of what all of them do.

What You Can Do With It

Read framework source code. Before reading this book, opening actiondispatch/routing.rb or roda.rb probably felt like reading a different language. Now it's Ruby solving problems you understand. When something in your application behaves unexpectedly, you can follow the execution into the framework and find the answer.

Write middleware confidently. Request logging, authentication, rate limiting, content negotiation, CORS headers — these all belong in middleware. You know the pattern. You know where they go in the stack. You know how to test them.

Debug routing problems. Routing bugs in production are some of the most disorienting because the framework seems to be lying to you. Now you know what the framework is doing. You can inspect the route table, add logging middleware to see what the env contains before routing, and identify whether the problem is in the route definition or the request.

Make informed framework choices. When someone proposes switching from Sinatra to Rails (or from Rails to Roda, or from Roda to anything else), you can evaluate the trade-offs with precision. Not "Rails has more features" or "Roda is faster" — specific statements about routing architecture, memory footprint, middleware organization, and ecosystem breadth.

Evaluate Rack middleware gems. The Ruby ecosystem has hundreds of Rack middleware gems for caching, authentication, logging, profiling, and more. You can now read any of them, understand what they do, and decide whether they're appropriate for your stack.

Build things the framework doesn't support. Sometimes you need something the framework doesn't provide. Before this book, that meant searching for a gem or filing a feature request. Now it might mean writing fifty lines of Rack middleware that solve exactly your problem without any framework coupling.

The Unsexy Part

There's a tendency in the software field to fetishize "building from scratch" as a virtue. It isn't. The appropriate level of abstraction for any given task is the one that lets you solve the problem without drowning in detail.

For most web applications, Rails is not only appropriate — it's excellent. The conventions are sound. ActiveRecord is battle-tested. The ecosystem is mature. "Building from scratch because you understand how it works" is not a good reason to write your own ORM.

What this book gives you is not a reason to abandon your existing tools. It gives you the ability to use them with full understanding. That's different, and more valuable.

The developer who knows Rails inside-out and understands the Rack layer beneath it will outperform the developer who knows only Rails, and will outperform the developer who insists on building everything from scratch. Understanding the foundation makes you better at using the abstractions built on it.

A Few Things Worth Doing

If you want to reinforce what you've learned:

Read Rack's middleware implementations. Rack::Session::Cookie, Rack::Runtime, Rack::Deflater — these are all short, well-written, and instructive. They're in your gems directory right now.

Read Roda's core. The main roda.rb file is about 1,000 lines and implements everything we discussed in Part III. Read it front to back. You'll recognize every pattern.

Open a Rails console and poke the middleware stack. Rails.application.middleware.each { |m| p m }. Find the session middleware. Find the router. Understand what order they're in and why.

Write a middleware for an existing application. Add request timing headers. Add a custom logger that formats output the way you want. Add a middleware that blocks requests from specific IP ranges. These are practical, finite exercises that solidify the pattern.

Read the Rack spec. The actual Rack specification is short enough to read in fifteen minutes. You know enough now to understand every word of it.

The Last Thing

At the beginning of this book, we said that Rails is just a callable. You may have believed it as a statement, but not felt it as a truth.

By now you've built a callable that speaks HTTP. You've built a server that calls callables. You've built middleware that wraps callables in other callables. You've built a routing tree that dispatches to callables. You've seen how Roda is a callable, and how its plugins and route handlers are all ultimately callables.

When you now hear "Rails is just a callable," you know it's true in the same way you know that a skyscraper is just concrete and steel. The material is simple. The engineering is sophisticated. Knowing the material doesn't diminish the engineering — it lets you appreciate it more accurately.

Go build something. You know what it's made of.