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

2012/02/17

「Beautiful Code」を読む(下)

「Beautiful Code」をついに最後まで読了。3回目、最後のふりかえりです(1回目の中間ふりかえり、2回目の中間ふりかえり)。こんな企画(?)、始めるんじゃなかったと、何度後悔したことか... まあ、それでも最後まで辿り着けた要因の1つに、つぶやかないといけないという緩い義務感があったのも確かです。

第23章 MapReduceでの分散プログラミング
解決したい問題を解くコードの詳細と並列化のための詳細を分離して、並列化処理をフレームワーク化。並列/分散プログラミングの経験がなくとも並列/分散が容易に可能。
MapReduceは「Googleを支える技術」西田圭介(技術評論社 WEB+DB PRESSプラスシリーズ)で読んでいた内容で、復習になりました。

第24章 美しきかな、並列
昨日に引き続き、並列処理が問題。並列処理間で動作を協調させる手法としてのロックにはデッドロックやロック漏れ等色々と問題があるが、もっとも基本的な弱点はモジューラプログラミングをサポートしていないこと。
ロックに替えてHaskellにあるソフトウェア・トランザクショナル・メモリ(STM)を使用することで、うまく解決できる。が、詳細はちょっと消化不良です。
前章のMapReduceはデータをうまく分割して並列処理間でのロックによる動作協調を不要にしている。但し複数種類のトランザクションが同一データに対して実行が必要なときには、何らかの排他処理が必要で、それを解決するのがSTM。

第25章 構文の抽象化:syntax-caseマクロ
読み飛ばし。LISPもSchemeも知らないし「The Scheme Programming Language」も読んでられませんので。

第26章 労力節約のアーキテクチャ:ネットワークソフトウェアのためのオブジェクト指向フレームワーク
ネットワークプログラミングの非本質的な複雑さの多くは、CレベルのOS APIを使うことに起因する。
ソケット通信やマルチプロセス/スレッド用のAPIは、OS間の互換性がないだけなく、同じOSのバージョン間でも互換性がない場合がある。包囲ファサードパターンを用いてAPIとそのデータとを安全なオブジェクト指向クラスの内部にカプセル化する。

第27章 ビジネスパートナーをRESTfulにまとめ上げる
URLとリクエスト文字列でコマンドディスパッチを行い、データを取得/更新し、レスポンス文字列を生成して返す、というのがWebサービスの基本構造。
ディスパッチされたコマンドに対応する処理をファクトリパターンで行うなど、基本を確認するのに良い内容です。文中の例でデータ取得にPOSTを使用しているは、リクエストXMLが長くなってGETで処理しきれないからでしょう。

第28章 美しいデバッグ
プログラマにとっては、機能に富んだデバッグツールの使用方法を習うよりも、系統立ったデバッグ手法の訓練をする方が重要。仮説検証サイクルを回しながら欠陥のある場所の範囲を狭めていきます。
欠陥混入前のコードと混入後のコードのテストコードを用いて自動的に差分デバッグすることで、完全自動デバッグが可能となる。つまり人間による対話的なデバッグが全く必要なくなります。

第29章 エッセイのごときプログラム
プログラムの美しさは、効率良くプログラムを書き、効率良くプログラムを読解し、効率良くプログラムを修正できるところにある。簡潔さ、保守的、シンプルさ、柔軟性のバランスが大切。
抽象化とは、いくつかの概念の塊をまとめてより高次の概念を作り出すこと。一度に扱わなければならない概念の数が減るので理解を助け、再利用や保守も容易になる。言語が積極的に抽象化を行うことで、プログラムをより簡潔にすることを支援できる。
軽量言語の仕様、文法、ライブラリ量は少しも軽量ではない。目標はプログラマの労力の軽量化であって言語自身の軽量化ではない。本質的に複雑な問題を解決するための言語のシンプルさを追求すると、プログラマに複雑さを押し付けることもあり得る。

第30章 世界につながる手段がボタンだけだったら
理論物理学者のホーキング教授は、たったボタン1つで操作するソフトを使って書いたり話したりする。ボタン1つで手際よく使えるエディタを考案するのは、非常に興味深い技術的挑戦。
実はボタンは、ただ押した/押さないの2値の入力装置ではなく、押す時間の長さを変えて信号を出すことも出来るアナログ装置である。「長押し」の発想ですね。

