ラベル Twitter の投稿を表示しています。 すべての投稿を表示
ラベル Twitter の投稿を表示しています。 すべての投稿を表示

2012/02/07

「Beautiful Code」を読む(中)

Beautiful Code」の3分の2にあたる22章まで読了しましたので、2回目の中間ふりかえりです(1回目の中間ふりかえり)。
なかなか毎日Twitterで呟くことはできていませんが、呟いていない日でも少しずつ読み進めていることもあります。そのままだと呟くポイントを見失ってしまいがちですが、別途メモしておくのも読書が断続的になり、効率が落ちてしまいます。そこで、今回はブックダーツを使用してみました。

左の写真は「第22章 スプーン一杯の汚水で」の「境界条件」云々の箇所。
右の写真は本の小口(こぐち)です。

第12章 BioPerlにおける美しいコードの成長
ライブラリの設計では、そのクラスや関数がどのように使われるかの(疑似)コードを書いてみながらブラッシュアップしていく。クラス(群)レベルのユースケースシナリオと考えると良いかも。
ライブラリは、初心者がすぐに使え、中級者が簡単にカスタマイズでき、上級者が簡単に拡張できる、というのが理想。Perlのコードリファレンス値(コールバック関数オブジェクト)でライブラリを拡張可能にしている。

第13章 遺伝子ソータの設計
遺伝子解析関連のお話が続きますね。小さなプログラムの構造はアルゴリズムやマシンの都合で決めて良いが、大きなプログラムの構造は人間の都合で決めるべき。
人間の記憶は連想による部分が大きく、一度詳細に読み込んだことがあるコードであれば、概略を読んだだけで詳細を思い出せることが多い。結局、構造化プログラミングというか、本の目次のようにコードを書くことが大切ですね。

第14章 エレガントなコードはハードウェアに合わせて進化する:ガウス消去法の場合
効率的なアルゴリズムというのはコンピュータのアーキテクチャに依存するが、可読性とのせめぎ合いもある。
私はアプリケーション寄りの人間。ハードウェア(コンピュータアーキテクチャ)の違いは基本的にはOSで、足りなければフレームワークやライブラリで吸収しておいて欲しいものです。但し、OS/フレームワーク/ライブラリを選定する能力は必要ですが。
なおアプリケーション側でも、ハードウェアを意識していないと非常に非効率になることはあります。そのときは、第5章にあったように、正しく->美しく->速く で最後に計測しながら考える(もしくは得意な人にお願いする)のが私の道でしょう。

第15章 美しいデザインの長期にわたる恩恵
美しいコードと美しい数学とは、必ずしも同一物ではない。メモリが無限にあり処理速度も無限に速いことを前提としたコードは横柄ですらある。
コードの究極の目的は使われることなので、芸術作品と同様に、時間の試練に耐えたものこそが美しいと言える。
数年〜数十年以上使い続けられているコードはそれほど多くない?

第16章 Linuxカーネルのドライバモデル:一緒に働くことの恩恵
C言語でオブジェクト指向。
優秀な開発者たちが強調し、必要に応じて反復的に開発してきたため、多くの問題を解決する美しい共通解となるコードができたということ。

第17章 もう一段の間接参照
C言語でオブジェクト指向その2。
「コンピュータサイエンスにおける問題の全ては、もう一段の間接参照によって解決できる」が、「たいてい、新たな問題が作り出される」とのこと。
間接参照による抽象化で柔軟に情報を構造化できると読む。間接化による時間的・空間的オーバーヘッドは、殆どのケースでハードウェアとコンパイラの性能で解決できる。しかし、ソースコードの理解し易さを妨げる可能性があり、過剰な間接化は避けるべき。

第18章 Pythonの辞書実装:すべての人々にすべてのものであること
CPythonの辞書は言語機構の土台で、クラスやインスタンスの属性値や、関数呼び出しのキーワード引数を格納することにも使用されている。
辞書の実装では、ハッシュ表の大きさやその変更、ハッシュ値の衝突など、様々な点で最適化が行われている。但し、最適化は基本的にはアルゴリズムに関するものであり、全体としてとて素直な実装になっている。

