Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Wrap every method with just one line

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Wrap every method with just one line

Feature Flag 基盤構築の一環として実装したサーバーサイドロジックの紹介です。
Ruby において include するだけですべての method をトラップして実装を差し込む手法を用いて、クライアントにサーバーサイドロジックの一部を確認/上書きできる用になります。

Avatar for Shimpei Otsubo

Shimpei Otsubo

January 31, 2020
Tweet

More Decks by Shimpei Otsubo

Other Decks in Programming

Transcript

  1. ©2020 Wantedly, Inc. Wrap every method With just another line

    Meguro.rb#30 Jan 31, 2020 - Shimpei Otsubo
  2. ©2020 Wantedly, Inc. Shimpei Otsubo @potsbo Developer Experience Squad, Wantedly,

    Inc. Kubernetes Dev Tools CI / CD AuthN / Z Productivity Dvorak
  3. ©2020 Wantedly, Inc. Thread.current resp header middleware ͲΜͳ஋Λ࢖͔ͬͨʁΛfeedback ͲΜͳ஋Λ࢖ͬͯ΄͍͔͠ʁΛࢦఆ Thread.current

    req header Header Λհͯ͠ methodͷධՁ஋Λ read /write )FBEFSͳͷͰNJDSPTFSWJDFͰ఻ൖՄೳ call return
  4. ©2020 Wantedly, Inc. class Experiment def self.enable?(name, target) # some

    consistent logic here end end Experiment.enable?(:show_new_button, current_user) # => true or false Wantedly ʹ͓͚ΔABςετͷํ๏ ಉҰͷuserʹରͯ͠͸ৗʹಉҰͷboolean͕ฦΔmethod
  5. ©2020 Wantedly, Inc. Thread.current͔Βuser͕ࢦఆͨ͠஋͕͋Ε͹ͦΕΛར༻ ͳ͚Ε͹Thread.currentʹར༻ͨ͠஋Λ٧ΊΔ class Experiment def self.enable?(name, target)

    # some consistent logic here end def self.wrapped_enable?(name, target) request_value = Thread.current[:request][name] return request_value unless request_value.nil? actual_value = enable?(name, target) Thread.current[:response][name] = actual_value end end ˞Thread.currentͱheaderͷؒΛͭͳ͙middlewareΛผ్༻ҙ
  6. ©2020 Wantedly, Inc. Renameͯͦ͠ͷ··࢖͑ΔΑ͏ʹ͢Δ class Experiment def self.real_enable?(name, target) #

    some consistent logic here end def self.enable?(name, target) request_value = Thread.current[:request][name] return request_value unless request_value.nil? actual_value = real_enable?(name, target) Thread.current[:response][name] = actual_value end end
  7. ©2020 Wantedly, Inc. ҰൠԽͯ͠ΈΔ class FeatureFlag def self.intercept(name) request_value =

    Thread.current[:request][name] return request_value unless request_value.nil? actual_value = yield Thread.current[:response][name] = actual_value end end class Experiment def self.real_enable?(name, target) # some consistent logic here end def self.enable?(name, target) FeatureFlag.intercept(name) do real_enable?(name, target) end end end ϒϩοΫͰғΈ͑͢͞Ε͹Ͳ͜Ͱ΋PWFSSJEFՄೳʂ
  8. ©2020 Wantedly, Inc. Helperͷ͍ΖΜͳmethod ͰػೳΛग़͠෼͚͍ͯ͠Δ৔ॴ͕͋Δ module I18nHelper # the new

    landing page currently supports only Japanese!! def show_new_landing_page? I18n.locale == :ja end end
  9. ©2020 Wantedly, Inc. ϒϩοΫͰғΉ͚ͩͰXSBQͰ͖Δ class FeatureFlag def self.intercept(name) ... end

    end module I18nHelper # the new landing page currently supports only Japanese!! def show_new_landing_page? FeatureFlag.intercept(:show_new_landing_page?) do I18n.locale == :ja end end end
  10. ©2020 Wantedly, Inc. ϒϩοΫͰғΉ͚ͩͰXSBQͰ͖Δ class FeatureFlag def self.intercept(name) ... end

    end module I18nHelper # the new landing page currently supports only Japanese!! def show_new_landing_page? FeatureFlag.intercept(:show_new_landing_page?) do I18n.locale == :ja end end end ຖճॻ͘ͷ͸ྲྀੴʹ໘౗
  11. ©2020 Wantedly, Inc. class FeatureFlag def self.intercept(name) ... end end

    module I18nHelper # the new landing page currently supports only Japanese!! def show_new_landing_page? FeatureFlag.intercept(:show_new_landing_page?) do I18n.locale == :ja end end end खಈͰίʔυΛ͍͡ΔͷͰ͸ͳ͘
  12. ©2020 Wantedly, Inc. class FeatureFlag def self.intercept(name) ... end end

    module I18nHelper include FeatureFlag def show_new_landing_page? I18n.locale == :ja end end *ODMVEF͚ͩͰղܾͰ͖ͨΒ޾ͤ Ұߦ௥Ճ͢Δ͚ͩʂʂ
  13. ©2020 Wantedly, Inc. Ͱ͖ΔΑ͏ʹͨ͠ module FeatureFlag def self.included(base) base.class_eval do

    extend ClassMethods @_already_patched = [] @_patch_target = base end end module ClassMethods def intercept(name) ... end def method_added(name) if !@_already_patched.include?(name) && self == @_patch_target orig_method_name = "_#{base}_orig".to_sym @_already_patched << name @_already_patched << orig_method_name alias_method orig_method_name, name
  14. ©2020 Wantedly, Inc. ॳظԽ module FeatureFlag def self.included(base) base.class_eval do

    extend ClassMethods @_already_patched = [] @_patch_target = base end end module ClassMethods def intercept(name) ... end def method_added(name) if !@_already_patched.include?(name) && self == @_patch_target orig_method_name = "_#{base}_orig".to_sym @_already_patched << name @_already_patched << orig_method_name alias_method orig_method_name, name ͲͷNPEVMFͰJODMVEFͨ͠ͷ͔͓֮͑ͯ͘
  15. ©2020 Wantedly, Inc. module ClassMethods def intercept(name) ... end def

    method_added(name) if !@_already_patched.include?(name) && self == @_patch_target orig_method_name = "_#{base}_orig".to_sym @_already_patched << name @_already_patched << orig_method_name alias_method orig_method_name, name private orig_method_name define_method(name) do |*args| intercept(name) do send(old_name, *args) end end end super end end end ͢ͰʹXSBQ͍ͯ͠ͳ͍͔ͷ֬ೝ
  16. ©2020 Wantedly, Inc. module ClassMethods def intercept(name) ... end def

    method_added(name) if !@_already_patched.include?(name) && self == @_patch_target orig_method_name = "_#{base}_orig".to_sym @_already_patched << name @_already_patched << orig_method_name alias_method orig_method_name, name private orig_method_name define_method(name) do |*args| intercept(name) do send(old_name, *args) end end end super end end end طଘ࣮૷ͷୀආ
  17. ©2020 Wantedly, Inc. module ClassMethods def intercept(name) ... end def

    method_added(name) if !@_already_patched.include?(name) && self == @_patch_target orig_method_name = "_#{base}_orig".to_sym @_already_patched << name @_already_patched << orig_method_name alias_method orig_method_name, name private orig_method_name define_method(name) do |*args| intercept(name) do send(old_name, *args) end end end super end end end 8SBQ࣮૷