DHH and Rails: How Conventions Made Web Apps Ship Faster
Explore how DHH and Ruby on Rails popularized convention over configuration, speeding up web apps, reducing boilerplate, and enabling faster product iteration.

Why Rails Felt Faster Than What Came Before
Before Rails, building a web app often started with a long “setup tax.” You picked (or built) a folder structure, decided how URLs should map to code, wired up database connections by hand, and wrote the same glue code repeatedly. None of that shipped a feature—but it still consumed days.
A second drag was decision fatigue. Even small choices—file naming, where to put business logic, how to organize tests—had to be renegotiated again and again. Multiply that by a team and a growing codebase, and speed gets lost in meetings, documentation, and inconsistent patterns.
The idea: fewer choices, more progress
Rails popularized a simple promise: if you follow the common way of doing things, you shouldn’t have to configure everything. That’s “convention over configuration” in plain language.
Instead of asking you to specify every setting, Rails assumes sensible defaults:
- A predictable place for models, views, and controllers
- Standard naming that automatically connects code to database tables
- Common URL patterns that don’t require manual wiring
When the framework already “knows” what you mean, you write less boilerplate and get to working screens sooner.
Why that felt fast in practice
Speed wasn’t just about writing fewer lines of code. Conventions changed how quickly you could iterate:
- Faster starts: new projects and features began with structure already in place.
- Smoother teamwork: developers could jump into unfamiliar parts of the app and still know where to look.
- Quicker iteration loops: changes were easier to make because the app stayed organized in a familiar way.
This article focuses on that practical impact—how Rails conventions shorten the path from idea to running feature—without turning the story into hero worship. The point isn’t that one person or one framework is “magic,” but that good defaults remove friction from building products.
DHH and the Origin of Ruby on Rails
David Heinemeier Hansson—usually shortened to DHH—is the creator of Ruby on Rails. He built Rails while working at 37signals (now Basecamp) and published it as open source in 2004. That timeline matters because Rails wasn’t designed in a vacuum: it was shaped by the day-to-day pressure of shipping a real product.
Extracted from a real app, not a whiteboard
Rails began as an internal framework used to build Basecamp. Instead of starting with a grand theory of how web frameworks should work, DHH pulled out the parts that were repeatedly useful: routing requests, organizing code, talking to a database, rendering HTML, and handling common web patterns.
Because it came from production needs, Rails focused on removing friction from routine tasks. It wasn’t trying to be everything for everyone—it was trying to make the common case fast.
What “opinionated framework” actually means
Rails is often described as “opinionated.” In plain terms, that means Rails makes decisions for you—especially about structure and defaults—so you don’t have to.
For example, it nudges teams toward:
- A standard folder layout and naming conventions
- A consistent way to model data and relationships
- Predictable patterns for controllers, views, and routes
Those opinions reduce the number of choices you need to make before you can build something useful. Fewer early decisions usually means faster first versions and quicker iteration.
The community effect: shared defaults, shared vocabulary
Rails didn’t just ship code; it created a shared way of talking about web apps. When thousands of teams follow the same conventions, you get a common vocabulary (“models,” “migrations,” “scaffolds,” “RESTful routes”) and transferable skills. That lowers onboarding time, makes help easier to find, and turns “how do we do this?” into “Rails already has a standard for that.”
Convention Over Configuration, Explained Simply
Rails popularized a straightforward idea: for the common case, the framework should guess correctly so you don’t have to spell everything out. You get sensible defaults for how code is organized, how components connect, and how data maps to the database. You only configure what’s unusual.
The core idea: defaults first, exceptions second
“Convention over configuration” means Rails assumes you’re building a fairly typical web app—users, pages, forms, database tables—and it provides a standard way to do each of those things. If you follow the conventions, pieces “just line up” with minimal setup.
That’s different from configuration-heavy approaches where your first steps are often creating and maintaining a web of settings: extra files, manifests, or endless flags describing what your app already implies. Conceptually, you spend time telling the framework what you want before you can start building.
A simple example of Rails making a decision for you
Rails uses predictable naming and placement to connect parts automatically:
- If you have a model called
Article, Rails expects a database table calledarticles. - A controller named
ArticlesControllermaps to URLs and actions related to articles. - Files go in familiar locations like
app/models/article.rbandapp/controllers/articles_controller.rb.
Because Rails knows where to look and what to call things, you avoid repetitive wiring. You write the feature, not the glue.
The trade-off
The cost is less freedom up front: if you want a custom structure or unconventional naming, you may need extra configuration (and you’re swimming against expectations). The benefit is speed and consistency—especially when multiple people work on the same codebase and rely on shared patterns.
Rails MVC and the Power of Predictable Structure
Rails popularized MVC for a broad audience not by inventing it, but by making it feel obvious. MVC is easiest to understand when you think of it as three responsibilities:
- Models: the “business objects” of your app. They store data (often via the database) and hold rules like validations, pricing logic, and state changes.
- Views: what people see. Templates that turn data into HTML (or JSON), focusing on presentation rather than decision-making.
- Controllers: the traffic directors. They receive a request, ask models for what’s needed, and choose which view (or response) to return.
How Rails wires it together with minimal setup
The speed boost comes from Rails conventions that connect these layers automatically. If you create a PostsController, Rails expects it in app/controllers/posts_controller.rb. A Post model lives in app/models/post.rb. Views for that controller naturally land in app/views/posts/.
Because names and locations are predictable, Rails can infer a lot: routes map to controller actions, controller actions render matching view templates by default, and models map to database tables with conventional naming. You can override behavior—but you don’t have to negotiate every decision up front.
Predictable structure is a team multiplier
When every Rails app is organized similarly, onboarding gets faster. Teammates know where to look for a validation, where a template should live, and how a feature is likely shaped. That reduces “where is this code?” time and increases “ship the change” time.
“Fat model, skinny controller” (and where it breaks)
A common guideline is fat model, skinny controller: keep controllers simple and push reusable rules into models. It helps avoid copy-pasted logic across endpoints.
The limit: not all business workflows belong in a single Active Record model. As apps grow, teams often introduce service objects or form objects to keep models from becoming dumping grounds while still keeping controllers tidy.
Scaffolding: From Idea to Working CRUD in Minutes
Rails scaffolding is a shortcut for creating a working baseline of a feature—fast. With a single command, Rails can generate a model, database migration, controller actions, routes, and basic views for Create/Read/Update/Delete (CRUD). The result isn’t a slide deck or a mockup; it’s a running slice of the app you can click through.
What scaffolding actually gives you
A scaffold wires together the “boring but necessary” parts so you can prove the idea quickly:
- A database-backed resource (with fields you choose)
- Forms for creating and editing records
- Pages for listing and viewing records
- Conventional routes and controller actions
This matters because product iteration often gets stuck on setup work. Scaffolding helps you bypass that and start learning from something real.
Scaffolds are for learning, not for finishing
Scaffolding is best seen as a prototype generator. The default views are plain, the UX is minimal, and the code reflects generic assumptions. That’s a feature, not a flaw: it nudges you to treat scaffolds as a starting point, not “the design.”
A common healthy workflow is:
- Scaffold a resource to get the end-to-end loop working.
- Put it in front of someone (even internally) to validate the flow.
- Refactor: adjust validations, permissions, UI, and business rules.
Cautions: speed doesn’t remove responsibility
Generated code still needs review. You’ll want to add tests, tighten authorization, and improve error handling. And because scaffolded pages are utilitarian, plan time for real UX work—copy, layout, accessibility, and edge cases. Scaffolding accelerates the first draft; it doesn’t replace engineering judgment.
Generators and Migrations: Iteration Baked Into the Workflow
Rails didn’t just introduce conventions in theory—it wired them into day-to-day work through generators, migrations, and naming rules that reinforce each other. That cohesion is a big reason teams can iterate quickly without the codebase turning into a pile of one-off decisions.
Generators, migrations, and conventions as one system
A Rails generator doesn’t merely “create files.” It creates expected files in expected places with expected names—models in app/models, controllers in app/controllers, tests in the right folder, and, crucially, a migration that updates the database structure.
Because Rails leans on naming (like User mapping to a users table), the generated pieces tend to connect with minimal extra wiring. Less time is spent deciding where something goes or what to call it, and more time is spent shaping the feature.
Migrations make change a normal part of the product
Migrations treat the database schema as something that evolves alongside the application. Instead of “the database is done, now we code,” Rails encourages a steady rhythm: build a feature, adjust the schema, learn from real usage, then refine.
Each migration is a small, timestamped step that can be reviewed, tracked in version control, and replayed across environments. That makes iterative product changes—adding fields, tweaking constraints, introducing new tables—much less risky over time.
Example workflow: add a field, validate it, ship
Say you want to add a role to users:
- Generate the change:
rails g migration AddRoleToUsers role:string - Run it:
rails db:migrate - Update the model: add validations (and maybe an enum) in
User. - Adjust forms and views, update tests, deploy.
That’s a tight loop: the schema change and the application change move together, so you don’t end up with “mystery columns” or code that assumes data that isn’t there.
Discipline matters
Speed only stays sustainable if migrations are kept clean: avoid editing old migrations after they’ve shipped, write reversible changes when possible, and treat schema changes like production code—with reviews and careful naming. Rails makes iteration easy; teams keep it safe by staying consistent.
DRY by Default: Less Boilerplate, More Focus on Features
“Don’t repeat yourself” (DRY) is the simple idea that your app should have one clear source of truth for each piece of knowledge. In a web app, repetition often sneaks in when the same concept is spelled out in multiple places—routes, controller logic, view templates, and even database queries.
A concrete DRY example: a Posts feature
Imagine you’re building a basic blog with Post records. Without DRY habits, you might copy the same “find the post by ID” code into show, edit, update, and destroy. Rails nudges you toward a single shared method instead:
before_action :set_post, only: %i[show edit update destroy]
def set_post
@post = Post.find(params[:id])
end
That’s DRY in action: one change (say, switching to Post.friendly.find) updates every action.
How Rails conventions cut duplication across routes, controllers, and views
Rails conventions make DRY easier because different layers “agree” on naming and structure. When you use RESTful routes (resources :posts), Rails expects a PostsController with standard actions, and it looks for views in predictable paths like app/views/posts/show.html.erb.
Because those pieces line up, you write less glue code. A link helper like link_to @post.title, @post works because Rails can infer the correct route from the model instance. Partial naming conventions (render @posts) can automatically pick posts/_post for each item.
DRY can be overdone
Pushing DRY too far can hurt readability: tiny abstractions, metaprogramming, or “one method that handles everything” may save lines but cost understanding. A little repetition is sometimes the clearest option—especially in views and business logic. The goal is maintainability, not minimal character count.
The Happy Path: Why Defaults Accelerate Product Iteration
Rails is famous for optimizing “the happy path”: the most common way teams build and ship a typical database-backed web app. It assumes you’ll have users, forms, validations, CRUD screens, routes, emails, background jobs, and a relational database—and it makes those flows smooth and predictable.
Happy path development, in plain terms
Happy path development means you spend most of your time doing the “normal” thing, without wrestling the framework. When you name a model Order, Rails expects an orders table, knows where the file lives, and can infer how controllers, views, and routes should line up. You’re not proving every choice; you’re following a well-worn trail.
Defaults that remove decision fatigue
New projects have an endless list of early decisions: folder structure, naming, configuration style, testing setup, how to handle forms, where to put business logic. Rails deliberately answers many of those questions up front.
That matters because decision fatigue is real: the more small choices you make, the slower you move—and the harder it is for teammates to predict what you did. Rails defaults create a “good enough” starting point, so you can begin building features immediately and only customize when the need is clear.
Faster experiments, tighter feedback loops
Product iteration is about running more (and better) experiments: shipping a small change, watching what users do, and adjusting quickly. Rails supports that rhythm by making it easy to:
- model a new concept and wire it into the app quickly
- add validations and error messages without extra plumbing
- produce working endpoints and pages that are consistent with the rest of the code
Shorter build times lead to shorter feedback loops—and that’s where speed turns into learning.
When the happy path breaks
Rails defaults can feel restrictive when your problem is unusual: highly specialized domains, extreme scale requirements, strict regulatory constraints, or unconventional data storage and workflows. In those cases, you may spend more time bending conventions than benefiting from them. The key is recognizing when defaults are helping—and when you should intentionally step off the trail.
Team Speed: Shared Conventions Reduce Coordination Costs
Rails didn’t just speed up individual developers—it sped up teams. The “Rails way” is really a set of shared expectations: where files live, how classes are named, how requests flow through controllers to views, and how data is modeled. When most projects follow the same patterns, teammates spend less time decoding structure and more time shipping features.
What “the Rails way” looks like day to day
Conventions show up in small, repeated decisions:
- Models in
app/models, controllers inapp/controllers, views inapp/views - Predictable naming (
PostsControllermanagesPost) - Standard RESTful routes for common actions (
index,show,create, etc.) - A familiar approach to forms, validations, and partials
None of these is magical alone. Together, they reduce the number of “How do we do this here?” conversations.
Faster onboarding and fewer handoffs
When a new developer joins, Rails conventions act like signage in a building: you can find what you need without asking for a guided tour. That cuts onboarding time and lowers the risk of knowledge being trapped in one person’s head.
Better code reviews, less bikeshedding
Conventions also improve code reviews. Reviewers can focus on product logic, edge cases, and performance instead of debating folder structures or inventing new patterns. When there’s a default, the burden of proof shifts: you only argue when you’re deviating for a good reason.
The trade-off: conformity isn’t always correct
The flip side is that teams can follow conventions out of habit. It’s healthy to justify exceptions—especially for unusual domains, scaling constraints, or security requirements—while still using Rails defaults as the starting point.
Batteries Included: Integrated Tools That Ship Products Faster
Rails earned its “batteries included” reputation by treating a web app as a whole product, not a puzzle of disconnected parts. Instead of asking you to assemble a stack for routing, templating, background work, email, file uploads, security defaults, and testing, Rails ships with a coherent set of tools designed to work together from day one.
Standard solutions for common needs
Most web products hit the same milestones early: user accounts, forms, validations, database changes, sending emails, handling errors, and deploying reliably. Rails leans into those repeatable needs with built-in patterns and sensible defaults. That means teams spend less time debating which library to pick or how to wire it up, and more time shaping features and polishing the user experience.
When the “standard” path is already paved, shipping becomes a matter of filling in application-specific details—models, rules, and UI—rather than inventing architecture for every new project.
Fewer seams, less glue code
Speed isn’t only about having tools; it’s about how well they fit together. In a mix-and-match setup, a surprising amount of effort goes into translation layers: adapting one library’s configuration format to another’s expectations, reconciling competing conventions, or duplicating concerns like logging, instrumentation, and error handling.
Rails reduces that friction by integrating its components around shared conventions. Data validation, database persistence, and rendering views follow consistent rules. Errors surface in predictable ways. Configuration tends to live in familiar places. The result is less “glue code” and fewer one-off decisions that slow down delivery and complicate maintenance.
The trade-off: framework-wide change
The flip side of tight integration is that upgrades can have wider blast radius. When Rails changes defaults or deprecates an approach, multiple parts of an app may need attention at once. Teams often accept this cost because the day-to-day gains in delivery speed and coherence outweigh occasional upgrade projects—but it’s a real factor to plan for.
Where Convention Over Configuration Can Hurt
Rails conventions are a speed multiplier when you stay close to them. But the same conventions can slow you down when your app starts bending the framework into shapes it wasn’t designed to make effortless.
Signs you’re fighting the conventions
A few practical “smoke signals” usually show up early:
- You’re constantly overriding defaults (autoloading, inflections, routing patterns) just to make things “feel right.”
- You’ve introduced custom directory rules that new teammates can’t guess without a map.
- Heavy metaprogramming makes core behavior hard to trace (“Where is this method defined?” becomes a daily question).
- Basic tasks require remembering project-specific rituals rather than standard Rails patterns.
When this happens, the time you saved via convention often gets paid back with interest in onboarding, debugging, and code review.
Performance and scaling: the real trade-offs
Rails can scale, but it doesn’t magically remove performance work. Convention-friendly code can still become slow if you’re not watching queries, caching, background jobs, and object allocations.
Where conventions can hurt is when you assume defaults are “always optimal.” For example, naive Active Record usage can create N+1 queries, and default caching decisions may be too generic for your hottest endpoints. Scaling typically means measuring, then adjusting deliberately.
Faster iteration isn’t “no technical debt”
Rails helps you ship and learn quickly—but quick changes can accumulate inconsistencies: model bloat, callback chains, or business logic drifting into controllers. Conventions reduce friction; they don’t automatically enforce clean boundaries.
How to customize without losing the benefits
Customize deliberately:
- Make small, reversible changes first; avoid rewriting core conventions early.
- Document deviations in a short “How our Rails app differs” note.
- Keep boundaries clear (service objects, concerns, jobs) so customization stays contained rather than leaking everywhere.
The goal is to earn flexibility without turning “convention over configuration” into “configuration everywhere.”
A Modern Parallel: Conventions vs. “Vibe-Coding” Defaults
Rails accelerated teams by standardizing structure: where things go, what they’re called, and how the pieces connect. A similar speed dynamic is showing up today with vibe-coding platforms like Koder.ai, where the “default” is less about folder layout and more about turning intent into a working application through chat.
Koder.ai focuses on the same outcome Rails optimized for: a shorter path from idea to a running feature. Instead of hand-wiring the first version, you describe what you want in a conversation, and the platform helps generate and iterate on a real app (web, backend, or mobile). You can then refine like you would after a Rails scaffold—adjusting behavior, permissions, and UX—while keeping the feedback loop tight.
The underlying lesson is consistent: teams move faster when the early, repeatable decisions are made once (by a framework or platform) and everyone can build on top of those defaults.
Practical Takeaways for Building and Iterating With Rails
Rails is fastest when you treat its conventions as a default operating system for your product team—not a set of suggestions you debate on every ticket. The goal is to preserve momentum while still leaving room for intentional exceptions.
Rules of thumb for using conventions well
Start by leaning into Rails’ “expected” choices: conventional naming, standard folder structure, RESTful routes, and the built-in way of handling forms, validations, and background jobs.
As a simple habit, ask: “Can a new teammate predict where this code lives and how it behaves?” If the answer is yes, you’re probably staying close to convention—and future changes will be cheaper.
A lightweight decision framework
Follow conventions until there’s a measurable need not to. “Measurable” can be any of the following:
- A performance bottleneck you can reproduce and quantify
- A recurring developer pain point (e.g., a pattern that causes bugs or slows reviews)
- A clear product requirement that Rails’ default shape can’t express cleanly
If you can’t point to one of those, prefer the Rails way. It keeps the system understandable and makes iteration smoother.
Keep exceptions small and written down
Every team eventually makes a few deliberate deviations—custom service objects, alternative form patterns, specific routing conventions, or a standard approach to querying.
Capture these in a short “team playbook” (a single page in your repo). Include:
- The exception
- When to use it (and when not to)
- One concrete example from your codebase
This prevents exception creep and helps new hires ship confidently.
The real takeaway
Conventions aren’t just a coding preference. Used well, they’re a product strategy tool: they reduce decision overhead, shorten feedback loops, and let your team spend more time learning from users than arguing about structure.
FAQ
What does convention over configuration mean in Rails?
Rails uses shared naming and folder rules so developers spend less time wiring an app together. A model named Article maps to an articles table, and related controllers and views follow expected locations.
Why did Rails make web development feel faster?
Rails gives a new project a familiar structure from the start. That removes many early choices about routes, files, database access, and common web features, so a team can begin building sooner.
Who created Ruby on Rails?
DHH, David Heinemeier Hansson, created Ruby on Rails while working on Basecamp at 37signals. He released Rails as open source in 2004 after extracting patterns from building a real web product.
How does Rails MVC help a team?
MVC separates an app into models for data and rules, views for presentation, and controllers for handling requests. Rails places each part in predictable locations, which makes a feature easier to find and change.
What is Rails scaffolding used for?
A Rails scaffold generates a basic working CRUD feature: a model, migration, routes, controller actions, and simple pages and forms. It works well for testing a flow quickly, but teams still need to improve permissions, tests, accessibility, and the interface.
Why are Rails migrations useful?
A migration records a database schema change in code, such as adding a role field to users. Teams can review it, keep it in version control, and run the same change across development, test, and production environments.
What does DRY mean in a Rails app?
DRY means keeping one clear place for repeated knowledge or behavior. For example, a controller can load a post in one shared method instead of copying the same lookup into every action.
When do Rails conventions help, and when can they hurt?
They help when the app follows common database-backed web patterns such as users, forms, CRUD screens, validations, and standard routes. They can get in the way when unusual data models, workflows, or technical constraints require frequent overrides.
How do Rails conventions speed up onboarding and code reviews?
Shared conventions let new developers predict where code lives and how requests flow through the app. Reviews can focus more on business rules, security, and edge cases instead of recurring debates about structure.
How is Koder.ai similar to Rails conventions?
Koder.ai uses chat to turn an app idea into web, backend, or mobile software, while Rails uses code conventions to organize a traditional application. Both reduce repetitive setup, but Koder.ai starts from natural-language instructions and Rails starts from a conventional codebase.