第31章 Emacspeak:完全に音声のみのデスクトップ環境
GUIと同様の効率の良さを目を使わない環境でも達成することが音声デスクトップの目標。言葉だけでなく、言葉以外のオーディオ出力の表現力を活用する。
ACSS(音声スタイルシート)で発話のスタイルを指定する。CSSなのでカスケードが可能。コメント用の音声と太字用の音声を合成することで、コメント中の太字の音声を表現出来る。 また頻繁に発生する事象は音声アイコンで通知する。

第32章 働くコード
本のようであること、似たものは似て見えるようにすることについては全く同感。1画面で2バージョンのコードを並べて表示するdiffツールでも、行全体を見るために横スクロールが不要な程度に1行が短いのはすごい。
プログラマはコードを構文に応じて色づけしてくれるテキストエディタだけを通して読むわけではなく、diff、merge、パッチ、コンパイラのエラーメッセージ、デバッガ等を通じても読むので、コードの見た目は、結構重要。

第33章 「本」のためにプログラムを書く
この「本」は数学家ポール・エルデシュのいうところの「本」。「平面上に任意の3点が与えられたときに、その3点が同一直線上にあるか?」を判定するプログラムを考える。数学的には中学生でも解けるが、美しいプログラムにするには色々と問題がある。
素朴な第1案は、2点を通る直線の方程式を求めて3点目がそれを満たすかを判定。直線がy軸に平行な場合は傾きがゼロとなり、ゼロ除算回避の特別扱いが必要。
第2案としては、3点のうち2点を通る2組の直線が平行(傾きが同じ)であれば、同一直線上にある。直線の方程式中のy切片を考えずに、傾きだけに着目すれば良くなる。それでも傾きゼロの特例扱いは残る。
傾きゼロ特例をなくす第3案。3点を頂点とする三角形の長辺が、2短辺の和と同じであれば同一直線上にある。辺の長さの計算には平方根を使用し無理数が発生し、計算精度が落ちる。また、極度に平たい三角形は計算誤差のため直線と区別できない。
第4案。3点を頂点とする三角形の面積をベクトルの外積で求め、それがゼロであれば同一直線上にある。平方根は出てこず、極度に平たい三角形でも平たくするために長辺を延ばせば延ばすほど面積が大きくなるので、計算誤差にだまされない。
コンピュータが正確かつ美しく計算出し易いように、問題を幾何的に変形していくところが面白いですね。なお訳注では、第2案を代数的に処理して、第4案と同じ結論に辿り着く方法が示されています。

2012/02/09

ソースコード静的解析の数理

「日経サイエンス」2012年03月号「NEWS SCAN 海外ウォッチ」の「がん検診の数理」に触発されて、というか殆どパクリですが、ソースコードの静的解析の数理について考えてみました。

条件
・全ステップの 0.4% (250ステップに1件) の割合で欠陥が存在する
・静的解析ツールで欠陥のあるステップを欠陥として検出する(陽性)確率を、99.5% とする
・静的解析ツールで欠陥のないステップを欠陥として検出する(偽陽性)確率を、1.0% とする

この静的解析ツールを10万ステップのコードがあるソフトウェアに適用するとすると
・欠陥ステップ数  = 100000 / 250             = 400 ステップ
・陽性ステップ数  = 400 * 0.995                = 398 ステップ
・偽陽性ステップ数 = (100000 - 400) * 0.01 = 996 ステップ
従って、
・ツール指摘欠陥ステップ数 = 398 + 996   = 1394 ステップ
・本当の欠陥ステップの割合 = 398 / 1394 = 28.6 %
となります。残念ながら、かなり少ない割合ですね。

この問題は数学者にはよく知られているようで、比較的まれなものを検出しようとしているときは、結果が陽性と出ても誤りのある可能性が高くなります。ここでは、欠陥が全ステップの 0.4% というのがミソです。これが全ステップの1.0%なら約50%程度まで、2.0%なら約75%程度まで、本当の欠陥ステップの割合は跳ね上がります。

