読者です 読者をやめる 読者になる 読者になる

その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

プログラムを書くときに心がけていること (12個)

「プログラムを書いてお金をもらう」という活動を始めてから1年ちょっと経ったので、
その中で学んだ事や、普段から気をつけている事をメモっておきます。
忘れっぽいので書かないと忘れてしまいそうです。しかし忘れてはならない。

以下メモ

1度やれば良い処理を2度以上やらない

1度だけ実行すれば十分な処理、例えば初期化処理なんかを複数回やるのは無駄だからやらない事。
「無駄」なだけ*1 で済めば良いが、最悪な場合にはプログラムがよくわからない動きをする事がある。*2

1度実行すれば良い処理を複数回実行するのは、パフォーマンス的にもソフトウェアの品質的にも得することが1つもないので排除すべき。
「そんなことやらねーよ!」と思っていても、プログラムの規模が大きくなってくると無意識のうちにやっている事があるので注意が必要。

同じ事を何度も書かない

上のにも似ているが、こっちはいわゆるDRY原則の方。
同じ処理を行うコードをあちこちに書くと、そのコードにバグが見つかったときなんかに修正するのが大変でよろしくない。*3
なので、同じ処理をするコードは関数やメソッド、あるいはクラスに抽出した方が保守のコストが低くなる上に、可読性も向上するし、再利用も出来るしで良い。
コードを書き始める前やコードを書いている間は、常に「どこか抽出できる所はないか」と処理の共通部分を探すように心がけるべき。

テストは積極的に書く

テストを書いておくと精神が安定する。
テストが通っているうちは「このプログラムは正しい動作をしている」と判断する事が出来るから。*4

テストドリブンだとその機能に関して正しい実装が保証されるので、「本当はこういう機能が欲しかったのに……ええい、作り直しじゃ!」という手戻りが少なくなる。
TDD は大変良いが、余裕が無くなってくるとついついおろそかになってしまって、「テスト? 後だ後!」となってしまうので改善していきたい。

あと、テストを書いておくとレグレッションを防げる (場合が多い) ので大変助かる。
リファクタリングなんかでソースコードをガンガンいじくり回す時でも、「テストが通れば大丈夫」という指標があるので安心。
ただ、過信は禁物。

コメントの書き方には注意を払う

コメントは無いと困るが、ありすぎても邪魔なので、「書くべき所」と「書くべきではない所」をしっかり区別する必要がある。
また、「目立たせる書き方」と「目立たせない書き方」を区別する必要もあると思っている。*5

あと、コメントの内容は簡潔に、かつ常に最新の情報を提供する事。
コメントが古いままだと、コメント対象のソースコードと整合性が保てなくなって悲劇が起こる。現に起きた。

プログラミングとはすなわち命名する事である

変数名、関数名、メソッド名、クラス名、ひいてはプロジェクト名と、プログラミングは命名する事がやたら多い。
プロジェクト名やクラス名は比較的サックリ命名出来るイメージだけど、変数名、関数名、メソッド名は命名がしんどい。

名前は長ければ長いほど情報量を詰め込めるので自己説明的に出来るけれど、それだと可読性が落ちてしまうし、
長々しい名前をタイプするのは面倒だし、Typo する可能性も高くなる。*6 *7 *8

なので、コメントにも通じる所だけれど、ネーミングはなるたけ簡潔であるべきだ感じている。長くても3〜4単語でいきたい。
一言でその機能を説明出来る英単語があればそれを使う。*9

後述するが、関数名・メソッド名が長くなってしまう場合は、その関数・メソッドに機能を詰め込みすぎている可能性があるので、
設計を見直した方が良いかもしれない。

あと、命名とは少し違うけれどVCS のコミットログも簡潔にわかりやすく書くべき。長すぎるとトレーサビリティが落ちる。
というかそもそも英語が危ういので、Poor English でも良いので正しく (誤解を生まないように、一意性が損なわれないように) 書く事。

1つの関数・メソッドに機能を詰め込み過ぎない

1つの関数 (メソッド) は1つの機能のみを提供するのが理想的だと思う。
単機能を提供する関数の方がテストやデバッグが簡単な上に再利用もしやすい。

あと、単機能の関数だと関数名が簡潔になるので「この関数は何をする関数なのか」が一目で分かって良い。
例えば、「標準偏差を計算してそれをデータベースに保存する」という処理を行う関数の名前が
calcStddevAndStore() だとちょっとわかりにくい。(標準偏差を計算するのはわかるが、どこに何をストアするのかがわからない)
かと言ってcalcStddevAndStoreItToDB() とかだと名前が長すぎてわかりやすさが逆に損なわれる。
これが単機能を提供するcalcSeddev() とStore2DB() という2つの関数に分かれていると、何をする機能なのかが一撃で分かるので便利。
(あと、この場合だと関数の再利用もしやすくなるのでなおよし)

暗黙のお約束は排除する

