Slide 1

Slide 1 text

Building Rails with Trailblazer, The Good, Bad and Ugly 開拓拓者們建立鐵道的辛酸⾎血淚淚史

Slide 2

Slide 2 text

Why This Talk? Share some experience Collect insights from people here Make some friends Free conference tickets

Slide 3

Slide 3 text

@wenchuan_lin

Slide 4

Slide 4 text

1 Experience with Ruby?
 3 Form Object?
 Service Object? 2 Experience with Rails? 4 Trailblazer(TRB)?

Slide 5

Slide 5 text

Controller def create run Song::Create do |result| redirect_to songs_path(result["model"]) end render :new end def create authorize! :create, Song @song = Song.new(params[:song]) if @song.save current_user.increment_song_counter redirect_to @song else render :new end end Rails Rails With TRB

Slide 6

Slide 6 text

Model class Song < ActiveRecord::Base has_many :authors end class Song < ActiveRecord::Base has_many :authors validates :name, :author, presence: true after_save :notify_author end Rails Rails With TRB

Slide 7

Slide 7 text

TRB Operation class Song::Create < Trailblazer::Operation step Model( Song, :new ) step Policy::Pundit( Policy, :create? ) step Contract::Build( constant: Song::Create ) step Contract::Validate() step Contract::Persist() fail Notifier::DBError step :update_song_count! step :notify_author def update_song_count!(options, current_user:, **) current_user.increment_song_counter end def notify_author!(options, **) #… end end class Song::Create < Reform::Form property :name validate :name, presence: true end Reform

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

The Advanced Business Logic Framework It extends the basic MVC pattern with new abstractions.

Slide 10

Slide 10 text

Then Why Trailblazer?

Slide 11

Slide 11 text

Story • Huge Web Form • Complicated Associations between Models • Increasing Requirements and Features

Slide 12

Slide 12 text

The Decision ✅ Great Fit to Our Scenario ✅ Integration with Rails (Validation / I18n) ✅ Online Documentation / Book ✅ Incrementally Adoptable

Slide 13

Slide 13 text

2016 Q3 - Kickoff / Initial commit 2017 Q1 - Only 3 Operations Created... 2017 Q2 - 2 Core Business Concepts Migrated 2017 Q4 - EmailMessage 2018 Q2 - OnlineAppForm Now... TimeLine

Slide 14

Slide 14 text

7xx Classes, 5x Concepts Business / Utils / Migration….

Slide 15

Slide 15 text

Obstacles

Slide 16

Slide 16 text

::call !"" ::build_operation # !"" #initialize # # !"" #setup! # # # !"" #assign_params! # # # # # !"" #params! # # # !"" #setup_params! # # # !"" #build_model! # # # # !"" #assign_model! # # # # # !"" #model! # # # # !"" #setup_model! # !"" #run # # !"" #process Callstack in Operation Too many….

Slide 17

Slide 17 text

DSL in Trailblazer-Rails Form / Present / Call / Run…..

Slide 18

Slide 18 text

You need more than Book / Documentation But Sometimes the source code is difficult to trace - Trailblazer - Trailblazer-operation - Trailblazer-rails - Trailblazer-loader - Reform / Reform-Rails - Disposable / Twin - Cell - ……

Slide 19

Slide 19 text

Getter, Setter Reform #to_nested_hash #deserialize! ActiveModel #attributes #assign_attributes

Slide 20

Slide 20 text

*main process of Reform object
 **alias method for #valid?
 #valid? 
 Method (A) #validate Method (B) #validate_with Method(C) Reform ✅ * ✅ ❎ ActiveModel ✅ ** ✅ ✅ Validation Layer

Slide 21

Slide 21 text

Populate In Reform songs: [ {name: "Midnight Rendezvous"}, {name: "Information Error"} ] class Song < ActiveRecord::Base belongs_to :album end class Album < ActiveRecord::Base has_many :songs end class AlbumForm < Reform::Form collection :songs, populate_if_empty: Song do property :name end end

Slide 22

Slide 22 text

Miscellaneous I18n Scope / Simple Form / Form builder / Trailblazer Loader

Slide 23

Slide 23 text

def update fail 'Invalid submit value' if !params[:complete].present? && !params[:update].present? obj = resource_instance obj.assign_attributes(items_completion_params) if params[:update] ? obj.save : obj.complete_items respond_to do |format| format.html { redirect_to obj, notice: "#{params[:commit]} successfully completed." } format.json { render json: {status: :ok} } end else if params[:update] respond_to do |format| format.html { redirect_to obj, alert: obj.errors.full_messages.join(', ') } format.json { render json: {status: :bad_request, msg: 'Failed to update remark'} } end else flash.now[:alert] = 'Failed to complete' obj.items.select(&:_complete).each { |i| i.status = Dealing::STATUS_DEALING } render :edit end end end Revisit, Refactor, Rewrite def update result = Dealing::Save.call(params) if result.success? # ... elsif result['complete.failure?'] flash.now[:alert] = 'Failed to complete' render :edit else # ... end end class Dealing::Save < Trailblazer::Operation step Model( Song, :find ) step Nested { :build! } step Contract::Build( constant: Dealing::Update ) step Contract::Validate() step Contract::Persist() #=> save failure :error! def build!(options, params:, **) if params[:complete].present? Dealing::Complete elsif params[:update].present? self.class else fail 'Invalid submit value' end end end class Dealing::Complete < Trailblazer::Operation step Contract::Build( constant: Dealing::Complete ) step Contract::Validate() step Contract::Persist() #=> complete_items failure :error! failure :revert_status! def revert_status!(options, **) #... end end Save Complete

Slide 24

Slide 24 text

What do we get from Trailblazer?

Slide 25

Slide 25 text

Cost • Another framework / DSL to learn • Sometimes it is not so friendly to Rails • The part of document is incomplete • Debug is harder than before

Slide 26

Slide 26 text

The Benefits

Slide 27

Slide 27 text

Easy to Test Manual / Automation

Slide 28

Slide 28 text

Business Process Driven Process Builder / Policy / Concept Folder

Slide 29

Slide 29 text

Maintainability Separation of Concerns

Slide 30

Slide 30 text

Resilient Team Respond to Change / Build Convention

Slide 31

Slide 31 text

That’s IT? Tips of Technology Adoption

Slide 32

Slide 32 text

Goal Oriented Set a Goal in Early Stage, and Retrospective

Slide 33

Slide 33 text

1 Training / Team Support Discussion / Code Review / Pair Programming

Slide 34

Slide 34 text

34 Be a Evangelist 守、破、離 / Keep improving

Slide 35

Slide 35 text

More than a Tool / Framework Level Up the Mindset

Slide 36

Slide 36 text

Conclusion

Slide 37

Slide 37 text

No Conclusion Just some friendly advice …..

Slide 38

Slide 38 text

Separate Business⚡ Persistence Layers

Slide 39

Slide 39 text

Step-Wise, Keep Pushing

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

Ruby, Rails, Trailblazer

Slide 42

Slide 42 text

Thank you