Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ApplicationController の継承を分割してエラーを減らした話/dividin...
Search
Masatoshi Moritsuka
March 01, 2024
Technology
410
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ApplicationController の継承を分割してエラーを減らした話/dividing-application-controller
Masatoshi Moritsuka
March 01, 2024
More Decks by Masatoshi Moritsuka
See All by Masatoshi Moritsuka
拙者、『型は欲しいが型は書きたくない』者たちとの和睦を結び、るびぃにおける型の領地安堵を実現せんと欲す者也 #sekigahara01/sekigahara01
sanfrecce_osaka
4
2.5k
Rails の CLI ツールの書き方/writing-rails-cli-tool
sanfrecce_osaka
0
59
Time.zone.parse('dark')/time-zone-parse-dark
sanfrecce_osaka
0
120
外部APIが絡むテストをちょっといい感じに書く/a-little-nice-writing-external-api-testing
sanfrecce_osaka
0
34
gem_rbs_collection へのコントリビュートから始める Ruby の型の世界/contributing-gem-rbs-collection
sanfrecce_osaka
0
610
Rails と人魚の話/rails-and-mermaid
sanfrecce_osaka
0
480
パターンマッチ使ってるかい?(kyobashi.rb)/use-ruby-s-pattern-matching-on-kyobashi-rb
sanfrecce_osaka
0
270
Input object ではじめる入力値検証/input-value-validation-using-input-object
sanfrecce_osaka
0
610
実例で学ぶRailsアプリケーションデバッグ入門 〜ログインできちゃってました編〜/rails-application-debug-introduction
sanfrecce_osaka
2
930
Other Decks in Technology
See All in Technology
ZOZOTOWNの進化と信頼性を両立する負荷試験
zozotech
PRO
2
170
脱金融のフューチャー・デザイン / Future Design Beyond Finance
ks91
PRO
0
150
ソニー銀行におけるビジネスアジリティ向上のためのクラウドシフト戦略
srenext
0
310
しぶいSRE: サーバから見えない障害にどう向き合うか。ラストワンマイルのデバッグ実践 / Shibui SRE
kanny
13
6.2k
ローカルLLMとLINE Botの組み合わせ その3 / LINE DC Generative AI Meetup #8
you
PRO
0
130
DMM.com 購入改善推進チーム におけるCodeRabbitを用いた レビューフロー改善の一例
ysknsid25
2
640
Road to SRE NEXTの今までとこれから
hiroyaonoe
0
350
Genie Ontologyは銀の弾丸かを考える / Is Genie Ontology a Silver Bullet?
nttcom
0
310
Compose 新機能総まとめ / What's New in Jetpack Compose
yanzm
0
280
環境凍結という Toil を倒す -セルフサービス型 Ephemeral テスト環境の 設計と実践
shirouz
1
2.4k
AI Coding Agent時代のcdk-nagガードレール 〜組織ルールを強制CIで守り抜く設計の挑戦〜
mhrtech
3
260
インフラと開発の垣根を超えていき!〜元AWSインフラエンジニアがAWS開発で奮闘している話〜
hatahata021
3
250
Featured
See All Featured
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
460
YesSQL, Process and Tooling at Scale
rocio
174
15k
Believing is Seeing
oripsolob
1
170
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
67
56k
The Invisible Side of Design
smashingmag
301
52k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
350
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Deep Space Network (abreviated)
tonyrice
0
220
Prompt Engineering for Job Search
mfonobong
0
370
Designing for Timeless Needs
cassininazir
1
350
ラッコキーワード サービス紹介資料
rakko
1
3.9M
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
350
Transcript
ApplicationController の 継承を分割して エラーを減らした話 森塚 真年(@sanfrecce_osaka) 2024/03/01 Wantedly x Qiita
Meetup #2 Ruby を用いたプロダクト開発 #wantedly_qiita_meetup
自己紹介 森塚 真年 GitHub: @sanfrecce-osaka Twitter(X): @sanfrecce_osaka Qiita: @sanfrecce_osaka from:
大阪府枚方市 趣味: コミュニティ・勉強会 株式会社エンペイ Ruby3.2/Rails7.0 Node.js v18/Vue.js 3.3/Vuetify 3.4
前提 : この発表での ApplicationController について 具象コントローラの基底クラスを ApplicationController と呼称 呼び分けが面倒なので便宜上 基底クラスを継承した基底クラスも
API の基底ク ラスも ApplicationController 長いので AC という略称も使います
本編
こんなことありませんか?
例 : mastdon(v4.2.8)
class ApplicationController < ActionController::Base # 略 # if/unless/only/except オプション 😇
before_action :store_referrer, except: :raise_not_found, if: :devise_controller? before_action :require_functional!, if: :user_signed_in? before_action :set_cache_control_defaults # skip_before_action 😇 skip_before_action :verify_authenticity_token, only: :raise_not_found # 略 end
# AC を継承した AC 😇 class Disputes::BaseController < ApplicationController #
略 # 継承先の AC で skip_before_action 😇 skip_before_action :require_functional! before_action :set_body_classes before_action :authenticate_user! before_action :set_cache_headers # 略 end
# AC を継承した AC を継承した AC 😇 class Settings::ApplicationsController <
Settings::BaseControl before_action :set_application, only: [:show, :update, :destroy, :regenerate] before_action :prepare_scopes, only: [:create, :update] # 略 end
module Settings module TwoFactorAuthentication class ConfirmationsController < BaseController # 略
# 具象コントローラで skip_before_action 😇 skip_before_action :require_functional! before_action :require_challenge! before_action :ensure_otp_secret # 略 end end end
つらい 😹 AC が関心を持ちすぎている 異なるユースケースの関心が含まれている リスコフの置換原則が守られていない 結果、色んなところで分岐が発生する
enpay でも頻発 障害 バグ 修正漏れ
どのように解決するのか 責務ごとに境界を区切る 境界ごとに AC を作成する AC の直接の親クラスは ActionController::Base API の場合は
ActionController::API 境界ごとにインターフェース( パス) を統一する
module や namespace で 境界を区切る resources :payments, module: :payments do
resources :histories end namespece: :account do resources :settings end
境界ごとに ApplicationController を作成
module Payments class ApplicationController < ActionController::Base before_action :validate_params before_action :authenticate_account!
before_action :authorize! # 略
private # 共通の振る舞いがない場合は空実装 def validate_params end def authorize! # 具象コントローラで共通の処理
end end end
module Accounts class ApplicationController < ActionController::Base # 重複は許容。共通化したい場合は module や
concern に切り出す before_action :validate_params before_action :authenticate_account! before_action :authorize! # 略
private # 共通の振る舞いがない場合は空実装 def validate_params end def authorize! # 具象コントローラで共通の処理
end end end
ユースケースごとに異なる場合 module Payments class HistoriesController < ApplicatonController # 略 private
# 共通の振る舞いがない場合はオーバーライド def validate_params # 具象コントローラ個別の処理 end def authorize! super # 共通処理を呼び出す # 具象コントローラ個別の処理 end
境界を切る基準 URL( パス) payments/{payment_id} URL( パス) をインターフェースと捉える 認証 認可 ロギング
キャッシュ エラー監視 layout の指定 etc
境界を分けていけば どの選択肢も選べそう! そのまま モジュラモノリス Rails エンジン
やってみて
うまくいったこと コードを読み書きする際に考えることが減った 疎結合 分岐減 単純な構成なので理解しやすい Sentry の通知や障害も減った AC で責務ごとの規約・関心を表現できる
一方
やりたかったこと id の部分のインターフェースを統一させたい module( ディレクトリ) ごとに AC を作りたい
# こう書けるとスッキリするが /payments/{payment_id} ではなく # /payments/{id} になる resources :payments, module:
:payments do # ここは /payments/{payment_id} resources :histories end
# param を使って指定すると /payments/{payment_id} になるが resources :payments, param: :payment_id, module:
:payments do # ここが /payments/{payment_payment_id} になってしまう resources :histories end
# これでもいけるけど # module: :payments を 2回 書くのも嫌なので・・・ resources :payments,
param: :payment_id, module: :payments resources :payments, only: [], module: :payments do resources :histories end
scope module: :payments do # 最終的にこんな形に resources :payments, param: :payment_id
resources :payments, only: [] do resources :histories end end
ご清聴 ありがとうございました
None