To become a better developer, they say, read a lot of code. Although we, as a profession, often find more enjoyable to write a hundred lines of code rather than read ten, this advice stands more than ever. So let’s explore some codebases, starting with Rails applications.
Last june, 37signals released a new product, Writebook – free of charge, and full source code included1. An excellent occasion to see how the company that initiated Ruby on Rails writes code.
I’ve downloaded and run the app, explored the source code, and took some notes. Here are my takes on this code base.
Writebook is a web app for publishing book-like content on the web. Books supports pages composed in Markdown, sections separators, and full-page pictures.
Writebook’s presentation on 37signals website will show you how the app looks like, and what it does. I recommend you to have a short look at this presentation, to know what we’re talking about – then come back to this article.
Writebook is free, but its code is not truly open-source. You are allowed to read the code, and to make modifications, but not to publish them, or to re-use part of the code in another product.
This means the code is not hosted in a public repository (for instance on GitHub). Instead, once you “purchase” the application (for free), you get access to a zip file containing the full source code2.
Positionnable
module, which acts on a position_score
database attribute. The position score is a floating-point number, which means a leaf can be moved by changing only a single score : the one of the moved leaf itself. If ever the interval between two positions becomes too small, positions are rebalanced using a post-commit hook.delegated_types
, rather than Single-Table Inheritance.There is a pretty syntax to declare enums:
class Book < ApplicationRecord
enum :action, %w[ revision trash ].index_by(&:itself)
app/models
: FirstRun
, DemoContent
, etc.Controller methods are reduced to their shortest expression. Most action methods are only a few-lines long:
class BooksController < ApplicationController
def index
@books = Book.accessable_or_published.ordered
end
def new
@book = Book.new
end
def create
book = Book.create! book_params
redirect_to book_slug_url(book)
end
To support these short controller methods, many pre-checks are extracted to callbacks:
class BooksController < ApplicationController
before_action :set_book, only: %i[ show edit update destroy ]
before_action :set_users, only: %i[ new edit ]
before_action :ensure_editable, only: %i[ edit update destroy ]
Some of them are further extracted into concerns – like UserScoped
, BookScoped
, which contain methods like before_action :set_user
, etc.
No model validations means that most controllers simply use exception-throwing methods (like update!
), and propagate the exception in case of invalid data. There’s no need to handle the failure case explicitely, which helps to make the methods shorter.
My take: I wonder if this approach of simplifying all controller code by removing error handling is workable in larger-scale apps. Maybe letting the browser handle required fields and formats is sufficient, but I’m not fully conviced yet.
aria
attributes, a for-screen-reader
CSS class, and so on.cache
directive.content_for
, for configuring :title
, :head
, :header
, :footer
, and so on.filter
property).ActionText
, but doesn’t use Trix
(ActionText’s defaut editor). Instead, it uses House
, a new internal editor from 37signals. The editor is vendored as a single vendor/house.min.js
file.assets/product.css
).:has
rules and :is
scopes (see assets/pages.css
).:has
is used everywhere. allow_browser versions: :modern
is used to restrict access to browsers that support it.arrangement_controller.js
, a ~250 lines Stimulus controller). No external library is used for the drag-n-drop code.async
, #privateMethods
, and so on.Turbo::StreamsChannel.broadcast_render_later_to
, to add a small “This page is being edited by another editor” indicator on the page. The code to support this in leafables_controller.rb
is surprisingly small.test/fixtures
(rather than factories)ActionDispatch::Integration
) tests.assert_changes
and assert_difference
helpers.test/test_helper.rb
is also very short, almost no configuration.concerns/positionable.rb
(implements a list with customized ordering), the authentification and session code, things like this.There is not a single comment in the code. None. The only comments are in Rails-generated boilerplate.
My take: it looks like that the general philosophy is to have methods and variables named sufficiently clearly to make comments unnecessary. I disagree: sometimes why the code does something can’t be captured by naming alone.
Authentification and sessions don’t use any external gem (like devise
). Instead the app declares its own SessionsController
and AuthenticationConcern
. The actual Sessions are stored in a dedicated database table.
My take: the code of this authentication infrastructure is surprisingly light and clear – but non-trivial nonetheless. I guess the benefits of writing your own code is that you don’t pay the price for the full configurability and extra levels of indirection of an external library.
I’m amazed by the terseness and concision of the code base. Methods are short, and don’t leak complexity everywhere. That said, there’s a real business complexity in some parts: digging in the complexities of the Leafable
model or the drag-dropping Javascript code can take a while. Short code isn’t always easy to read, but it feels simple, and not overwhelming.
The terseness of the code also comes from the use of Rails by Rails creators. They know the framework by heart, use it to the maximum, and push code to the framework when needed. After reading this code base, I think more of Rails as 37signal’s public web framework.
This codebase also embodies Rails as a one-person framework: a single developper, knowing the inside of the framework perfectly well, can write an ambitious web app using all the available resources Rails has to offer.
Next, I consider exploring other large Rails codebases: GitLab, Mastodon, maybe others. Let’s see where it goes.
More precisely, Writebook’s source code is available – but not open source. As the FAQ states, “While you are free to review the code and make modifications to Writebook for your own use, you can not use or repurpose the code for your own purposes outside Writebook.” ↩
The “source available” nature of Writebook means that this article cannot link to the actual code: it would have to be hosted publicly, which is not allowed under Writebook’s license. ↩