Rails Glossary > The Rails Doctrine

The Rails Doctrine

The Rails Doctrine is a set of conventions and design decisions that come out of the box in every Rails application and can vastly improve the experience of developing Rails apps for the majority of cases.

The Rails doctrine is a set of principles and philosophical foundations that shaped the framework and still guide its development.

Most of them come from a core of beliefs that shaped David Heinemeier Hansson's way of thinking, but they are also rooted in how Yukihiro Matsumoto, Ruby's creator's, world view.

As it happened with the 15-minute blog, The Rails Doctrine came to life through something published by DHH on the web.

Let's explore what makes the Rails doctrine and why each part matters and is part of why Rails is how it is:

Programmer happiness

Matz has repeatedly said that he designed Ruby thinking about how programmers, starting with himself, felt while writing code using the language.

As subjective as the concept of “happiness” may be, Ruby tries to make its users happy by being as expressive and readable as possible, even at the cost of other features like performance or explicitness.

This philosophy is also present in every aspect of Rails, where writing and reading code should feel natural and enjoyable. Rails prioritizes developer ergonomics over abstract computer science ideals.

The framework's API is designed to be intuitive and to read like English. We spend more time reading code than we spend writing it so, making it clear and understandable is a win.

Code like the following is easily understandable even for people that don't have experience with the framework:

user = User.find_by(name: params[:name])

But it's not all about syntax sugar: it's about reducing cognitive load and mental friction. By eliminating the need to write boilerplate code, Rails allows developers to focus on solving problems rather than fighting extensive configuration or repetitive tasks.

This principle of the Rails doctrine is possible thanks to Ruby and the many constructs it has that make writing terse code which is a delight to read and write.

Because Rails is a strongly opinionated framework, some people consider that its philosophy eventually leads to the opposite of developer happiness. In the end, the concept is subjective, and the Rails way definitely clicks better with some people.

Convention over configuration

There's probably nothing that defines Rails better than the Convention over Configuration principle.

As unique as they can be, most web applications follow similar patterns and structures.

The CoC principle sets sensible defaults and conventions to allow developers to be productive from the get-go, instead of making a boatload of decisions before having a working prototype.

Conventions encompass almost every aspect of Rails applications: naming, routing, models, views, database tables, etc. and they reduce the number of decisions we have to make at every step of building features for applications.

As powerful as conventions are, we can override them using configuration, but following the Rails way, we can make us and our teams more productive: new team members can jump into Rails projects with the leverage of understanding the conventions and structure.

If we spend enough time learning about the conventions and don't diverge from them unless there's a good reason to, we will enjoy our time with Rails.

The menu is omakase

DHH borrowed this concept from Japanese cuisine, where omakase means “I'll leave it up to you”.

This is a blunt message that conveys that the framework makes opinionated choices about the patterns, approaches, dependencies, and general direction rather than being a one size fits all type of solution.

Rails comes with a curated set of tools like Active Record for database interactions, Action View for templating, the newly introduced Solid Stack that replaces dependencies with the database, etc.

This approach applies to architectural decisions as well. Rails favors MVC over more abstract patterns, servers-rendered HTML over client-side JS frameworks like React or alternatives.

Consider that these opinions are not arbitrary: they come from years of experience building web applications that serve millions of users.

However, the omakase part of the Rails doctrine also means that Rails innovations and progress will mostly come from 37 signals needs, which might not match ours.

No one paradigm

Just like Ruby is a multi-paradigm language that got inspiration from a diverse group of languages like Small Talk, Perl, Lisp, Eiffel, etc. Rails doesn't dogmatically adhere to any paradigm.

It embraces a pragmatic mix of OOP, functional and procedural programming rather than sticking to one paradigm and forcing everything into it.

The model layer of the MVC architecture uses OOP, while the helpers are basically a set of functions that are globally available in the view context.

The same can be said about DSLs and macros, which use functional tools and metaprogramming to define behavior at runtime to improve conciseness and readability.

All in all, Rails doesn't stick dogmatically to a single paradigm, it leverages Ruby's features flexibly to make the best fit for the use cases that it's optimized for.

The mix of paradigms comes with a cost: understanding what's happening behind the scenes might be a bit difficult at first but, once we familiarize ourselves with the way paradigms are used, things get easier.

Exalt beautiful code

Extending Ruby's design principle, Rails gives a significant amount of relevance to the code's beauty: it shouldn't only be functional or understandable, it should also be aesthetically pleasing.

Beauty is subjective but, in Ruby and Rails land, it means writing code that's terse and pleasant to read and write. To achieve this, Rails uses Ruby idioms and a carefully crafted API that is concise and good at communicating intent and purpose:

class Product < ApplicationRecord
  has_many :variants
  validates :name, presence: true
end

Even if we are not familiar with the framework, or even the language, we can probably understand what the code does. Moreover, it adds plenty of behavior and conveniences without us even having to know all about them.

