The "What" and "Why" or How We are hiding those ugly IF's in our Service Objects
Tags: ruby, rails, 5days5blogposts
Published: 2021-04-20 10:32:24

---
title: The "What" and "Why" or How We are hiding those ugly IF's in our Service Objects
published: true
description: The "What" belongs to `perform` public method and the "Why"s reside in private methods.
tags: Ruby, Rails, 5days5blogposts
---

We use [Service Objects](https://dev.to/joker666/ruby-on-rails-pattern-service-objects-b19) to encapsulate and organize business domain logic in our Rails applications. But how do we organize the "What" and "Why" within a single Service Object?

The "What" and "Why"? What do I mean? I hope the following code bites makes clear my point here.

### Before
```ruby
class Customers::CreateService < ApplicationService
  def initialize(customer_params)
    @customer_params = customer_params
  end

  def perform
    @customer = Customer.new(@assignment_params)
    if @customer.save
      sync_customer if TestApp.config[:sync_enabled]     
      create_qualified_notification if @customer.status_qualified?
      create_twilio_proxy_session if TestApp.config[:proxy_enabled]
      Result.new(@customer, true)
    else
      Result.new(@customer, false)
    end
  end

  private

  def sync_customer
    ...
  end

  def create_qualified_notification
    ...
  end

  def create_twilio_proxy_session
    ...
  end
end
```

As you can see in this before version of our Service Object we are mixing the "What" and "Why" within the `perform` public method. We are putting what the perform method does when a customer is created, for example, it creates a qualified notification, but we are also putting the "Why" here, it is, we are creating the qualified notification because the customer is being created with `qualified` status.

The "What" is what the Service Object does and the "Why" is the control-flow logic.

### After
```ruby
class Customers::CreateService < ApplicationService
  def initialize(customer_params)
    @customer_params = customer_params
  end

  def perform
    @customer = Customer.new(@assignment_params)
    if @customer.save
      sync_customer     
      create_qualified_notification
      create_twilio_proxy_session
      Result.new(@customer, true)
    else
      Result.new(@customer, false)
    end
  end

  private

  def sync_customer
    if TestApp.config[:sync_enabled]
      ...
    end
  end

  def create_qualified_notification
    if @customer.status_qualified?
      ...
    end
  end

  def create_twilio_proxy_session
    if TestApp.config[:proxy_enabled]
      ...
    end
  end
end
```
As you can see in the after version we are moving the control-flow logic, the "Why", to the private methods and keeping only the "What" in the `perform` public method:

```ruby
 sync_customer     
 create_qualified_notification
 create_twilio_proxy_session
```

The argument for this is that anyone from our team or future me can read the `perform` method and reason about what it is trying to accomplish faster because it's just the "What".

*Much of the credit goes to [JP](https://github.com/jeanpaulsio) for recommending this "What" and "Why" separation in a code review*