introduction_to_trailblazer



introduction_to_trailblazer

0 0


introduction_to_trailblazer


On Github y-yagi / introduction_to_trailblazer

Trailblazer 入門

Ginzarb 第35回 / @y-yagi

Trailblazerとは

Trailblazer

Trailblazer

Trailblazer: A High-Level Architecture For The Web より引用

Trailblazer

  • 通常のMVCとは異なる層を提供する
    • Operation(サービスオブジェクト)、View Model(cells)、Form等
  • 各処理を適切な層に記載する事で、view / controller / modelがfatになるのを防ぐ
  • また、各層を疎結合にする事で各層毎でのテストをしやすくする

Trailblazer

  • Webフレームワークではなくて、あくまでWebフレームワークと一緒に使用する事を前提としたライブラリ
    • Rails + Trailblazer
    • Sinatra + Trailblazer
    • Grape + Trailblazer
    • Hanami + Trailblazer
    • etc
  • Trailblazer自体にWebフレームワークとしての機能は無い

何故 Trailblazerが必要なのか?

Rails辛い問題

Rails辛い問題

  • 気付くとfat controller
    • fat controllerを避けようとした結果、今度はmodelがfatになる
  • viewにビジネスロジックが記載されている
    • viewから直接DB参照してたり
  • ビジネスロジックをどこに書けば良いのかわからない
    • プロジェクト / 人毎にビジネスロジックを定義する場所がバラバラになる
  • etc

それらの問題を解決する為に作られたのがTrailblazer。 Rails標準では足りてない部分を補う。

MVCからドメインロジックを駆逐せよ

ここまで概要

Trailblazerのstackについて

Trailblazerのstack

Trailblazerのstack

  • trailblazer gemが提供するのは先の図でいうOPERATION部分
  • 基本的に機能毎に、gemが分かれている(View Modelはcell等)
    • 正確にはFORMもreform gemに分かれている
    • trailblazer gemのdependencyに含まれているのはreformだけ。後は必要に応じて追加する形。
  • gemはそれ単体で使用出来るようになっている
    • trailblazer gemは使用した事無くても、cellは使用した事ある、という人もといるのでは

Controller

  • HTTPのエンドポイントとしての処理のみを書く
    • リダイレクトやviewのrenderなど
  • 当然ビジネスロジックは書かない
class CommentsController < ApplicationController
  def new
    form Comment::Update
  end

  def create
    run Comment::Update do |op|
      return redirect_to comments_path(op.model)
    end

    render :new
  end
end

Model

  • Modelにはassociaton、scope、finderのみを定義する
  • 当然ビジネスロジックは書かない
  • callback / validationも書かない
class Comment < ActiveRecord::Base
  has_many   :users
  belongs_to :thing

  scope :recent, -> { limit(10) }
end

Operation

  • ビジネスロジックを定義する(service object)
  • modelを保存する処理を定義するのはOperationだけ
  • validation / callback / authorizationもOperationに含まれる
class Comment::Create < Trailblazer::Operation
  contract do
    property :body
    validates :body, length: {maximum: 160}
  end

  def process(params)
    if validate(params)
      ...
    else
      ...
    end
  end
end

Operation

Trailblazer: Trailblazer: Operationより引用

Form

contract do
  property :body
  validates :body, length: {maximum: 160}

  property :author do
    property :email
    validates :email, email: true
  end
end

Callback

  • operationクラスで実行するCallback処理を定義する
  • operationクラスに直接定義しても良いし、当然別ファイルに分けても良い
class Comment::Create < Trailblazer::Operation
  callback :after_save do
    # this is a Disposable::Callback::Group class.
  end
end
class AfterSave < Disposable::Callback::Group
  on_change :notify!
end

Policy

  • 認可処理
  • punditっぽく書ける
    • "policy class is heavily inspired by the excellent Pundit gem"との事
  • punditで書いたpolicy classをそのまま使う事も可能
class Thing::Policy
  def initialize(user, thing)
    @user, @thing = user, thing
  end

  def create?
    admin?
  end

  def admin?
    @user.admin == true
  end
  # ..
end

View Model

class Comment::Cell < Cell::ViewModel
  property :body
  property :author

  def show
    render
  end

  private
    def author_link
      link_to "#{author.email}", author
    end
end
<div class="comment">
  <%= body %>
  By <%= author_link %>
</div>

Views

  • view層はそのまま使える
  • ただ、パーツ毎にcellを使い、viewはシンプルな状態のままにしておくことが推奨されている
<h1>Comments for <%= @thing.name %></h1>

 This was created <%= @thing.created_at %>

   <%= concept("comment/cell",
   collection: @thing.comments) %>

Representer

class SongRepresenter < Representable::Decorator
  include Representable::JSON

  property :title
  property :track
end
SongRepresenter.new(song).to_json
#=> {"title":"Fallout","track":1}

その他gem

などもある

File Layout

  • classes, views, assets, policiesをまとめてconceptsディレクトリ配下におく
  • conceptsディレクトリはリリース毎に分ける

File Layout

File Layout

gemgem-trbrb: The Trailblazer book's example app.にTrailblazer本用のサンプルアプリがあるので、詳細はそちらを参照。

まとめ

  • "Trailblazer gives you a high-level architecture for web applications"
  • TrailblazerはMVCスタックにより適切な構成を構築する為の仕組み
  • trailblazer gem だけではなく、各層毎にgemが提供されている
    • まずはview model(cell)を入れてviewを綺麗にしていく、というようなアプローチも出来る

気になること

  • 学習コストの高さ
    • Webフレームワーク + Trailblazerになるので、最初の学習コスト高そう
    • どのくらいの規模になるとその学習コストがペイ出来るかは難しい
  • fat operationにならない?
    • callback / formを適切に分割出来れば大丈夫?
    • この辺りの勘所は実運用してみないとわからなそう

参考資料

END

Trailblazer 入門 Ginzarb 第35回 / @y-yagi