「関数は何行までならよいですか」と聞かれることがあります。
目安はありますが、行数だけで良し悪しは決まりません。
一言でいうと
長い関数を分ける基準は、行数ではなく、同じ抽象度で1つの目的を説明できるかです。
20行でも読みにくい関数はあります。80行でも、順番に処理を読むだけで理解できる場合もあります。
行数だけで判断しない
次の関数は短いですが、読みにくいです。
function f(u: User) {
return u.a && u.b > 18 && !u.c && u.d?.includes("x");
}
行数は1行です。しかし、何を判定しているのか分かりません。
逆に、少し長くても、処理の流れが自然なら読みやすいことがあります。
分けるべきサイン
| サイン | 分ける理由 |
|---|---|
| ネストが深い | 条件を追う負担が大きい |
| コメントで区切りがある | 関数として切り出せる可能性がある |
| 変数が多い | 複数の関心が混ざっている |
| テストしづらい | 小さな単位で確認できない |
| try/catchが広い | 失敗箇所が分かりにくい |
特に、コメントが「ここから入力チェック」「ここから保存処理」のようになっている場合は、関数名に置き換えられることがあります。
Extract Function
長い関数を分ける代表的なリファクタリングが、Extract Functionです。
function checkout(cart: Cart) {
validateCart(cart);
const total = calculateTotal(cart.items);
return createOrder(cart.userId, total);
}
外側の関数は流れを示し、詳細は小さな関数へ分けます。
分けすぎのサイン
関数分割にもやりすぎがあります。
- 1処理を追うために何度もジャンプする
- 関数名が実装と同じことしか言っていない
- 引数が多くなりすぎる
- どの関数が本体か分からない
- テスト対象が細かすぎて意味が薄い
関数分割の目的は、読む人の負担を減らすことです。ファイル数や関数数を増やすことではありません。
初学者向けの目安
最初は次の基準で考えると十分です。
- 1画面に収まらなくなったら見直す
- ネストが3段以上なら見直す
- 関数名に
andが入るなら見直す - コメントで処理を区切っているなら見直す
- テストしたい部分だけ切り出せないなら見直す
絶対ルールではなく、考えるきっかけとして使います。
まとめ
関数の良し悪しは、行数だけでは決まりません。
長い関数は、抽象度、変更理由、ネスト、テストしやすさを見て分けるか判断します。