久保清隆のブログ

ライフハック、健康、旅行など、役立つ情報を書きます。

きれいなプログラミングコードの書き方:プログラミングの基礎知識

プログラマによって色々なプログラミングスタイルがあると思うが、センス・オブ・プログラミング! 抽象的に考えること・データ構造を理解することを読んで、きれいなプログラムを書く方法については共通点があると思ったので、本書を参考にきれいなプログラミングコードを書く方法についてまとめた。




目次

目的を理解する

何らかのコーディング規約に従ってプログラムを書くなら、常にその理由を理解すること。
盲目的に規約に従うことは、規約が全くないこと以上に危険。
例えば、「即値を直接書いてはいけない」という規約を守って、

a = 10 

を、

CONST10 = 10
a = CONST10

と書いても意味はない。
「即値を直接書いてはいけない」という規約は、

  • 「数字の意味を理解できること」
  • 「変更したい時に一か所だけ変更すれば全て変更できる」

というところに意味がある。

LIMIT = 10
a = LIMIT

のように、意味をわかるようにする必要がある。
コーディング規約は、きちんとその意味を理解した上で守らなければ意味がない。


書く時のことよりも、読む時のことを考える

変数名の長さをどうするか、について以下の2つの意見がある。

  • 変数名をあまり長くすると、タイプするのが大変だし、タイプミスも増えるから、短めの名前にするのがよい
  • 変数名を短くしようとすると、わかりにくくなるから、省略しないで長い名前にするのがよい

前者は書く時の利便性、後者は読む時の利便性を重視している。
プログラムは、常に読む時のことを重視して記述されるべきである。
なぜなら、プログラムは、必ず保守されることになるからだ。変数は、少し長くなってもわかりやすさを重視すべきである。


愚直でも読みやすく

かつては、タイプ量が少ないプログラムほど、よいプログラムという説が横行したが、プログラムを書くなら、ソースを短くするというくだらないことに労力をかけるよりも、あとの読みやすさを優先させるべきである。
ただし定石は守った方がよい。
プログラムが多少縦に長くなっても、読みやすいプログラムを書こう。


インデントは統一する

インデントとは、ソースを書く時に「if」などをわかりやすくするようにつける字下げのこと。

  • 多人数で開発を行っているのであれば、そのプロジェクトのコーディング規約に合わせる。
  • 個人で書いているなら、世間に広く使われているスタイルを選び、以後ずっとそれを使う。


コメントは無駄なコメントを書かずソースの意図を書く

コメントについても以下の2つの対立した意見がある。

  • コメントは、あとでプログラムを読むときの助けになるから、大量に書くべき。
  • コメントは、あとでプログラムを読むとき、邪魔にしかならないから、できるだけ書かない。

入門書では前者が支持されているが、世の中に存在する大半のコメントは無駄であるか有害である。

@user_id #ユーザID

と書くのは無駄である。なぜなら変数名を見ればわかるからだ。
ボックスコメントも、プログラム全体の見通しを悪くするし、書くのも面倒であるし、コメントの書き換え忘れにより嘘のコメントになることが多々あるので、必要最小限に抑えるべきである。プログラムは直したけど、コメントは直し忘れるというのはよくある話である。
逆に、コメントがなくても読めるプログラムを書くように心がけるべきだ。
コメントを書く場合は、「なぜそのようなソースを書いたのか」という意図がわかるようなコメントにすべき。意図を残しておかないと後でプログラムを保守する人がわからなくなる場合には書くべきである。
ソースを見れば意図も一目瞭然というのが理想だが、どうしてもうまく書けないとき、必要悪として補うものという認識を持った方が良い。

※ドキュメントに書く内容は以下のような役割もある。

  • プログラムの概念や考え方を説明する
  • プログラムが本来どう動くべきかを定義する。あるプログラムの動きについて、それがバグなのか仕様なのかは、ドキュメントで定義されていなければならない。


例外は、本当に例外的な場合だけに使う

例外処理機構は便利だが、例外はプログラムの流れを強引にねじまげ、しかも逃げ道を残さないという面もある
例えば、データを検索するプログラムの場合、データが見つからなかったとき0件を返す仕様になっていれば、プログラムでは見つからなかった場合を意識する必要はないが、例外を返すようにしていると、フラグなどを導入したプログラムを書かざるを得なくなってしまう。
うかつに例外を使うべきではない。


名前のつけ方を重視

