Cutting Edge

ソース コードを読みやすくするヒント

Dino Esposito

Dino EspositoInternational Obfuscated C Code Contest (国際難読化 C コード コンテスト) というのを聞いたことはありますか。簡単に言えば、故意に読みづらい C 言語コードで問題を解決するプログラムを書き、そのコードの汚さを競う公開コンテストです。ここ数年間に優勝したプログラムのソース コードは、ioccc.org/years.html (英語) で公開されています。

C コードの難読化を競うコンテストは、プログラミングのスタイルや読みやすさの重要性がわかる愉快な取り組みです。今回は、自身にも同僚にも読みやすく、理解しやすいコードを書くために従いたい最も重要な実践手法をいくつか紹介します。

読みやすさという特性

ソフトウェア開発におけるメンテナンスの容易さとは、既存のコードを変更する場合の容易さを表す特性です。この場合の既存のコードの変更とは、バグ修正、ハウスキーピング、新機能の実装、なんらかのパターンへのリファクタリングなどの目的を実現するために行う変更を指します。ISO/IEC 9126 の文書では、メンテナンスの容易さがソフトウェアの基本特性の 1 つに挙げられています。ソフトウェア特性の詳細については、bit.ly/VCpe9q (英語) の文書を参照してください。

コードのメンテナンスが容易かどうかには、さまざまな要因が関係します。その 1 つが読みやすさです。読みにくいコードは、理解するのも困難です。開発者がコードをきちんと理解しないで手を加えようとすると、コードはさらに悪い方向に進みます。

ただし、読みやすさというのはきわめて主観的な問題です。コードの読みやすさのレベルをチェックしてレポートするような自動ツールを開発するのはほぼ不可能です。たとえ、読みやすさの自動測定を実現できたとしても、そのようなツールが利用される可能性は低く、信頼する開発者も少ないでしょう。結局、読みやすさとは、個々の開発者がチェックしなければならない手作業を必要とする特性です。読みやすいコードを書く能力は、個々の開発者がスキルを広げるために育むべき教養の一部です。

一般に、読みやすさとは、プログラミングのキャリアを始めるときに正しく身に付けるように学習し、時間をかけて成熟させ、改善していくべきものです。スタイルや優れたデザインも同じですが、読みやすさとは専門家だけが持っているものではありません。さらに重要なのは、時間に余裕ができるまで先延ばしにしないことです。

読みやすさに対する実用的アプローチ

読みやすいコードを書くかどうかは、他の開発者に対する配慮の問題です。StackOverflow のユーザーは以前、「コーディングするときは、常に、そのコードをメンテナンスすることになる担当者があなたの居場所を探すストーカーにならないようにすべきだ」と投稿しています。また、いつか自分がコードをメンテナンスする立場になるかもしれないと考えることも大切です。

他人のコードを読むときに、いらだちを感じる点がいくつかあります。コードが読みにくくなる理由の 1 つは、明確な目標のないデータ構造やアルゴリズムです。もう 1 つは、判断が難しく、コメントで詳しく説明されていない不明瞭な方針でコードが作成されている場合です。以下に例を示します。

// Find the smallest number in a list of integers
private int mininList(params int[] numbers)
{
  var min = Int32.MaxValue;
  for (var i = 0; i < numbers.length; i++) {
    int number = numbers[i];
    if (number < min)
      min = number;
  }
  return min;
}

わかりやすくなるようにこの例を C# に移植するとします。しかし、正直なところ、これは C# の開発者が記述しようと考えるコードではありません。C# と Microsoft .NET Framework を使用する場合は、LINQ を使用するのとほぼ同じ結果になるようにコードを記述します。Java で記述した部分は別にして、1 つのプロジェクトに同じようなコードが見つかります。ある意味、コードベース全体を .NET Framework と C# に移植するために雇われたような感じです。

実際の .NET プロジェクトでも、このようなコードを目にします。目的を見失うことなく読みやすくするために考えるべきことがいくつかあります。関数の中でまず読みやすくないのが名前です。名前の表記法に問題があります。この名前には動詞が含まれておらず、大文字と小文字の使い方も適切ではありません。おそらく、GetMinFromList のような名前が妥当です。しかし、最も問題なのは、名前に付けた private 修飾子です。

