達人プログラマーを久々に読み返したの備忘録兼ねてメモ
まえがき
- 達人プログラマーになるためには
- 新しいもの好き
- 研究好き
- 批判的
- 現実的
- 何でも屋
* 自らの技術に興味を持つこと
* あなたの仕事について考えること! →各意思決定すべてにおいて自分自身が何を行っているのか考え続ける。
* 達人と大規模チーム →個人の貢献がプロジェクトを支えている
* 継続は力なり →持っているスキルを日々磨き、新たなツールレパートリーを増やしていく
第1章 達人の哲学
1. 猫がソースコードを食べちゃった
- 問題に対してプロとして可能な限りの対処を行うように努力すること
* 責任を持つこと。いい加減な言い訳よりも対策を用意すること →責任を認め取り得る選択肢を提案する
2. ソフトウェアのエントロピー
- エントロピーとはある系における無秩序の度合い
* 割れた窓を放置しておかないこと →割れた窓が大規模な破壊につながる。発見と同時に修復すること
* チームのコードが清潔で美しいものであるとき、それを汚さないように最新の注意を払うこと
3. 石のスープと蛙の煮物
- 変化の媒体たれ
- 道理にかなった要求を考え出す
- 要求を引き出せるように作り上げる
- 人に見せて感嘆させる
- さも重要でないように要求を追加する
* 大きな構想を忘れないこと →あなた個人が行っていることだけを注意するのではなく、常に周囲で何が起こっているのかも注意する
4. 十分によいソフトウェア
- ユーザがそれを使っていくための必要十分条件であること
* 今日の素敵なソフトウェアは明日の完璧なソフトウェアよりも好まれる
* 品質要求を明確にしてやめ時を知ること →洗練しすぎて台無しにしてはならない。あるべく状態で筆をおく。
5. あなたの知識ポートフォリオ
- 常にあなたの知識ポートフォリオに投資すること
- 定期的に投資を行う
- 多角化
→特定の技術における全詳細を知る。その後により多くの技術に親しみ変化に対応できるようにする - リスク管理
→技術の卵をすべて同じかごの中に入れてはならない - 安く買い、高く売る
→今後クローズアップされる技術を一般的になる前に学んでおく - 見直しと再配分
* 知的資源獲得のため * 毎年少なくともひとつの言語を学習する * 四半期毎に技術書を読む * 技術書以外の書籍を読む * 講習を受講する * ローカルユーザグループに参加する * 異なった環境に慣れ親しんでみる * 最先端にとどまり続ける * インターネットを使う
6. 伝達しよう!
- 伝える事象と、伝える方法は車の両輪だと考えること
- 言いたいことを知る
- 聞き手のことを知る
- タイミングを選ぶ
- スタイルを選ぶ
- 見栄えをよくする
- 聞き手を巻き込む
- よい聞き手になる
- 聞き手の立場になる
第2章 達人のアプローチ
7. 二重化の過ち
DRYの原則ーDont Repeat yourself繰り返しをさけること(達人プログラマーの道具の中で最重要なものの一つである)
→2箇所以上に同じ知識を記述すること(コード、ドキュメントなど)
→片方を変更すると、もう片方も変更しないとならない
修正コスト、メンテナンスコストなどの低下につながる
信頼性の高いソフトウェア開発、開発そのものを簡単にする、簡単なメンテナンス
- どのように二重化が発生するのか?
- やむをえない二重化
- 多重化した情報表現
- コードの中のドキュメント
- ドキュメントとコード
- 言語の問題
- 不慮の二重化
→誤った設計によって二重化が発生する - 手抜きの二重化
→昔使ったルーチンをコピーして修正すればいいじゃん - 開発者間の二重化
→コミュニケーションロスや気づかないことによる二重化
→再利用しやすいようにしておくこと
8. 直行性(独立性、分離性)
- 直行性とは?
簡単な設計、製造、テスト、拡張できるシステムを構築する上で必要な重要な概念
2つ以上の物事で片方を変更しても、もう片方に影響を与えない→直行している
* 関係の無いモノ同士の影響を排除すること →局所的な変更が簡単にできるようになる →生産性の向上、リスク削減(問題発生部分を切り離せる)
9. 可逆性
- 確定事項として処理するのではなく、変わるかもしれないという対策を施しておくこと
→最終決定などというものは存在しない。直行性の話にも関わっている
* 柔軟なアーキテクチャー →抽象的なインターフェースをうまく定義することによってサードパーティの製品を隠してしまうことができる →どんなメカニズムを使用するにしても可逆性を持たせるようにすること
10. 曳光弾
- 曳光弾による開発は使い捨てではない
記述したものは残しておく、完全に動作するものではなくともその後徐々に肉付けをしていくことは様々な利点がある - 早いうちからユーザーにものを見せることによるフィードバック
- 徐々にシステムを統合していくことでデバッグ、テストがより早く正確になる
- 常にデモを見せることができる
- 進捗が明確になる
* 目標を見つけるには曳光弾を使うこと * 早いうちからユーザにものを見せることができる * 開発者の活躍できる舞台を創造することができる * 統合プラットフォームを手に入れることができる * でも可能なものがある * 進捗が明確になる
* 目標が100%確かで無い段階では見直し、修正が発生する可能性がある →しかし、肉付け部分の修正だったり、コード単位が小さくなるので修正が容易になる
11. プロトタイプとポストイットノート
- プロトタイプとの違い 、プロトタイプの真の目的は学びにある
使い捨て、システムの最終形態への理解を深めるためのもの
コンセプトを確認した後は1から再構築する。
* プロトを作成しているとき、全員が使い捨てだという意識があるかどうかに注意する
12. 専門の言語
- 問題領域に近いところでプログラミングを行うこと
* ミニ言語の実装 →可読性の高い専用言語を使ってサポート、メンテナンス性を高めてコスト削減をする
13. 見積もり
- 伝達したい正確性によって表現をかえる(単位を変える)
6ヶ月と130日と表現するのとでは捉えられる正確性にちがいがでる。 - 問題領域(なにがたずねられているのか)を考える
- モデルを作成する
- モデルをコンポーネントに分割
- パラメータに値を与える
- 答えの算出
第3章 基本的なツール
14. プレイン・テキストの威力
知識をテキストに格納するとき、それが人間が読んで理解することが出来る
印字可能な文字からなる、人間が直接読んで理解することが出来る形式
→共通の標準(=プレイン・テキスト)を用いたやり取りができる
- 知識はプレイン・テキストに保存すること
* 透明性の保障 →プロジェクトの枠を超えてデータが長生きする 可読性と変更容易性が高まり、アプリの枠を飛び越えて生き続けられる
* さまざまな活用ができる →コンピュータの正解はすべてプレインテキストを操作することができる ファイル比較ツールによって変更管理も容易にできる
* テストが容易になる →データをプレインテキストから生成できるようにしておけばテストデータの追加、変更、更新が簡単に行えるようになる
15. 貝殻(シェル)遊び
シェルを使うことでGUIを超えた複合的な操作が出来る
- GUIでは出来ないような複合的な操作が可能
→GUI環境では設計時に意図されたこと以外の作業を行う能力は用意されていない
* スクリプトファイルとしてまとめておけば、何度も行う作業を自動することも可能
* 手っ取り早くいくつかのコマンドを組み合わせたい場合は、コマンドラインが適している
16. パワー・エディット
エディターを知り尽くして生産性を向上させる
- 1つのエディターを知り尽くして全ての編集作業がそれで行われることが理想
* 反射的に操作できるようになることが目標
* エディター選定時の基本的機能 * 設定可能であること →全ての操作がキーボード上で行える * 拡張性があること →新たな言語の登場などに備えられる * プログラム可能であること →マクロの組み込みやスクリプティング用プログラム言語 * ソースコード編集に優れた機能 →テンプレート補完、自動インデント、など
17. ソースコード管理
修正の記録や後戻りが出来るということはソフトウェア開発にとってすさまじく有益なこと
常にソースコード管理をしようすること
- 今と昔のバージョンの違いは?
- このコードのどこを修正した?
- 誰がいつ修正した?
- バグ修正とその他の作業を並行的に作業していける
- リポジトリから自動的に最新のソースコードを抜き出してビルドを行うようなメカニズムを作りこめる
18. デバッグ
- バグを見つける為の戦略やコツ
- 非難するのではなく問題を修復する
- パニックに陥らない
→バグが起きたという思考に切り替える - 常に問題の原因の根に目を向ける
- バグを報告してきたユーザにインタビューする
- データ表示デバッガーを使う
→「変数=データ値」という可視化 - 時間的な経過を見るにはスタック・トレース
* selectはおかしくない →問題はたいていの場合、我々側にある
* 仮定せずに証明すること
19. テキスト操作
めんどくさい手作業をコンピュータにまかせる
- テキストの汎用的は編集作業など、常時行う作業をシステム化する
* テキスト操作言語を学ぶ * Unix系:awk, sedコマンド * 言語:Perl, Python * データベーススキーマのメンテナンス * Javaメンバに対するアクセス(setter, getterなど) * テスト・データの生成 * 書籍の執筆
20. コード・ジェネレータ
コードを生成するコードを作成すること
複雑さをなくし、失敗する確率を減らしてくれる
- 消極的なコードジェネレータ
→タイピング量を減らす為のもの - 新規ソースファイルの生成
- プログラミング言語の一括変換
- 積極的なコードジェネレータ
→利便性を追求したもの- スキーマ変更に応じてソースコードを編集してくれるようなものなど
第4章 妄想の達人
21. 契約による設計
正しいプログラムを作る為に要求されたこと以上も、それ以下のことも行わない
- ルーチンと呼び出す側の契約
あるルーチンにおける全ての事前条件が呼び出し側で満足された場合、
ルーチンは作業完了時に全ての事後条件と全ての不変表明を保証する - 事前条件
→ルーチンからの要求。正しいデータを引き渡すのは呼び出し側の責任 - 事後条件
→そのルーチンが終了時に保証すること - クラス不変表明
→ルーチンの終了時に不変表明が保証される
- 処理を始める前に受け付ける条件は厳格に、戻る際には可能な限り確約を少なくする
* 契約を用いて設計を行うこと
* 仮定をドキュメントしておくこと →トラブル発生時に起点に調査できる
* 契約違反となることが起きたときはクラッシュさせる
22. 死んだプログラムは嘘をつかない
- 早めにクラッシュさせる
→例外を早めに補足すること
リソースの開放、トランザクションの後片付けやログの出力などを忘れずに行う
23. 表明プログラミング
- もし起こり得ないというのであれば、表明を用いてそれを証明すること
→事前条件をassertなどでチェックする。起こり得ないことをチェックする
24. いつ例外を使用するか
- 例外とは予期せぬ事態に備えるものであり、プログラムの一覧の流れなのかに組み込むべきではない
→すべての例外ハンドらを除外しても、プログラムが動作することができなければ
例外ではない状況下で例外が使用されている
* 例外的な問題のみに使用する →エラーとの使い分けをする
25. リソースのバランス方法
- 始めたことは終わらせること
→リソースを割り当てたルーチンがそのリソースを解放すること
* リソースは割り当てた順序と逆の順序で解放する
* コード中の異なった場所で同じ組のリソースを割り当てる場合、常に同じ順序で割り当てる →デッドロックの可能性を削減することができる
* javaではfinally節でリソースの解放を行うこともできる。
* 各リソースごとにラッパーを生成しておき、そのラッパーにすべての割当と開放の追跡を行わせる
第5章 曲げるか壊すか
26. 結合度の最小化とデメテルの法則
- 結合度を最小にする
→恥ずかしがりやなコードを記述すること
→自分自身を他に明らかにしない。あまり多くの人と対話しない。
オブジェクト階層を掘り下げるのではなく、必要とするものを直接要求する
* モジュール間の結合度を最小にする
* デメテルの法則を適用する →オブジェクトの中のメソッドは以下のいずれかのカテゴリーに属しているメソッドのみ呼び出すべきである * 自分自身 * メソッドに引き渡されたパラメータ * 自身が保持しているオブジェクト * 直接保持しているコンポーネントオブジェクト
27. メタプログラミング
- システム設定を変更できるようにする
→アルゴリズムの選択、データベース製品、ミドルウェア技術、インターフェイススタイル
* メタデータを使う →チューニングパラメータ、ユーザプレファレンス、インストールディレクトリ
* メタデータとは「データに関するデータ」
* 抽象概念はコード上に、詳細はメタデータ上に置くこと →設計を分離することができ、より柔軟で適応性の高いプログラムを作ることが出来る 再コンパイルせずにカスタマイズ可能
28. 時間的な結合
- 常に並列性を意識した設計を行うこと
→ワークフローを分析する
UMLアクティビティ図(並行作業と順序だてる作業が一目でわかる)
* 並行性を考慮していないアプリケーションに後付で平行性を付与することは非常に難しい →並行性を考慮して設計を行うことで拡張要件やパフォーマンス要求に強くなる
29. 単なる見かけ
- MVC設計によってモジュール間の結合度を下げることができる
→表示を行うビューとそれを管理するコントローラーからモデルを分離すること
同じデータモデルを使って複数のビューをサポートすることができるようになる
モデルとビュー/コントローラーの結合度を低くすることで柔軟性を高めることができる
30. ホワイトボード
- 近代版分散ホワイトボードシステム(JavaSpace , T Space)
→オブジェクトそれぞれを完全に分離し、知識の消費者側と生産者側が匿名、かつ非同期にデータを交換できるフォーラムを提供するもの
第6章 コーディング段階
31. 偶発プログラミング
- 問題なく動作していたとしてもプログラムがなぜ動いているのかを把握すること
→動かなくなったときもその理由がわからないため、バグ発生時に修正に時間がかかる
* 動いているように見えるだけで動いていないのかもしれない →常に何をやっているのかを意識すること。完全に理解しないコードは作成しない
* 偶然の状況下で動いているのかもしれない、他の状況下では動かないかもしれない →信頼の置けるものだけを前提とする
* ライブラリの次リリースでは動作が変更になるかもしれない →仮定をドキュメント化する。仮定をテストすること。
* 不要、余計な呼び出しはコード実行を遅くし、バグを混入するかもしれない →過去のしがらみにとらわれない。リファクタリングを欠かさない。
32. アルゴリズムのスピード
- O()(オーダー)記法で見積もる
→メモリ消費の見積もりにも適用できる
O(n*2)は同じものでも関係はわからないなどに注意する。
* コード自身が何をやっているのかも考慮する →nがとりうる値によってオーダーの速度が異なる
* 見積もりの後に必ず検証をすること
33. リファクタリング
- コード記述のやり直し、再構築、再設計などの総称
* コードをリファクタリングするときの基準 * 二重化DRY原則に反している * 直行していない設計 * 知識が時代遅れ * パフォーマンスの改修
* リファクタリングを早めにこまめにすること →将来拡大した問題を修復する為に多くの時間を要することになる
* リファクタリング時の注意 * 機能追加と同時に行ってはならない * テストが完了しているか確認する。頻繁にテストする * 各作業を局所的な小さな修正にする
34. テストしやすいコード
- 契約に対してテストを行う
→コードが契約に合致しているのか、契約がわれわれの思っている通りになっているのかを確認する
契約と、契約に沿ったテストを設計すること
* コード実装の前にテストを作成しておけばインターフェイスのテストをしていることにもなる →テストコードはソースコードに近いところに置くこと。モジュール内に埋め込むことでも良い
* ログファイルを設計すること
35. 邪悪な魔法使い(ウィザード)
- コードなどを自動で生成してくれるもの(コードジェネーター)
→偶発的なプログラミングにならないように、理解できないウィザードのコードは使わないこと
第7章 プロジェクトを始める前に
36. 要求の落とし穴
- 要求は掘り起こすものである
→要求の陰に潜む理由をドキュメント化しておくこと
* ユーザの要求を取り出す方法 →ユーザの視点に立つ、ユーザと働くこと
* 要求をドキュメント化する →過度に記述しないこと要求とは設計でも、アーキテクチャでもない 要求とはニーズそのものである
* プロジェクトの用語集を作成する →プロジェクト全員が同じ表現ができるようする
37. 不可能なパズルを解く
- 枠にとらわれず考えるのではなく、枠を見つけ出す
→考えを制約している枠を見つけ出す。考えを制約している枠についての検証をする。 - 簡単な手段は存在するのか?
- 正しい問題を解決しようとしているのか、末端の問題に迷っているだけなのか?
- なぜそれが問題なのか・
- 解決を難しくしている真の原因は何なのか?
- この手段でなければいけないのか?
- 多少なりともこの方法でやり遂げなければならないのか?
38. 準備ができるまでは
- 準備が出来てから開始すること
→ソフトウェア開発は科学的なものではないため、経験の経験からくる問題提起を信用する
* プロジェクト最初の一歩に躊躇がでたらプロトタイプを試してみる
39. 仕様の罠
- 過度の設計は様々な機会を逸してしまう可能性がある
→コーディング担当者のプログラミング努力を奪い去る設計は行わない
40. 丸と矢印
- 形式的方法論はいくつかの欠点がある
- システムを使用するユーザの本当の意味での要求の検証ができないく、結局は設計者が説明する
→可能であればプロトタイプをユーザに見せたたき台にする - 専業化を進めるため、システム全体の理解がしにくい
- ダイナミズムを表現できるようなものがいまだに存在しない。
* 形式的開発方法は道具箱の1つの道具であることを忘れないように。 →形式的開発方法論にとらわれず必要なものを必要なだけ使い、進歩させていく
## 第8章 達人のプロジェクト ### 41. 達人のチーム * われ窓をなくす →メンバ個々に品質に貢献していかなければならない * 蛙の煮物 →チーム全体が環境の変化を監視しているかどうか * 伝達しよう →チームお互いで情報交換を行う →チームの個性やコミュニケーション促進のためにチームに名前を付けたりする * DRY原則 →ライブラリアンを指名してリポジトリの監視を行う * 直行性 →チームの編成は機能ごとですべき →直行性を保てていればチームの作業が他チームに影響を及ぼさない * 自動化 →自動化担当を選出すること * 絵画のやめ時を知る
42. どこでも自動化
- シェル、バッチを使って自動化ツールを作成するべきだ
→単純繰り返し作業は人には向かないため手作業は危険である
→人はもっと高度な作業に専念すべき
* プロジェクトのコンパイル、コードの生成、回帰テストなどすべてを自動化すること
* 管理の自動化 →自動化作業を行うシェルスクリプトを作成しても実行を忘れる危険性がある →自動的に実行されるワークフローを作成すること
43. 容赦ないテスト
- 早めに何度も自動でテスト
→優れたプロジェクトは成果物のコードよりテストコードの方が多い
* テストがすべて終わるまでコーディングは終わらない →モジュールごとの単体テストをすべて完了しておくことが前提条件である
* ソフトウェアのテスト * 単体テスト * 統合テスト * 妥当性確認および検証 * リソース消費、エラー、リカバリー * メモリー * ディスク容量 * CPU処理時間 * ディスク処理時間 * ネットワーク帯域幅 * カラー・パレット * ビデオ解像度 * 便利性テスト * パフォーマンステスト
* テストコードのテストをする必要がある →バグを埋め込み破壊工作を試みる
* プログラムがとりえるすべての状態を把握する必要がある →その状態から逆算してテストデータを注意深く検討していく
44. すべてはドキュメント
- 日本語もプログラミング言語のひとつである
→DRY原則に注意を払って記述すること
* ドキュメントは付け足すものではなく組み込むものである * コードの中のコメント →技術上のトレードオフ、意思決定の理由、却下された代替案などを記述する * 実行可能ドキュメント →ドキュメントからDDLを生成するようなツールを作成すること →ドキュメントとスキーマ情報、双方を修正するなど、DRY原則に反さないこと
* ドキュメントは印刷したものは常に時代遅れとなる →web等でオンライン参照できるようにするべき、最新verの管理をする
* マークアップドキュメントを用いた方法がおすすめ →簡単かつ自動的にほかの公開可能形式に変換することができる
45. 大きな期待
- ユーザーの期待をやや上回ること
→プロジェクトの成果はお客様の期待にどれだけ答えたかに現実的に判断される
→お客様のビジョンをないがしろにしないこと
* 曳光弾、プロトタイプなどを使って要求を洗い出すのも重要なテクニック
46. 誇りと愛着
- 作品に署名すること
→プロとしての意識をもち自分の作品、仕事に責任を持つこと
→自分の署名が入ったコードを見せることで、きちんと記述、テスト、ドキュメント化されたものであることを確認させる
【感想】
- DRY原則、直行性
品質の良いシステムを作るには必要不可欠
コードにもドキュメントにも
2. 偶発的プログラミング 使っているものをすべて理解していることが今後の目標
3. 早めにクラッシュさせる、いつ例外を使用するか 例外処理をないがしろにしない
4. 早めに何度も自動でテスト テストコード記述の学習を行う
5. 知識のポートフォリオに常に投資を行う