変数名、関数名、クラス名、メソッド名などはプログラムの読みやすさという点において、極めて重要な意味をもつ。
また、変数に変な名前をつける人は、そもそも変数が何を表現するものであるのか、はっきり意識できてないことが多い。それがはっきり意識できているなら、適切な名前が付けられるはず。
変数名や関数名がすぐに思い浮かばない場合、いったん手を止めて自分が何をしようとしているのかを考え直した方が良い。


命名法

  • 意味のある名前をつける

flagとかmodeといった名前を平気でつけるベテランプログラマがいるが、何のflagなのか、何のmodeなのかをわかるように書くべきである。

  • スコープの広さを意識する

スコープとは、ある名前があったとき、その名前が適用される範囲のことを意味する。
ローカル変数、インスタンス変数、グローバル変数などあるが、スコープの広いものほど、命名には気を遣う必要がある。
ローカル変数なら「p」などの1文字の変数名を使ってもさほど問題ない。
しかし、スコープが広い名前、特にグローバル変数は、十分に長い名前をつけなければ意味がわかならなくなってしまう。
また名前の衝突を避けるためには、命名規則を設けて、名前にプレフィクス(接頭辞)をつける。

  • 一貫性を持たせる

例えば何かを生成する関数の名前としては、create_xxx、make_xxx、消す場合はdestroy_xxx、delete_xxxなどが考えられるが、プログラム全体で統一する必要がある。
makeやcreateが混ざっていると読みにくい。


省略しない

省略記法を統一的に運用するのは極めて難しい。出来るだけ省略しないようにする。
ただし、ローカル変数などスコープの範囲が狭いものは、名前が短くても困らないので省略記法を使ってもさほど問題は出ない。


同じことを書いてはいけない

同じことを複数個所で書くと、必ずあとではまる。
理由は以下の通りである。

  • 修正する時にはすべての個所を直さなければならない

修正漏れでバグを出してしまうし、テストしなければならない項目が爆発的に増える。

  • 枝分かれしてしまうと、手に負えない

コピペされてしまったプログラムは、いずれ別々に手を入れられてそれぞれ異なる姿になっていく。すると、やはり修正する際、同じ修正を両方に入れることになるので大変。

  • 自分で何をしようとしているのかわかっていない可能性が高い

同じ処理を複数個所に書かないようにするには、その部分を関数にくくりだす方法が有効。
それをしないということは、適切な関数名が思いつかないとか、適切な引数が何になるのかよくわからない、という可能性が高い。


コピペをやめる

コピペするとプログラムの行数があっという間に増えていくからいかにもたくさん仕事をした気になるが、それは後に大変な借財を残すことを認識すべき。


関数に分割する

なぜ関数に分けるのか?

  • 同じことを複数の個所に書かないようにするため
  • 長い関数は読みにくいため
  • データのスコープ(有効範囲)を絞るため(ローカル変数のスコープが小さくなる、など)
  • プログラムの入出力を明確にするため(データの流れがわかりやすくなる)


机上デバッグは時間の無駄

机上デバッグではまずバグは見つからない。なぜなら、プログラマーには何らかの思い込みがあるからだ。
机上デバッグは思い込みを除去する役割を果たしてくれない。
実際に動かしてみて、どこがどのように意図通りに動いていないのかを検証するのが一番。
ただし、それを「行き当たりばったりでプログラムを書く言い訳」にしてはいけない。
また、再現性の薄いバグは、机上デバッグ以外に追跡の方法がない。


良いコードとコーディングレベル

[ThinkIT] 第1回:良いコードとは、心得5ヶ条 (1/4)
に「良いコードの定義」と「コーディングレベル」が記述されていたので追記。
具体例なども書かれていて素晴らしい記事。感謝です。

良いコード

  • 読みやすい
  • 適切なコメント
  • 速い、見た目がよい
  • 修正個所がすぐに分かる
  • 機能の追加・削除が楽
  • バグが無い
  • セキュリティが考慮されている
  • 仕様を満たしている
  • 落ちない

コーディングレベル

レベル1
外部仕様を満たすことができないプログラム
レベル2
外部仕様を満たすが読みにくいプログラム
レベル3
読みやすくなっているが、コードを分割できていないプログラム
レベル4
コード分割できているが、オブジェクト指向プログラミングできていない
レベル5
柔軟性/拡張性が高いプログラム


レベル5のコードを書けるように日々精進しよう。


センス・オブ・プログラミング! 抽象的に考えること・データ構造を理解すること

センス・オブ・プログラミング! 抽象的に考えること・データ構造を理解すること