コードを眺めてみると、この関数がユーティリティとして機能することがわかります。つまり、このコードは再利用可能で、コードベースの他のさまざまな場所から呼び出すことができます。したがって、private とマークすることは必ずしも適切ではありません。ただし、開発者は YAGNI (You Ain’t Gonna Need It、今必要なことだけを行う) の原則に従う重要性を理解しているため、明確に必要とされていないコードを公開しないと考えるのもわかります。

コードの作成者は再利用の可能性を予測できましたが、作成時には再利用の必要性はありませんでした。そのため、再利用可能なヘルパー関数に簡単に変換できるように記述しましたが、ホスト クラス内でのみ可視になるように private とマークしました。このコーディングの意図は、外部の読み手にとってはすぐにわかりません。しかし、その目的を説明する数行のコメントを記述するだけで状況は変わります。適切なコメントを追加しなければ、わかりやすいコーディングになりません。読み手はいずれ意味を理解するでしょうが、時間がかかります。悪くすれば、作成者に反感を持つかもしれません。

読みやすさのための実用的規則

コードの読みやすさは、その重要性は広く認識されていながら必ずしも形式化されていないテーマの 1 つです。言い換えれば、形式化されていないため、コードの読みやすさがほぼ意味のない考え方になります。結論から言えば、読みやすさは 3 つの C のルールに従って取り組みます。3 つの C とは、コメント (Comment)、一貫性 (Consistency)、明確さ (Clarity) です。

現在の IDE ツールは、数年前と比べれば非常に洗練されています。開発者は、Visual Studio プロジェクトでヘルプ ファイルを作成することも、独自のドキュメントを組み込むことも必要なくなりました。ツール ヒントはあらゆる場面に表示され、コメントから自動的に作成されます。最新の IDE では編成用コメントの定義が容易になり、考える必要があるのはコメントのテキストだけで、残りは IDE が行います。編成用コメントはこれまでのコメントと同じものですが、メソッドやクラスの目的を簡単に説明するために追加します。これらのコメントは、プラットフォームや言語の標準に従って記述します。また、パブリック コードを作成する場合は、編成用のコメントは必須だと考えます。

読みやすさの向上に向けたもう 1 つの基本ステップは、見てすぐにわかるコードにはコメントを付けないことです。このようなコメントは余計なだけで、関連情報が追加されることはありません。その名のとおり、コメントとは、見てすぐにはわからないコードの意図することを説明するテキストです。コメントは、コードの特定の側面に関する洞察力に富んだ解説にすべきです。

2 つ目の "C" は一貫性 (Consistency) です。コードを記述する際、全チームが同じガイドラインを使用する必要があります。このようなガイドラインを全社で使用するとさらによくなります。多くのガイドラインは、ガイドラインがどうあるべきかを定義するところで終っており、何が正しく何が間違っているかの意味づけを試みることで終っています。あえて言えば、コード全体で同じ処理を常に同じ方法で行うことの重要性と比較した場合、何が正しくて何が間違っているかはあまり重要ではありません。

たとえば、文字列操作を行うライブラリを記述しているとします。ライブラリ内の数か所で、文字列に特定の部分文字列が含まれているかどうかを確認する必要があるとします。これを行うにはどうすればよいでしょう。.NET Framework と Java SDK では、同じ結果を実現する方法が少なくとも 2 つあります。使用できるのは Contains メソッドか IndexOf メソッドです。ただし、この 2 つのメソッドは目的が異なります。

Contains メソッドはブール値の答えを返し、部分文字列が特定の文字列内に含まれているかどうかだけを示します。IndexOf メソッドは見つかった文字列の位置を示す 0 から始まるインデックスを返します。部分文字列が見つからなければ、IndexOf は -1 を返します。純粋に機能だけを見れば、Contains と IndexOf は同じ目的を実現できます。

ただし、コードの読み手にとってはこの 2 つのメソッドから受けるメッセージが異なります。読み手はコードを見直して、Contains ではなく IndexOf を使用する特別な理由があるかどうかを確認することになります。もちろん、もう 1 回コード行が見直されても問題があるわけではありません。しかし、数千行のコードから成るコードベース全体でこの見直しを行うとすると、時間にもコストにも影響があります。これは、読みやすくないコードにかかる直接コストです。

