ソフトウェア設計のトレードオフと誤り―プログラミングの際により良い選択をするには
https://gyazo.com/745af1a4788ea94f60706a241d6d1d4d
はじめに
1章 イントロダクション
1.1 すべての決断とパターンの結果
1.2.1 コードの測定
1.3.1 スケーラビリティ
1.3.2 開発スピード
1.4 まとめ
2章 コードの重複は必ずしも悪ではない:コードの重複 vs コードの柔軟性
2.1 コードベース間の共通のコードと重複
2.1.1 コードの重複を必要とする新しいビジネス要件の追加
2.1.2 新しいビジネス要求の実装
2.1.3 結果の評価
2.2 ライブラリとコードベース間のコードの共有
2.2.1 共有ライブラリのトレードオフとデメリットの評価
2.2.2 共有ライブラリの作成
2.3 異なるマイクロサービスへのコード抽出
2.3.1 分離したサービスのトレードオフとデメリット
2.3.2 サービス分離に関する結論
2.5.1 リクエストハンドラーの共通部分の抽出
2.5.3 継承とコンポジションのトレードオフ
2.5.4 本質的な重複と偶然の重複に着目する
2.6 まとめ
3章 例外 vs 他のエラーハンドリングパターン
3.1 例外の階層
3.1.1 すべてのエラーを捕捉する vs きめ細やかに処理する
3.2 コードで例外を処理するベストプラクティス
3.3 例外処理のアンチパターン
3.3.1 エラー発生時のリソースのクローズ
3.3.2 アプリケーションフローを制御するために例外を使うアンチパターン
3.4 サードパーティーライブラリの例外
3.6 Tryを使った関数型アプローチにおける例外処理
3.6.1 本番環境でのTryの使い方
3.6.2 Tryと例外を投げるコードの混合
3.7 例外処理の実装におけるパフォーマンスの比較
3.8 まとめ
4章 柔軟性と複雑性のバランス
4.1 ロバストではあるが拡張性のないAPI
4.1.1 新しいコンポーネントを設計する
4.1.2 もっとも簡単なコードから始める
4.2 好きなメトリクスフレームワークを利用できるようにする
4.3 フック経由でAPIに拡張性を与える
4.3.1 フックAPIの想定外な利用への対処
4.3.2 フックAPIの性能への影響
4.4 リスナー経由でAPIに拡張性を与える
4.4.1 リスナーの利用 vs フックの利用
4.4.2 イミュータブルな設計
4.5 APIの柔軟性分析 vs メンテナンスコスト
4.6 まとめ
5章 早すぎる最適化 vs ホットパスの最適化:コードの性能に影響する決断 5.1 早すぎる最適化が悪である場合
5.1.1 アカウントを処理するパイプラインの作成
5.1.2 誤った仮定を元にした最適化処理
5.1.3 性能の最適化をベンチマークする
5.2 コードの中のホットパス
5.2.2 SLAに対応する並列ユーザー(スレッド)数を設定する
5.3 ホットパスになりうる部分がある単語サービス
5.3.1 「今日の単語」を取得する
5.3.2 単語が存在するか検証する
5.3.3 HTTPサービスを用いてWordsServiceを公開する
5.4 コードの中のホットパスを検出する
5.5 ホットパスの性能を改善する
5.5.1 既存の解決策に対してJMHマイクロベンチマークを作成する
5.5.2 キャッシュを用いて単語の存在検証機能を最適化する
5.5.3 性能テストを修正し、入力単語数を増やす
5.6 まとめ
6章 API のわかりやすさ vs メンテナンスコスト
6.1 他のツールから利用されるベースのライブラリ
6.1.1 クラウドサービスクライアントを作る
6.1.2 認証の実現方法を探る
6.1.3 設定のメカニズムを理解する
6.2 依存するライブラリの設定をそのまま公開する
6.2.1 バッチツールの設定
6.3 依存するライブラリの設定を隠蔽するツール
6.3.1 ストリーミングツールの設定
6.4 クラウドクライアントのライブラリに新しい設定を追加する
6.4.1 バッチツールへの新しい設定の追加
6.4.2 ストリーミングツールの設定の追加
6.4.3 UX の使いやすさとメンテナンスのしやすさについての2つの解決策の比較
6.5 クラウドクライアントライブラリの設定を非推奨にする/ 削除する
6.5.1 バッチツールからの設定の削除
6.5.2 ストリーミングツールからの設定の削除
6.5.3 UXの良さとメンテナンスのしやすさにおける2つの解決策の比較
6.6 まとめ
7章 日付と時間のデータを効率よく扱う
7.1 日付と時間情報の概念
7.1.1 機械時間: 時点、エポック、期間
7.1.2 常用時 : 暦法、日付、時間、時間量
7.1.3 タイムゾーン、UTC、UTCからのオフセット
7.1.4 私を悩ませる日時の概念
7.2 日時情報を仕事で扱うための準備
7.2.1 スコープを制限する
7.2.2 日付の要求の明確化
7.2.3 適切なライブラリ、パッケージを利用する
7.3 日時のコードの実装
7.3.1 概念を適用し続ける
7.3.2 テスト容易性の改善
7.3.3 日時をテキストとして表現する
7.3.4 コメント付きのコード解説
7.4 認識してテストすべき境界条件
7.4.1 カレンダー計算
7.4.2 夜中のタイムゾーン切り替え
7.4.3 曖昧な時間やスキップされた時間を取り扱う
7.4.4 更新されるタイムゾーンデータの取り扱い
7.5 まとめ
8章 データローカリティとメモリーの活用
8.1 データローカリティとは何か?
8.1.1 計算処理をデータ側に移動する
8.1.2 データローカリティを使った処理のスケーリング
8.2 データのパーティション化とデータ分割
8.2.1 オフラインでのビッグデータのパーティション化
8.2.2 パーティション化 vs シャーディング
8.2.3 パーティション化のアルゴリズム
8.3 複数のパーティションのビッグデータのセットを結合する
8.3.1 同じ物理マシン上にあるデータの結合
8.3.2 データの移動が必要な結合
8.3.3 ブロードキャストを活用した結合の最適化
8.4 データ処理:メモリー vs ディスク
8.4.1 ディスクベース処理を利用
8.4.3 アクセス時間の計算
8.4.4 RAMベースの処理
8.5.1 ブロードキャストなしの結合の実装
8.5.2 ブロードキャストを伴う結合の実装
8.6 まとめ
9章 サードパーティーライブラリ:あなたが使うライブラリはあなたのコードとなる
9.1 ライブラリをインポートしてその設定に対して完全な責任を負う:デフォルト値に注意する
9.2 並列実行モデルとスケーラビリティ
9.2.1 非同期、同期 APIを使う
9.2.2 分散時のスケーラビリティ
9.3 テスト容易性
9.3.1 テストライブラリ
9.3.3 統合テストツールキット
9.4 サードパーティーライブラリの依存関係
9.4.1 バージョン衝突の防止
9.4.2 多過ぎる依存関係
9.5 サードパーティー依存関係の選択と維持
9.5.1 第一印象
9.5.2 コードを再利用する別の方法
9.5.3 ベンダーロックイン
9.5.4 ライセンス
9.5.5 ライブラリとフレームワークのどちらにするか
9.5.6 セキュリティとアップデート
9.5.7 意思決定のためのチェックリスト
9.6 まとめ
10.1 データソースのat-least-once 配信
10.1.1 単一ノード間のトラフィック
10.1.2 アプリケーションからの呼び出しのリトライ
10.1.3 データ生成とべき等性
10.1.4 コマンドクエリ責務分離(CQRS)を理解する 10.2 重複排除ライブラリの素朴な実装
10.3 分散システムで重複排除を実装する際のよくある誤り
10.3.1 ノードが1つの場合
10.3.2 複数ノードのコンテキスト
10.4 レースコンディションを防ぐためにロジックをアトミックにする
10.5 まとめ
11章 分散システムのデータ配信
11.2.1 Kafkaをコンシューマー側から見る
11.2.2 Kafkaブローカーの設定を理解する
11.3 プロデューサーの処理内容
11.3.1 プロデューサーの一貫性と可用性の選択
11.4 コンシューマーの実装とデータ配信セマンティクス
11.4.1 コンシューマーの手動コミット
11.4.2 最初または最新のオフセットからの処理再開
11.4.3 (実質)厳密に1回のデータ配信
11.5 データ配信保証の仕組みにより耐障害性を向上させる
11.6 まとめ
12章 バージョンと互換性の管理
12.1 バージョン管理概論
12.1.1 バージョンのプロパティ
12.1.2 後方互換性と前方互換性
12.2 ライブラリのためのバージョン管理
12.2.1 ソース、バイナリ、セマンティック互換性
12.2.2 依存グラフと菱形依存
12.2.3 破壊的変更の取り扱い方
12.2.4 内部だけで使用されるライブラリの管理
12.3 ネットワークAPIのバージョン管理
12.3.1 ネットワークAPI呼び出しのコンテキスト
12.3.2 カスタマーフレンドリーなわかりやすさ
12.3.3 一般的なバージョン管理戦略
12.3.4 バージョン管理に関するさらなる考慮事項
12.4 データストレージのバージョン管理
12.4.3 ストレージシステム内のデータマイグレーション
12.4.4 想定外を想定する
12.4.5 APIの分割とストレージ表現
12.4.6 ストレージフォーマットの評価
12.5 まとめ
13章 流行を追いかけ続けること vs コードのメンテナンスコスト
13.1.1 依存性注入の自作
13.1.2 フレームワークを利用した依存性注入
13.2.1 シングルスレッドでの処理の作成・ブロッキング処理
13.2.3 リアクティブによる実装
13.3.1 非関数型言語での関数型コードの作成
13.3.2 末尾再帰最適化
13.3.3 不変性の活用
13.5 まとめ
付録A データライフサイクルとトレードオフ
A.1 データの表現方式
A.1.1 即値(リテラル)
A.1.2 定数
A.1.3 コマンドライン引数
A.1.4 環境変数
A.1.5 設定ファイル
A.1.6 ダウンロードコンテンツ方式
A.1.7 オンラインデータベース
A.2 トレードオフを考慮する視点
A.2.1 デプロイまでの手順
A.2.2 複数のデータセットのハンドリング
A.2.3 起動時間
A.2.4 セキュリティ
A.3 ハイブリッド方式
A.3.1 複数のデータソースの透過利用
A.3.2 ソースコードの自動生成
A.3.3 設定DSL
A.3.4 設定ファイルをバンドル
A.3.5 ライブリロード
A.3.6 .envファイル
A.4 まとめ
訳者あとがき