Manager for customer billing and subscriptions in Rails I'm looking to get rid of a couple dependencies that I have a sneaking suspicion are present in the code that I'm writing.

Right now I have a service class that manages my subscriptions for part of my application in Rails. The problem is that we have Recurly as our management platform right now, but I don't know if we will keep this in 6 months, 12 months, 5 years, etc. So there is an inherent dependency in place for this that I want to try to eliminate.

Additionally, I have a couple lines that I've added to manage updating subscription status for plans on our ActiveRecord models that I think might be adding some additional complexity to the class that I don't know if that's a good practice or if there is another pattern I should be following.

  module Tollbooth
      class Manager
        include Tollbooth::Querying

        attr_reader :business

        def initialize business
          @business = business
        end

        ##################################################
        # Customer and plan details
        ##################################################

        def on_trial?
          current_subscription.trial_ends_at &amp;&amp; current_subscription.trial_ends_at &gt;= Time.zone.now
        end

        def trial_ends
          current_subscription.trial_ends_at
        end

        def next_billing_date
          current_subscription.current_period_ends_at
        end

        def set_to_expire?
          current_subscription &amp;&amp; current_subscription.canceled_at.present?
        end

        def current_subscription
          @current_subscription ||= Recurly::Subscription.find(business_subscription_uuid)
        end

        def pending_subscription
          return(@pending_subscription) if defined?(@pending_subscription)
          @pending_subscription ||= begin
            current_subscription.pending_subscription
          rescue Recurly::Resource::NotFound
            nil
          end
        end

        def current_plan
          @current_plan ||= Recurly::Plan.find(current_subscription.plan_code)
        end

        def pending_plan
          @pending_plan ||= Recurly::Plan.find(pending_subscription.plan_code)
        end

        def billing_info
          @billing_info ||= account.billing_info
        end

        def transactions
          account.transactions
        end

        ##################################################
        # Changing plan details
        ##################################################

        def change_subscription_to code
          current_amount  = current_plan.unit_amount_in_cents['USD']
          future_amount   = Recurly::Plan.find(code).unit_amount_in_cents['USD']
          timeframe       = current_amount &gt; future_amount ? 'renewal' : 'now'
          success, result = query(current_subscription, :update_attributes, { plan_code: code, timeframe: timeframe })
          business.update(plan: Plan.where(plan_code: code).first) if success
          # The above line is one where I'm not sure if this is how I should be doing this since Plan is another ActiveRecord model
          success
        end

        def start_subscription code
          success, result = query(account.subscriptions, :create, { plan_code: code })
          business.update(subscription_uuid: result.uuid, subscription_state: 'active', plan: Plan.where(plan_code: code).first) if success
   # The above line is one where I'm not sure if this is how I should be doing this since Plan is another ActiveRecord model
          success
        end

        def cancel_subscription
          success, result = query(current_subscription, :cancel)
          success
        end

        def reactivate_subscription
          success, result = query(current_subscription, :reactivate)
          success
        end

        def destroy
          account.destroy
        end

      end
    end
I think the real test of this architecture is the refactoring effort involved in moving away from Recurly. Ideally, you'd just need to rewrite your service layer classes, and none of the rest of your application.

The only major issue I see here is you've got a bunch of public methods that are returning Recurly business objects, which could allow you to couple your entire system to Recurly. Without seeing the rest of the code, I would mark all methods that return Recurly business objects as private or protected, and only expose the methods that are transactional in nature --- and even then I would limit the arguments and return values of those methods to primitive values, or business objects written by your team for this application.

There is one minor nitpick, though. The class name Tollbooth::Manager doesn't really communicate what it does. You describe this as a "service class", so why not name it accordingly: Tollbooth::SubscriptionService or Tollbooth::SubscriptionManager. Normally I would steer people away from naming classes "SomethingManager", but this class does indeed appear to manage things, so I think the "Manager" suffix works here.

If the rest of your application needs data provided by Recurly, I would recommend creating your own classes to represent that data, and then map them over from the Recurly objects (also known as Data Transfer Objects). This would provide a layer of decoupling in case you switch subscription providers in the future.