コードの一貫性という感覚は、常に備えておかなければならない責務です。開発者としては、後からコードを整理する時間を十分に取れるとは考えずに、最初からわかりやすいコードを記述することを目指します。チーム リーダーとしては、チェックイン ポリシーにコードの一貫性に関するガイドラインを適用します。理想を言えば、一貫性のテストに合格しないコードのチェックインは許可すべきではありません。

ReSharper の最新バージョンが、この考えの実現にかなり役立つ可能性があります。このような無料のコマンド ライン ツール (スタンドアロンのツール セット) を使用すると、コード品質分析手法を、継続的インテグレーション (CI) やバージョン管理システムに適切に統合できます。これらのコマンド ライン ツールによって、オフラインのコード検査を実行できます。ReSharper を一緒にインストールすると、このオフラインのコード検査が Visual Studio 内でリアルタイムに実行され、コード内に含まれる重複部分を捕捉できます。CI のカスタマイズ機能によっては、アドホック コンポーネントにコマンド ライン ツールをまとめることが必要になる場合があります。ReSharper の詳細については、bit.ly/1avsZ2R (英語) を参照してください。

最後の 3 つ目の "C" は明確さ (Clarity) です。コードを明確にするには、スラスラと簡単に読めるようにスタイルを設定します。スタイルには、適切なグループ化と入れ子を含めます。一般に、IF ステートメントを使用すると、余分なコードが増えます。プログラミング言語の 1 つの柱である条件付きステートメントを避けることをできない場合もありますが、IF ステートメントの数を抑えると、入れ子が少なくなり、コードが読みやすくなります。また、入れ子になった IF ステートメントの代わりに、IF… ELSE … IF … ELSE 構造を使用することも考えます。

タスクによっては数行のコードが必要になり、"メソッドの抽出" リファクタリングの実行が困難になったり、不適切な場合があります。このような場合、この数行を空白行で区切ったブロック内に保持します。そうすれば、コードの内容が変わらずに、コードが読みやすくなります。最後に、ソース コードにスタイルを設定する方法については、オープン ソース プロジェクトが参考になります。

短さに勝るものなし

行が長くなると、人間の目には読み辛くなります。そのため、新聞や雑誌は、テキストを複数の段に分けて印刷しています。コードでも同じように、メソッドの水平方向の行の長さと垂直方向のスクロールの両方を制限します。メソッド本体の理想的な長さは、一般的に最大 30 行程度です。このレベルに達したら、警鐘を鳴らし、リファクタリングを検討するようにします。最後に、プロジェクト フォルダーを適切に整理して、フォルダーと名前空間を一致させると、個々のコード要素も適切に整理される可能性が高くなります。

読みやすく明確なコードをテーマにすると、わかりやすいコードの記述は面倒で時間がかかるという不満を聞くことがよくあります。こうした意見が出ないように努める必要があります。その方法は 2 つあります。1 つは、コード アシスタント ツールを使用する方法です。このツールは、リファクタリングの提案、不適切なパターンの検査、実行されないコードや重複コードのチェックを行い、わかりやすいコードの記述を支援します。ツールのすべての機能を利用できるようにすると、実際に、わかりやすく読みやすいコードを記述していない場合に言い訳ができなくなります。コード アシスタント ツールは、複数の大手ベンダーから提供されています。どれを選んでも同じです。

もう 1 つは、慣例としてよりわかりやすいコードを記述するように個々の開発者の自己啓発や姿勢に重点を置くことです。経験豊富な開発者はこのような姿勢を備えています。コードの最終形とはどの程度かけ離れているかを大まかに把握し、正確にコードを整理できるかどうかは、開発者の経験が豊富かどうかを区別する重要な特性です。


Dino Esposito は、『Microsoft .NET: Architecting Applications for the Enterprise』(Microsoft Press、2014 年) および『Programming ASP.NET MVC 5』(Microsoft Press、2014 年) の共著者です。JetBrains の .NET Framework および Android プラットフォームのテクニカル エバンジェリストでもあります。世界各国で開催される業界のイベントで頻繁に講演しており、software2cents.wordpress.com (英語) や Twitter (twitter.com/despos、英語) でソフトウェアに関するビジョンを紹介しています。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの James McCaffrey に心より感謝いたします。