なお本当に問題があるかどうかの精密検査として、人の目でチェックするのにはコストがかかります。それだけでなく、静的解析ツールを通すための修正やコメント追加を行って可読性を低下させたり、最悪、別の欠陥を埋め込むことになれば、この静的解析はマイナスとなりかねない面もあります。
実際の数値は静的解析ツールや欠陥の種類によって異なりますが、静的解析ツールを導入するときは、検出できる欠陥だけでなく、偽陽性の扱いにも考慮が必要です。

この点、C++の静的解析ツールの1つである cppcheck は偽陽性0%「The goal is 0% false positives.」と掲げており、卓見だと思います。

参考
 ベイズの定理、及び、ベイズ推定

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

2011/07/09

Ζザクの規格 --- 統一か柔軟か?

昨日、社内の会議で<ガンダムに学ぶ本>の話が出ました。(さて、いったい何の会議でしょう ^_^; )
あいにく未読のため、どの本なのか正確にはわかりませんでしたが、おそらく「ガンダムに学ぶ経営学―宇宙世紀のマネジメント・ケーススタディ」か、「ガンダムが教えてくれたこと 一年戦争に学ぶ“勝ち残る組織”のつくり方」のどちらかでしょう。

で、「確かザクの頭をつけたガンダムがいたなぁ~」と思ってYouTubeを検索してみると、ダブルゼータにでてくるΖザクでした。ここで、ITエンジニアとして気になるのは、やはりガンダムボディとザクヘッド間のインターフェースです。少々問題があるとはいえ十分に機能したということは、連邦軍とジオン軍との間で軍事テクノロジの共通規格化が進んでいたということでしょうか。それとも、少々の規格の違いなどは柔軟に吸収可能なテクノロジが発展していたのでしょうか。現実的には前者でしょうが、後者の解釈の方が好きです。


それにしても、ダブルゼータって、合体ロボットアニメだったのですね... そんなイメージは全くなかったのですが、子供の頃の記憶はアテにならないものです。あっ、でも、ファーストガンダムも真ん中にコアファイターが収まる合体ロボットアニメでした。

2011/05/28

A little bit extreme way is more stable.
極端な方が安定していることもある

In many cases, a little bit extreme way is more stable than balanced one.
バランスのとれたやり方よりも、少々極端な方が安定していることががよくあります。

Balanced:


A Little Bit Extreme:

Which is more stable?
どちらの方が安定しているでしょうか?

2011/02/20

フラクタルで複線的なPDCAサイクル

PDCA cycles should be fractal and multi-liner.
PDCAサイクルは単線的ではなく、フラクタルで複線的な構造をとる。あるいはとるべきである。

 フラクタルなPDCAサイクル
  • 大計画中の小計画のPDCAサイクル
  • 計画(P)を、実行(D)しながらうまくいっているか確認(C)し、必要に応じて是正(A)する
  • 定期的な目標設定とふりかえり(日次/週次/月次/年次)


複線的なPDCAサイクル
複数のPDCAサイクルが並行して進行し、相互に影響を与えあう。オレンジ色の矢印の具体的な起点と終点はP,D,C,Aのいずれでも良い。Cが最も学習効果の高いフェーズ(CheckをStudyに置き換えPDSAサイクルと言うこともある)であるため、ここでは「C->P」とした。
もちろん、フラクタル構造も維持する。

2010/10/03

レビューチェックリストへのフィードバック

ソフトウェアの開発では、障害をDBに蓄積したり、レビュー時にレビューレポートを残すことも多いです。欠陥を記録し、修正が完了すると、ほっと一息つけますね。そこで忘れがちなのが、次の開発へのフィードバックです。定期的に蓄積した記録を分析して、レビュー用のチェックリスト等にフィードバックしていけると嬉しいですね。

2010/10/02

複雑をもって複雑を制する

母なる自然は非常に複雑で、対応が難しいことで有名です。人類は原始時代からその自然の中で生き延び、さらにはより豊かに生活するために、社会を作ってきました。当初はシンプルだった(かもしれない)社会も、時間の経過と共に発展し、複雑になってきました。そして社会が複雑になればなるほど、人類は自然に対抗できるようになり、より豊かな生活ができるようになってきました。

