SOLID Ruby Code with Pub/Sub

If you are a programmer, very likely you've heard of pub/sub.

Today I am going to show you how this pattern can be useful when applied with one of the SOLID principles.

Imagine we have a user approval feature. After approving a user, an email must be sent and a job be triggered.

class UserApprovalsController < ApplicationController
  def create
    # ..
    UserApproval.new(user).call
  end
end
class UserApproval
  def initialize(user)
    @user = user
  end

  def call
    @user.approve!
    send_email
    trigger_job
  end

  private

  def send_email
    WelcomeMailer.notify(@user).deliver_later
  end

  def trigger_job
    HardWork.perform_later(@user)
  end
end

This code may seem ok, but the UserApproval class is doing so much and breaking the single responsibility principle (SRP), with time it can turn into a mess.

Let's refactor it to use the pub/sub pattern (through the Wisper gem):

class UserApprovalsController < ApplicationController
  def create
    # ..
    user.approve!
  end
end
class User < ActiveRecord::Base
  include Wisper::Publisher

  def approve!
    update(status: :approved)
    broadcast(:user_approved, self)
  end
end

Here I removed the UserApproval class and I am calling the approve! method directly on controller.

This method just updates the instance and broadcasts a message with a payload.

class NotifierListener
  def user_approved(user)
    WelcomeMailer.notify(user).deliver_later
  end
end
class HardWorkListener
  def user_approved(user)
    HardWork.perform_later(user)
  end
end

So, two distinct classes (subscribers) are responsible for doing just one thing each.

Our code now has less complexity, it's easier to test and maintain.

See you.

Written on April 11, 2017

Share: