Slide 1

Slide 1 text

0 リファクタリングのための第一歩 
 2024-11-29 第109回NearMe技術勉強会 Kaito Asahi

Slide 2

Slide 2 text

1 ⽬次 1. リファクタリングとは? 2. リファクタリングの例2つ a. メソッドチェーンの利⽤ b. ポリモーフィズム 3. リファクタリングは本当に必要か? 4. リファクタリングのユースケース 5. まとめ ※細かいリファクタリング⼿法については触れていません!

Slide 3

Slide 3 text

2 リファクタリングとは?

Slide 4

Slide 4 text

3 リファクタリングとは? ● リファクタリング(Refactoring) ○ 外部的な振る舞いはそのままで、内部のコードの可読性を⾼めるなどの 内部構造の改善のこと Ex) - 不要な定数の削除 - 異なるがカプセル化できる様な関数群をまとめる - あるキャンペーン⽤の料⾦計算ロジックなど - ifロジックなどでのネストの深いコードの改善 - early return などでネストを減らす etc…

Slide 5

Slide 5 text

4 コードリファクタリングの 具体例を少しだけ挙げます

Slide 6

Slide 6 text

5 リファクタリングの例 ● 汎⽤的な for ループをメソッドチェーンに置き換える Ex) 配列 nums から、偶数であるものを取り出して表⽰する const nums = [1, 2, 3, 5, 8, 13] const result: number[] = [] for (const num of nums) { if (num % 2 === 0) { result.push(num) } } console.log(result)

Slide 7

Slide 7 text

6 リファクタリングとは? ● 汎⽤的な for ループをメソッドチェーンに置き換える Ex) 配列 nums から、偶数であるものを取り出して表⽰する const nums = [1, 2, 3, 5, 8, 13] const result: number[] = [] for (const num of nums) { if (num % 2 === 0) { result.push(num) } } console.log(result) forの中全体を確認することで、 フィルタする処理だということがわかる

Slide 8

Slide 8 text

7 リファクタリングとは? ● 汎⽤的な for ループをメソッドチェーンに置き換える Ex) 配列 nums から、偶数であるものを取り出して表⽰する const nums = [1, 2, 3, 5, 8, 13] const result: number[] = [] for (const num of nums) { if (num % 2 === 0) { result.push(num) } } console.log(result) forの中全体を確認することで、 フィルタする処理だということがわかる フィルタすることは分かりやすく示したい!

Slide 9

Slide 9 text

8 リファクタリングとは? ● 汎⽤的な for ループをメソッドチェーンに置き換える Ex) 配列 nums から、偶数であるものを取り出して表⽰する(filterメソッドの利⽤) const nums = [1, 2, 3, 5, 8, 13] const result: number[] = [] for (const num of nums) { if (num % 2 === 0) { result.push(num) } } console.log(result) const nums = [1, 2, 3, 5, 8, 13] const result = nums.filter( (num) => num % 2 === 0 ) console.log(result)

Slide 10

Slide 10 text

9 リファクタリングの例 ● ポリモーフィズムの利⽤ Ex) Dog, Catクラスにて、鳴き声を出⼒する class Dog { makeSound(): string { return "Woof"; } } class Cat { makeSound(): string { return "Meow"; } } function playWithDog(dog: Dog) { console.log(dog.makeSound()); } function playWithCat(cat: Cat) { console.log(cat.makeSound()); } const myDog = new Dog(); const myCat = new Cat(); playWithDog(myDog); playWithCat(myCat);

Slide 11

Slide 11 text

10 リファクタリングの例 ● ポリモーフィズムの利⽤ Ex) Dog, Catクラスにて、鳴き声を出⼒する class Dog { makeSound(): string { return "Woof"; } } class Cat { makeSound(): string { return "Meow"; } } function playWithDog(dog: Dog) { console.log(dog.makeSound()); } function playWithCat(cat: Cat) { console.log(cat.makeSound()); } const myDog = new Dog(); const myCat = new Cat(); playWithDog(myDog); playWithCat(myCat); やっていることは同じ (コードの重複)

Slide 12

Slide 12 text

11 リファクタリングの例 ● ポリモーフィズムの利⽤ Ex) Dog, Catクラスにて、鳴き声を出⼒する abstract class Animal { abstract makeSound(): string; move(): void { console.log("Moving..."); } } class Dog extends Animal { makeSound(): string { return "Woof"; } } class Cat extends Animal { makeSound(): string { return "Meow"; } } function playWithAnimal(animal: Animal) { console.log(animal.makeSound()); } const myDog = new Dog(); const myCat = new Cat(); playWithAnimal(myDog); playWithAnimal(myCat); コードの重複の解消 抽象クラスの作成

Slide 13

Slide 13 text