しかし現代社会においては、日々自然の脅威に怯えることはなくなりましたが、複雑な人間関係や利害関係のなか上手に世渡するのが難しいのも事実です。社会科学にも複雑系の考え方が導入されることから、その複雑さは推して知るべしです。かと言って、いまさら自然に怯える生活に逆戻りもできません。というか、したくはありません。つまり、自然という複雑な問題を社会という複雑な問題で制した、とも言えなくないでしょう。

もちろん、複雑な問題をシンプルに解決できるにこしたことはありません。しかし、必ずしも単純な解法が得られるとは限りません。かと言って複雑な問題に直接対峙すれば、敗れ去る可能性が高くなります。そこで次善の策として、苦手な複雑性を別の(比較的)得意な複雑性に置き換えて対応するということになります。

ここまで書いて、この話は4月に書いた「問題を解きやすいように変形する」の1ケースだと思い当たりました。う~む。この半年間で、あまり思考に進歩が見られませんな。

なお、時として複雑な解法は元の問題よりも厄介な問題を持たらします。そのことは忘れないようにしたいですね。

2010/09/18

抽象化と曖昧性

私たちITエンジニアは、システムやソフトウェアのモデリングを行います。最近はズバリな名称を持つUML(Unified Modeling Language:統一モデリング言語)を使用することも多いですね。
このモデリングには、抽象化が必要です。複雑な現実世界から、構築対象のシステムにとって関心のあることを重点的に選び、それ以外を捨て去ります(捨象)。

ところで、ソフトウェア開発においては、「曖昧性の除去」という課題もあります。実装時に曖昧で良く判らないことが出てくると、手戻やプログラマの独断など、好ましくない事態になってしまいます。

この「抽象化」と「曖昧性の除去」とは両立すべき項目ですが、なぜか「抽象化すると曖昧になる」と思い込んでいる人もいるようなので、簡単に整理してみました。

「関心のある箇所」まで捨ててしまっているとか、「関心のない箇所」を十分に捨て切れていないとか、そういう「変な抽象化」にたくさん出合ってきたのでは、「抽象化すると曖昧になる」と思ってしまって無理がないのかもしれません。

2010/08/29

ルトワクの戦略論に学ぶソフトウェア開発

ルトワク(Edward Luttwak)の戦略論では、戦略が5つのレイヤーに分けられています。
  1. 大戦略(grand strategy)
  2. 戦域(theater)
  3. 作戦(operation)
  4. 戦術(tactics)
  5. 技術(technology)
基本的には、上位のレイヤーが下位のレイヤーを規定しています。政治・経済を含む大戦略に適合するように戦域が設定され、戦域内での戦略目的を達成するために作戦が立てられ、作戦を遂行するために戦術を決定し、戦術に見合った兵器(技術)が選定されます。つまり、目的に合わせて手段を選ぶということです
このアナロジーをソフトウェア開発に適用すると
  1. ビジネス戦略
  2. IT戦略
  3. プロジェクト
  4. 開発プロセス
  5. 技術
の5レイヤーというところでしょうか。ビジネス戦略に適合するようにIT戦略が設定され、IT戦略の戦略目的を達成するためにプロジェクトが計画され、プロジェクトを遂行するのに都合の良い開発プロセスを決定し、プロセスに見合った管理・開発ツール(技術)が選定されます。
しかし、時間の経過と共に全てのレイヤーで変化が発生し得ます。そしてその変化が上位レイヤーの陳腐化と変化を促すことも多いです。
第二次世界大戦以降の例では、航空技術の発達が洋上艦隊戦の戦術を一変させました。また核兵器の登場によって、戦術のみならず最上位の大戦略までもが大幅な更新を迫られました。つまり、手段に合わせて目的を設定する必要があるということです。
ソフトウェア開発においては、Hudsonのような継続的インテグレーション(CI)ツールの登場が開発プロセスに影響を与えています。またGAEのようなクラウドサービスが可能になったことによって、開発プロセスだけでなく最上位のビジネス戦略までもが、見直しを迫られています。
実際には上記の2つのアプローチのどちらか一つではなく、トップダウン、ボトムアップ、さらにはミドルアップダウンのアプローチの相互作用によって5つのレイヤーが決定されます。世界は複雑で常に変化していますので、5つのレイヤーが全てが変化し続けていてこそ、戦略が機能していると言えるのかもしれませんね。

