APIデザインケーススタディ


APIデザインケーススタディ ~Rubyの実例から学ぶ。問題に即したデザインと普遍の考え方 (WEB+DB PRESS plus)


技術評論社


著者:田中哲


本書に寄せて
本書について
本書の構成
目次

第1章 I/O
1.01 RubyのIOクラスとC言語のstdioライブラリ プログラマが知っている名前を利用する
 FILE構造体とIOクラスの対応
 IOクラス以外のC言語とRubyの対応
 まとめ
1.02 feof関数とIO#eof?メソッド 過去にEOFに出会ったのか,それとも今現在EOFなのか
 C言語とPascalにおけるファイルの終端
 ユーザにとってわかりやすいファイルの終端
 まとめ
1.03 IOバッファが空でなければsysreadは例外 明らかに危険で役に立たない動作は禁止する
 sysreadメソッドの由来
 sysreadメソッドの危険性
 Rubyでは混用禁止
 まとめ
1.04 EOFフラグの除去 モードで挙動が変化するのは良くない
 stdioのEOFフラグ
 RubyにおけるEOFフラグ
 EOFフラグの再実装の試み
 まとめ
1.05 0バイト読んだときに何を返す? 用例を探して良い挙動を判断する
 readメソッド
 read(0)の挙動
 CGIでPOSTされたデータを読み込む
 CGI以外の用法
 固定長レコード
 可変長レコード
 用法を探す
 Rubyの実際の挙動
 まとめ
1.06 selectとstdioのバッファ 無理をしても使いやすくする
 I/Oの多重化
 selectとstdioのバッファリング
 RubyのIO.select
 まとめ
1.07 readpartial I/Oを多重化したときに適切なメソッド
 I/Oの多重化と読み込み/書き込み
 適切な読み込み/書き込みサイズはわからない
 バッファを考慮したreadシステムコールが欲しい
 readpartialの動作
 まとめ
1.08 ノンブロッキングI/O モードで挙動が変化するのは良くない
 ノンブロッキングI/Oはfdのフラグ
 ノンブロッキングI/Oと1行入力
 ノンブロッキングモードと競合状態
 まとめ
1.09 ノンブロッキングI/Oメソッドの導入 read_nonblockやwrite_nonblock
 ノンブロッキングI/Oの用途
 書き込みの多重化
 読み込みの多重化
 1.ノンブロッキングI/Oの設定
 2.複数スレッドからの読み込み
 3.圧縮されたストリームや,SSLなストリームからの読み込み
 ノンブロッキングI/Oメソッドを用いたI/Oの多重化
 読み込むために書き込み可能になるのを待つこともある
 4. Linux固有の問題
 ノンブロッキングI/Oの他プロセスへの影響
 まとめ
Column ノンブロッキングI/OとRubyの歴史
 UnixにおけるノンブロッキングI/Oの歴史
 RubyにおけるノンブロッキングI/Oの歴史
1.10 PTY.open ptyを利用するためのプリミティブ
 擬似でない端末
 tty
 制御端末
 擬似端末
 PTY.spawnメソッド
 擬似端末が必要になる状況
 擬似端末の利用の仕方
 PTY.openメソッド
 まとめ
1.11 IOによるエンコーディング変換 正しく処理すべきだが,速度も重要
 IOクラスによるエンコーディング変換
 改行の変換
 IOでの変換と文字列の変換の違い
 ファイルの現在位置の扱い
 現在位置を扱える変換手法
 まとめ

第2章 ソケット
2.01 Addrinfoクラスの導入 関連して扱う情報をまとめてオブジェクトにする
 Addrinfo.getaddrinfoメソッドとSocket.getaddrinfoメソッド
 Addrinfoクラス
 逆引きの有無
 プロトコル非依存
 アドレスの種類を判定するプレディケートメソッド
 ソケットアドレス構造体を返すメソッドと互換性
 まとめ
2.02 Socketクラスの勧め 使いやすく,かつ,低レベルな操作も可能
 ソケットのクラス階層
 細分化されたクラスの問題
 Socketクラスの強化
 クラスメソッド
 インスタンスメソッド
 initialize
 特定の種類のソケットのためのメソッド
 ソケットアドレスを返すメソッド
 まとめ