12 リファクタリングの規模 ● ⽇常のコーディング中でのリファクタリング ○ あるPull Requestにて、⾃分の修正したコードを振り返ったときに、デグレードが 確認できたらすぐロールバックする程度のリファクタリング ● プロジェクトとしてのリファクタリング ○ 1つのリポジトリ、複数のFeature単位での⽐較的⼤きなリファクタリング ○ コードが作成されてから時間が経った後でのリファクタリング

Slide 14

Slide 14 text

13 リファクタリングの規模 ● ⽇常のコーディング中でのリファクタリング ○ あるPull Requestにて、⾃分の修正したコードを振り返ったときに、デグレードが 確認できたらすぐロールバックする程度のリファクタリング ● プロジェクトとしてのリファクタリング ○ 1つのリポジトリ、複数のFeature単位での⽐較的⼤きなリファクタリング ○ コードが作成されてから時間が経った後でのリファクタリング 明らかに難易度が高い

Slide 15

Slide 15 text

14 プロジェクトとしてのリファクタリング (1) 現状の課題の分析‧集約 → 現状、コードロジックで何が課題であるのかを洗い出す (2) リファクタリングにより期待できる成果 → リファクタリング後にどの様な良いことが起こるのか (3) リファクタリングコスト → どのくらいの時間がかかることが予測されるか

Slide 16

Slide 16 text

15 そもそも、 分析に必要なリソースはあるか?

Slide 17

Slide 17 text

16 リファクタリングのための現状分析 可読性の低そうなコードを発⾒ ↓ どの様な経緯でこの様なコードになったのかの追跡 ↓ 改善策を⽴てて、リファクタリング計画に加える

Slide 18

Slide 18 text

17 リファクタリングのための現状分析 可読性の低そうなコードを発⾒ ↓ どの様な経緯でこの様なコードになったのかの追跡 ↓ 改善策を⽴てて、リファクタリング計画に加える これ、探し出せますか?

Slide 19

Slide 19 text

18 リファクタリングのための現状分析 ● 該当コードになった経緯の追跡⽅法 (1) Git Blame - コードベースで blame から対象PRを探し出して、そこからタスクチケットなどを頼り に当時のコンテキストを追う

Slide 20

Slide 20 text

19 リファクタリングのための現状分析 ● 該当コードになった経緯の追跡⽅法 (1) Git Blame - コードベースで blame から対象PRを探し出して、そこからタスクチケットなどを頼り に当時のコンテキストを追う → PRのDescriptionや、元のタスクチケットなどが整理されていない場合、どうしてその 様なコードになったのかなどは追いきれない可能性がある → Design Docや、タスクチケットは、どちらかというと意思決定の最終段階に偏っている ことが多い

Slide 21

Slide 21 text

20 リファクタリングのための現状分析 ● 該当コードになった経緯の追跡⽅法 ⭐ (2) ADR - Architectural Decision Record - 意思決定のプロセスをドキュメントとして保存しておくもの

Slide 22

Slide 22 text

21 リファクタリングのための現状分析 ● 該当コードになった経緯の追跡⽅法 ⭐ (2) ADR - Architectural Decision Record - 意思決定のプロセスをドキュメントとして保存しておくもの → 過去のコンテキスト、意思決定のための⽐較検討、ステータスを確認できる! → 過去の意思決定を踏まえて、そもそもリファクタリングの必要性、作業にかかりそうな コスト予測がよりしやすくなる!

Slide 23

Slide 23 text

22 リファクタリングのための現状分析 ● 該当コードになった経緯の追跡⽅法 ⭐ (2) ADR - Architectural Decision Record - 意思決定のプロセスをドキュメントとして保存しておくもの → 過去のコンテキスト、意思決定のための⽐較検討、ステータスを確認できる! → 過去の意思決定を踏まえて、そもそもリファクタリングの必要性、作業にかかりそうな コスト予測がよりしやすくなる! ※ADRについては過去の勉強会で扱っています → https://speakerdeck.com/nearme_tech/architecture-decision-record-adr

Slide 24

Slide 24 text

23 リファクタリングには、 コードだけでなく ビジネスサイドの理解も不可⽋

Slide 25

Slide 25 text

24 ビジネスサイドの理解とリファクタリング ● ビジネスロジック ○ 企業の運営ルールやプロセス、ワークフローを反映したコード部分 ■ キャンペーン計算ロジック、税制対応、カスタム割引ルール

Slide 26

Slide 26 text

25 ビジネスサイドの理解とリファクタリング ● ビジネスロジック ○ 企業の運営ルールやプロセス、ワークフローを反映したコード部分 ■ キャンペーン計算ロジック、税制対応、カスタム割引ルール → ビジネスロジックを⼗分に理解していないと、ビジネス要件を満たさないままリファク タリングをしてしまう恐れがある

Slide 27

Slide 27 text

