All lessons

Spot the Tax · Card 19 of 20

When the controller knows about every downstream concern

Why a create action that fires payment, inventory, email, analytics, and Slack inline becomes a coordination nightmare.

The code

What will this cost you in six months?

class OrdersController < ApplicationController
  def create
    order = Order.create!(order_params)

    PaymentService.charge(order)
    InventoryService.reserve(order)
    OrderConfirmationMailer.with(order: order).deliver_later
    AnalyticsService.track(order, "order_placed")
    SlackNotifier.notify_sales(order) if order.total_cents > 1_000_00
    AffiliateService.credit(order) if order.referrer_code.present?

    redirect_to order
  end
end

The problem

Every concern that runs after an order is placed lives in this controller. Adding loyalty points means editing this controller. Adding fraud screening means editing this controller. Every team that wants to do something when an order is placed has to come and add a line. The action becomes a junk drawer of unrelated calls, and any failure in one of them risks taking down the others or leaving the system in an inconsistent state.

Take a moment. Before revealing, ask yourself how you'd let other parts of the app react to an order being placed without the controller having to know about each one.