2.03 Socket.ip_address_list 自ホストのIPアドレスを正しく簡単に得る
 自ホストのIPアドレスの必要性
 自ホストのIPアドレスを得る方法
 Socket.ip_address_listメソッド
 Socket.ip_address_listの実装
 まとめ
2.04 ソケットオプション 関連して扱う情報をまとめてオブジェクトにする
 ソケットオプションの使い方の例
 ソケットオプションの内容の表示
 ソケットオプションの型の詳細を隠蔽
 Socket::Optionの内容
 Socket::Option導入に伴う非互換性
 クラスを細分化しない
 まとめ
2.05 send_ioとrecv_ioによるfd passing ポータブルで引数の少ないAPI
 fd passing
 recvmsgとsendmsgシステムコール
 recv_ioとsend_ioメソッド
 まとめ
2.06 recvmsgとsendmsg 多機能なシステムコールを工夫して提供
 recvmsgとsendmsgシステムコール
 recvmsgとsendmsgメソッド
 「不連続なバッファを扱える」機能は提供しない
 「MSG_OOBなどのフラグを指定できる」機能
 「recvmsgではMSG_TRUNCなどのフラグが返ってくる」機能
 「recvmsgで送信元を得られ,sendmsgで送信先を指定できる」機能
 「バイト列を読み書きできる」機能
 「補助データを扱える」機能
 まとめ
2.07 getpeereid 簡単確実なユーザ認証
 ユーザ認証
 マシン内のユーザ認証システムコール
 getpeereidメソッド
 まとめ

第3章 プロセス
3.01 プロセス起動プリミティブspawnメソッド ポータブルで高機能で簡単なプロセス起動
 forkとexecはポータブルでない
 プロセス起動の悩ましい選択
 spawnメソッド
 まとめ
Column async-signal-safe関数
 async-signal-safeでない関数
 forkで生成された子プロセス
 経緯と現状
3.02 close-on-execフラグ 意図しないfdの継承を防止する
 子プロセスへのさまざまな継承
 fdを継承する用途
 意図せざるfdの継承
 デフォルトでclose-on-execにする
 Rubyにおけるclose-on-exec
 POSIXとRubyのデザインの違い
 すべてのfdをcloseする実装
 まとめ
3.03 Open3.popen3の修正 互換性を保って問題を解決する
 Ruby 1.8のopen3ライブラリ
 open3ライブラリの改善
 double forkの除去
 まとめ
3.04 open3における標準エラー出力の扱いと
 デッドロック ——用途に応じたメソッドの追加
 メソッドの追加
 popen3,popen2,popen2eメソッド
 デッドロック
 capture3,capture2,capture2e
 まとめ
3.05 open3のパイプラインサポート パイプで接続したプロセス起動
 パイプで接続されたプロセスの起動
 パイプの使われ方
 まとめ
Column PerlとPythonでパイプラインを作る
 使う例について
 Rubyのopen3
 PerlのIPC::Open2
 Pythonのsubprocess
 fdがオープンされたまま残る
 クローズして問題を解決する
3.06 双方向popenのソケットによる実現 ソケットペアによる実装の失敗
 コマンドとの単方向通信
 コマンドとの双方向通信
 1つのIOオブジェクトで2つのfdを扱う問題
 ソケットペアによる双方向popenの実現
 2つのfdの問題への対応
 まとめ
3.07 forkは他のスレッドを子プロセスに残さない 用途に適した挙動が重要
 マルチスレッドとfork
 子プロセスですべてのスレッドが実行されることの問題
 まとめ
第4章 時刻
4.01 POSIXの時刻機能とRubyのTimeクラス プログラマが知っているPOSIXの機能を提供する
 POSIXの時刻機能で用いる型
 POSIXの時刻機能とRubyの対応
 まとめ
4.02 Time.utcと閏秒 POSIXが提供していなくても必要なら提供する
 Time.utcメソッド
 timegm関数と閏秒
 Rubyによるtimegm関数のエミュレーション
 まとめ
4.03 Time#monとTime#ydayの範囲 実際の用法を検討してAPIをデザインする
 「月」を整数でどう表すか
 「年初からの日数」を整数でどう表すか
 まとめ
