プログラマーの尾関です。
仕事でプログラムをしていると、自分で一からコードを書くよりも誰か他の方が書いたコードを引き継いだりすることが多いです。
その際に、前任者が在籍している、もしくは引き継ぎ資料があればスムーズに引き継ぎできますが、場合によっては、ソースコードだけ渡されて「後はよろしく」なんてことがあります。
そこで、今回は「他の方が書いたコードを引き継いだ」ときに、そのコードを理解するために私がやっていることをまとめました。
■1. どのコードから読むか見当をつける方法
まずはどのコードから読むかです。重要な部分から見ていくのが良いと思います。ゲームプログラムであれば、重要なのはゲームのメインとなる部分です。
例えばアクションゲームであれば、メインキャラクターの処理、ステージの処理、当たり判定の処理などが重要な部分になります。
▼「ゲームシーケンスの管理モジュール」に注目する
重要な機能が記述されているモジュール群を見つけたら、次にそのなかでも重要なモジュールを見つけます。最初に見るべき重要なモジュールは「ゲームシーケンスの管理モジュール」です。
シーケンス管理モジュールには、たいてい以下のような名前がついていることが多いです。
- Manager (Mgr) : マネージャー
- Sequence (Seq) : シーケンス
- Controller (Ctrl) : コントローラー
あと、重要なモジュールはファイルサイズが大きいことが多いので、そういったコードから見るのもありですね。
■2. コードの読み方
続いてコードの読み方です。
▼シーケンス管理モジュールの読み方
ゲームシーケンスは、たいていステップ(Step)変数 / ステート(State)変数 があり、それを switch文で制御していることが多いです。なのでこれを中心に流れを見ていきます。
そのときに理解したシーケンスの流れは、テキストにまとめたり、図にまとめておくと後で見返すときに役に立ちます。
特に図を作ると、視覚情報で確認できるので全体の把握が容易となりますね。
仕事で作った画像は出せないので、趣味で作ったローグライクのターン制処理のフローです。
このようにステップ名を矢印でつなぐだけの簡単なものですが、これを作るだけでも整理して理解できるようになってオススメです。
あとはこれらの情報を共有のファイルサーバーやWikiにアップしておくと良いです。Wikiは共有しやすく他のメンバーも編集可能ですが、自分しか見ない情報であればテキストにしておくだけでも十分です。
▼コメントを入れる
ソースコードに自分のコメントを追記するのも良いです。コメントを増やすだけであれば、コードへの影響がないため気軽に追加できます。
コメントが少ないコードであれば、どんどん追加して問題ないですし、すでにコメントがあってもその意味がわかりにくければ、自分なりのわかりやすいコメントを入れていくのも良いです。
▼リファクタリングする
リファクタリングはコードを理解する際、とても役に立ちます。
- リテラル値を定数に置き換える
- enumの型を指定する
- 変数に const を付ける (定数化できるならば)
- 公開しなくても良い関数を private にする
- 配列へのアクセスは関数を通して要素数チェックをする
- コンパイラの警告を除去する
ゲームプログラムはどうしてもルーズな作りになりやすいので、そのあたりを整えます。
また、リファクタリングの「コードの不吉な臭い」に該当するような以下の部分も修正していきます。
- 重複したコード (→ 同一の関数にまとめる)
- 長すぎる関数 (→ 関数を分割する)
- 多すぎる引数 (→ 引数を構造体にする)
- 1つの機能を追加するのに複数箇所修正が必要 (→修正が入りそうなところを定数化、共通の関数化)
- 長すぎるswitch文 (→ 関数テーブルにする)
ただ、リファクタリングもやり過ぎると時間がかかりすぎたり、バグを混入してしまう可能性があります。
なので使えるところは使って、修正がたくさん入りそうなところは、どんどんリファクタリングすると良いかと思います。
■3. その他:よくわからないコードの対処方法
調べたけれどわからないコード、どこで処理をしているのかわからないコードを探すときに個人的に使っている方法を紹介します。
▼高速なファイル検索ツールを使う
コードを読んでいると、特定のリソースをロードしていたりして、そのリソースがどこにあるかを知りたいときがあります。
そういったときは、ファイル検索ツール「Everything」が高速でおすすめです。
Windows標準でもファイル検索機能はありますが、検索速度が遅いので、こちらが役に立っています。
▼使い方がよくわからない変数を調べる方法
ある変数の使われ方を調べたいといったときに、1ファイルであれば対象のファイルを開いて検索、複数ファイルであればgrep検索で調べることになると思いますが、変数名がよくある名前 (例えば “id” など) の場合、検索しづらいときがあります。
その場合、「あえて未定義の変数名にしてコンパイルする」と良いです。
すると、使っている場所が未定義変数のコンパイルエラーで表示されるため、使われ方を簡単に探し出すことができます。
▼特定の画面を処理しているコード部分が全くわからない
巨大なプロジェクトでは、ある画面を記述しているコードの部分が全くわからないことがあります。
その場合、私は以下の手順で当たりをつけています。
- 画面に出ている文字(メッセージ)や画像から定義しているリソースを探す
- 対象のリソースを読み込んでいる or 使っている場所からコードを割り出す
一見、遠回りしているようですが、この手順を使うと、以外にも素早く対象のコードを見つけ出せることがあります。
▼リソース追加の手順をまとめる
よくわからないコードへの対処方法とは別の話題ですが、リソース追加の要望に対応しなければならないこともあります。
例えば、
- 操作可能なプレイヤーキャラクターを増やしたい
- 敵キャラを追加したい
- 特殊技を追加して欲しい
- アイテムを増やしたい
などです。
これが1箇所への変更であれば問題ないですが、たいていはコードの複数箇所を修正しないと問題が起きる可能性があります。
複数箇所への修正は、漏れがあるとゲームが止まってしまうこともあるかもしれません。あるゲームでは、新しいキャラクターを追加するために40以上の書き換えが必要でした。
そういった場合に、変更手順をテキストやWikiにまとめておくと、ミスも減らせて、情報共有ができて良いと思います。
■最後に
最後に、コードを引き継いだときの心構えを紹介しておきます。
コードを引き継ぐときに大切なのは、書いた人の思想や気持ちを理解することです。
引き継いだコードは自分とは異なる思想で書かれているため、意図がつかみにくいかもしれません。特に他社様の書かれたコードを引き継ぐと、文化の違いのため、自社で書いたコードよりも理解が難しいです。
ですが、そのコードが書かれたときの状況を考えたり、「何を思ってそのコードになったか?」を考えることで、より理解が深まるかもしれません。
例えば、書き方のクセを理解するのも良いかもしれません。ある処理を実装するときに、Aというモジュールを使って、Bという書き方をしていたとすると、他に似たような処理を調べると、同じようにAを使ってBの書き方をしていることが多いです。
そうやって思想を知ることで、調べる速度や理解する速度が上がっていく、というわけです。