Introduction to Dependency Management for Service Objects

Welcome back! By now, you have learned how to set up a Rails app, create controllers, and manage views. In our last lesson, we discussed service objects and how they help keep the business logic separate from controllers. When solving the previous practices, you may have noticed that in some cases we declared the data in many functions of the service instead of making it more structural. Today, we're taking this a step further by looking into dependency management for service objects in Rails. Effective dependency management ensures that our services are modular, testable, and easier to maintain.

What You'll Learn

In this lesson, we'll explore how to manage dependencies within service objects. Specifically, we’ll look at how to use dependency injection to make your services more flexible and easier to test. Using our SandwichService example, you'll learn the specifics of constructing services with dependencies and see how this design improves code maintainability.

Here’s a preview of the SandwichService class we'll be diving into:

class SandwichService
  def initialize(bread: Bread.new, cheese: Cheese.new, grill: Grill.new)
    @bread = bread
    @cheese = cheese
    @grill = grill
  end

  def make_sandwich
    @grill.turn_on
    bread_name = @bread.get_name
    cheese_name = @cheese.get_name
    @grill.turn_off
    "Sandwich with #{bread_name} and #{cheese_name}"
  end
end

This SandwichService class illustrates a well-architected service object. It receives its dependencies (Bread, Cheese, and Grill) through initialization, promoting flexibility and easier testing.

Full Code Example

To understand how the SandwichService works in context, here is the complete code along with all the necessary files.

Sandwich Service Object

app/services/sandwich_service.rb

class SandwichService
  def initialize(bread: Bread.new, cheese: Cheese.new, grill: Grill.new)
    @bread = bread
    @cheese = cheese
    @grill = grill
  end

  def make_sandwich
    @grill.turn_on
    bread_name = @bread.get_name
    cheese_name = @cheese.get_name
    @grill.turn_off
    "Sandwich with #{bread_name} and #{cheese_name}"
  end
end

Bread Dependency

app/services/bread.rb

class Bread
  def get_name
    "Whole Wheat"
  end
end

Cheese Dependency

app/services/cheese.rb

class Cheese
  def get_name
    "Cheddar"
  end
end

Grill Dependency

app/services/grill.rb

class Grill
  def turn_on
    puts 'Grill is on'
  end

  def turn_off
    puts 'Grill is off'
  end
end

Usage_example (Controller or any place you use the service)

app/controllers/sandwiches_controller.rb

class SandwichesController < ApplicationController
  def create
    sandwich_service = SandwichService.new
    @sandwich = sandwich_service.make_sandwich
    render plain: @sandwich
  end
end

Routes

config/routes.rb

Rails.application.routes.draw do
  resources :sandwiches, only: [:create]
end
Why It Matters

Understanding dependency management in Rails is crucial for building scalable and maintainable applications. Good dependency management ensures that service objects are single-responsibility and can be reused across different parts of your application. It also makes the codebase easier to test, as dependencies can be mocked or stubbed during testing.

Benefits include:

  • Modularity: Keeping services modular makes it easier to update parts of your application without affecting others.
  • Testability: Injecting dependencies allows you to replace real objects with mocks or stubs, making unit tests more reliable and faster.
  • Maintainability: Clear separation of concerns and well-defined dependencies improve the readability and maintainability of your code.

By mastering dependency management for service objects, you will be able to write cleaner, more efficient, and easier-to-maintain code. Exciting, right? Let’s start the practice section and put these principles into action.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal