API design for C++
https://www.amazon.co.jp/dp/B00EYXMA6Q https://gyazo.com/68aa992b042924ae0f8efc0bb867bfb7
1. はじめに
契約請負人の比喩
家をフルスクラッチで作ることはとても大変な作業
配管・電気・建築など複数の業者を雇うことになるだろう
そのような業者が何ができるのか,何を提供するのか,を明確にするのがAPIの定義である
C++のAPIは以下で構成される
ヘッダ (.h)
OSSであれば.cppなどのソースコードも含まれる
ライブラリ (.o, .so または .aなど)
ドキュメント
あなたが開発したAPIは世界中の何千人もの開発者に使われる可能性があり,まったく想定していなかった使い方をされるのはまず間違いない.このことは設計段階で予測しておく必要がある.優れた設計のAPIは会社の最大の財産になるが,お粗末なAPIは悪夢のようなサポート地獄を招き,さらに競合する相手にユーザを取られる可能性さえある.
2. 優れたAPIの特徴
p32 メンバ変数はpublicにしてはならない
通常,ユーザはパブリックAPIの境界を守ろうとはしないものだ.ユーザに内部構造へのフックを渡せば,それを使って自分の目的を果たすだろう.差し迫った問題へのソリューションを見つけたユーザにとっては幸いに思える.だが,将来的に見れば,こうした実装の詳細は変更が難しくなり,製品の改良や最適化にも支障を来すのである.
publicでなくgetter/setterを使う利点
アサーション,遅延評価,キャッシュ,通知,デバッグ,並行制御,アクセスコントロール
p37 非constのポインタや参照を一つ返すだけでも,内部状態のリークは起こりうる.結果としてAPIを通さずにオブジェクトの状態を変更されうる.
p39
APIではなんとしてもPimplイディオムを採用してほしい.
プライベート関数は,プライベートメソッドとしてパブリックヘッダに開示せず,.cppファイルに静的関数として宣言すべきだ (Pimplイディオムを使うともっとよい.)
p43.
「不要なときは書かずにおけ」.APIのパブリックなクラスと関数の数は最小限に.
p42. 仮想関数の追加は慎重に.オーバーライドしたメソッド内で「delete this」を呼び出されることもありうるのだから.
p52. 関数の名前とパラメータの順序に一貫性をもたせる
begin と end と使うと決めたら start と finish は使わない
mallocとcallocのように,インタフェースが不一致なのも好ましくない
p61 パブリックヘッダにプラットフォーム固有の#if/#ifdef 行を入れてはならない.
p65
実際に完全な定義を#includeする必要がない限り,クラスには前方宣言を使うべきだ.
3. パターン
p79 Pimpl
Pointer to implementation の略
前方宣言したImplクラスのポインタだけを含めることで,ヘッダに実装の詳細やprivateメンバの存在を書かないテクニック
Pimplを使う場合は,デフォルトコピーコンストラクタがポインタをシャローコピーすることに注意.
以下のようなhackを封じることができるので有用
code: pub.cpp
p97 シングルトンの使いすぎに注意.依存性の注入だけで済むならば,それが好ましい
シングルトンパターンに関連する問題の大半は,シングルトンがグローバル状態へのアクセスを保持し,制御するように設計されていることに端を発している.
通常,設計の早い段階で,「セッション」または「実行コンテクスト」オブジェクトをシステムに導入することを考えたほうがよい.
p115 ファサードパターン
アダプター,ファクトリー,プロキシパターンとは異なる
いわゆる「APIをまとめて呼び出す高レベルAPI」
4. デザイン
技術的負債が見てとれる4つの末期症状
1. 壊れやすさ: 一部に触れただけで,問題がないように見える箇所が壊れる.
2. 硬直性: シンプルな変更がシンプルな努力で実装できないコードベース.
3. 不動性: 再利用性が困難で,凝集度が高く密結合していて,リファクタリングができないソフトウェア
4. 引き継ぎ不能性
この負債を返済するときの方針は2つ
1. 進化: リファクタリングを繰り返す
2. 革新: 古いコードを捨てる
間をとって,ファサードパターンで新しいAPIを切って,古いコードをその下に隠蔽するという手がある
テストをしっかり書ければ,臭いものにフタだが,このアプローチはうまく機能する
p164 継承より合成を使おう
合成は継承と等価な事ができるだけでなく,基底クラスのあのメソッドを仮想関数にしたい・・・といった危険な欲望が芽生えるのを防いでくれる
p164 OCP
Open/Closed Principleの略
拡張にはオープンで,修正にはクローズドであるべき
p177 例外
例外はオール・オア・ナッシング.一度使ったらクライアントにも使用を強要する
エラー通知を例外抜きで行うのは難しい.errnoなどは副作用になってしまう
5. スタイル
6. C++の使用法
p211 マーシャル・クラインのビッグスリー原則
「デストラクタ,コピーコンストラクタ,代入演算子の3つは常に共存する必要がある」
どれかが欠けるなら,すべてを削除すべき
シングル引数コンストラクタには必ずexplicitを使い,暗黙の型変換を防ぐ
p218 constキーワードを削除するくらいなら,mutableを使おう
p275 ヘッダーでインライン化を行わない.これをやると共有オブジェクトのアップデートだけでソフトウェア・アップデートを完了できない.クライアントのコードも更新する必要が出てしまう
パフォーマンス問題があると証明されるまではinlineキーワードは使わなくとも良い
p278 メモリを節約する最高の方法はコピーオンライト