
長い関数・巨大ファイルの読み方|一人保守で迷子にならない順番
「この送料の計算、どこで決まってるんだろう」
調べようと開いたファイルは3000行。目当ての関数だけで800行。if の中に foreach、その中にまた if。スクロールして下まで来たころには、上で読んだ分岐の条件をもう覚えていない。もう一度上に戻って、また途中で迷子になる——そんな午後、ありませんか。
長いコードが読めないのは、あなたの読解力が足りないからではありません。何年もかけて継ぎ足された800行を、上から順に全部頭に入れようとすれば、誰でも迷子になります。必要なのは、読み方の順番を変えることです。
この記事では、長い関数・巨大な1ファイルを「全部読まずに、必要なところだけ確実に読む」ための手順を、一人保守の現場目線で一緒に整理していきます。
結論:長いコードは、上から順に全部読まなくて大丈夫です。やることは4つ。①何を知りたくて読むのかを1行で書く、②中身を読む前に、入口・分岐・出口だけ拾って「地図」を描く、③追いかける値を1つに決めて、その値が変わる場所だけを読む、④読んだことを行番号つきでメモしながら、最後は動かして確かめる。そして、読めたからといって、その場で分割や書き直しはしない。まずは「知りたいこと」を1行書くところから始めましょう。
なお、ここで挙げるコマンドやエディタの機能は一例です。言語・エディタ・バージョンによって使えるものが違うので、手元の環境で試しながら読み替えてください。
何が起きているのか:長いコードが読めない2つの理由
まず、なぜこんなに読みにくいのかを知っておくと、少し気が楽になります。
1つ目は、コードが「継ぎ足し」で育っていること。 最初は100行だった関数に、「この顧客だけ例外」「この時期だけキャンペーン」「この不具合の暫定対応」と、改修のたびに if が足されていきます。一つひとつの改修は正しくても、全体を見直す時間はなかなか取れません。結果として、ひとつの関数に入力チェック・計算・DB保存・メール送信・ログ出力が全部入っている、という形になりがちです。
2つ目は、人が一度に覚えておける量には限りがあること。 上から順に読むと、「いまどの if の中にいるか」「この変数はどこで何が入ったか」を全部覚えたまま進むことになります。ネストが3段、4段と深くなれば、覚えきれなくなるのは当然です。
つまり、読めないのはコードの形と読み方の組み合わせの問題です。読み方のほうを、覚えなくていい形に変えれば、長いコードでもちゃんと読めるようになります。
手順1:何を知りたくて読むのかを、1行で書く
最初にやるのは、コードを開く前のひと手間です。このコードを読んで、何が分かれば今日はゴールなのかを1行で書きます。
- 「送料が0円になる条件はどこで決まっているか」
- 「注文確定メールは、どの処理のあとに送られているか」
- 「このエラーメッセージは、どの分岐で出ているか」
目的が決まると、読まなくていい部分がはっきりします。送料の条件を知りたいなら、メール送信の部分やログ出力の部分は「ここは送料と関係ない」と飛ばしてかまいません。
長いコードで迷子になるいちばんの原因は、「念のため全部理解しておこう」と思ってしまうことです。ここは現場でもつい欲張りたくなるところですが、今日知りたいことだけ分かれば十分です。全体の理解は、何度か読みに来るうちに少しずつ積み上がっていきます。
手順2:中身を読む前に「地図」を描く

