140 Experience
0 Lessons Completed
0 Questions Solved


Thanks Chris! I put this into a concern to be able to reuse it across multiple mailboxes:

Posted in Recording pattern (Basecamp 3)

As far as I know (knowledge gathered from what I could find + personal experience trying to implement it - I have an app using this pattern):

  • a recordable has_many :recordings, as: :recordable, not one
  • Recordables are immutable. You don't update a recordable, you create a new one.
  • you will have a hard time building the same architecture without the Event model

Posted in Recording pattern (Basecamp 3)

Thanks Ciprian, I appreciate your contribution :)
Unfortunately, it seems that this repo covers only the basics. For instance, the Bucket#record method is a simplified version of the one used by Basecamp.

I'm wondering about the best way to approach scheduled notifications.

Having users who set their timezone and pick the best time to receive a regular notification (can be daily or less often), I came up with 2 options.

Option A: Individual schedules
Use resque-scheduler with dynamic schedules, one per user.
Each schedule has its own frequency and will call SendDigestJob, which itself tells the Mailer to prepare the mail and deliver it now

Option B: Batch deliver_later
Run a task every hour, fetch the users who should receive their notification in the next hour, and call the Mailer with "deliver_later(wait_until:)"

Option A is my favorite but will result in a myriad of scheduled jobs.
Am I missing something? Are there better options?


Posted in how do i debug

Posted in Recording pattern (Basecamp 3)

Has anyone tried to unravel the recording pattern used in Basecamp 3 ?

You can find breadcrumbs in the "On Writing Software Well" video series ( and a bit more details in this presentation (

It relies on a subpattern that is now part of rails, delegated types:, but there's also a notion of tree structure (recordings belong to other recordings) and of versioning/activity (there's an Event class involved as you can see here

The core looks something like this, but you can see a glimpse of it here (lots of things are hidden within the concerns, such as the parent/children that must live in the Tree concern).

class Recording < ApplicationRecord
  belongs_to :bucket
  belongs_to :creator
  belongs_to :parent, class_name: "Recording", optional: true
  has_many :children, class_name: 'Recording', foreign_key: :parent_id
  delegated_type : recordable, types: %w[ Todo Todolist Todoset Dock ]

So instead of having multiple models sharing the same concerns and attributes, you have the Recording model that takes care of all of that (and that's a lot of something as you saw above, in
Any content user-created (Document, Todo, Todolist, etc.) is immutable: instead of updating it, they create a new version, and the recording points to that new version while you get to keep a track of the changes thanks to the Event class.

Now in this video, here there's a mention that copying is a lot faster thanks to this pattern.
They don't need a background job anymore to copy everything, but I don't really get why it's so much faster.
My understanding is that they don't have to copy the immutable objects, but they still have to duplicate the whole tree of recordings (the recording that points to the copied object as well as any of its descendants - other recordings that point to immutable objects related to the copied object), and they also need to duplicate things associated to the recording such as events or subscribers. It doesn't feel like there's a lot less to do.

Another thing I don't get is the children association part in the record method that you see here: I'm not sure what the children are supposed to be. They should be recordables but children is used for recording descendants. Also there's no recursion happening.

So that's where I left things so far, I'll have another look later but I thought you guys my have some interesting insights!