Ruby 클래스 메서드를 작고 집중적으로 유지하기

2804 단어 rubyrails
Ruby 프로그래밍의 이점 중 하나는 짧은 메서드를 작성하기 쉽다는 것입니다. 이는 서로 다른 메서드를 개별적으로 테스트하기 쉽기 때문에 유용합니다. 또한 가장 중요한 것은 클래스가 작은 메서드로 구성될 때 클래스를 읽기가 더 쉽다는 것입니다. 종종 잠시 후 프로그램으로 돌아가면 컨텍스트가 충분하지 않을 수 있으며 짧고 집중된 메서드를 작성하는 것이 도움이 됩니다.

예를 들어 내 Shopify 앱 중 하나에서 사용자가 워크플로에 여러 필터를 추가할 수 있습니다.

예를 들어 주문이 생성되면 워크플로 조건으로 주문을 확인한 다음 확인에 통과하면 그에 따라 태그를 추가해야 합니다. 각 조건에 대해 사용자가 AND(모든 조건이 일치해야 함) 또는 OR(모든 조건이 일치해야 함)를 추가했는지 확인한 다음 Shopify API를 호출하여 데이터를 가져와야 합니다.

저는 앱의 비즈니스 로직을 처리하기 위해 서비스 개체를 사용하는 것을 좋아합니다. 아래의 서비스 객체는 워크플로 조건이 통과되었는지 여부를 확인하는 객체입니다.

class CheckWorkflowConditions
  attr_accessor :shop

  def initialize(shop:, workflow:, order_id:)
    @shop = shop
    @workflow = workflow
    @order_id = order_id

    @filter_check_results = []
  end

  def passes?
    return false if no_filters?

    return atleast_one_filter_passes? if any_conditions_filter?
    return all_filters_passes? if all_conditions_filter?
  end

  private

  def no_filters?
    @workflow.filters.empty?
  end

  def any_conditions_filter?
    !all_conditions_filter?
  end

  def all_conditions_filter?
    @workflow.all_conditions
  end

  def atleast_one_filter_passes?
    @workflow.filters.each do |filter| 
      perform_filter_check(filter)
      break if includes_passed_filter?
    end
    includes_passed_filter?
  end

  def all_filters_passes?
    @workflow.filters.each do |filter| 
      perform_filter_check(filter)
      break if includes_failed_filter?
    end
    !includes_failed_filter?
  end

  def perform_filter_check(filter)
    @filter_check_results << CheckOrderWithFilter.new(shop: shop, order_id: @order_id, filter: filter).get_result
  end

  def includes_passed_filter?
    @filter_check_results.include?(true)
  end

  def includes_failed_filter?
    @filter_check_results.include?(false)
  end
end



CheckWorkflowConditions 서비스 개체는 Eloquent Ruby의 구성된 메서드 기술을 따랐습니다. 그건:
  • 각 메서드는 한 가지 작업을 수행합니다. no_filters? 메서드는 필터가 있는지 여부만 확인합니까? 마찬가지로 이 클래스의 다른 모든 메서드는 각각 한 가지 작업에만 집중합니다.
  • 각 방법은 단일 개념 수준에서 작동합니다. 높은 수준의 논리는 어떤 메서드의 세부 사항과도 섞이지 않습니다.
  • 각 메소드에는 기능을 지정하는 이름이 있습니다. 메서드 이름 종류는 메서드가 수행하려는 작업을 알려줍니다.

  • 위의 서비스 개체는 또한 각 메서드가 한 가지 방법만 있어야 한다는 조언을 따르지 않으므로 모든 논리가 메서드의 맨 아래에서 반환됩니다. passes? 메서드는 여러 반환 값을 갖지만 복합 기법을 따랐기 때문에 읽기 쉽고 이해하기 쉽습니다.

    또한 Shopify API 호출과 관련된 논리가 다른 서비스 개체CheckOrderWithFilter.new(shop: shop, order_id: @order_id, filter: filter).get_result에 위임되었습니다. 이렇게 하면 전체 수업이 워크플로 조건의 통과 또는 실패 여부를 확인하는 데 더 집중하여 테스트하기가 더 쉬워집니다.

    루비 코드 쓰기(및 읽기)는 클래스가 짧고 집중된 메서드로 구성될 때 더 즐거워집니다.

    이 게시물은 원래 Weightless에 게재되었습니다.

    좋은 웹페이지 즐겨찾기