目的が決まったら、いきなり中身を読み始めずに、関数の「形」だけを先に拾います。拾うのは3つだけです。
- 入口:この関数は何を受け取るか。引数、グローバル変数、
$_POSTやリクエスト、DBから最初に読み込んでいるもの。 - 分岐:大きな
if/switch/ ループがどこにあるか。ネストの深い中身は読まず、「何行目から何行目が、どんな条件のブロックか」だけ見ます。 - 出口:この関数は何を返すか、何を変えるか。
return、DBへの保存、画面出力、メール送信、例外を投げる場所。
エディタの機能を使うと、この地図づくりがぐっと楽になります。
- 折りたたみ(フォールディング):ブロックを全部たたむと、関数の骨組みだけが見えます。VS Codeなら「すべて折りたたむ」のあと、知りたいブロックだけ開いていけます。
- アウトライン表示:ファイル内の関数・メソッドの一覧を出せます。巨大ファイルで「どこに何の関数があるか」を最初に眺めるのに便利です。
- 定義へ移動/参照の検索:呼び出している関数へ飛んだり、どこから呼ばれているかを一覧したりできます。
エディタが使えないサーバー上でも、grep で骨組みは拾えます。
# ファイル内の関数の一覧と行番号(PHPの例)
grep -n -E "^\s*(public |private |protected |static )*function " order.php
# 長い関数の中の、分岐と出口だけを行番号つきで抜き出す(例:200〜1000行目)
sed -n '200,1000p' order.php | grep -n -E "^\s*(if|else|elseif|switch|case|foreach|for|while|return|throw)\b"
2つ目のコマンドの行番号は、200行目を1行目として数えた番号になる点だけ気をつけてください(元の行番号に直すには199を足します)。
拾ったものは、紙やメモに箇条書きの地図にしておきます。
calcOrder() 210〜1010行
入口:$order(注文), $customer(顧客), 設定 SHIPPING_FREE_LINE
230-310 入力チェック(エラーなら return false)
320-540 商品ごとの金額計算(foreach)
550-700 送料の計算 ← 今日見るのはここ
710-860 クーポン・キャンペーン
870-980 DB保存・メール送信
出口:return $total(990行目)
これだけで、800行が「6つのかたまり」に見えてきます。今日読むのは、そのうちの1つだけです。
手順3:追いかける値を1つに決めて、変わる場所だけ読む
地図ができたら、いよいよ中身です。ここでも上から順には読みません。手順1の目的に関わる値を1つ決めて、その値が「作られる・変わる・使われる」場所だけを拾います。
送料の例なら、追いかけるのは $shipping です。
# $shipping が出てくる行を、行番号つきですべて出す
grep -n '\$shipping' order.php
出てきた行を、次の3種類に分けて印をつけます。
- 作られる:最初に値が入る場所(
$shipping = 800;など) - 変わる:上書き・加算・条件つきの書き換え(
$shipping = 0;/$shipping += ...) - 使われる:合計に足される、画面に出る、保存される
送料が0円になる理由を知りたいなら、見るべきは「変わる」の行と、その行を囲んでいる if の条件だけです。800行あっても、実際に読む行は数十行に絞れることがほとんどです。
途中で、値が別の関数に渡されたり、別の名前の変数に入れ直されたりしたら($fee = $shipping; など)、そこから先は新しい名前で同じことを繰り返します。エディタの「参照を検索」を使うと、この追いかけがかなり楽になります。
手順4:読んだことを、行番号つきでメモしながら進む
長いコードを読むときにいちばんもったいないのは、一度分かったことを、翌週また一から読み直すことです。読みながら、分かったことを行番号つきでメモしておきます。
2026-10-03 calcOrder() 送料の調査
- 552行 送料の初期値は設定 SHIPPING_BASE(800円)
- 581行 合計が SHIPPING_FREE_LINE 以上なら $shipping = 0
- 603行 顧客区分が「法人」なら $shipping = 0(2019年の改修。git blame で確認)
- 640行 離島の住所なら +1200(ここは0円のあとに足される → 法人でも離島は有料)
- 未確認 クーポンで送料が変わる処理が 710行以降にあるか
ポイントは3つです。
- 行番号を書く:あとで同じ場所にすぐ戻れます。コードが変わったときのために、日付も添えておきます。
- 「未確認」も書く:分からなかったことを残しておくと、次に読む人(未来の自分)が続きから始められます。
- 「なぜこうなっているか」は推測で埋めない:経緯が気になる行は、
git blameやコミットログで確かめてから書きます(git blameで「なぜこのコードか」を追う)。
このメモは、そのまま調査ログや運用ドキュメントの材料になります。コードの中にコメントとして書き足したくなったら、それは読み終えて、内容に自信が持ててからで十分です。
手順5:最後は、動かして確かめる
読んで「たぶんここだ」と思えたら、検証環境で実際に動かして確かめます。長いコードほど、読み違いが紛れ込みやすいからです。
- ログを仕込んで値を出す:怪しい行の前後で、追いかけている値と条件の結果を出力してみます。本番で原因を追うためのログの考え方は改修時にログを仕込むでまとめています。
- デバッガで止めて見る:PHPならXdebugのように、行で処理を止めて変数の中身を見られる道具があります。一度設定しておくと、長い関数の調査がぐっと速くなります。
- 条件を変えて2回動かす:「法人で離島」「個人で離島」のように、条件を1つだけ変えて結果を比べると、どの分岐が効いているかがはっきりします。
本番環境で試すのは避けて、検証環境か、手元に用意した環境で行ってください。
AIのコード要約を使うときは「仮説」として扱う
最近は、エディタに組み込まれたAIアシスタントに長い関数を要約してもらうこともできます。地図づくりの最初のとっかかりとしては、とても助けになります。
ただし2つだけ気をつけておきたいところがあります。
- ソースコードを社外のサービスに渡してよいか、先に社内のルールや契約を確認する。顧客のコードや、パスワード・APIキーが書かれたままのファイルは特に注意が必要です。
- 要約は「仮説」として受け取り、行番号で裏取りする。長いコードほど、例外的な分岐が要約から抜け落ちることがあります。手順3の
grepで、実際の行を自分の目で確かめてからメモに書きましょう。
読めても、その場で分割しない
読み終えると、「この800行、分割したほうがいいな」と感じると思います。その感覚は正しいのですが、読んだその日に分割や書き直しを始めるのは、少し待ってください。
テストのない長い関数は、どこかの分岐が「たまたま正しく動いている」ことがあります。読むだけなら本番は壊れませんが、分割した瞬間に、その「たまたま」が崩れることがあります。
手を入れるときは、まず変更前の動きを確かめる手段を用意してからにしましょう。その進め方はテストがないコードに手を入れる前にやる安全策と触れないレガシーコードに"最初の一歩"をにまとめています。今日の地図とメモは、そのときの大事な下書きになります。
具体例:800行の関数で、送料0円の理由を30分で見つけた日
ある通販サイトを一人で保守している担当者の、よくある流れです。
- 問い合わせ:「離島のお客さまなのに、送料が0円で注文が入った」という連絡が来た。
- 以前のやり方:注文計算の関数(約800行)を上から読み始めた。途中のクーポン処理で迷子になり、1時間たっても送料の場所にたどり着けなかった。
- 順番を変えたやり方:
- 目的を「送料が0円になる条件を全部見つける」と1行で書いた。
- 折りたたみで関数の骨組みを見て、送料の計算が550〜700行あたりにあると地図に書いた。
grep -n '$shipping'で送料の変数が出てくる行を全部出し、「変わる」行を4か所に絞った。- 4か所をメモしていくと、クーポン処理の中(750行目)に「送料無料クーポンなら最後に
$shipping = 0」という行があり、離島の加算を上書きしていることが分かった。 - 検証環境で「離島+送料無料クーポン」の注文を作り、0円になることを確かめた。
かかった時間は30分ほど。変わったのは担当者の能力ではなく、読む範囲を800行から十数行に絞ったことでした。直すかどうか(離島でもクーポンを優先するのが仕様なのか)は、ここから依頼者と相談です(「これはバグか仕様か」の決め方)。
影響:読み方の順番を変えると、何が変わるか
- 調査の時間が読める:「全部読むまで分からない」から、「この値を追えば分かる」に変わり、問い合わせに「今日中に原因をお伝えします」と言いやすくなります。
- 同じ場所を二度読まなくて済む:行番号つきのメモが残るので、次の調査は続きから始められます。
- 改修の影響範囲が見えやすくなる:地図があると、「このブロックを変えると、出口のどれに響くか」を事前に考えられます(既存システムの改修|影響範囲を見落とさない調査の順番)。
- 「自分しか読めない」が少しずつ減る:地図とメモを共有しておけば、次にこのコードを開く誰かの助けになります。
明日やること
- 次に長いコードを開くとき、先に目的を1行書く。「今日は何が分かればゴールか」をメモの一番上に置きます。
- エディタの折りたたみとアウトライン表示を試す。使っているエディタで、関数を全部たたむ操作を1つ覚えておきます。
- 入口・分岐・出口だけの地図を書いてみる。行番号とブロックの役割だけの箇条書きで十分です。
- 追いかける値を1つ決めて、
grep -nで出てくる行を全部出す。「作られる・変わる・使われる」に分けて印をつけます。 - 読んだことを日付と行番号つきでメモに残す。調査ログや運用ドキュメントの置き場所に保存しておきます。
今日できるのは、1の「目的を1行書く」だけでも十分です。それだけで、次にファイルを開いたときの迷い方がずいぶん変わります。
長い関数・巨大ファイルを読むときのチェックリスト
- 何を知りたくて読むのかを、1行で書いたか
- 目的に関係ないブロックは「今日は読まない」と決めたか
- 関数の入口(引数・グローバル変数・最初に読むデータ)を書き出したか
- 大きな分岐とループの位置を、行番号で拾ったか
- 出口(return・DB保存・画面出力・メール送信・例外)を書き出したか
- 追いかける値を1つに決め、出てくる行をすべて拾ったか
- 値が「変わる」行と、それを囲む条件を確認したか
- 別の変数や関数に渡ったあとも、名前を変えて追いかけたか
- 分かったこと・未確認のことを、日付と行番号つきでメモしたか
- 経緯の推測は、git blame などで確かめてから書いたか
- 読んだ内容を、検証環境で動かして確かめたか
- AIの要約を使った場合、実際の行で裏取りしたか
- 読んだその日に、テストなしで分割・書き直しを始めていないか
全部できていなくても大丈夫です。「目的を1行」「値を1つだけ追う」の2つがあれば、長いコードで迷子になることはかなり減ります。
よければ、こちらも
- 仕様書がないシステムの仕様を、現状から起こす進め方:読んで分かったことを、仕様として残していくときに。
- git blameで「なぜこのコードか」を追う|履歴の読み方:「なぜこの分岐があるのか」を確かめたいときに。
- テストがないコードに手を入れる前にやる安全策|一人保守の現場で:読めたあと、実際に手を入れる前に。
- 技術的負債の見える化|優先順位のつけ方を一人運用の現場で:「この関数、いつか分割したい」を負債として記録しておくために。

長いコードの前で手が止まったのは、それだけ丁寧に、全部を理解しようとしてきたからです。その誠実さは、そのまま残して大丈夫です。変えるのは、読む順番だけ。
800行は、一度に読まなくていい。今日は1つの値を追いかけて、分かったことを1行メモする。それを何度か繰り返すうちに、あのファイルは「怖い場所」から「地図のある場所」に変わっていきます。次に開くときは、まず目的を1行、書いてみてください。
ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。