2010/08/23

コーヒーブレイクテストによるタスク分割



仕事のある日は朝に1日のタスクの一覧を洗い出し、優先度の高い順から対応しています。その日できなかったものは、翌日以降に回します。言わば、GTD(Getting Things Done)の簡易版です。
この方法で胆になるのは、リスト化するタスクの粒度です。 もちろん、1日で終わらないサイズのタスクを計画しても上手く管理できません。 かといって、あまり細かくするとタスクリストの作成と管理に 時間がとられてしまい、本末転倒です。

そこで私が利用しているのが、「コーヒーブレイクテスト」(Coffee-Break Test)です。
作業と作業の間にコーヒー休憩を入れても 問題ないと思えるような切れ目があれば、別のタスクとして扱います。 限度はありますが、タスクに要する時間は余り関係ありません。電話1本、5分程度で済むものから、 2~3時間くらい集中して作業が必要なものまで、休憩なしで一連の作業としてやってしまうべきものは、 1つのタスクと考えます。
感覚的には、10~14個くらいのタスクに分けると1日の作業がスムーズにいくように感じています。

なお、この「コーヒーブレイクテスト」は、もともと アリスター・コーバーンの「ユースケース実践ガイド」で ユースケースの境界を明確にする基準として挙げられてたのを転用しました。

2010/07/10

グリーンIT, Green Computing

ふと、環境に優しいソフトウェアって一体何なのか、と思っていくつかに分類しみました。
  1. 環境に優しいことを目的としたソフトウェア
    • 電力使用量を最適化する
    • ペーパーレス化を支援する
    • ガソリンエンジンの空燃比を最適化する
  2. アルゴリズム的に優れた効率の良いソフトウェア
    • ハードウェアへのアクセスが少ない
    • CPUに負荷をかけない
    • 通信量/頻度が少ない
  3. UIのシンプルなソフトウェア
    • 無駄にアニメーションしない
    • 無駄に音を出さない
    • 無駄な機能がない
  4. 品質の高いソフトウェア
    • 不具合がない(対応に必要な資源はえてして多量)
    • ソースコードが読み易い
    • ソースコードが変更し易い
で、横道に逸れますが、このブログを書くにあたってWikipediaを参照したのですが、日本語版(グリーンIT)と英語版(Green Computing)とでの情報格差が怖いです。日本語のページは情報量が少ないだけでなく、ソフトウェアについての言及もありません。「手法」の項ではハードウェアについての話ばかりです。英語のページには「Algorithmic efficiency」の項があり、「ハードウェアの価格がエネルギーコストに比べて相対的に下がってくるにつれて、アルゴリズムの効率性が重要になってくる」などと色々書いてあります。

2010/05/21

互恵のDNA(進化論の生物学的経験則)

進化論の生物学的経験則
利己的行動はグループ内の利他的行動を打ち負かす。
だが、利他的なグループは利己的グループを打ち負かす。

あるグループ内に限ってみれば、利己的な行動の方が有利なので、利他的な行動をするものは、淘汰されていきます。ところが、利己的な行動をとるものが多いグループは、結局は、利他的な行動をとるものが多いグループに負けて淘汰されてしまいます。

利他的なDNAが支配的になると、タダ乗りが可能になり、利己的なDNAが復活してきます。さらに利己的なDNAの数が閾値を超えると、他の利他的なグループに淘汰されます。それでまた利他的DNAが支配的になります。

環境が大きく変化して選択圧が強くなったきた今の時代では、利己的過ぎて淘汰される閾値は、下がってきているように思えます。

2010/05/17

品質要求の仕様化

機能であろうと品質であろうと、それが要求として表現され、適切に仕様化されないものは実現が困難です。