26 ビジネスサイドの理解とリファクタリング ● リファクタリングとビジネス要件の衝突例 Ex) キャンペーン計算ロジック ● 現状 ○ 複雑なキャンペーンロジックがコードベースに埋め込まれている ○ 新⼈エンジニアが「コードが汚い」という理由だけでリファクタリングを実施 ● 結果 ○ ビジネス要件(特定条件での割引適⽤など)が失われる ○ 顧客への請求ミスや収益減少などの重⼤な問題につながる

Slide 28

Slide 28 text

27 もちろん、常に起こるわけではない

Slide 29

Slide 29 text

28 ビジネスサイドの理解とリファクタリング ● 技術とビジネスのバランスを取る⽅法 (1) ビジネス背景の把握 (2) リファクタリング計画にビジネス要件を反映 (3) テストでの動作保証

Slide 30

Slide 30 text

29 ビジネスサイドの理解とリファクタリング (1) ビジネス背景の把握 ● 前提 ○ 意思決定は、ADRやその他ドキュメントなどでまとめておく ● やること ○ 過去のドキュメント(ADRや設計書)やGit履歴から背景を追跡 ○ 関係者(プロダクトマネージャー、営業チームなど)との対話を通じて、コードに埋め込ま れたビジネスルールを確認

Slide 31

Slide 31 text

30 ビジネスサイドの理解とリファクタリング (2) リファクタリング計画にビジネス要件を反映 ● やること ○ 改善対象のコードがどの様なビジネス価値を生み出しているのか を明確化 ○ リファクタリング前後でその価値が維持されている 様に設計

Slide 32

Slide 32 text

31 ビジネスサイドの理解とリファクタリング (3) テストでの動作保証 ● やること ○ ビジネスロジックに関するテストケースを充実させて、可能な限り全てのパターンに対して の動作保証がされている ことを示す

Slide 33

Slide 33 text

32 複雑性の良し悪しを⾒極める

Slide 34

Slide 34 text

33 リファクタリングの際に考慮する「複雑性」 リファクタリング → 複雑に絡み合っているものを解いて管理しやすいようにする but… 複雑さを解く → ビジネス要件を満たさずに崩壊する可能性もある... → 良い複雑性と悪い複雑性を⾒極めることが⼤事!

Slide 35

Slide 35 text

34 リファクタリングの際に考慮する「複雑性」 ● 良い複雑性 ○ ⽬的が明確 ■ 複雑性がビジネス価値や競争優位性を⽣み出すために存在している ● Ex) 特定顧客向けのカスタマイズ機能や業界特化のルール ○ ⾃律性がある ■ 各コンポーネントが独⽴しており、他に影響を与えず変更‧運⽤可能 ○ 明瞭さ ■ コードや設計が⾃⼰説明的であり、意図がすぐに理解できる ○ ユニークさ ■ 各部分が特定の役割を持ち、他と重複していない

Slide 36

Slide 36 text

35 リファクタリングの際に考慮する「複雑性」 ● 悪い複雑性 ○ ⽬的不明確 ■ なぜそのコードや設計が存在するのか理解できない ○ 相互依存性が⾼い ■ ⼀部を変更すると他の部分に影響が波及する ○ 不透明さ ■ コードや設計が分かりづらく、意図や動作が把握困難 ○ 冗⻑性 ■ 同じような機能や処理が複数箇所に存在

Slide 37

Slide 37 text

36 「複雑性」をフレームワークで分類する ● クネビン‧フレームワーク 問題の種類を性質別に分類をし、それぞれの分類に対してプロセスを体系づけるもの https://hirolaboratory.com/%E3%82%AF%E3%83%8D%E3%83%93%E3%83%B3%E3%82%AB%E3%83%8D%E3%83%B4%E3 %82%A3%E3%83%B3%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF%E3%8 1%A8%E3%81%AF%EF%BC%9F%E5%88%86%E9%A1%9E%E3%82%84/

Slide 38

Slide 38 text

37 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 1. 単純(Simple) - 問題例 - コード内のハードコーディングされた定数を削除し、設定ファイルに移動する - 特徴 - 解決策が明確で、標準的な⼿順で対応可能 - 対応策 - 定数を設定ファイルに移動し、コードから参照するように変更

Slide 39

Slide 39 text

38 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 2. 困難(Complicated) - 問題例 - ⼤規模なクラスが単⼀責任の原則を犯しているため、リファクタリングして責務を 分割する必要がある - 特徴 - 専⾨知識が必要で、複数の設計オプションが存在 - 最適な解決策を⾒つけるためには分析が必要 - 対応策 - クラスの役割を分析し、関連する機能ごとに新しいクラスやモジュールに分割

Slide 40

Slide 40 text