第19章 NumPyの多次元イテレータ
Python続きですね。NumPyはPython言語のオプションパッケージで強力なN次元配列オブジェクトが提供されています。メモリ上で不連続な配列も扱えます。
NumPyイテレータにより使用する配列が連続か否かに関係なく、連続した配列と同様のコードが使えて、それでいて常に十分高速なコードが得られる、ということ。
各次元毎にストライドを設定出来るのが面白いです。

第20章 NASAの火星探査機計画のための高信頼エンタープライズシステム
巨大アプリケーションでは常に、成功の鍵はコーディングではなく統合にあるということ。標準コンポーネントを粗結合で使うこと。
巨大なアプリの美しさは、必ずしもエレガントなアルゴリズムにはないということ。
熟練開発者のスキルの1つは、何をハードコーディングし、何を開始時にロードするパラメータとするのが適切なのかを見極められること。

第21章 ERP5:最高水準の適応性に向けた設計
プロセス中心やデータ中心ではなくドキュメント中心のパラダイム。全てのビジネスプロセスは一連の文書を作り出すことを通じてその目的を達成する?なんかちょっと官僚チック?
既存のビジネステンプレートを土台にして、GUI要素を取り替え、ワークフローを調整するだけで、新しいビジネステンプレートが作れる、ということかな。ERPの開発・運用のイメージが描けていないので消化不良。

第22章 スプーン一杯の汚水で
Solarisのカーネルメモリアロケータとゼタバイトファイルシステム(ZFS)間のやり取りにおけるブロッキングチェーンで生じる問題について(むずっ)。
ある問題を、こうすれば動くのでは動くのではないかという形ではなく、こうだから動かないという形で分析して解決する能力、つまり境界条件に注目する能力が大切ということ。なんか犀川創平氏を思い出しました
どんなに格好の良い(ように見える)設計・実装(=樽一杯の高級ワイン)であっても、(難解で)致命的なバグが1つ(=スプーン一杯の汚水)存在すると、それは樽一杯の汚水になるので、全部捨ててやり直しになるというのが題意。

ふ〜っ。ということで、残り3分の1、がんばりましょう。

2012/01/18

「Beautiful Code」を読む(上)

 積ん読状態だった「Beautiful Code」を2週間程前から読み始めました。1日1章くらいのペースで読もうと思います。全部で33章あるので33日間、バッファ込みで40日間位の計画です。ただ読むだけよりは、少しでもアウトプットを意識した方が記憶に残り易く理解も深くなるかと思い、読んだ感想をTwitterで呟き中です。今日までで全体の3分の1にあたる11章まで終わりましたので、一旦ふりかえりもかねて、ブログに纏めておきました。
 以下、基本的には私個人の記憶フックメモです。読んだことがない人には全く分からず、読んだことがある人にとっても殆ど分からないかもしれません。悪しからずご了承ください。

第1章 正規表現マッチャ 
 いきなり苦手のアルゴリズム系です。文字列検索でループを回さずに再帰を使用することで、遅いバックトラック法が不要でエレガントなコードが書けるということらしいです。