「この関数を呼んだら、その次の行でclose() を忘れずに呼んで下さい」みたいなお約束は排除するべき。
こういう「暗黙のお約束」は、実装した本人であれば忘れることは少ないだろうが、あとでそのコードを触る他人にとってはつらい。
第三者はその約束をうっかり忘れてしまうかも知れないし、そもそもその約束を知らない可能性がある。

基本的に、「暗黙のお約束」は破られると考えた方が良い。なので、そうした類の設計は避けるべき。

自分に厳しくしてくれるツールは積極的に使う

JSLint とかCheckstyle とかPerl::Critic とか、そういったツールは積極的に使うべき。
基本的にはこれらに従って損することは無いはずで、むしろ無視して被る損害の方が大きいと思われる。

あと、コンパイラ等の警告レベルも最大にした方が良いと思っているのでマックスにしている。

マジックナンバーやデータがハードコードされた文は可能な限り無くす

マジックナンバーについては、(文脈から) 一目で意味が分かる数字 *10 以外は使うべきではないと思っている。
(ただ例外として、-1〜3までの範囲の整数だったら使っても良いと思っている。使わざるを得ないケースがあるので。*11 )
例えば、同時にアクセス出来るユーザー数が100人だったとして、それを表現する為にプログラム中に"100"と直書きするよりは
"const int MAX_USER = 100;"と記述して、定数MAX_USER を使った方が明らかに可読性が上がると思うので。

ハードコードはデバッグを面倒にするし、そもそもダサいのでなんか嫌。
大体の場合は、頑張ればハードコードせずに済むので頑張るべき。
ハードコードは最後の手段という風に考えている。が、なんだかんだでやってしまうので辞めたい。

ペアプロは有効なので、できるだけやる

ペアプログラミングは賛否両論分かれる所だけれど、僕は好き。というか、現に役に立つと思う。
ペアプロすると、自分が思いつかなかったアイデアをパートナーからもらう事ができて、
そこから問題解決に繋がる事がままあるので大変有益だと思う。一人でふつふつ煮詰まって何も出来ないよりよっぽどマシだ。
また逆に、自分がパートナーにアイデアを伝えることによって問題が解決する場合もあるので、それもまた良い。
ペアプロはそういう「傍目八目」な感じが良いのだと思う。

あと、目が多い分、犯した間違いを発見しやすくなるし、何より他人の書くコードを見るのは勉強になる。
また、コードの内容だけではなく、便利なエディタの機能や、知らないUnix コマンドなんかも教え合えるので、スキルの底上げが図れて大変良い。

細かい粒度でコミットする

VCS の話。
1つの機能を実装したり、1つのバグを修正したりしたらその都度コミットするべき。
変更の粒度を細かくしておくと、(Git で言う所の) reset やcheckout がやりやすくなるというか、リビジョンでの管理が便利になるので良い。
更に、細かくコミットしておくと複数人数で作業しているときに変更どうしがかち合いにくくなるのでこれまた良し。

あと、`git log --oneline` みたいな感じで、1行でコミットログを表示する時に読みやすくなるので微妙にありがたい。

できるだけソースを書かない

「自分が欲しい機能」は「他の誰かも欲しいと思っている機能」である場合が多いので、ググるとライブラリ等がヒットする可能性が大きい。
公開されているライブラリはもちろんテスト済みだろうし、既に多くの人に使われて不具合が潰されているだろうから、大体のものは組み込めばすぐに使えるはず。
出来合いのものを使った方がよっぽど楽なので、既にものが存在しているならそれを使った方が良い。

自分でコードを書くと、将来的にそれを保守する必要も出てくるので、コードを書く時間だけではなく保守に要する時間も総合的なコストとしてかかってしまう。
だったら、出来るだけコードを書かない方が良いですよね、っていう。

で、もしライブラリとかが提供されていなくて、自分でその機能を書いた場合にはライブラリ化して公開する事を考える。
今までお世話になったライブラリ・モジュールへの恩返しの意味も込めて、自分の制作物は還元すべき。


そんな感じの

メモでした。気をつけます。

*1:単純に重複処理分の時間が余分にかかるだけ

*2:JavaScript とかだと、そういう事が良くある気がする

*3:修正のし忘れが出てしまうかもしれない……などなど

*4:まあ、そう簡単な話では無いんですが……

*5:前者はJavaDoc みたいな書き方。後者はワンラインでコメントアウトするやり方("// THIS IS COMMENT" みたいな)、という風に自分で定義づけている

*6:まあ、最近の開発環境は補完がパワフルに効くので大丈夫では

*7:あと、名前が長いとその分転送量が増えるので、JavaScript 等ではパフォーマンスにも関わってくる

*8:ただ、特殊な環境でのプログラミングになるとどうしても名前を長くする必要が出てくるので、それは別という事で

*9:「プログラムでの命名作業に使える! 頻出単語帳」みたいなのが欲しい

*10:例えば、バイトを扱っているなら1024 とか。時刻を扱っているなら24 とか。ただ、これらも何らかの定数にした方が良いとは思う

*11:-1 とか3 は、デフォルトの設定のCheckstyle だと警告を出してくる