More Related Content Similar to クラウドワークス プロダクトの持続的開発のためのリファクタリング実践アプローチ (20) クラウドワークス プロダクトの持続的開発のためのリファクタリング実践アプローチ2. CrowdWorks Inc. Product Div.
アジェンダ
1. 弊社紹介
2. 目的・課題
3. Fat Modelの技術的負債
4. 解決方法
4.1. 設計手法
4.2. Fat Modelの弱点
4.3. 構造Before/After
4.4. 分析手法
4.5. 作戦方針
4. CrowdWorks Inc. Product Div.
サービス紹介
オンラインで直接つながり
マッチング
仕事依頼
業務実行・納品
発注者=クライアント
(企業・個人)
40万社
受注者=クラウドワーカー
(主に個人)
240万人
6. CrowdWorks Inc. Product Div.
リファクタリングは力学的にどうしても後手後手になりやすい。
そのためリファクタリング専門チームを創設。
チーム人数:2名
意図:既に発生したバグを退治するのは本当のバグ退治ではない。そもそもバグが生ま
れない構造に作り変えるのが真のバグ退治。
リファクタリング専門チーム「バグハンター」
9. CrowdWorks Inc. Product Div.
解決したい課題
課題 狙う効果
開発生産性 コード変更にあたり、コード分析コストや変更
検討コストが大きく、生産性に課題。
リファクタリングにより理解容易性向上、影響範
囲局所化等を狙い、開発生産性を高める。
エンジニアス
キル
粗悪な設計は質の高い設計導入を阻む。
エンジニアが粗悪な設計を真似、学習する可
能性があり、スキル低下の要因に。
リファクタリングにより質の高い設計の導入を
容易にする。
お手本となるコードによりエンジニアのスキル
向上を狙う。
製品の
信頼性
バグを埋め込みやすい構造。重大インシデ
ント化した場合、製品の信頼性を毀損。
バグを埋め込みにくい構造へ昇華させ、弊社の
持続可能成長性を向上させる。
10. CrowdWorks Inc. Product Div.
現状の構造的課題
View
Controller
(Skinny Controller)
ActiveRecord
(Fat Model)
Fat Modelが大量に存在する。
Railsのお作法ではFat Modelがある
べき姿なのかも知れない。
しかし巨大化複雑化しすぎていて、生
産性低下を招いている。
12. CrowdWorks Inc. Product Div.
Fat Modelが抱える技術的負債
技術的負債 説明
関連コードの
散在(低凝集)
本来業務概念的に関連し合うコードが、様々なクラスにあちこちに
散在している。
あるモデルに対する処理が全く別のモデルに書かれているなど、
責務外の実装が多い。
コードの追跡が困難。
コピペコード 同じ制御コードが至るところにコピペしてある。仕様変更に弱く、修
正漏れがあるとバグ化。
意図不明な
コード
何をやらせたいのか意図不明なコード。
理解や修正を妨げる。
13. CrowdWorks Inc. Product Div.
Fat Modelが抱える技術的負債
技術的負債 説明
うねるコード 条件分岐(if, case-when)やループ制御(each do)などが多重に
ネストしており、遠くから見るとうねっているように見えるコード。複
雑で理解困難。
共通化に反する
Concern
共通処理の定義に便利なConcernに、respond_to?やis_a?な
ど特定クラスの場合の条件分岐が大量に入り込んでいて、共通
化に反している。複雑な上、Concernをincludeしているクラス全
てに変更影響があり触ると危険。
異なるコンテキス
トの混在
ActiveRecordにあらゆるコンテキストの実装が入り込んでいて、
巨大化の主要因になっている。
17. CrowdWorks Inc. Product Div.
武器となる設計手法
手法 説明 対応負債
ValueObject ある特定の値と、その演算ロジックをカプセル化する設計パ
ターン。業務概念ごとの高凝集化の基本。
消費税、システム利用料など。
・低凝集
・コピペコード
composed_of ActiveRecordのカラムをValueObjectへマッピングする
Railsの構文。カラムを操作するロジックを ValueObjectへ
委譲できる。
同上
ユビキタス言語 チームで概念認識を合わせるために共有する言葉。
対象ドメインの業務概念の認識合わせに用い、ソースコード
上の命名でも表現する。
・意図不明なコード
18. CrowdWorks Inc. Product Div.
武器となる設計手法
手法 説明 対応負債
FirstClass
Collection
ループ制御(each doなど)をカプセル化するパターン。 ・うねるコード
RuleObject 複雑な条件分岐をカプセル化するパターン。 ・うねるコード
Strategy
(区分Object)
case-whenで処理切替するロジックを単純化するパターン。
case-whenの条件分岐コピペを削減する。
・コピペコード
・うねるコード
・共通化に反する
Concern
境界付けられた
コンテキスト
概念(モデル)は状況(コンテキスト)によって意味や扱いが異
なる場合が多々ある。システムを取り巻くコンテキストを分析
し、各コンテキストに即した特化型ドメインオブジェクトを設計
する。
・異なるコンテキストの混
在
21. CrowdWorks Inc. Product Div.
弱点部位
弱点 説明 難易度 用いる設計手法
クラスメソッド そのクラスにいなくても良いメソッド。
結合度が低く、ValueObjectとして容易に引き剥がす
ことが可能。
簡単 ValueObject
privateメソッド 定義クラスからしかコールされないため、依存度は低
め。
依存パラメータをコンストラクタで渡すようにすれば
privateメソッドごとValueObject化可能。
やや簡単 ValueObject
ローカル変数 演算の途中経過を格納している中間成果物であること
多い。
中間成果物を、成果物を得る演算処理とまとめて
ValueObject化する。
やや簡単 ValueObject
22. CrowdWorks Inc. Product Div.
弱点部位
弱点 説明 難易度 用いる設計手法
うねるコード 条件分岐やループ制御で多重にネストしたコー
ド。
ループ制御はFirstClassCollection化し、条件
分岐はRuleObject化する。
やや簡単 ・FirstClassCollection
・RuleObject
has_many ActiveRecordのhas_manyで関連付けられた
コレクションに対するループ制御を、
FirstClassCollection化する。
やや簡単 ・FirstClassCollection
case-when case-when分岐(特に分岐コピペ)をStrategy
化する
中 ・Strategy
23. CrowdWorks Inc. Product Div.
弱点部位
弱点 説明 難易度 用いる設計手法
ActiveRecordの
カラム
Railsのcomposed_ofでValueObject化が可
能。ActiveRecord上のロジックを
ValueObjectへ委譲できる。
これができれば理想的には ARから永続化以外
のほとんどのロジックを一掃可能!
難しい composed_of
26. CrowdWorks Inc. Product Div.
Context B Context C
View
Controller
ActiveRecord
(Skinny Model)
Context A
First Class
Collection
Value
Object
Value
Object
Value
Object
Value
Object
Value
Object
Context D
First Class
Collection
Value
Object
Value
Object
Value
Object
Value
Object
Value
Object
ARには永続化責務のみが残る
ActiveRecordのロジックを
ValueObjectなどに委譲
構造Afterイメージ図
抽出したオブジェクトは
コンテキストごとに分ける
28. CrowdWorks Inc. Product Div.
サイクロマティック複雑度などメトリクス
を解析し、Technical Debt(技術的負
債)の度合いを算出してくれるオンライン
ツール。Githubと連携動作する。
チームKPIとしても利用。
本ツールの公開APIを利用し、特定クラ
スのメトリクスを自動取得するスクリプト
を組み、リファクタの成果を観測してい
る。
メトリクス解析ツール Code Climate Quality
29. CrowdWorks Inc. Product Div.
縦軸:Remediation points。技術的負債の指標値。公開APIで取得可能。
黄色実線:現在リファクタ中の、負債化してるConcernのひとつ。
Code Climate Quality 最近の計測結果
30. CrowdWorks Inc. Product Div.
静的型チェックツール Sorbet(ソルベ)
Rubyの型チェックツール。
静的型付言語と同様に型チェックにより
実装正確性、コードトレーサビリティの
正確性を向上させる。
6月にリリースされたばかりで潜在バグ
が多く、クラウドワークスでは試験運用
中。
31. CrowdWorks Inc. Product Div.
クラスの親やincludeしてるmoduleの
一覧を返す、Ruby標準ライブラリのメ
ソッド。
共通化に失敗しているConcernを何個
もincludeし、複雑怪奇な構造になって
いるクラスの依存関係を調べるのに必
須。
クラス祖先解析API Module#ancestors
32. CrowdWorks Inc. Product Div.
分析手法 影響スケッチ
書籍「レガシーコード改善ガイド」に記
載の分析手法。
リファクタ対象の影響範囲を知るため
の方法である。
右図のように、クラスやメソッドの依存
関係を図式化し、影響範囲を見える化
する。
33. CrowdWorks Inc. Product Div.
書籍「レガシーコード改善ガイド」に記載の分析手法。
リファクタ対象の影響範囲を知るための方法である。
リファクタ対象を、テストも書かずにいきなりリファクタしてみる。
どの辺までリファクタしなければならないか影響範囲が分かる。
分析手法 試行リファクタリング
35. CrowdWorks Inc. Product Div.
リファクタリングの候補選定には、価値、難度、リスクの3軸で評価する(書
籍「レガシーソフトウェア改善ガイド」)
価値 チームにとってどれほど有益であるか。理解容易性が上がった、
すぐ機能追加できるようになった、バグを埋め込みにくくなった、
など。
難度 リファクタリングの技術的な難しさ。
リスク リファクタリングに失敗した場合、どれほどのリスクが発生する
か。例えばお金周りのデータが壊れるなど。
リファクタリング対象選定基準
36. CrowdWorks Inc. Product Div.
• 依存度の小さい末端ロジックから攻める
• いきなりコアな部分から着手すると、他からの依存度が高く影響範囲が広すぎて手
に負えなくなる可能性が高い。
• クラスメソッドやprivateメソッドなど他からの依存度が低い末端ロジックから少しずつ
切り崩していくのが基本。
• 集中攻撃
• 五月雨式にあちこちいろんなクラスをリファクタするのではなく、どれか特定のクラス
に絞って集中的にリファクタする。
• 効果①:そのクラスに関する知見が高まる。
• 効果②:思考のスイッチングコストを低減できる。
戦術方針
37. CrowdWorks Inc. Product Div.
start
候補リストから対象選定
影響範囲分析 &
試行リファクタリング
リファクタで
きそう?
本実装プロセスへ
課題を
メモしておく
yes
no
分析プロセス
38. CrowdWorks Inc. Product Div.
start
ドメインオブジェクト
設計
テストコード実装
リファクタリング実行
コードレビュー
end
設計before/afterを
QiitaTeamで記事化
本実装プロセス
デプロイ
動作確認