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
リファクタリングのための第一歩
Search
NearMeの技術発表資料です
PRO
November 29, 2024
Programming
190
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
リファクタリングのための第一歩
リファクタリングに関する勉強会資料です!
NearMeの技術発表資料です
PRO
November 29, 2024
More Decks by NearMeの技術発表資料です
See All by NearMeの技術発表資料です
Claude Code × git worktree で並列開発 (続き) -差分のサービスだけを併設する-
nearme_tech
PRO
1
50
Claude Code × git worktree で並列開発 — サブモジュール構成のリポジトリで成立させる —
nearme_tech
PRO
0
54
LLM + 強化学習
nearme_tech
PRO
0
31
PosthogのA/Bテスト機能の紹介
nearme_tech
PRO
1
44
AIフレンドリーなプロダクトに向けて
nearme_tech
PRO
2
65
初めてのLean言語
nearme_tech
PRO
0
100
Apache Airflow Workflow orchestration without turning cron into spaghetti
nearme_tech
PRO
2
37
実務で役立つ幾何学 ボロノイ図の基礎から グラフ・ネットワーク応用まで
nearme_tech
PRO
1
76
SQL/ID抽出タスクから考える 実践的なハルシネーション対策
nearme_tech
PRO
1
88
Other Decks in Programming
See All in Programming
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
2
350
「つくるAI」だけではバグは見つからない ~テストに必要な「見つけるAI」を分離させる戦略~
mfunaki
0
230
Press start. Python's next generation.
willingc
PRO
3
320
Seeing Through Serverless: Observability for AWS Lambda with ADOT and CloudWatch Application Signals
seike460
PRO
1
120
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
2
500
Hello, Hiroshima Geospatial Data! — Exploring DoboX with Python
ra0kley
0
180
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
2
2.3k
FastAPI の並行処理モデルを完全に理解する
hoto17296
9
3.8k
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
160
AIと壁打ちしながら進めるコスト管理
fufuhu
2
1.9k
tsc.rip を支える技術 / Kyoto.なんか #8
susisu
0
4.3k
Snowflakeで業務アプリを作ろう。 Snowflakeのアプリ機能解説&実践ガイド
ayumu_yamaguchi
1
150
Featured
See All Featured
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
370
The Curious Case for Waylosing
cassininazir
1
500
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
680
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
520
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Fireside Chat
paigeccino
42
4k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
Deep Space Network (abreviated)
tonyrice
0
290
Ethics towards AI in product and experience design
skipperchong
2
360
Unsuck your backbone
ammeep
672
58k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
290
Transcript
0 リファクタリングのための第一歩 2024-11-29 第109回NearMe技術勉強会 Kaito Asahi
1 ⽬次 1. リファクタリングとは? 2. リファクタリングの例2つ a. メソッドチェーンの利⽤ b. ポリモーフィズム
3. リファクタリングは本当に必要か? 4. リファクタリングのユースケース 5. まとめ ※細かいリファクタリング⼿法については触れていません!
2 リファクタリングとは?
3 リファクタリングとは? • リファクタリング(Refactoring) ◦ 外部的な振る舞いはそのままで、内部のコードの可読性を⾼めるなどの 内部構造の改善のこと Ex) - 不要な定数の削除
- 異なるがカプセル化できる様な関数群をまとめる - あるキャンペーン⽤の料⾦計算ロジックなど - ifロジックなどでのネストの深いコードの改善 - early return などでネストを減らす etc…
4 コードリファクタリングの 具体例を少しだけ挙げます
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)
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の中全体を確認することで、 フィルタする処理だということがわかる
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の中全体を確認することで、 フィルタする処理だということがわかる フィルタすることは分かりやすく示したい!
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)
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);
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); やっていることは同じ (コードの重複)
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); コードの重複の解消 抽象クラスの作成
12 リファクタリングの規模 • ⽇常のコーディング中でのリファクタリング ◦ あるPull Requestにて、⾃分の修正したコードを振り返ったときに、デグレードが 確認できたらすぐロールバックする程度のリファクタリング • プロジェクトとしてのリファクタリング
◦ 1つのリポジトリ、複数のFeature単位での⽐較的⼤きなリファクタリング ◦ コードが作成されてから時間が経った後でのリファクタリング
13 リファクタリングの規模 • ⽇常のコーディング中でのリファクタリング ◦ あるPull Requestにて、⾃分の修正したコードを振り返ったときに、デグレードが 確認できたらすぐロールバックする程度のリファクタリング • プロジェクトとしてのリファクタリング
◦ 1つのリポジトリ、複数のFeature単位での⽐較的⼤きなリファクタリング ◦ コードが作成されてから時間が経った後でのリファクタリング 明らかに難易度が高い
14 プロジェクトとしてのリファクタリング (1) 現状の課題の分析‧集約 → 現状、コードロジックで何が課題であるのかを洗い出す (2) リファクタリングにより期待できる成果 → リファクタリング後にどの様な良いことが起こるのか
(3) リファクタリングコスト → どのくらいの時間がかかることが予測されるか
15 そもそも、 分析に必要なリソースはあるか?
16 リファクタリングのための現状分析 可読性の低そうなコードを発⾒ ↓ どの様な経緯でこの様なコードになったのかの追跡 ↓ 改善策を⽴てて、リファクタリング計画に加える
17 リファクタリングのための現状分析 可読性の低そうなコードを発⾒ ↓ どの様な経緯でこの様なコードになったのかの追跡 ↓ 改善策を⽴てて、リファクタリング計画に加える これ、探し出せますか?
18 リファクタリングのための現状分析 • 該当コードになった経緯の追跡⽅法 (1) Git Blame - コードベースで blame
から対象PRを探し出して、そこからタスクチケットなどを頼り に当時のコンテキストを追う
19 リファクタリングのための現状分析 • 該当コードになった経緯の追跡⽅法 (1) Git Blame - コードベースで blame
から対象PRを探し出して、そこからタスクチケットなどを頼り に当時のコンテキストを追う → PRのDescriptionや、元のタスクチケットなどが整理されていない場合、どうしてその 様なコードになったのかなどは追いきれない可能性がある → Design Docや、タスクチケットは、どちらかというと意思決定の最終段階に偏っている ことが多い
20 リファクタリングのための現状分析 • 該当コードになった経緯の追跡⽅法 ⭐ (2) ADR - Architectural Decision
Record - 意思決定のプロセスをドキュメントとして保存しておくもの
21 リファクタリングのための現状分析 • 該当コードになった経緯の追跡⽅法 ⭐ (2) ADR - Architectural Decision
Record - 意思決定のプロセスをドキュメントとして保存しておくもの → 過去のコンテキスト、意思決定のための⽐較検討、ステータスを確認できる! → 過去の意思決定を踏まえて、そもそもリファクタリングの必要性、作業にかかりそうな コスト予測がよりしやすくなる!
22 リファクタリングのための現状分析 • 該当コードになった経緯の追跡⽅法 ⭐ (2) ADR - Architectural Decision
Record - 意思決定のプロセスをドキュメントとして保存しておくもの → 過去のコンテキスト、意思決定のための⽐較検討、ステータスを確認できる! → 過去の意思決定を踏まえて、そもそもリファクタリングの必要性、作業にかかりそうな コスト予測がよりしやすくなる! ※ADRについては過去の勉強会で扱っています → https://speakerdeck.com/nearme_tech/architecture-decision-record-adr
23 リファクタリングには、 コードだけでなく ビジネスサイドの理解も不可⽋
24 ビジネスサイドの理解とリファクタリング • ビジネスロジック ◦ 企業の運営ルールやプロセス、ワークフローを反映したコード部分 ▪ キャンペーン計算ロジック、税制対応、カスタム割引ルール
25 ビジネスサイドの理解とリファクタリング • ビジネスロジック ◦ 企業の運営ルールやプロセス、ワークフローを反映したコード部分 ▪ キャンペーン計算ロジック、税制対応、カスタム割引ルール → ビジネスロジックを⼗分に理解していないと、ビジネス要件を満たさないままリファク
タリングをしてしまう恐れがある
26 ビジネスサイドの理解とリファクタリング • リファクタリングとビジネス要件の衝突例 Ex) キャンペーン計算ロジック • 現状 ◦ 複雑なキャンペーンロジックがコードベースに埋め込まれている
◦ 新⼈エンジニアが「コードが汚い」という理由だけでリファクタリングを実施 • 結果 ◦ ビジネス要件(特定条件での割引適⽤など)が失われる ◦ 顧客への請求ミスや収益減少などの重⼤な問題につながる
27 もちろん、常に起こるわけではない
28 ビジネスサイドの理解とリファクタリング • 技術とビジネスのバランスを取る⽅法 (1) ビジネス背景の把握 (2) リファクタリング計画にビジネス要件を反映 (3) テストでの動作保証
29 ビジネスサイドの理解とリファクタリング (1) ビジネス背景の把握 • 前提 ◦ 意思決定は、ADRやその他ドキュメントなどでまとめておく • やること
◦ 過去のドキュメント(ADRや設計書)やGit履歴から背景を追跡 ◦ 関係者(プロダクトマネージャー、営業チームなど)との対話を通じて、コードに埋め込ま れたビジネスルールを確認
30 ビジネスサイドの理解とリファクタリング (2) リファクタリング計画にビジネス要件を反映 • やること ◦ 改善対象のコードがどの様なビジネス価値を生み出しているのか を明確化 ◦
リファクタリング前後でその価値が維持されている 様に設計
31 ビジネスサイドの理解とリファクタリング (3) テストでの動作保証 • やること ◦ ビジネスロジックに関するテストケースを充実させて、可能な限り全てのパターンに対して の動作保証がされている ことを示す
32 複雑性の良し悪しを⾒極める
33 リファクタリングの際に考慮する「複雑性」 リファクタリング → 複雑に絡み合っているものを解いて管理しやすいようにする but… 複雑さを解く → ビジネス要件を満たさずに崩壊する可能性もある... →
良い複雑性と悪い複雑性を⾒極めることが⼤事!
34 リファクタリングの際に考慮する「複雑性」 • 良い複雑性 ◦ ⽬的が明確 ▪ 複雑性がビジネス価値や競争優位性を⽣み出すために存在している • Ex)
特定顧客向けのカスタマイズ機能や業界特化のルール ◦ ⾃律性がある ▪ 各コンポーネントが独⽴しており、他に影響を与えず変更‧運⽤可能 ◦ 明瞭さ ▪ コードや設計が⾃⼰説明的であり、意図がすぐに理解できる ◦ ユニークさ ▪ 各部分が特定の役割を持ち、他と重複していない
35 リファクタリングの際に考慮する「複雑性」 • 悪い複雑性 ◦ ⽬的不明確 ▪ なぜそのコードや設計が存在するのか理解できない ◦ 相互依存性が⾼い
▪ ⼀部を変更すると他の部分に影響が波及する ◦ 不透明さ ▪ コードや設計が分かりづらく、意図や動作が把握困難 ◦ 冗⻑性 ▪ 同じような機能や処理が複数箇所に存在
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/
37 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 1. 単純(Simple) - 問題例 - コード内のハードコーディングされた定数を削除し、設定ファイルに移動する -
特徴 - 解決策が明確で、標準的な⼿順で対応可能 - 対応策 - 定数を設定ファイルに移動し、コードから参照するように変更
38 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 2. 困難(Complicated) - 問題例 - ⼤規模なクラスが単⼀責任の原則を犯しているため、リファクタリングして責務を 分割する必要がある
- 特徴 - 専⾨知識が必要で、複数の設計オプションが存在 - 最適な解決策を⾒つけるためには分析が必要 - 対応策 - クラスの役割を分析し、関連する機能ごとに新しいクラスやモジュールに分割
39 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 3. 複雑(Complex) - 問題例 - ユーザーインターフェースの改善によるユーザーエクスペリエンス向上を⽬指すリ ファクタリング
- 特徴 - 因果関係が不明瞭で、ユーザーの反応が予測しづらい - 試⾏錯誤による学習が必要 - 対応策 - プロトタイプを作成し、ユーザーテストを繰り返してフィードバックを得る。
40 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 4. 混沌(Chaos) - 問題例 - リリース直前に発⾒された重⼤なバグの修正 -
特徴 - 即座の対応が求められ、原因究明よりもまずはバグ修正が優先される - 対応策 - 迅速に修正を⾏い、テストを実施して影響範囲を確認 - 根本原因を分析し再発防⽌策を講じる
41 「複雑性」をフレームワークで分類する 〜クネビン‧フレームワーク〜 5. 無秩序(Disorder) - 問題例 - 複数の異なる技術スタックやアーキテクチャが混在しているプロジェクトで、どこ から⼿をつけるべきか不明
- 特徴 - 問題がどの領域に属するか不明確で、どこから⼿をつけるべきか判断しづらい - 対応策 - 状況を整理し、それぞれの領域に分類してから適切な対応策を決定する
42 リファクタリングユースケース
43 リファクタリングユースケース • メルペイの「あと払い」サービスリファクタリング - コンテキスト - ⻑年のコーディングによるコードの負債の積み重ね - アプローチ
- SOLID原則に基づき、コードの責務を明確化し、依存関係を整理 - マイクロサービス化を進め、独⽴性と可読性を向上 - 成果 - コード変更時の影響範囲が明確になり、⽣産性が向上 - テストスタブを⽤いたユニットテストの効率化に成功 https://engineering.mercari.com/blog/entry/20221221-refactoring-along-solid/ S : 単⼀責任の原則(SRP) O :オープン‧クローズドの原則(OCP) L : リスコフの置換原則(LIP) I : インタフェース分離の原則(ISP) D: 依存関係逆転の原則(DIP)
44 リファクタリングユースケース • PIP-Makerの⼤規模リファクタリング - コンテキスト - Adobe FlashからHTML5やJavaScriptへの移⾏が必要となり、⼤規模な技術移⾏が 求めらていた
- アプローチ - フロントエンドとバックエンドでTypeScriptを採⽤し、技術的親和性を⾼める - IaaSからPaaSへの移⾏を通じて、システムの拡張性と保守性を向上 - 成果 - 成果処理速度と操作性が⼤幅に改善され、ユーザー満⾜度が向上 https://sg.wantedly.com/companies/company_641519/post_articles/515613
45 リファクタリングユースケース • ラクスによる技術的負債解消プロジェクト - コンテキスト - ⻑年放置されていた技術的負債が開発効率を低下させていた - アプローチ
- リファクタリング対象をパターン分けし、優先順位を設定 - 開発チームとビジネスサイドで共有しながら進⾏ - 成果 - 可読性の向上により、レビュー効率が改善 - 開発チーム全体で納得感を持ちつつリファクタリングを実施 https://logmi.jp/brandtopics/323993
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
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/
48 Thank you