Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

코드는 어디로 가나요?

Rails 튜토리얼을 마치고 자신만의 앱을 시작한 후에는 상황이 혼란스러워집니다. CRUD가 아닌 일반 논리는 어디로 가나요? Twitter에서 팔로어를 확보하는 것이 MVC에 어떻게 적합합니까? 두 사람에게 물어보면 네 가지 답을 얻을 수 있습니다. 또는 당신의 스레드는 책상에 머리를 부딪치는 동안 몇 시간 동안 서로를 모욕하는 똑똑한 사람들로 이어집니다. 어느 쪽이든, 당신은 두통으로 남아 있습니다.

일부 없이는 꿈꿔오던 앱을 구축할 수 없습니다. 일반, 비 Rails 논리. 그렇다면 코드를 어디에 두고 간단하게 유지하시겠습니까?

시작하기 쉬운 곳

기존 ActiveRecord 모델과 관련이 있다고 생각되는 논리가 있으면 먼저 해당 모델에 적용하겠습니다. 예를 들어 Game 모델을 만들고 CSV 파일에서 많은 게임을 가져오고 싶었습니다. 그 방법을 Game 클래스:

앱/모델/game.rb
class Game < ActiveRecord::Base
  def self.parse_from_csv(csv_string)
    games = []
    CSV.parse(csv_string, quote_char: "'") do |row|
      games << Game.from_csv_row(row) if (row[0] == 'G')
    end
    games
  end

  def self.from_csv_row(row)
    Game.new({
      dgs_game_id: row[1],
      opponent_name: row[2],
      created_at: row[4],
      updated_at: row[4],
    })
  end
end

분석법에 필요한 모든 정보를 바로 사용할 수 있습니다. 쉽게 테스트할 수 있습니다. 그리고 아마도 새로운 기여자가 해당 로직을 먼저 찾는 곳일 것입니다.

하지만 계속해서 그 모델을 추가하고 변경하면 크고 복잡해집니다. 모델의 다른 부분은 이상한 방식으로 상호 작용합니다. 더 많이 변경할수록 변경하기가 더 어려워집니다.

이 경우 해당 코드를 비 ActiveRecord 모델로 리팩터링하고 싶을 것입니다.

비 ActiveRecord 모델

Rails 앱에 있다고 해서 Active/Action에서 상속받아야 한다는 의미는 아닙니다.

일반 Ruby 개체에서 고유한 Ruby 코드를 작성하고 Rails 앱에서 사용할 수 있습니다. 이러한 개체는 문제의 일부를 모델링하기 때문에 여전히 모델이라고 할 수 있습니다. 데이터를 저장하는 ActiveRecord 데이터베이스가 없을 뿐입니다.

다음에 내가 그 게임 CSV 파서에서 작업했을 때 Game 수업이 너무 많아졌습니다. 그래서 파서 로직을 자체 GameCSVParser로 옮겼습니다. 수업.

전체 커밋이 여기에 있지만 비 ActiveRecord 클래스는 다음과 같습니다.

앱/모델/game_csv_parser.rb
class GameCSVParser

  def initialize(csv_string)
    @rows = CSV.parse(csv_string, quote_char: "'")
  end

  def games
    game_rows.map { |row| Game.new(game_attributes(row)) }
  end

  private

  def game_rows
    @rows.select { |row| is_game_row?(row) }
  end

  def game_attributes(row)
    {
      dgs_game_id: row[1],
      opponent_name: row[2],
      created_at: row[4],
      updated_at: row[4],
    }
  end

  def is_game_row?(row)
    row[0] == 'G'
  end
end

추가하는 로직이 특정 ActiveRecord 모델과 관련이 없다고 생각되면 바로 새로운 일반 Ruby 객체를 생성하겠습니다. 또는 코드가 앱에 아직 존재하지 않는 것의 일부인 것처럼 보이는 경우. 그렇지 않으면 대부분 리팩토링을 통해 나타납니다.

일반 Ruby 객체를 사용하면 무엇이든 작성할 수 있습니다. 하지만 무엇이든 쓸 수 있다는 사실을 알고 방향에 도움이 되지 않습니다. 어떤 방법이 필요합니까? 모든 새 개체는 어떻게 상호 작용합니까?