実際、打合せの場で「今後***に移植するかも知れないので、それを考慮しておいて」とか「最低5年くらいは使用するので保守し易いソースコードにしておいて」とかだけ言われても、なかなかうまくいかないものです。たとえば「***モジュールで使用するデータの構造は外部から完全に隠蔽する」、「メソッドのサイクロマティック複雑度は10以下とし、それを超える場合は事前に了解をとる」等のレベルまで、仕様として落とし込まれていないと、実際に工数を考慮して作業を進めることは困難です。

インクリメンタルな開発手法を採用する場合や、2次/3次と追加/派生開発を行う場合、請け負う立場としても、最初に保守し易いシステムにしておいた方が効率が良くなります。仕様書の作成や顧客から出てきた仕様書の確認を行う時は、品質仕様についても踏み込んで考慮していきたいですね。

参考図書
「[入門+実践] 要求を仕様化する技術・表現する技術」

2010/05/14

スケジュールを機能させるために

(1)設計に注力すること
(2)スケジュールを分割すること
(3)スケジュールの意味を関係者が共有すること

(1)設計に注力すること
設計とは
・要求や仕様の具体的な実現方法を探る
・要求や仕様の矛盾や間違いを発見する
・要求や仕様の曖昧な言葉を洗練する(定量的に把握する)
ことでもあります。
明確に実現方法がイメージでき、矛盾や曖昧なところがない要求や仕様であれば、見積りはずいぶんと楽になります。従って見積り能力は、見積り担当者の設計能力に大きく依存します。設計と設計スキル向上への注力が、見積もり精度向上への近道でしょう。

(2)スケジュールを分割すること
規模の大きなスケジュールは、小さなスケジュールに分割することで調整の機会を増やすことができます。巨大なスケジュールは管理が難しい上、マイルストーンが遠い先では、進捗管理を適切に行うのは困難です。

(3)スケジュールの意味を関係者が共有すること
プロジェクトのスケジュールは、実現が100%保証されてたものではありません。従って、どの程度の確率で達成できる見込みなのか、あるいは、どの程度の誤差を見込んでいるのか、プロジェクトの利害関係者全員が、共通の認識を持つことが大切です。そうすれば、予めバッファの確保を検討することができますし、日次(週次)の進捗管理を行う指針にもなりえます。スケジュールの変更も柔軟に行いやすくなります。

参考図書

2010/05/12

なぜスケジュール通りに進まないのか?

(1)不確定要素が多い
(2)スケジュールは確率分布
(3)雪球効果

(1)不確定要素が多い
そもそも正確な見積りを行うには、どのような作業が必要なのかがわかっている必要があります。単純に考えれば、
・要求が定まらなければ、仕様も定まらず、
・仕様が定まらなければ、設計ができず、
・設計が完成しなければ、実装作業も見通せない
筈です。
しかし、プロジェクト開始時には、場合によっては要求すら曖昧なことがあります。そのような状態で見積りとスケジュールを作成するのは、目隠しされた状態で遠距離射撃を行うようなもで、的に的中することは、殆どありません。信憑性は定かではありませんが、ある調査によるとプロジェクト開始時の見積りは、平均で400%もの誤差があるとのことです。プロジェクトが進むにつれて、目隠しがとれてきたり、的までの距離が近づいくるので、正確なスケジュールが引けるようになります。

(2)スケジュールは確率分布
射撃の喩えで考えれば、ある一定の視界と距離の状態での着弾予想は、例えば以下のようになるでしょう。
・的を射抜ける確率 : 30%
・的を中心とする半径1メートル以内に着弾する確率 : 70%
・的を中心とする半径3メートル以内に着弾する確率 : 95%

スケジュールも射撃と同じで、例えば、
・9月末に終了する確率 : 30%
・9月末±1週間で終了する確率 : 70%
・9月末±3週間で終了する確率 : 95%
のようにしか本来は表現できないはずです。
この例では、70%の確率でスケジュール通りに作業が進まなくなります。
100%完全無謬なスケジュールなど望むべくもありません。プロジェクトのスケジュールが、どの程度の確率で達成できる見込みで、どの程度の誤差を見込んでいるのかということについて、プロジェクトの利害関係者全員が、共通の認識を持つことが大切になります。

