• Convention Over Configuration, But Not For Style

    Recently DHH added Rubocop by default to Rails, and posted about his decision in a A writer’s Ruby blog post:

    Some languages, like Go, have a built-in linter, which applies a universal style that’s been set by the language designers. That’s the most totalitarian approach. A decree on what a program should look like that’s barely two feet removed from a compile error. I don’t like that one bit.

    It reminds me of Newspeak, the new INGSOC language from Orwell’s 1984. Not because of any sinister political undertones, but in the pursuit of a minimalist language, with no redundant terms or ambiguities or flair. Imagine every novel written in the same style, Hemingway indistinguishable from Dickens, Tolkien from Rowling. It would be awfully gray to enjoy the English language if there was only a single shade of prose.

    The best code to me is indeed its own form of poetry, and style is an integral part of such expression. And in no language more so than Ruby.

    There are probably people who would prefer the more conventional, literal style, and they could encode that preference in a lint rule. I’d have absolutely no problem with that, as long as they’re not trying to force me to abide by their stylistic preferences.

    Now, in The Rails Doctrine DHH writes about Convention over Configuration:

    One of the early productivity mottos of Rails went: “You’re not a beautiful and unique snowflake”. It postulated that by giving up vain individuality, you can leapfrog the toils of mundane decisions, and make faster progress in areas that really matter.

    Who cares what format your database primary keys are described by? Does it really matter whether it’s “id”, “postId”, “posts_id”, or “pid”? Is this a decision that’s worthy of recurrent deliberation? No.


    Let me try to unpack the two posts. Table names and primary and foreign key columns have strong conventions in Rails:

    class Post < ApplicationRecord
      has_many :comments
    end
    
    class Comment < ApplicationRecor
      belongs_to :post
    end
    

    Implicit in the code above is that our database has a table posts with a primary key field id, and a table named comments with a primary key field id and a foreign key post_id referencing posts.id. There are many arguments to make about these specific conventions: About the plural table names, about using snake case, about the Ruby class names being singular, etc. The point over convention over configuration is that those changes don’t matter. The convention saves of from making unimportant decisions, in DHH words:

    Part of the Rails’ mission is to swing its machete at the thick, and ever growing, jungle of recurring decisions that face developers creating information systems for the web. There are thousands of such decisions that just need to be made once, and if someone else can do it for you, all the better.

    Let’s get back to Ruby syntax. The argument seems to be that the following two ways of writing the same code are different forms of self expression and the building blocks of poetry:

    has_many :posts
    
    has_many(:posts)
    

    I am not convinced by that argument. I used to think that creating a style-guide for each team was a worthwhile exercise. Since then, I’ve been on 3 different teams in 12 years (hardly a lot by tech standards). I’ve come to experience the power of hitting the ground running on an unfamiliar Rails application, exactly because of convention over configuration. I’d rather we have more of that, with a convention for code style across teams.

    In A writer’s Ruby, DHH says:

    Imagine every novel written in the same style, Hemingway indistinguishable from Dickens, Tolkien from Rowling. It would be awfully gray to enjoy the English language if there was only a single shade of prose.

    That would be an awful world indeed, but I don’t think it’s a fair comparison. Novels are mostly individual works of art. Code style is mostly a team endeavour with very different goals than literary works. Presumably, the team is working towards producing a maintainable code base that is easy to work on by current and future members of the team. Predictable style and idioms are better than poetic code. I would hate for all the novels I read to have the same style. I would hate just as much for the instructions on my dishwasher to be in the style of James Joyce or Leo Tolstoy.

    For now, I am using standardrb, even if I don’t like all the conventions.

    Read on →

  • The REPL: Issue 112 - December 2023

    Rethinking Serverless with FLAME

    Mind blown. This promises to be scalable and elastic with minimal code shenanigans. Like they mention: It doesn’t solve a problem. It removes it. Thanks to the power of the Erlang VM.

    Everyday performance rules for Ruby on Rails developers

    Overall, very good advice for Rails performance.

    Ruby 3.3’s YJIT: Faster While Using Less Memory

    Like having a cake and eating it too: Ruby got faster, and is using less memory. I’ve personally seen 20% improvement in speed building this blog

    Read on →

  • This Blog on Ruby 3.3.0

    Per tradition, this Christmas a new version of ruby was released.

    It promises performance improvements, especially with the YJIT turned on. Let’s see how it does using jekyll the static site generator for this very blog.

    Before (ruby 3.2.2 without YJIT)

    $ ruby -v
    ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]
    
    $ jekyll build
    Configuration file: /Users/ylansegal/Personal/blog/_config.yml
                Source: /Users/ylansegal/Personal/blog/src
           Destination: /Users/ylansegal/Personal/blog/_site
     Incremental build: disabled. Enable with --incremental
          Generating...
           Jekyll Feed: Generating feed for posts
                        done in 2.676 seconds.
     Auto-regeneration: disabled. Use --watch to enable.
    
    $ jekyll build
    [...]
                        done in 2.685 seconds.
    $ jekyll build
    [...]
                        done in 2.679 seconds.
    

    Average: 2.68 seconds

    After (ruby 3.3.0 with YJIT)

    $ ruby -v
    ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +YJIT [arm64-darwin23]
    
    $ jekyll build
    Configuration file: /Users/ylansegal/Personal/blog/_config.yml
                Source: /Users/ylansegal/Personal/blog/src
           Destination: /Users/ylansegal/Personal/blog/_site
     Incremental build: disabled. Enable with --incremental
          Generating...
           Jekyll Feed: Generating feed for posts
                        done in 2.079 seconds.
     Auto-regeneration: disabled. Use --watch to enable.
    
    $ jekyll build
    [..]
                        done in 2.212 seconds.
    
    $ jekyll build
    [...]
                        done in 2.163 seconds.
    

    Average: 2.15 seconds

    Of course this is unscientific, but 20% local reduction in build time is impressive!

    Read on →

  • The REPL: Issue 111 - November 2023

    River: a Fast, Robust Job Queue for Go + Postgres

    I don’t write go-lang, and don’t have any insights into this new queue. The introduction of why a database based queue solves the dual-write problem are clear and applicable to any other system. Transactionality is one of the main reasons that I recommend GoodJob. The other one, also discussed is that operationally, having less data-stores is a win.

    A number of Postgres improvements also make it more performant than previous attempts at using db-backed job queues.

    Coincidentally, I was listening to a recent podcasts. They were discussing Redis as a store for background queuing. I was disappointed that they didn’t mention the dual-write problem as a pro of relational database queues.

    Rob Pike’s 5 Rules of Programming

    Concise and interesting. I’ve internalized as a best practice avoiding premature optimization. Rule 5 has me thinking a bit. Most web application programming doesn’t need to think much about data structures in memory, rather about how to design the database schema for storage.

    Read on →

  • The REPL: Issue 110 - October 2023

    Postgres Goodies in Ruby on Rails 7.1

    Rails 7.1 is out with some very interesting features for Potsgres users. Composite primary keys support in particular caught my eye: When partitioning tables, using a composite primary key that includes the partition key is a best practice. Now, Rails supports the composite primary keys in the model and associations (through query_constraints) ensuring that when reading from the table, the partition key is always used.

    Improved support for CTEs is also welcome!

    Writing Object Shape friendly code in Ruby

    It turns out that the way you structure classes (and more precisely variable instantiation) in ruby > 3.2 has performance implications. Ben Sheldon discusses how to structure classes to take advantage of those optimizations. It is an interesting demonstration on how code style and the ruby interpreter interact.

    The article doesn’t mention how much it impacts performance. I wonder: On a typical web request, how much can this save by structuring your classes for optimization?

    The TLDR on Ruby’s new TLDR testing framework

    It’s called TLDR and it blows up if your tests take more than 1.8 seconds to run.

    Testing is a near and dear topic to me. I have not tried this new framework, but I have some initial thoughts:

    • 1.8s is not a lot of time for a whole test suite.
    • Test that fast need to avoid database interactions at all costs. In my experience that leads to heavy mocking, which in turn can lead to unit test passing but the components break on integration.
    • TLDR seems incompatible with large systems (e.g. majestic monolith). For good or bad.
    • Pushing the envelope can lead to some great ideas. For example:

    TLDR automatically prepends the most-recently modified test file to the beginning of the suite

    This is brilliant. I have a script that guesses which test files to run on a branch based on what changed in git. After reading this, I immediately incorporated ordering the files by modification date.

    Read on →