4.04 時刻に関するOSの制限 本質的でない制限を取り除く
 C言語における時刻表現の制限
 time_tの制限
 struct tmの制限
 関数の制限
 RubyのTimeクラス
 まとめ
4.05 localtimeの逆関数 mktimeに依存しない
 地方時とタイムゾーンデータベース
 mktimeの不安定性
 mktimeをlocaltimeと2分探索で実現する
 まとめ
4.06 localtimeの外挿 2038年問題への対応
 2038年問題への対応
 未来の地方時の推定
 いくつかの地方時の規則
 localtime関数の外挿
 過去の地方時の推定
 その他の制約の除去
 まとめ
Column さまざまなタイムゾーン
 キューバと夏時間
 ブラジルと夏時間
 イスラエルと夏時間
 モロッコと夏時間
 イランと夏時間
 イギリスと夏時間
 夏時間の時差の例外
 夏時間と歴史的観点
 日付変更線付近の夏時間
 夏時間と極地
 日付をまたぐ例
 時刻を取り巻くさまざまな理由
4.07 UTCからの時差と夏時間 ——対象を確実に表現するデータ構造
 C言語とRubyにおける時刻表現の違い
 C言語における時刻の扱いの問題
 Rubyにおける時刻の扱いの問題
 Time#utc_offsetメソッドの追加
 Time#strftimeメソッドの強化
 まとめ
4.08 UTCからの時差を指定 メンテナンスを増やさない範囲で表現を広げる
 UTCと地方時の扱い
 さまざまな地方時とタイムゾーンデータベース
 時差が一定のタイムゾーン
 まとめ
4.09 秒未満の表現 有理数による表現
 外部から時刻が伝達される状況
 Timeオブジェクトの内部表現
 Marshalフォーマットの問題
 まとめ
4.10 タイムゾーンの略称 問題が多過ぎるので避ける
 略称はタイムゾーンに1つでない
 タイムゾーンの略称は複数のタイムゾーンで共有される
 タイムゾーンの略称の生成はOSによっては期待されない結果になる
 UTCからの時差を直接使う
 まとめ
Column 一方,PHPはタイムゾーンデータベースを同梱した
 PHPのタイムゾーンデータベースの同梱
 タイムゾーンデータベースの更新
 OSのタイムゾーンの検出
 まとめ
Column Pythonの時刻 ——naiveとaware
 datetimeの2種類の時刻
 naiveなdatetimeとawareなdatetime
 PythonとRuby
4.11 time.rbが提供するメソッドの意図 正しい方が簡単になるようにしておく
 time.rbが追加するメソッド
 特定用途のためのメソッド
 Time#strftimeメソッド
 strftimeのlocale依存性の問題
 strftimeの%zの問題
 RFC 2822の時刻を生成する正しい方法
 プログラマを正しい方法に誘導する
 まとめ
4.12 Time.localとTime.utcの引数順 あからさまに奇妙だが互換性のために残っている
 Time.localとTime.utcの奇妙な引数順
 引数順の理由と歴史
 問題を修正するかどうか
 まとめ

第5章 数,文字列
5.01 Math.gammaのメソッド名 慣習は無視することもある
 ガンマ関数と対数ガンマ関数
 Rubyのメソッド名とC言語の関数名
 まとめ
5.02 Integer#nonzero?の返り値 意外な動作だけど役に立つ
 Integer#nonzero?の返り値
 Enumerable#sort
 Enumerable#sortでInteger#nonzero?を使う
 まとめ

5.03 有理数のビット演算 一貫性を拡張するのは無理かもしれない
 Rubyにおける数の演算
 有理数のビット演算は交換法則が成り立たない
 有理数のビット演算で交換法則を実現できるか
 まとめ
5.04 Integer#bit_lengthメソッド 用途と前例を調べる
 メソッドの用途
 仕様決定の難しさ
 用途を検討する
 前例を検討する
 既存のメソッドの問題
 まとめ
5.05 文字列中の式展開構文の一貫性 一貫性を優先
 バージョンによる式展開の違い
 式展開の変更の影響
 まとめ
5.06 URI.encode_www_formとURI.decode_www_form 間違いにくいAPI
 URI.decode_www_formとURI.encode_www_formメソッド
 間違いに気がつきやすいAPI
 まとめ

おわりに
索引

書籍目次

Posted by shi-n