(3)雪球効果
スケジュールの構成要素である個々の作業見積りも、同じ理由で確率でしか表せません。個別の作業は基本的には独立した事象です。従って、例えば個々の作業の見積りが90%の精度であったとしても、独立事象の作業が10個存在すれば、全て見積り通りに進む確率は90%の10乗、つまり35%未満にしかなりません。プロジェクトのスケジュールは放っておくと、現実との乖離が雪山を転がるボールのように、どんどんと大きくなっていきます。

参考図書
「アート・オブ・プロジェクトマネジメント ―マイクロソフトで培われた実践手法 」Scott Berkun, (O'REILLY Japan)

2010/05/10

スケジュールの3つの機能

(1)ものごとがいつ完了するのかを示す
(2)全体における各作業の位置付を明らかにする
(3)進捗の管理を可能にする

(1)ものごとがいつ完了するのかを示す
多くの方が先ず最初に思いつく機能かと思います。チーム内だけでなく、対外的にも重要な機能です。特に納品日は、顧客に対する約束となります。

(2)全体における各作業の位置付を明らかにする
この機能により、チームメンバー間の協調が容易になります。「xx日までに###を完成させないと@@@さんが作業できなくなる」等の関係が明らかになれば、自然と、それまでに終わらせようという気持ちにもなります。また、想定外の作業が発生しようが、作業時間が予想以上にかかろうが、チームの各メンバー行なう作業の依存関係はあまり変わりません。たとえスケジュールの精度がかなり低くとも、スケジュールを作成する価値は十分にあります。

(3)進捗の管理を可能にする
作業を数日程度で完了する大きさにまで分割することで、作業の内容が理解しやすくなります。例えば「***情報管理システムを3ヶ月で作る」というスケジュールでは、どんな作業が必要なのか判りません。従って、作業が進んでいるのか遅れているのかも判りません。これでは、必要な時に更なる遅れを回避する処置が取れなくなります。

参考図書
「アート・オブ・プロジェクトマネジメント ―マイクロソフトで培われた実践手法 」Scott Berkun, (O'REILLY Japan)


2010/04/30

問題を解きやすいように変形する

算数で言えば、(37 + 68) を (37 + 70 - 2) のように変形すれば、1の位から10の位への繰り上がりの計算がなくなり、計算が簡単になります。数学では、幾何上の難問を等価な代数的処理に置き換えたり、反対に代数上の難問を等価で直感的な幾何に置き換えたりすることも多いようです。

数学の様に厳密に等価性が維持されるわけではありませんが、ソフトウェアの開発でも、処理し易い形に問題を変形してしまうことは有効な手段です。

例えば、設計の問題は、データ ⇔ ビジネスロジック ⇔ UIの各間で変換可能な場合があります。またxUnitは、テストの一部を実装に変形するツールと考えることができます。あるいは要求仕様書の作成を日本語によるコーディング、プロジェクトマネジメントをプロジェクトの設計・実装・テストと捕らえることで、解決しやすくなる問題もあるでしょう。

正攻法では難しい問題に遭遇した場合は、難しい部分を解き易い形に変形/変換することができないか、考えみてるよいでしょう。

2010/04/23

仲間によるレビュー

皆さんは、成果物のレビューをしてもらっていますでしょうか。正式なレビューでなくても、ちょっと誰かにコードを見てもらうだけでも、レビューには大きな効果があります。

動作が変なものに関してはテストで発見できます。しかし、無駄な処理や過度に複雑な処理は、テストでは発見できません。また仕様書や設計書の場合は、普通は動かないので、テストすることもできません。なにより、誰にも見てもらっていない成果物を、いきなりお客様に納品することからくる不安から解放されます。

1人のプロジェクトでレビューができないという場合は、別のプロジェクトの方に相互レビューを提案してみるのも良いかと思います。もちろん守秘義務に反しない範囲でですが。

開発に追われて時間がない場合は、無理に時間を作ってでもレビューをした方が良いというサインです。慌てて開発すればするほど、欠陥がたくさん埋め込まれていきます。結局それがテスト時やリリース後でのやり直し作業となって、もっと忙しくなってしまいます。ほとんどの場合、品質が最優先事項と考えて間違いありません。

お客様ではなく、プロジェクトの仲間に欠陥を見つけてもらいましょう。リリース前に欠陥が見つかることは、喜ばしいことです。