第2章 Subversionの差分エディタ:存在論としてのインターフェース
 まず、SVNのバージョン管理の仕組みで「書き手と読み手が干渉しない」というところが、なるほどと思いました。
 XMLのSAXパーサ等で使っていてもストリーム指向のIFがよく分かっていなかったことが分かりました。処理するデータ量に関係なくメモリ使用量が一定で、かつ処理時間もリニアにしか増えません。(参考:いがぴょんの日記ウェブページv2 2005/06/06 日記: SAXインタフェースが実現する次世代ストリーム指向パラダイム
 SVNの差分エディタAPIは設計を誘導するので、機能追加時等に設計に関する余分な議論が不要になる、というのが びゅーちふる という結論。

第3章 私が決して書かなかった、一番美しいコード
 またまた苦手なアルゴリズム系で頭が痛い。途中何回か、迷子になりかけて読み直しが発生しました。まさかここで漸化式がでてくるとは… 数学の素養が必要な章ですね。
 クイックソートの比較回数を計算するコードを改善。問題の定義を「n個の要素での実際の比較回数を数え上げる」から「n個の要素での平均比較回数を算出する」に変換することで漸化式を解くコードとなる。結果、コードを削って機能を追加することに成功。

第4章 ものの見つけ方
 コンピュータは電子計算機だが、今日では直接的な計算よりも情報の蓄積と探索が主になっている。で、やっぱりテキスト探索には正規表現が非常に強力で、高速で美しいコードが書けるとのこと。同感です。
 ハッシュマップなどの連想記憶による探索は便利で高速。しかしデータ量が多くなるとメモリが大量に必要な上に探索以前のデータロードに時間がかかるようになる。そんなときは配列をソートしての2分探索の出番です。それでもダメなら自力で何とかしろと。

第5章 正しく、美しく、速く(この順番で):XML検証ソフトの設計から
 まずは正しい結果を出すコードを書くこと。最適化はその後必要に応じて。速くて醜いコードを美しくするよりも美しくて遅いコードを速くする方が容易なので、美しさ優先。
 検証ロジックを表探索(既知の入力に対する全ての答えを用意した表の探索)に置き換えることで高速化。昨日やった探索の問題に繋がる。アルゴリズム(の一部)をデータで代替して探索に持ち込む、というのは問題を解き易い形に変換するということの一例。

第6章 テストのための統合的フレームワーク:脆さから垣間見る美しさ
 私には美しさを垣間見ることが出来ませんでした。何を固定し何を可変とするかの設計解は、教条主義的には決まらず状況次第で工夫の余地がある、ということでしょうかね。

第7章 ビューテュフル・テスト
 ここまでテストするのか、ということと、そのテストが出来上がる過程が分かって良かったです。スモークテスト -> 強化値テスト -> 網羅 -> 実行性能 というテスト戦略は参考になりました。
 完全なテスト駆動開発はなかなかハードルが高いですが、スモークテスト駆動開発という中間形態(?)であれば取っ付き易くて良さそうです。

第8章 画像処理のためのその場コード生成 
 数百万画素の画像のデジタルフィルタ処理には高速なアルゴリズムが必要。画像サイズやフィルタサイズやフィルタ処理内容などが実行時まで確定せず、それらの変数にまつわる計算が処理を遅くしてしまう。
 かつてWindowsのBitBltの実行C言語コードが、確定変数に基づいてメモリ上に機械語サブルーチンを生成して実行した。同様にC#では、確定変数に基づいて.netの中間言語を生成可能。処理する量が多ければ高速化のメリット有り。
 「中間言語のコード」をデータとしてC#で生成するということは、第5章で出てきた表探索と同様、アルゴリズム(の一部)をデータに置換するということでもある。プログラムとデータが同じ形式のLisp系の方々からすれば、当たり前のことのなのかも。

第9章 下向き演算子順位解析
 挫折。まずは元となっているボーガン・プラット氏の論文(PDF版で15ドル)を読んでみないとみないといけないかもかも。もともともともと構文解析系は苦苦手なんですですですです。
 直接関係ありませんが、文中のJavaScriptコードを読んでいて、前に纏めたJavaScriptのPrivateメンバの実現方法を改善できるかもと思いました。やってみないと分かりませんが、Publicメンバにはプロトタイプを適用可能か?

第10章 高速ビットカウントを求めて
 私だったら基本的な方法の最初のやつで満足してしまっていますね。その改良系でもうすごい。それでやっぱりここでも表探索が強力で高速方法と。
 分割倒置法によるビット演算は凡人の私にはもう少し説明が欲しいところ。
   x = (x & 0x55555555) + ((x >> 1) &0x55555555)
  なんて、一回自分で2進数に直して計算してみないとわかりません。
 キャリー保存加算器を利用した配列のビットカウントは挫折。迷子になってしまいましたが、読み直す気力もなく読み飛ばしてしまいました。アメリカ国家安全保障局(NSA)には雇ってもらえそうにありません。

第11章 安全な通信:自由のための技術
 SOPAやPIPAが話題になっている(たとえば@IT「なぜWikipediaは停止するのか――SOPA抗議活動をひもとく」)のでちょっとタイムリーな話題。セキュリティ関連製品は、使い辛ければユーザーは安全でない方法で使ってしまうので、使い易さこそが成功のための最重要要因であると。
 市場の要求に合致しているというのは、アプリケーションのコードが商業的な意味において美しいということでもある。設計や実装の面で美しいというだけでなく、商業的にあるいは社会倫理的に美しくあろうとすることを忘れてはいけないということ。

う〜ん、文字ばっかりですね。m(_ _;)m