39 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 3. 複雑(Complex) - 問題例 - ユーザーインターフェースの改善によるユーザーエクスペリエンス向上を⽬指すリ ファクタリング - 特徴 - 因果関係が不明瞭で、ユーザーの反応が予測しづらい - 試⾏錯誤による学習が必要 - 対応策 - プロトタイプを作成し、ユーザーテストを繰り返してフィードバックを得る。

Slide 41

Slide 41 text

40 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 4. 混沌(Chaos) - 問題例 - リリース直前に発⾒された重⼤なバグの修正 - 特徴 - 即座の対応が求められ、原因究明よりもまずはバグ修正が優先される - 対応策 - 迅速に修正を⾏い、テストを実施して影響範囲を確認 - 根本原因を分析し再発防⽌策を講じる

Slide 42

Slide 42 text

41 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 5. 無秩序(Disorder) - 問題例 - 複数の異なる技術スタックやアーキテクチャが混在しているプロジェクトで、どこ から⼿をつけるべきか不明 - 特徴 - 問題がどの領域に属するか不明確で、どこから⼿をつけるべきか判断しづらい - 対応策 - 状況を整理し、それぞれの領域に分類してから適切な対応策を決定する

Slide 43

Slide 43 text

42 リファクタリングユースケース

Slide 44

Slide 44 text

43 リファクタリングユースケース ● メルペイの「あと払い」サービスリファクタリング - コンテキスト - ⻑年のコーディングによるコードの負債の積み重ね - アプローチ - SOLID原則に基づき、コードの責務を明確化し、依存関係を整理 - マイクロサービス化を進め、独⽴性と可読性を向上 - 成果 - コード変更時の影響範囲が明確になり、⽣産性が向上 - テストスタブを⽤いたユニットテストの効率化に成功 https://engineering.mercari.com/blog/entry/20221221-refactoring-along-solid/ S : 単⼀責任の原則(SRP) O :オープン‧クローズドの原則(OCP) L : リスコフの置換原則(LIP) I : インタフェース分離の原則(ISP) D: 依存関係逆転の原則(DIP)

Slide 45

Slide 45 text

44 リファクタリングユースケース ● PIP-Makerの⼤規模リファクタリング - コンテキスト - Adobe FlashからHTML5やJavaScriptへの移⾏が必要となり、⼤規模な技術移⾏が 求めらていた - アプローチ - フロントエンドとバックエンドでTypeScriptを採⽤し、技術的親和性を⾼める - IaaSからPaaSへの移⾏を通じて、システムの拡張性と保守性を向上 - 成果 - 成果処理速度と操作性が⼤幅に改善され、ユーザー満⾜度が向上 https://sg.wantedly.com/companies/company_641519/post_articles/515613

Slide 46

Slide 46 text

45 リファクタリングユースケース ● ラクスによる技術的負債解消プロジェクト - コンテキスト - ⻑年放置されていた技術的負債が開発効率を低下させていた - アプローチ - リファクタリング対象をパターン分けし、優先順位を設定 - 開発チームとビジネスサイドで共有しながら進⾏ - 成果 - 可読性の向上により、レビュー効率が改善 - 開発チーム全体で納得感を持ちつつリファクタリングを実施 https://logmi.jp/brandtopics/323993

Slide 47

Slide 47 text

46 参考⽂献(1/2) ● 糞コードは直すな。 ○ https://qiita.com/kotauchisunsun/items/d03c1e6936ffb250e4a1 ● 新卒エンジニアが3ヶ⽉間のリファクタで学んだこと ○ https://techblog.openwork.co.jp/entry/2022/05/20/121238 ● リファクタリングをする際にソースコードの設計からはじめてはいけない ○ https://tech-blog.monotaro.com/entry/2023/11/28/090000 ● ラクスによる技術的負債解消プロジェクト’ ○ https://logmi.jp/brandtopics/323993 ● PIP-Makerの⼤規模リファクタリング ○ https://sg.wantedly.com/companies/company_641519/post_articles/515613

Slide 48

Slide 48 text

47 参考⽂献(2/2) ● メルペイの「あと払い」サービスリファクタリング ○ https://engineering.mercari.com/blog/entry/20221221-refactoring-along-solid/ ● クネビン(カネヴィン)フレームワークとは?分類やスクラム開発導⼊時の活⽤例を解説 ○ https://hirolaboratory.com/%E3%82%AF%E3%83%8D%E3%83%93%E3%83% B3%E3%82%AB%E3%83%8D%E3%83%B4%E3%82%A3%E3%83%B3%E3%83 %95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%8 2%AF%E3%81%A8%E3%81%AF%EF%BC%9F%E5%88%86%E9%A1%9E%E3% 82%84/ ● リファクタリング(第2版)- 既存のコードを安全に改善する - ○ https://www.ohmsha.co.jp/book/9784274224546/

Slide 49

Slide 49 text

48 Thank you