最初のチェックインから16年後、SQLiteは世界で最も広く導入されているデータベースエンジンになりました。このようなオープンソースプロジェクトは、コードを理解しやすく保守しやすくする方法を学ぶための優れた教材です。
まず次のコードスニペットから、SQLiteコードベースに関するいくつかの事実を見てみましょう。

この関数からは、いくつかの点が読み取れます。
- 関数は static として宣言されている。
- 関数はエラーコードを返す。
- 関数のパラメータは少数しかない。
- 関数はできるだけ早く終了する。
- 特定の条件を確認するためにアサーションが使われている。
- グローバル変数は使われていない。
- 変数名が分かりやすい。
- メソッドが短い。
- 本体内に不要なコメントがない。
- 関数本体が適切にインデントされている。
SQLiteのソースコードをたどると、実装の一貫性が分かります。同じベストプラクティスルールがすべての関数に適用されています。
SQLiteコードベースから学べるベストプラクティスをいくつか紹介します。
データモデルは構造体に格納する
Cプログラミングでは、関数は変数を使って処理を実行します。これらの変数には次のようなものがあります。
- 静的変数。
- グローバル変数。
- ローカル変数。
- 構造体の変数。
どのプロジェクトにもデータモデルがあり、それは多くのソースファイルから使用される可能性があります。グローバル変数を使うことも選択肢の1つですが、良い方法ではありません。一般に、データを構造体にまとめる方が望ましい方法です。
CQLinq と CppDepend を使って、定義されている構造体を検索してみましょう。

データモデルを指定するために、多くの構造体が使われています。
関数は短く簡潔に保つ
関数の長さに関するアドバイスが、 LinuxコーディングスタイルのWebページ:
Functions should be short and sweet, and do just one thing. They should
fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
as we all know), and do one thing and do that well.
The maximum length of a function is inversely proportional to the
complexity and indentation level of that function. So, if you have a
conceptually simple function that is just one long (but simple)
case-statement, where you have to do lots of small things for a lot of
different cases, it's OK to have a longer function.コード行数が30行未満の関数を検索してみましょう。

90%を超える関数が30行未満です。
カプセル化
カプセル化とは、実装内部の関数とデータを隠蔽することです。Cでは、static キーワードを使ってカプセル化を行います。これらのエンティティは、ファイルスコープの関数と変数と呼ばれます。
次のCQLinqクエリを実行して、すべての static 関数を検索してみましょう。

ご覧のとおり、多くの関数が static として宣言されています。
関数パラメータの数
NbParameters > 8 の関数は呼び出しにくく、パフォーマンスを低下させる可能性があります。もう1つの方法は、引数渡しを処理する専用の構造体を用意することです。

パラメータが8個を超える関数はごく少数です。
ローカル変数の数
NbVariables が8を超える関数は、理解と保守が難しくなる可能性があります。NbVariables が15を超える関数は非常に複雑であり、より小さな関数に分割すべきです(ツールによって自動生成された場合を除きます)。

ローカル変数が15個を超える関数はごく少数です。
複雑な関数を定義しない
複雑な関数を検出するメトリクスは多数あります。NBLinesOfCode、パラメータ数、ローカル変数数は基本的なものです。
複雑な関数を検出するための、ほかにも興味深いメトリクスがあります。
- 循環的複雑度は広く使われている手続き型ソフトウェアメトリクスで、その結果はプロシージャ内で取り得る判定の数に等しくなります。
- ネスト深度は関数に対して定義されるメトリクスで、関数本体内で入れ子になったスコープの最大深度を表します。
- 最大ネストループは、関数内のループネストの最大レベルです。
これらのメトリクスで許容される最大値は、標準的な値が存在しないため、主にチームの判断に依存します。
リファクタリングの候補となる関数を検索してみましょう。

複雑と見なせる関数はごくわずかです。
const正確性を保つ
Cでは、 const キーワードを使って、オブジェクトが変更できないこと、関数がパラメータを変更しないことを示せます。適切な場所すべてで const を使うことは「const正確性」と呼ばれます。最初は難しいですが、const を使うとコーディングスタイルが本当に引き締まります。
少なくとも1つの const パラメータを持つ関数を検索してみましょう。

関数の結合度
多くの関数を呼び出す関数は、理解と保守が難しくなる可能性があります。関数の求心性結合度(efferent coupling)は最小限に抑えることが推奨されます。
SQLiteでは、高い求心性結合度を持つ関数はごくわずかです。

可能な場合は関数を早めに終了する
関数からの早期終了、特に関数冒頭のガード節による早期終了は、その後のロジックを単純化するため推奨されます。
SQLiteのソースコードでは、このベストプラクティスがほぼすべての関数に適用されています。
まとめ
有名なオープンソースプロジェクトを探索することは、常にプログラミングスキルを高める良い方法です。プロジェクトをダウンロードしてビルドする必要はありません。GitHub上でコードを探索するだけで十分です。
