Deprecation in Rails: How to gracefully remove old code

Today, we're going to talk about something that affects every project with a long history: old code. Instead of ignoring it or deleting it in a panic, we can manage it in a civilized way. This is called deprecation and is a super important practice that keeps our code base healthy and organised. In the Rails world, we have a powerful tool for this: ActiveSupport::Deprecation.

Why not delete it immediately?

Before we start looking at the code, let's think about why we should bother with deprecation at all. When working in a team or creating a library that others use, suddenly removing a method can break the application at the most unexpected moment. Deprecation is like putting up a "Diversion" sign. It gives other programmers time to adapt to changes while clearly communicating that the old route will soon be closed. It's professional, polite and saves you from many headaches.

ActiveSupport::Deprecation in practice

In Rails, we have the ActiveSupport module, which is a treasure trove of useful tools. One of these is the class Deprecation, created specifically to handle this process. Let's see how it can be used in practice, based on the notes you provided.
Suppose that in our application we had a method called pending_amount, but in the course of refactoring we changed its name to pending_balance because it better reflects what it does. We want everyone to start using the new name, but we don't want the old code to stop working overnight.
First, let's create a central location for our deprecation mechanism. This is a good practice that allows for consistency in the messages throughout the application.

# lib/my_rails_app_name.rb
module MyRailsAppName
  def self.deprecator
    # Initialize a new Deprecation instance.
    # The first argument is the version in which we plan to remove the old method.
    # The second is the name of our application or library.
    @deprecator ||= ActiveSupport::Deprecation.new('1.0', 'MyRailsAppName')
  end
end

This means we have one place to manage our 'alarm'. Now let's use it in the model. Let's assume that our method is in the Account class.

# app/models/account.rb
class Account < ApplicationRecord
  # This is our new, shiny method
  def pending_balance
    # ... complex business logic ...
  end

  # We create an alias so that the old method name (`pending_amount`)
  # still works, but actually calls the new method.
  alias_method :pending_amount, :pending_balance

  # And now the most important part: we mark the old method as deprecated.
  # Whenever a developer uses `account.pending_amount`,
  # a warning will appear in the logs that they should use `pending_balance`.
  deprecate pending_amount: :pending_balance, deprecator: MyRailsAppName.deprecator
end

And that's it! The process is simple, but extremely powerful. When another developer (or you in six months' time) calls the pending_amount method, a clear message will appear in the console in the style of: DEPRECATION WARNING: pending_amount is deprecated and will be removed from MyRailsAppName 1.0. Use pending_balance instead. This is a clear signal: 'Hey, it still works, but change it at the earliest opportunity!'

Summary

Managing the lifecycle of code is a key skill for a seasoned engineer. Using deprecation with ActiveSupport::Deprecation in Rails applications is a simple and elegant method that allows API evolution without revolution. It gives time for adaptation, keeps the code clean and promotes good communication within the team. Next time you want to remove something, think twice – maybe it's better to deprecate it first?

Happy deprecating!