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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Naoki Kitora
September 29, 2025
Programming
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
リファクタリング入門 〜日常的にコードを育てるための第一歩〜
Naoki Kitora
September 29, 2025
Other Decks in Programming
See All in Programming
Discordを用いたラボオートメーション関連情報収集の自動化
noguhiro2002
0
460
GKE アップグレード前に知っておきたい Blue/Green と PDB の関係
stkk
0
110
引き算の組織 ― アウトカムとAIに全振りするために辞めたこと ― / Organization by Subtraction
hirokiyamamoto14
PRO
0
310
まだ間に合う!今年の夏こそSchemeのマクロ展開器を完全理解!
omasanori
0
570
高専キャリア LT 発表内容
crysta1221
5
4.7k
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
510
Loosening the Reins: Go Generics Get More Flexible
kuro_kurorrr
0
350
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
800
AIに既存システムを理解させる技術 ~レガシーを見捨てないハーネスエンジニアリング入門~
ochtum
0
170
freeeにおけるEvalsの実践例の紹介
freee
PRO
0
160
Oxlintはいいぞ(続)
yug1224
1
480
30年振りにコンパイラの定数整数除算を改善した
herumi
9
4.3k
Featured
See All Featured
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Making Projects Easy
brettharned
120
6.7k
sira's awesome portfolio website redesign presentation
elsirapls
0
350
It's Worth the Effort
3n
188
29k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
430
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
490
Code Review Best Practice
trishagee
74
20k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
970
Marketing to machines
jonoalderson
1
5.7k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
360
The browser strikes back
jonoalderson
0
1.6k
Accessibility Awareness
sabderemane
1
180
Transcript
リファクタリング入門 〜日常的にコードを育てるため 第一歩〜 関ジャバ 2025年 9月度 2025-09-26 木虎 直樹
自己紹介 木虎 直樹 株式会社ティアライン CTO アプリケーションエンジニア (Java, Python, Scala, JavaScript,
etc.) インフラエンジニア (OS, ミドルウェア、ネットワーク、クラウド) プロジェクトマネージャ (アプリケーション開発、AI 開発、etc.)
DISCLAIMER リテラル値をハードコーディングしている箇所が多数ありますが、紙面 都合上やむなく そ ようにしておりますことをあらかじめご了承ください。
Agenda • リファクタリングと • なぜリファクタリングをする か • いつリファクタリングをする か •
どこをリファクタリングする か (リファクタリング事例) • リファクタリング 進め方
リファクタリングと リファクタリング (名詞): 外部から見たとき 振る舞いを保ちつつ、理解や修正が簡単になるように、ソフトウェア 内部構造を変化させること リファクタリングする (動詞): 一連 リファクタリングを適用して、外部から見た振る舞い
変更なしに、ソフトウェアを 再構築すること ソフトウェア設計を改善 コードを洗練
なぜリファクタリングをする か • コードが理解しやすく修正が簡単になるためバグ 入り込む余地が最小化 ◦ 生産性向上 ◦ コード 読まれる時間
ほうが長い ▪ パフォーマンスよりもまず 可読性 • 最初からすべてを見通して詳細に設計する 不可能 ◦ 実装 過程で気づく ◦ 使ってから気づく ◦ 運用してから気づく • ソフトウェア 成長とともにエントロピーが増大 ◦ 追加開発により当初考えていなかったことが発生 ◦ 車輪 再発明 ◦ 具体性 高い (抽象度 低い、汎用性 低い ) 実装
ハードウェアで なくソフトウェアだからしやすい
いつリファクタリングをする か • 変更要求に対応する準備 ◦ 変更を容易にするため • バグ修正や調査 タイミング ◦
コード修正 前に何をしている か理解するため • 理解 できるが、良くない書き方を見つけたとき ◦ ゴミ拾い • 一通り 実装が完了し、コードレビューを依頼する前 ◦ 推敲
どこをリファクタリングする か (リファクタリング事例) コード 不吉な匂い (Code Smells) する箇所 • 謎な名前
(Mysterious Name) • 重複したコード (Duplicated Code) • 長い関数 (Long Function) • 巨大なクラス (Large Class) • ネストが深い (※) • etc. ※ Martin Fowler 著書リファクタリング「第 3章 コード 不吉な匂い」に 挙がっていない
謎な名前 (Mysterious Name) なぜダメ? 名付け 設計 • 適切な名前がつけられるということ 、そ クラスやメソッド、変数
役割が明確か つ適切であるということ • 適切な名前がつけられていれ コードが読みやすい ◦ メソッド 実装を読まなくても処理が想像できる ◦ コードを詳細に追っていかなくても変数に何が入っているか想像できる
謎な名前 (Mysterious Name) public class InvoiceService { public double cal(double
a, double b) { return a * b * 1.1; } } public class InvoiceService { private static final double TAX_RATE = 0.1; public double calculateTotalPrice(double unitPrice, double quantity) { double subtotal = unitPrice * quantity; return subtotal * (1 + TAX_RATE); } }
謎な名前 (Mysterious Name) 一種 ありがちなダメな名前 ***Flag (e.g. updateFlag) true (or
false) 場合にどういう意味な か直感的にわからない 更新するべきかどうかを保持 : shouldUpdate 更新したというステータスを保持 : updated 更新しても良いかどうかを保持 : canUpdate ***Flag 副作用 if (updateFlag == true) { // 比較したくなる }
謎な名前 (Mysterious Name) 一種 これまでに見たも でも特に印象に残っているも latitude, mild 緯度 わかるけどマイルドって何
? 緯度 次に来る 普通に考えたら経度 (longitude) で ? 経度、ケイド、けいど、けいど ? けいど?! ……
軽度!!
重複したコード (Duplicated Code) なぜダメ? 似ているけど違う部分 ないか読まなけれ ならない 修正 際 もれなく重複箇所を洗い出し、すべて修正しなけれ
ならない コピペでし し 量産される……
重複したコード (Duplicated Code) public class DiscountCalculator { public double calculateForRegularCustomer(double
price) { double discounted = price * 0.9; return discounted < 100 ? 100 : discounted; } public double calculateForPremiumCustomer(double price) { double discounted = price * 0.8; return discounted < 100 ? 100 : discounted; } }
重複したコード (Duplicated Code) public class DiscountCalculator { public double calculateForRegularCustomer(double
price) { return applyMinimumPrice(price * 0.9); } public double calculateForPremiumCustomer(double price) { return applyMinimumPrice(price * 0.8); } private double applyMinimumPrice(double discounted) { return discounted < 100 ? 100 : discounted; } }
重複したコード (Duplicated Code) で最近見た例 • コピペで量産された 20個くらい 関数 (Python です)
◦ 関数 役割ごとに 10個から 20個存在する ▪ ここでいう関数 役割と データ読み込み、データ変換、データ書き出しなど ◦ 大体 コピペだが、長年 製品開発で一部だけ改良している亜種が存在 • 対応 ◦ 方針を検討 ▪ 関数をクラス メソッドとし、共通部分 抽象クラスに引き上げる ◦ 処理を分割 (メソッド/関数抽出) ◦ 抽象クラスを定義 ◦ 重複部分を抽象クラスに引き上げ ◦ 各関数を具象クラス・メソッドに変換
長い関数 (Long Function) なぜダメ? • 大抵 場合、複数 処理が 1つ 関数・メソッドに詰め込まれていて全体
見通し が悪く可読性が低い ◦ 概要 掴みづらさを補足するためにコメントが付与されていることも多い • それぞれ 処理を個別にテストできない
長い関数 (Long Function) public class OrderService { public double calculateFinalPrice(Order
order) { double subtotal = 0; for (OrderItem item : order.getItems()) { subtotal += item.getUnitPrice() * item.getQuantity(); } // 割引の適用 double discount = 0; if (order.getCustomer().isPremium()) { discount = subtotal * 0.1; } else if (subtotal > 10000) { discount = subtotal * 0.05; } // 税金の計算 double tax = (subtotal - discount) * 0.1; // 配送料の計算 double shipping = subtotal > 5000 ? 0 : 500; return subtotal - discount + tax + shipping; } } 変数 再代入も起こりがち
長い関数 (Long Function) public class OrderService { private static final
double TAX_RATE = 0.1; public double calculateFinalPrice(Order order) { double subtotal = calculateSubtotal(order); double discount = calculateDiscount(order, subtotal); double tax = calculateTax(subtotal, discount); double shipping = calculateShipping(subtotal); return subtotal - discount + tax + shipping; } private double calculateSubtotal(Order order) { return order.getItems() .stream() .mapToDouble(item -> item.getUnitPrice() * item.getQuantity()) .sum(); } // 以下略 }
ネストが深い なぜダメ? • 言うまでもなく読みづらい
ネストが深い public class UserService { public boolean canAccessResource(User user, Resource
resource) { if (user != null) { if (user.isActive()) { if (resource != null) { if (resource.isPublic() || user.hasPermission(resource)) { return true; } else { return false; } } else { return false; } } else { return false; } } else { return false; } } }
ネストが深い public class UserService { public boolean canAccessResource(User user, Resource
resource) { if (user == null) return false; if (!user.isActive()) return false; if (resource == null) return false; if (resource.isPublic()) return true; return user.hasPermission(resource); } }
ネストが深いわけで ないけど…… if (updateFlag) { // なんか処理する // まだ処理してる //
まだまだ続くよ // その後も続く何十行もの処理 // …… // …… // …… // …… // …… // …… // 100行以上処理が続いてたんじゃないかなぁ } else { throw new RuntimeException("updateFlag が false なのは不正") } 例外処理 先が原則
リファクタリング 進め方 • まず テスト ◦ Unit テストがなけれ テストを作る ▪
あるべき仕様がわからない場合 To Be で なく As Is で良い で作る • 小さな変更と変更 たび テスト ◦ 壊れたときにすぐわかる ▪ デバッグ範囲が限定される ◦ 成功したらコミット ▪ 壊れてもすぐに戻せる
忘れて ならないこと • リファクタリング 直接的にユーザに価値を届けるも で ない • 修正 必要がない場合
リファクタリング不要
まとめ • リファクタリングと • なぜリファクタリングをする か • いつリファクタリングをする か •
どこをリファクタリングする か (リファクタリング事例) • リファクタリング 進め方
参考書籍