많은 Rails 앱이 동일한 카테고리를 사용합니다. 일반 Ruby 개체의. 이러한 범주는 다른 개발자가 인식할 수 있는 코드를 작성하기 위해 따를 수 있는 패턴입니다. 이미 몇 가지에 대해 들어보셨을 것입니다.

서비스 개체, 발표자 및 작업

서비스 개체, 발표자 및 작업에는 특별한 것이 없습니다. 그것들은 인식할 수 있는 특정한 방식으로 작동하는 단순한 Ruby 객체입니다.

예를 들어 작업 요청 perform이 있는 일반 Ruby 클래스입니다. 메소드 및 @queue :

app/workers/fetch_games_for_player.rb
class FetchGamesForPlayer
  @queue = :default

  def self.perform(player_id)
    player = Player.scoped_by_id(player_id).ready_for_fetching.first
    player && player.fetch_new_games!
  end
end

perform 작업이 실행될 때 호출됩니다.

발표자 보기 내에서만 의미가 있는 코드가 있는 일반 Ruby 개체입니다.

앱/프레젠터/user_presenter.rb
class UserPresenter
  def show_related_users?
    @user.related.count > 3
  end
end

또한 Rails의 보기 도우미를 포함하거나 보기의 편의를 위해 몇 가지 다른 개체를 하나의 통합 개체로 취급할 수도 있습니다.

서비스 개체 수행하려는 프로세스를 나타내는 일반 Ruby 객체입니다. 예를 들어 게시물에 댓글을 작성하는 것은 다음과 같습니다.

  1. 댓글을 남겨주세요.
  2. 게시물 작성자에게 알림 메일을 보냅니다.

서비스 개체는 두 가지를 모두 수행할 수 있으며 해당 논리를 컨트롤러에서 제외할 수 있습니다.

여기에 서비스 개체에 대한 훌륭한 이해가 있습니다. 예제로 가득 차 있습니다.

간단한 프로세스의 경우 서비스 개체에 신경 쓰지 않습니다. 그러나 컨트롤러가 너무 무거워지기 시작하면 추가 논리를 배치하기에 좋은 위치입니다.

이러한 패턴을 사용하여 고유한 비즈니스 논리를 구성할 수 있습니다. 그것들은 그저 평범한 Ruby 객체이지만, 특정한 특징을 공유하고 이름이 있으며 다른 개발자와 이야기할 수 있는 Ruby 객체입니다.

어디서 시작합니까?

Rails가 아닌 비즈니스 로직이 갈 수 있는 다양한 위치가 있습니다. 선택하기 어려울 수 있습니다. 제가 하는 일은 다음과 같습니다.

  1. 논리가 대부분 기존 클래스와 관련이 있는 경우 ActiveRecord 모델이더라도 해당 클래스에 넣습니다.
  2. 기존 클래스에 맞지 않으면 로직을 담을 새로운 일반 Ruby 클래스를 만듭니다.
  3. 논리가 아직 존재하지 않는 것의 일부여야 한다고 생각되면 이를 위한 새로운 일반 Ruby 클래스를 만듭니다.
  4. 나중에 코드로 돌아와서 모델이 너무 복잡해지거나 해당 모델에서 코드가 더 이상 의미가 없으면 자체 일반 Ruby 클래스로 리팩토링하겠습니다.
  5. 코드가 보기에서만 의미가 있다면 도우미에 추가하거나 발표자를 만들겠습니다.
  6. HTTP 요청 중에 코드를 실행할 필요가 없거나 백그라운드에서 실행해야 하는 경우 작업에 들어갑니다.
  7. 프로세스의 여러 다른 모델이나 단계를 저글링하고 컨트롤러를 이해하기 너무 어렵게 만드는 경우 서비스 개체에 넣습니다.

당신은 어떤가요? 코드는 어디로 가나요? 그리고 이 외에 도움이 된 패턴이 있습니까? 댓글을 남겨 알려주세요.

아직 프로세스가 없으면 내 프로세스를 시도하십시오. 그것이 당신에게 어떻게 맞는지보십시오. 코드를 작성하는 완벽한 방법은 없지만 막혔을 때 이와 같은 프로세스가 시작하는 데 도움이 됩니다.