プログラミング作法

久しぶりに技術書で硬めの書籍を読んだ気がする。
購入日を調べたら2013年ということで、我ながら大分寝かせていたなと。

もろもろの雑感

可視でなければならないプライベート名には、アンダースコアを先頭に2個つけるというASCII Cの慣習

知らなかった。
一時期CakePHPの影響でこの様な名前付けをしていた気がするけど、源流を見つけた気がする。

単にサイズが大きいという理由だけで習得も使用も難しくなってしまう

これは、普遍的な真理だなと思った。

どうしても関数を増やさなければならない明確な根拠が生まれるまでは、広いインターフェイスよりも狭いインターフェイスの方が望ましい

初めは堅く、徐々に緩くだなと。
これもインターフェイスに限らずな気がする。

テストによってバグの存在は証明できるが、バグの不在は証明できない

名言。

CR(キャリッジリターン)は復帰で先頭に戻す、LF(ラインフィード)は改行

印刷機の名残りとは知らず勉強になった。
個人的にはLFに統一して欲しい気がするけど、Windows以外でも使われている様でなかなか難しそうだ。

ノウハウの明文化

本書はなかなかユニークな本で、普段自分が無意識にやっている様なことが明文化されている。
そういった本は結構あるんだけど、この本特にその粒度が細かい。

例えば、デバッグの章で

最新の変更点は要チェック

みたいなことが書かれている。
書かれていることは至極真っ当で、今までちゃんと動いていたものが、何か修正を加えて動かなくなったら、修正部分をまず疑うのが常套だ。
この様な優先付けは、自分も誰に教わったという訳でもなく何気なくやっているんだけど、こういったものが積もり積もって「ノウハウ」というものになるのかもしれないなと感じた。

この様な細かいことまで書かれているという点で、この本ななかなか稀有な存在な気がする。

まとめ

サンプルコードの多くがCやJavaで書かれているんだけど、それが自分にとって非常に読み辛かった。
他の書籍は、その言語を知らない人でも比較的読み易く書かれているが、本書はそうでもない。
自分は両方共あまり知らないので、コードの解析にめちゃくちゃ時間がかかってしまい、結果的に読まなくなってしまった。

これでは本末転倒だ。

結果的に読み飛ばすことで、なんとか読み終えることが出来たんだけど、ちょっと読み方を考えないとなーと感じた。

普段からガッツリCを書く人は、読み飛ばさず読み進めることで、めちゃくちゃ得ることは多いと思う。
一方、ポインタとかメモリ回りの話がよく出てくるので、その辺を言語側でやってくれるようなPHPみたいな言語を普段使っている自分のような柔いエンジニアには、ちょっとマッチョ過ぎる内容かなとは感じた。
まあ、だからまずCを勉強しろって言われるんだなとも。

入門書というよりは、中級者に脱皮したい初心者向けの本かもと思った。

参考資料

巻末に付いていたルール集をメモがてら転載しておく。

ルール集

スタイル

  • グローバルにはわかりやすい名前を、ローカルには短い名前を統一しよう
  • 関数には能動的な名前を
  • 名前は的確に
  • 構造がわかるようにインデントしよう
  • 自然な形の式を使おう
  • かっこを使ってあいまいさを解消しよう
  • 複雑な式は分割しよう
  • 明快に書こう
  • 副作用に注意
  • インデントとプレースのスタイルを統一しよう
  • 慣用句によって一貫性を確保しよう
  • 多分岐の判定にはelse-ifを使おう
  • 関数マクロはなるべく使うな
  • マクロの本体と引用はかっこを入れよう
  • マジックナンバーには名前をつけよう
  • 数値はマクロではなく定数として定義しよう
  • 整数ではなく文字定数を使おう
  • オブジェクトサイズは言語に計算させよう
  • 当たり前のことをいちいち書くな
  • 関数とグローバルデータにコメントを
  • 悪いコードにコメントをつけるな、書き直せ
  • コードと矛盾させるな
  • あくまで明快に、混乱を招くな

インターフェイス

  • 実相の詳細を隠蔽しよう
  • 直交性のある小さなプリミティブセットを選択しよう
  • ユーザーに内緒で何かするな
  • 同じことはどこでも同じように実行しよう
  • リソースの解放は割り当てと同じレイヤで
  • エラーの検出は低いレベルで、その処理は高いレベルで
  • 例外は例外的な状況にのみ使用しよう

デバッグ

  • おなじみのパターンを見つけよう
  • 最新の変更点は要チェック
  • 同じ間違いを繰り返すな
  • デバッグは今すぐに
  • スタックトレースを取得しよう
  • 打つ前に読め
  • 自分のコード他人に説明してみよう
  • バグを再現できるようにしよう
  • 分割統治しよう
  • 誤作動を「数値占い」で検証しよう
  • 出力表示によってバグ探索範囲を狭めよう
  • 自己検証コードを記述しよう
  • ログファイルを出力しよう
  • 作図しよう
  • ツールを使おう
  • 記録をとろう

テスト

  • 境界をテストしよう
  • 事前と事後の状態をテストしよう
  • アサーションを使おう
  • プログラミングは防御的に
  • エラーの戻り値をチェックしよう
  • テストはインクリメンタルに
  • テストは単純な部品から
  • 期待される出力を把握しておこう
  • 保存される性質を検証しよう
  • 独立した実装同士を比較しよう
  • テストの網羅範囲を測定しよう
  • 回帰テストを自動化しよう
  • 自給自足テストを作成しよう

性能

  • 時間計測を自動化しよう
  • プロファイラを利用しよう
  • ホットスポットに神経を集中しよう
  • 作図しよう
  • より優れたアルゴリズムやデータ構造を利用しよう
  • コンパイラの最適化を有効に
  • コードをチューニングしよう
  • 関係ない部分を最適化するな
  • 共通する式をまとめよう
  • 高価な処理を安価な処理に置き換えよう
  • ループは展開するか除去しよう
  • 頻繁に使われる値をキャッシュしよう
  • 専用のアロケータを書こう
  • 入力と出力をバッファリングしよう
  • 特殊なケースは別個に処理しよう
  • 結果を事前に計算しておこう
  • 近似値を使おう
  • より低級な言語で書き直そう
  • できる限り小さなデータ型を使って領域を節約しよう
  • 簡単に再計算できるものを記憶するな

移植性

  • 標準に固執しよう
  • 王道のプログラミングをしよう
  • 言語のトラブルスポットに気をつけよう
  • 複数のコンパイラで試してみよう
  • 標準ライブラリを使おう
  • どこでも使用できる機能だけを使おう
  • 条件コンパイルは避けよう
  • システム依存のコードは別個のファイルに
  • システム依存部分はインターフェイスの裏に隠蔽しよう
  • データ交換にはテキストを
  • データ交換には固定のバイト順を使おう
  • 仕様を変えるなら名前を変えよう
  • 既存のプログラムやデータとの互換性を維持しよう
  • ASCIIを前提にするな
  • 英語を前提にするな