This emphasis on beautiful code has practical benefits: code that's easier to understand is easier to maintain and modify.

Moreover, beautiful code generates a spark that keeps us motivated and happy to work with a Rails codebase, especially if the same care that goes into making the framework also goes into the codebases we work with.

Of course, some people might find explicitness more beautiful because of their expectations, and that's totally fine, because in Rails most of what's beautiful comes from the simplicity of the implementations and the thoughtfully abstracted complexity and that's not necessarily a solution that fits everybody.

Sharp knives

Ruby as a language provides many sharp knives by design, and Rails carries the philosophy in many parts.

Metaprogramming, monkey patching, having no type system, among others, are some Ruby characteristics that are not enjoyed by many but, at the same time, they are among the features that make Ruby so powerful and able to produce beautiful code.

The argument is that the use of the tools mentioned above can cause more harm than pleasure because, eventually, they can bite us because they break expectations about the way code should behave.

notification.remind_at = 2.days.from_now

To give users the ability to write code like this, Rails monkey patches the Integer class to add behavior that's not necessarily related to the numeric nature of the objects they represent. However, being able to handle dates in such a succinct way is a good example of a sharp, but lovely, knife.

The tensions between security and freedom are present everywhere in Rails, and most of the time, the framework doesn't shy away from siding with freedom.

The Rails reasoning is that, not providing sharp knives doesn't necessarily produce better outcomes, and that giving developers the power to learn when to use them and when to refrain from them is an essential part of the journey to becoming a good Rails developer.

Value integrated systems

Rails favors integrated, cohesive systems over loosely coupled, modular architectures.

This approach, also known as the “Majestic Monolith” is an alternative to microservices or loosely coupled architectures.

The framework is designed as a cohesive whole that is useful to solve most of the problems related to web applications: the database layer, templating, routing, session handling, assets, background jobs, etc.

Rails also concerns itself with the frontend with tools like Turbo, Hotwire, and Stimulus which allow us to write dynamic web applications without the need to write much JavaScript.

Even though it's a broad scope, Rails' philosophy of empowering small teams, or solo developers, to build fully functioning and modern web applications without resorting to external dependencies.

Deviating from the monolith can be tempting at times, but losing most of what Rails provides out of the box and duplicating efforts in the name of modularity is not worth it unless we have pressing issues that we cannot solve with omakase Rails.

There are many valid reasons, or moments, to break from the monolith, but most of the time, the decision sounds better than what it is in reality.

Progress over stability

Systems tend to become stale, especially when they've been around for a long time, like Rails has.

As real people depend on software, change can become an issue but, listening too much to the voice of conservatism can lead to software that doesn't innovate or adapt to the current times.

As users of the framework, we can expect breaking changes to happen in the name of the future. However, breaking changes are not introduced for the sake of it, they usually have the Rails greater good in mind, as advancing the framework is important for it to be alive and well into the future.

A big tent

Despite its opinionated nature, Rails maintains a “big tent” philosophy that welcomes developers with different backgrounds, skill levels, and preferences.

This welcoming nature provides developers from all walks of life, with different thoughts and ideas, a way to make an impact in Rails by providing diversity of thought and, by extension, disagreements.

You might think that welcoming dissent sounds weird in a doctrine, but the doctrine is an idealized form of what Rails is supposed to be, and dissent has pushed positive changes to the framework in the past.

Some developers use Rails in the API-only mode, others prefer type checking or using Rails to develop applications that don't conform to the MVC architecture, etc.

And, even if Rails would rather not be everything for everybody, being welcoming to people that don't agree 100% with the mainstream ideas is always a good thing: progress comes from frequently from dissent than it does with conformism.

By focusing on programmer happiness, providing sensible defaults, and creating integrated systems, Rails has influenced how we think about web development frameworks. These principles continue to guide Rails' evolution and inspire other frameworks to consider the human element in their design decisions.

Summary

The Rails doctrine represents the foundational philosophy that powered the development of the framework and influenced modern web development with its unique features and ideas.

Built on eight core principles, it emphasizes:

  • Programmer happiness over abstract perfection.
  • Sensible defaults over configuration and boilerplate.
  • Integrated systems over complex modularity.
  • Terse, beautiful and readable code.
  • Strong opinions that come from experience building web applications used by thousands of users.
  • Providing sharp knives: powerful features with potential downsides that, in the hands of the correct person, can improve the overall experience of developing applications.
  • Value integrated systems, a.k.a. “Majestic Monoliths” that address an entire problem domain. In web applications, this means they are concerned with everything needed to produce web applications: backend, frontend, database interactions, etc.
  • Progress over stability: the vision for the future of the framework trumps the wish for things to be stable and stay the same.

Understanding the Rails doctrine and where it's rooted at can help us deeply get what the framework and its ideas come from and why they exist in the first place.

Try Avo for free