- Amazon.co.jp ・本 (518ページ)
- / ISBN・EAN: 9784797369151
作品紹介・あらすじ
自由度の高い言語C++の可能性を引き出す、珠玉の12章。長期の運用に堪える安全なソフトウェア設計のために。
感想・レビュー・書評
-
言語に関係なくAPIデザインにとって重要なことから、それをC++でどう実現するかの実装イディオムまでつなげて書かれている。切り口も互換性/拡張/言語バインディング/テスティング/パフォーマンスなど多様で、ヘビーではあるけど読む価値はある一冊だと思います。
ただ、C++そのものについてそれなりに習熟していないと、特に実装イディオムに落とし込むところは厳しいかな。詳細をみるコメント0件をすべて表示 -
基本的にはAPI開発のための本なのだが、APIを高品質なソフトウェア部品と捉えると、当然全てのソフトウェアにも適用できるものと捉えることができるので、API向けと書きながらこの本は全てのソフトウェア開発者向けの本ということになる。実際、厚めの本であり、取り扱う内容は、多岐に渡っている。CodeCompleteを読んだ後、この本にも目を通しておくことを奨める。
-
図書館で借りてざっと見たところ手元に持ちたくなったので購入した。
読書記録 C++のためのAPIデザイン
2013/01/31(木)〜2013/03/07(木)
16日間 445分(7.5H)かかった。
[more]
お薦めのC++本
・ロベールのC++入門講座
・Effective C++
・Modern C++ Design
著者:マーティン・レディ
ピクサーの開発部門にいた人。リンデンラボでSecondLifeのAPI設計をした。
API: Application Programming Interface
C++のAPIは一般的に次の要素で構成される。
1.ヘッダ: .h, .hppファイル
2.ライブラリ:スタティックorダイナミックライブラリ
3.ドキュメント
また、ファイル形式やプロトコルはAPIとは呼ばない。
SDK: Software Development Kit
APIを使ったアプリを構築するためのパッケージ。
APIの他にサンプルソース、サポートツールなどが含まれる。
2章:優れたAPIの特徴
・情報の隠蔽
行う事で、高速化や検証など機能追加がしやすい。
メンバ変数を開示する理由はせいぜいパフォーマンス。直セスアクセスすると2−3倍高速になる。しかしinlineを活用すれば問題にならない場合が多い。
プライベートメンバをパブリックヘッダから隠すテクニック=Pimplイディオム
APIはぜひとも、Pimplイディオムを使うべき。プライベートはcppに隠蔽。
POD (Plane Old Data)型の構造体
・最小限の完全性
APIをクライアントが使い出したら、新規機能の追加は簡単だが、既存機能の削除は難しい。
「不確かなときには書かずにおけ」 余分な一般性が将来的に必要になることはまずない。
オーバーライドは再定義,オーバーロードは多重定義
オーバーライドは,上位のクラスから継承してきたメソッドを再定義すること
オーバーロードは,同名のメソッドや演算子を複数定義
・疎結合
結合度を低く保つ方が優れたAPIである。テク:前方宣言、ヘルパー名前空間で非メンバ関数を宣言、コールバック(boost::bindが便利)、オブザーバー、シグナル、(boost::signals)
3章:パターン
・Pimplイディオム pointer to implementation(実装へのポインタ)の略語
Publicヘッダには実装クラスのポインタを持たせる。実装はすべて実装クラスの中に押し込める。
デメリット:const関数も実は実装クラスのメンバ変数を変更出来る。書き方に注意。
・コピーセマンティックス 浅いコピーでPimplしたクラスでは問題になる。
コピー不能にする(コピーコンストラクタと代入演算子をprivate)か、ディープコピーを実装。
・シングルトン
1つのインスタンスしか持たないことを保証する。GetInstance()関数がよく使われる。
スレッドセーフにするためには、mutex内でインスタンス生成。しかしC++で完全なスレッドセーフなシングルトンは難しい。
・ファクトリメソッド
C++のコンストラクタの制約:戻り値なし。命名決まっている。
ファクトリメソッドにより、実行時にい生成する派生クラスを決めることができる。
新しい生成クラスにも対応させるには、オブジェクトファクトリを使う。
・APIのラッピングパターン:プロキシ、アダプター、ファサードなど
ープロキシパターン
関数呼び出しを転送するインタフェースを提供
ーアダプターパターン
インタフェースの変換。
ーファサード
複数のコンポーネントをラップする。
・オブザーバーパターン:コンポーネントの結合を解除する
ーMVCアーキテクチャ
コントローラとビューはモデルに依存するが、モデルは他に依存しない。
4章:デザイン
要件からクラス設計。
LSP原則:基本クラスは動作を変更せずに派生クラスと常に置き換えることが出来なくてはいけない。出来ないときはその派生クラスの設計は行わない。
OCP原則: クラスは拡張にはオープン、修正にはクローズであるべき。
クラスの命名法:2語程度の結合まで。インタフェースクラスはIを先頭に。名前空間もしくは接頭辞
関数の命名法:boolはIs,Are,Hasを付ける。Get,Setは値の取得、設定。アクションは動詞。肯定的な名前。中身は全て記述、長いなら関数を分割。
5章:スタイル
・本書の中心。フラットC API、など
5.1 フラットC API: CでコンパイルできるAPI
5.2 オブジェクト指向C++API:C++になじみのあるスタイル
5.3 テンプレートベースAPI: C++のテンプレート
5.4 データ駆動型API: 名前付きコマンドをハンドラに送るタイプ
send(\"func\",a,b,c)などと呼び出す。
WebサービスなどでのAPI
6章:C++の使用法
ヘッダでusingを使ってはいけない。
デストラクタ、コピーコンストラクタ、代入演算子は、セット=ビックスリー
コピーコンストラクタの自動生成は、C++0xでは=default, =deleteで制御可能
C++0xのこの機能はGNU C++ 4.4では実験的にサポート
explicit 明示的コンストラクタ。引数1つのコンストラクタで自動変換を防ぐ
コピーコンストラクタ Foo(const Foo &in_foo)
代入演算子 Foo &operator = (const Foo &in_foo)
mutable constメソッドでも変更出来るようになる。
テンプレート
ー明示的インスタンス化 実装定義は.cppに書いて、template class Foo<int>;と宣言すれば良い。ただし、記述したインスタンス以外は実装できない。
演算子
ー自由演算子とメンバ演算子
Foo &operator +=(Foo &lhs, const Foo &rhs) が自由演算子
どうしてもプライベートメンバにアクセスする必要があるときはメンバ演算子で定義すべき。そうでないと、friendが必要になる。
explicit 明示的
ーデフォルト引数 : 将来変更の可能性があるならオーバーロードで実装すべき
ーC++では定数の#defineを避ける。static constメンバを使うべき。
ーフレンドの使用は避ける
ーリンケージ ファイルを超えて利用できるかどうか。static=内部。extern=外部 匿名の名前空間によってリンケージのリークを防げる
シングルエクスポート: __declcpec(VC++), __attribute__(g++)
ーコーディング規約 Google C++ Style Guideがよく活用されている。
7章:パフォーマンス
ーパフォーマンス上の理由でAPIを歪んだ構造にしてはいけない。クリーンで論理的な問題領域の抽出表現で有り続ける必要が有る。
ーパフォーマンスを考える観点
1.コンパイルのスピード
2.ランタイムのスピード
3.ランタイムのメモリオーバーヘッド
4.ライブラリの容量
5.起動時間
ーテクニック
・RTTI(ラインタイム型情報)をオフ dynamic_cast未使用なら-fno-rtti
・ネック(ホットスポット)を見積もるときに直感に頼るな。
・constexpr定数になることがわかっている関数に記述することでコンパイラの最適化を行わせる。 C++0xの仕様。
・初期化リストを.cppに実装する。優れたAPI設計は実装の詳細はできるだけヘッダから隠すべき
・明示的なサイズ指定型=stdint.h
・メンバ変数は型毎にクラスタ化して、オブジェクトサイズを最適化する
・不必要なインライン化は実装を開示してしまうので避ける。バイナリ互換がくずれる。
ー情報
・プロセッサは毎年55%速度向上。一方メモリは7%だけ。
・前置インクリメント(++it)が高速。後置インクリメントでは一時変数の生成と破棄が行われる。
・[]演算子は通常境界チェック無し。at()関数は境界チェック有り。
ーツール紹介
・Valgrind系 プロファイル(Callgrind, KCachgrind,)フロントエンドGUI( Valkyrie, Alleyoop)、マルチスレッド(Helgrind, DRD)
・AMD CodeAnalyst。無料プラファイラ。OProfileがベース
・Coverity 静的コード解析
・gccコンパイラはMALLOC_CHECK_でメモリデバッグができる。
※ Valgrind系のツールはよく習熟したい。
8章:バージョン管理
・バージョン番号 1.2.3とか。メジャー、マイナー、パッチバージョン
ーメジャーバージョン 後方互換性が壊れる場合
ーマイナーバージョン ユーザーは変更無しに新しいマイナーリリースにUpgrade可能。逆はダメな場合(新機能を使った場合など)もあり。後方互換性はあるが前方互換性はない。
ーパッチバージョン 前方互換性もある場合。APIの振る舞いに変更はない。
・APIにはバージョン情報を提供すること。HasFeatureメソッドもあると良い。
・「APIとは契約である」 APIを変更すればクライアントのコードを壊す可能性がある。
リリース後は、APIは変更せず進化させるだけ。
・後方互換性 前バージョンのAPIと同じ機能性を提供するAPI
バージョンNのAPIに対するユーザーコードが、バージョンN+1に対してコンパイルできる
前のバージョンのAPI,データを読み込める保証
クライアント/サーバー互換性:古いバージョンのサーバと通信できるようにする。
・前方互換性 ダウングレードしてもそのまま使えること。
バージョンNへのコードがバージョンN-1でも動かせること。
9章:ドキュメント Doxygenなど
契約をドキュメント化する
1.事前条件
2.事後条件
3.クラスの不変条件:各インスタンスが満たす必要のある条件
ライセンス
カテゴリ2つ
1.プロプライエタリ: 所有権は発行者。クローズドソース
2.フリーのオープンソース: コピーや再配布できる 無料では無く自由。
2−A:Copyleft:コピーにも同じ条件でリリースすべきとする条件
Weak Copyleftならライセンスに縛られずにリンクするコードを配布可能
2−B:Permissive:元より強い制限でリリースしても良い。
10章:テスティング
単体テスト:
フィクスチャ設定;不変の初期設定、終了手順を用いる
スタブ/モック:依存関係を置き換えるアプローチ
フェイクオブジェクト:機能的な動作を持つがテスト用のシンプル実装
スタブオブジェクト:決められた結果を返すオブジェクト。
元のクラスから継承して設計する。
もしくは同じ名称にして置き換える
モックオブジェクト:測定機能付き。呼ばれた回数を返すなど。
モックフレームワークを用いると良い。
結合テスト
パフォーマンステスト
回帰テスト:後方互換性の確保
NULL入力:関数はNULLポインタ入力を回避するように。
QA技術者:マイクロソフトは2つに分けている
Software Test Engineer: プログラム経験は少ない。ブラックボックステスト
Software Design Engineer for Test: コードを記述できる。
テスト駆動型開発:最初にテストを記述してからコードを書く。必要最小限喝充分なものを実装できるようになる。
契約プログラミング
事前条件 require
事後条件 ensure
コードカバレッジ
コンパイラの最適化なしで計測すること
経験から、優れたカバレッジ率
関数カバレッジ 100% 関数呼び出し
ラインカバレッジ 90%
条件カバレッジ 75%
11章:スクリプト記述 Rubyなどからバインディング
流し読みした
12章:拡張性
仮想デストラクタを宣言すると、ユーザはこのクラスが継承可能だとわかる。
なのでSTLは継承しないで合成で用いる。exceptionやiostreamは例外で継承して用いる場合はある。
列挙型に拡張性を持たせるには、_ENDなどで最後の値を定義しておく。
付録A:ライブラリ
・スタティックライブラリ、ダイナミックライブラリの作成方法
static_lib: .a (UNIX,Mac) .lib(Win)
dynamic_lib: .so(UNIX) .dll(Win) .dylib(Mac)
リンカ ld.so(Linux) dyld(Mac)
・Windowsのライブラリ
.dll はインポートライブラリ .libも伴う必要が有る。staticの.libとはファイル形式が異なる。
・Linuxのライブラリ
static_libは.oのアーカイブに過ぎない。arコマンドでアーカイブできる。
リンカにアーカイブを与えるときの順序は重要。なのでライブラリはコマンドラインの最後に指定するのがベストプラクティス。
-sharedオプションを用いると.soが生成。また、-fPICによって位置独立コード(Position-independent Code)を生成させておくべき。
エントリポイントの注意点としては静的コンストラクタの初期化順序は定義されていないこと。
nm コマンド:ライブラリ内のシンボルを表示。
libtool コマンド:オブジェクトを与えてオプションでstatic, dynamicを生成出来る。
c++filtコマンド:マングルされたシンボル名を解除する。
ldd コマンド:依存しているdynamic_libを表示。
dynamic_lib検索
1.標準ライブラリディレクトリ /usr/libなど
2.LD_LIBRARY_PATHにコロン区切りでパスを定義
3.リンカの-rpathで検索。
・Macのライブラリ
-staticは使えない。システムのdylibがstaticを用意していないから。 -
C++のAPI設計時の参考に購入しました。
設計だけでなく、バージョン管理、ドキュメント、テストからスクリプトバインディング、ライブラリまで、至れり尽くせりの内容です。
explictキーワード等、コンパイラの非明示的な動作を制御する方法についても記述されており、一読しておけば試験時の手戻りを軽減できると思います。 -
夏休み1日10ページと決めて、約2ヶ月くらいで読み切った。C++でクラス作るときに考えるべきルールや文化みたいな事を知れます。製品開発クオリティのC++については知らずにきてしまっていたので今更だけど触れられてよかった。最初の方だけでも読む価値あり。
-
Pimplやgetter/setterを強く勧める本で、そういえばそんなものも当時流行っていたなぁ、と
個人としては参考になるところは特になかった -
コンビニエンスAPIまで
-
EfdectiveC++のあとに読んだ。
色々と、自分の中でなんとなく良くないコードとか思っていたもの考え方が保管された感じがする。
API開発する際のコード設計に関する話がメインです。
後半のプラグインとかテストのあたりはさくっと流しました。
ただ、API開発しない人もそもそもC++での最良なコード設計とか学べます。
virtualとかconstとか結構くどく、こうしたほうがコードを理解しやすいとかAPIとして提供する前提で説明しているお陰で、自分の中でのC++の書き方が固まってきた気がする。 -
貸し出し状況等、詳細情報の確認は下記URLへ
http://libsrv02.iamas.ac.jp/jhkweb_JPN/service/open_search_ex.asp?ISBN=9784797369151 -
オブジェクト指向、イディオム、デザインパターン、コーディング技法、パフォーマンス、バージョン管理、ドキュメント技法、テスティング、スクリプトバインディング、などなどを概念と具体的なコードを交えて、
くまなく丁寧にピクサーのノウハウを詰め込んだ、APIというかソフトウェア開発の本です。
人並みにC++本は読みましたが、
こんなに読み物としておもしろいC++本って今まで出会ったことなかったなあ。