Code Complete 上巻 再読完了
勉強本の助けを借りて自分の下手な勉強方法を改善しようプロジェクト。
いくつかの勉強本で紹介されている方法を採用。
斜め読みで消化できていなかった Code Complete第2版〈上〉—完全なプログラミングを目指して を再読し今日読了。
勉強方法
- 週3日決まった時間に読む。
- 気になったところを ChangeLog にメモし印刷して復習
完了までのぺース
- 6/24 P1-85
- 6/26 P89-150
- 6/28 P151-224
- 6/30 P225-316
- 7/2 P317-450
- 7/5 P451-564
決まった時間に斜め読みすることなく読めたと思う。こうして並べてみるとコンスタントに読めていることがよく分かる。
毎日読まないのが続けるコツかも。
感想
良い本物のプログラマを目指すなら必須の本だと思う。僕の周りでもこの本の価値を認めている人は多い。
もしこの本をぱらぱらとめくっても全くピンと来ないならば
- 天賦の才に恵まれ、良い方法論を自分で確立してしまった人
- この本のありがたみが分かるようなプロジェクトやコードにまだ遭遇していない人
のどちらかだと思う。
SICP を読んだときに、過去の自分に読むことをすすめたいと書いたように記憶している。
同様にこの本も過去の自分にすすめたい。
もし過去の自分が否定的な反論をした場合はこう返すつもり。
「自分の小さな経験の積み重ねとたまたま遭遇したプロジェクトで得た方法論と、多くの支持を得ており数々の論文・調査結果・数字に基づきまとめられた Code Complete。
どうして前者を全面的に信じる?後者も読んでみてから判断しても良いのでは?」と。
そうそう。既に僕は Code Complete の影響を受けている。
コードを書いていると耳元で「そのコードは良くないよ。なぜならば・・・」と Code Complete の注意がきこえる。
メモ
基本的には各章の終わりにあるチェックリストを全部頭にたたきこみたい。
- 上流工程チェックポイント
- システムの入出力の精度・頻度明記したか
- 要求される応答時間
- 要求はユーザーの言葉で書かれているか?
- プログラミング言語の選択
- 1行で実行できる行数の高い言語
- コンストラクションプラクティス
- 事前に行う設計と、コーディングしながらする設計を明確に定義して分けているか。
- 設計
- 良い設計は反復的!
-
- 設計は論理的ではなくヒューリスティックでありルーズであるが正しい結果を導く
- 設計段階で間違ってやり直す方が、コーディング後半で設計ミスにきづくより
- 実行時のパフォーマンスを低下させるのではないかという心配をコーディング中にするのは時期尚早。モジュール化に努め、システムのパフォーマンスを測定してからでおそくない
- プロトタイプを作るときは探ろうとしている未解決の問題を明確にする。
- コードは必ず捨てるつもりで最小限で書く(プロトタイプを別言語で書くのは効果的だ。)
- 設計をどれくらい吟味すればコーディングを開始できるか分からない場合、安全側に倒し、とことんしつこく設計を調べる
- 問題に対して、ボトムアップ、トップダウンの両方のアプローチをとったか?
- クラス
- ADT を使用する利点
- プログラムが一目で分かるようになる(あたりまえだけど良く肝に銘じよう)
- currentFont.attribute or 0x02 はいくつものチェックしないといけないポイントがあるよね
- インターフェースの抽象化しているものと矛盾するパブリックメンバを導入しない
- 書き手の便宜よりも読み手の便宜を考える。自分の書いたコードですら読む方が長いのだから。
- クラスのメンバデータが7個を超えたあたりからクラスを批判的に見る
- インスタンスが1つしかないクラスを疑う
- 派生クラスが1つしかないクラスを疑う
- P192 クラスチェックリストを印刷し読み上げる
- ADT を使用する利点
- 擬似コードプログラミング
- 標準ライブラリやほかのコードが使えないか?
- 防御的プログラミングチェック
- ルーチン
- ルーチンを作成する理由は十分か
- 独自のルーチンに分割することから利益を得られるすべての部分をルーチンに分割したか
- ルーチンのなまえは効果的か
- ルーチンののなまえはルーチンが行うことをすべて説明しているか
-
- ルーチンの凝集度は強いか。つまり1つの機能だけをうまく使うか?
- ルーチンの結合度は弱いか。つまりルーチン同士の結びつきが少なく扱いやすく、明白で柔軟性があるか。
- ルーチンにするにな短すぎる場合でもルーチンにするメリットはある。
- 短いルーチンは大きくなることがある
- 分かりやすい名前をつけられる
- クラス
- クラスに基本目標があるか?
- クラスによい名前がつき、その名前がクラスの基本目標を説明している
- クラスのインターフェースは一貫性のある抽象化は実現しているか
- クラスのインタフェースはそのサービスの実装方法について考えなくても良いほど抽象化されているか。ブラックボックスとして扱うことができるか
- ほかのクラスがそのクラスの内部データに干渉する必要がないほどクラスのサービスの完成度は高いか
- 関係のない情報をクラスの外に追い出したか
- クラスを修正するときにクラスのインターフェースの整合性を維持しているか
- メンバのアクセスを最小限に抑えているか
- クラスのメンバデータの公開を避けているか?
- 派生クラスを含む、クラスのユーザーについて推測していないか
- クラスがほかのクラスに依存していないか
- メンバーは protected ではなく private に
- メンバデータが7個以下か
- すべてのメンバデータはコンストラクタで初期化されているか
- 変数名の力
- 計算値による修飾 Total, Sum, Average, Max, Min, Record, String 修飾子は最後につける
- Numの使用は避ける。代わりにIndex, Counts などをつかおう
-
- 長いループは i j k よりも長い名前にする
- xxxFlag は使わない。 dataReady, recalcNeeded のように状態をちゃんと表す
- 一時変数 i, temp, xは使わない。
- ブール変数 done, error, found, success, ok 肯定的なブール変数を使うこと notFound などはだめ。
- 長さの上限は 10-16。短い変数が目につくようであれば必要な明確さを保っているか確認する。
- 条件文の使用
- if は正常なケースや頻度が高いパスを if に書く。else はその逆
- 明示的に空の else を考慮していることを表す
- ループ
- for ループは単純に使用すること。ほとんどの複雑なループ処理は while ループの方がうまく処理できる
- ループ本体が実行される条件を明文化し、ループ内部を調べなくてもループの制御を理解できるようにする
- ループは1回の処理で1つの機能に絞る
- ループ変数の最終値を使用するコードを書かない