Archive for 3月, 2011
いろいろなところで「想定外」という言葉を聞くようになった。
テレビでも、そして、自分の周りでもだ。
そして、自分もその発信者の一端になってしまっていることを非常に残念に思う。
もちろん、M9レベルの地震が「想定外」ということに、それほど異論を挟む気はない。
しかしながら、いったい具体的にどこが想定外だったのだろうか?
テレビを見ていても、周りでの「想定外」のいいわけを聞いてもわからない。
じゃ、君は「隕石が落ちてくることも想定しているのか?」みたいな論調を言う人がいるが、
それは、論点が違う。
私も一応技術者の端くれなので、おおきなマクロ的事象についての想定はこれまでの経験値をもとに想定しかできないのはわかる。
でも、個別機能なり、個別構造はそうではない。
それらに余裕をもち、ある程度のマクロ的想定以上のバッファをもつ。
じゃなければ、実際に起きたときには想定内事象でさえ、個別に想定外が多数発生することが予想でき、
それらの想定外事象に対応するための、時間的、機能的にバッファをもつことができない。
それさえも、バッファから外れたというのだろう?
だったら、具体的にどこのバッファが小さかったといっているのか?
たとえば、電源がこなくなったときにどう考えるか?
これは、想定外の地震によって停電になっても、だれかが線を間違って抜いてしまっても、同じ結果になることがある。
そして、自分たちにだけ影響があるような地震もこれまであった。
だれかが線をまちがって抜いてしまうようなことでも、非常におおきな問題がでてしまうのに、
いざ、この問題が起きたときに「想定外の地震の為、大規模停電の為」と言っていないだろうか?
この想定外の事象に、想定の思考を停止していたことを隠してはいないだろうか?
「地震」なり「大規模停電」になり、いったい何が「想定」から外れたのか?
を考えていく企業がこれから強くなっていくのではないだろうか?
「天災」は想定しても無駄という問題のすり替えによる思考停止にならないことを望む。
現在、表題の通りですが、
「この期間にご購入いただいた分の売上は、著作権者への印税や決済手数料を除き、全額を日本赤十字社への義援金とさせていただきます。
期間はただいまより2011年3月26日の午前0時まで。」
http://www.oreilly.co.jp/editors/archives/2011/03/deal-of-the-days-support-disater-relief.html
へどうぞ。
このキャンペーンを知ったのは、USからくるメールで知ったのですが、
さすがに、日本で起きている問題で、海の向こうでやっているキャンペーンだけで日本にはないということはなかったようです。
ちなみに、USのキャンペーンサイトは
http://oreilly.com/store/dd-jpn.html
になります。
こちらはいつまでなのかは、ちょっとわかりませんでした。
私もテクニカル的(O’reilly的にいえばCookbook系のドキュメント)な英語だったら読むのもよいのですが、
さすがに、考え方やら、もしくは全く知らないことをいきなり英語で読むことができるほどの根性も自信もありません。
という訳で、今回は日本語のファイルを購入してみることにしました。
ただ、英語版はDRM Freeなのですが、日本語版はそうではありません。
そのためもあり、epub形式はなくPDFのみとなります。
(このあたりからも、スマートフォンで不都合なく読むということは厳しそうです。)
このように、単に義援金としてお金を送るということだけではなく、このような形での参加もよいものだと思いました。
という訳で、
「詳細OpenCV」と「デザイニング・ウェブインターフェース」
にしました。
OpenCVは、大学時代に「コンピュータビジョン」という言葉も知らずに、
動画や画像から物体を認識するという研究室にいましたが、
なんで最近、こんなに簡単にARみたいなことがちらほらと出てくるのかな・・・と思ったら、やっぱり・・・・こんなものが・・・・
というところの興味です。
しかし、このような理論があったなんて、当時の大学教授も院生も教えてくれなかったし、だれも知らないように思えました。
(その当時にあったのかも知らないのですが・・・)
まあ、当時から知っていたら逆に興味を示さないのかもしれませんが・・・・
闇雲に自分なりの考えにぼっとうできたのはある意味では幸せな時間を過ごせたのかもしれませんが・・・・
さて、肝心の注文ですが、どうやら注文が殺到しているようで、
ちょっと非常に混み合って処理に時間がかかっているようです。
ただ、目的があくまでも義援金な訳ですから、
そのあたりはある程度はしょうがないですね。
ちょっとタイトルの意味は矛盾しているが、こんな表現がもっともしっくりくるとおもいましたのであえてそうしました。
つまり、もっと技術的に言えば、バッファ付きFirstInFristOutの仕組みを作るというものですが、例えば、こんな用途です。
アクセスログを分析するシステム。
このシステムで求められるのが、
1)結果ができるだけすぐにわかること。
2)アクセスログをとること自体が、アクセスの妨げにならないこと。
です。
従って、2)を満たした上で、1)を満たそうとすると、
定期時間における(cronによる)バッチ処理でもなく、アクセスがくるたびになんらかの計算やDBへの書込が動くようなオンライン処理でもない。
という訳です。
意外とこれらのノウハウって公開されていません。
そして、たいていはcronによるXX分間隔などで計算とか、
それほどアクセスがないから結局、アクセスがくるたびにDBにデータを即時で書き込んでしまってるのをよく見ます。
この解決として私が、よく使う方法は、「名前付きパイプ」を利用したアクセスログの書込と、読込を利用したデータの計算です。
「名前付きパイプ」を使って、「書込処理」と「読込処理」を分離すると
A)書込処理は、単なるファイルの書き出しと同じ手段をとれる。
B)読込処理は、単なるファイルの読み込みと同じ手段がとれる。
と当たり前ですが、これが分かれると、実装がしやすいのはもちろんですが、テストがしやすくなります。
そして、それぞれで分離できることは、その中間にいろいろな機能を後でつけることができるし、
それぞれを2つの処理として完全に分離すれば、cronによるスケジュールですし、
完全に同期して動くようにすればリアルタイム処理です。
また、中間である程度のバッファなり遅延が許可できるように作れば、
「遅延する即時処理」
のできあがりです。
つまり、
中間をどうつなげるか=バッチかリアルタイムなどを決める
ことになるのです。
そして、書込の際にDBへの接続が常に1つでいいし、同時に同じテーブルへの書込を作らなくすることもできます。
また、複数サーバからの出力を1カ所にあつめて、1つの読込処理にもすることができるのです。
私は、この設計方法を汎用機時代のJCLから学びました。
さらに私の定番の技が、syslog(syslog-ng等)を使って、データを複製することや、間にトリガーを登録することなどなど・・
syslog-ngには出力バッファの機能がありますから、処理が集中しているときにはある程度バッファしてくれますし、
読込処理が落ちていても、バッファ機能で、読込処理が準備された段階で書込を開始してくれる機能もあります。
これらは、syslogというUnix/Linuxでもっとも運用要件が厳しい用途の1つと思われる箇所で使われているシステムを借りてしまうのですから、
かなり、自分でつくるよりも、そして、パッケージ製品を使うよりもロバストで、かつ、汎用サービスとして構築できます。
(当たり前ですよね。Unix/Linux運用者は自分の勘や経験よりも、syslogの結果を信じて仕事をしているのですから・・・)
ただし、この難点は、アプリケーションエンジニアがネットワークエンジニアの範囲まで手をだしてしまうことで、
責任境界線を曖昧にしてしまうので、あまりそれぞれの作業者にはよい顔はされません。
ただし、そのような用途向けのパッケージを購入となれば、それなりに高い金額と、あまり、ノウハウがないエリアで試行錯誤をしていかなければなりません。
であれば、枯れた、そして、安定していて、ノウハウも関連ツールも豊富なツールを組み合わせて、
全体構成での実装をしていけば、安く、そして、信頼性も高いものも作れるのではないでしょうか?
前回の話はソフトウェアには「こびと」がすんでいるが、
その「こびと」の正体はソフトウェアに求めたインテリジェントな対応に対する一つの回答であり、
その良くない反応がバグにすぎない
という話である。
したがって、いままでのケースの網羅によるテストではうまく機能しない。
ケースが多すぎて把握するのも、その状態を作るのも非常に手間がかかるからである。
では、どうすればいいのか?
私にも解答はわかりません。
だったら、バグは事前にはわからなく、事後にしかわからない。
と割りきると
バグが起きた状態を把握することを管理、改善していくしかないと思います。
しかし、あまりにもこれでは場当たりてきですから、予防も考えなくてはなりません。
私の経験ではこびとによるバグが関連するバグは以下に対する不理解だったと思います。
1.社会的モラルに準拠するために出来ないこと
2.ビジネスモデルてきに意図的にやらないこと
3.経済的に社会がついてこれないこと
4.まだ、良い要素技術が確立していないこと
5.論理的に矛盾していること
これらを作った時点で考えて誰かがある目的で誰かの為にこびとを世の中に送り出したわけですから、
これらの理解をしようとすることはバグを作りださないことに役立ちます。
そして、広くひろまって、実績があるものは自分たちのBESTな案ではなく、BETTERだというだけで、
そしてそれを判断するには技術力より社会力のほうが重要だということです。
そして、それはいまではなく作り出されたときの状況下の判断力も必要だということです。
3,4,5は技術者は得意なのですが、1,2はわかっていても領域外ということで、
無関心を装ってしまいます。
そして、本来1,2が得意な人たちは、3,4,5が苦手で、それが正しい判断なのかが判断できずにいます。
ドッグイヤーと言われるIT業界ですが、
根本のところは変わっておらず、すでにたいていの問題にはなんらかの解決方法が提示されている現状では、
あたらしい技術用語にびびらない図太さと、社会とのコーディネート力が結果としてソフトウェアのバグを作らないということにつながるのではないか・・・
結局、コンピュータが生物(つまり人間)を模倣しようとしている以上、
その理解の方法も人に対する理解方法と同じようにするしかないのではないか?
バグの削減も、人(自分)の失敗も同じような管理になっていくのかな・・・
だから、バグを作らないために行動することが、新たなステージになるようにしなければならないと思うのです。
AIRのSQLite関連のソースをgoogle code上に乗せてみました。
まだまだ、未完成ですが・・・・
以前から使っていた、SQLiteのテーブルデータから、そのままDataGirdや、ListなどのdataProvidertとして使えるクラスを同期モードから非同期モードに作り替えてみました。
こんな感じに使えます。
import com.coltware.airxlib.db.collection.TableCollectionView;
:
public var list:TableCollectionView;
:
list = new TableCollectionView("project");
list.itemClass = ProjectModel; // SQLStatementのitemClassに設定されるクラスファイルを設定する
list.sqlConnection = table.sqlConnection; // SQLConnectionを設定する
list.start();
grid.dataProvider = list;
mxmlのサンプル
<mx:datagrid id="grid" width="95%" selectable="true" height="80%" paddingLeft="5"> <mx:columns> <mx:datagridcolumn headerText="ID" dataField="sysuid" sortable="true" width="100" /> <mx:datagridcolumn headerText="名称" dataField="title" sortable="true" /> <mx:datagridcolumn headerText="メモ" dataField="memo" sortable="true" /> <mx:datagridcolumn headerText="作成日" dataField="created_at" labelFunction="LabelUtil.date" sortable="true" width="120" /> <mx:datagridcolumn headerText="更新日" dataField="updated_at" labelFunction="LabelUtil.date" sortable="true" width="120"/> </mx:columns> </mx:datagrid>
とこれだけで、勝手に必要なデータをSELECTして表示します。
ソートもできます。(ただ、AdvancedDataGirdに対応していないのと、Tree構造にも対応していません。)
これ以外に、Flex:AIR SQLiteにXMLを使ってテーブルを作成するも、
パッケージ名を変えて公開しました。
こちらは、XMLファイルからSQLを作成し、そのテーブルを操作するクラスを作成します。
こちらと先ほどのTableCollectionViewを組み合わせると、そのクラスを通じてデータを更新すると、自動的にCollectionViewに対して変更イベントが発行されますので、
データがリフレッシュされるというように動くわけです。
以下のような処理をアプリケーションの起動時に実行しておきます。
public function startDb():void{
sqlconn = new SQLConnection();
sqlconn.addEventListener(SQLEvent.OPEN,hook_dbopen);
sqlconn.openAsync(file);
}
/**
* 必要なテーブルを設定するための処理
*/
private function hook_dbopen(event:SQLEvent):void{
var dbman:DBManager = DBManager.newInstance(sqlconn);
dbman.registerTable("table_uid","/xml/table.xml",ProjectTable);
}
そして、実際にデータを登録するときには
var table:ProjectTable = DBManager.getInstance().getTable("table_uid") as ProjectTable;
var item:Object = new Object();
item.title = "....";
:
table.insertItem(item);
みたいにすれば、データが登録できるという訳です。
ちなみに、”table_uid”という文字は何でもよくて、単に、TableオブジェクトをregisterTableで登録するときの名前で、
そのオブジェクトを後で、取得したいときのIDとして使います。
また、/xml/table.xmlは、table定義をXMLで定義したファイルで、今はソース上のパスに一致しています。
XMLの構造は、Flex:AIR SQLiteにXMLを使ってテーブルを作成すると基本的は変わっていません。
ちなみに、先ほどのTableCollectionViewのコンストラクタにこのtableを設定すれば、
この追加処理での変更イベントで、データが書き換わるというわけです。
じょじょに使い方を含めて公開しながら、更新していきたいと思います。
これは、単純なプログラムミスだとか、あらかじめわかりきっていたテストが不足しているとか、品質定義がないとか、
そんな話ではなく、現在のソフトウェアがもつ背景的原因から、ソフトウェアのバグがどうしてなくせないのかを考える。
さて、ちょっと話は突拍子もないところに飛んでしまうが、
ある人はコンピュータに「こびと」がすんでいる。という。
しかし、私がまだBASICという言語しか知らない当時、コンピュータに小人がいると聞いたことがないし、まして、社会にでてCOBOLをやっていても聞いたことがない。
でも、いつからか、それがあってもいいとおもえるようになった。
しかし、人間に都合が悪いときだけ現れる「こびと」が非常に大きな原因をしめていると言っても納得できる人もいるはずである。
しかしながら、これをなかなか他の人に説明はできない。
そもそも、「こびと」のせいにしても、それは下手な「いいわけ」にしか聞こえない。
でも、そもそも「こびと」とはなんなのだろうか?
「こびと」の正体は何なのだろうか?
「プログラマが指示をしていないことを勝手に判断する。」
んー、困る。
こんなことをするなんて、きっと、そのプログラムのバグに違いない。
と考えるのが、私が今までやってきたCOBOLなどの言語でカバーするシステムである。
まさしく、「計算機」としての役割だ。
計算機はすべてのINとOUTが透過的でなければならない。
きちんと、右と左で金額が必ずあっていなければならないようにだ。
現在のシステムが「計算機」としてしっくりくるなら、バグ0を目指すべきで、そのようなシステムを目指すべきだが、
「インテリジェント」「自立型」「変化に強い」みたいな用語があるようなシステムでは、残念ながらそうはなりそうにない。
このようなシステムは「オブジェクト指向」であり、プログラムが「自立的」なのだ。
つまり、IN/OUTが想定内であれば問題ないが、INが想定外だと「自立的」にそして、「インテリジェント」に反応しようとする。
ようは局所的に最善解をあらかじめ決めたルールで実行する。
このような部分解の集合が全体解として最善でないので「バグ」なのである。
現在のソフトウェアは「生物」の仕組みをまねることで、「インテリジェンス・自立型・変化に強い」を実現しようとしている部分がある。
だから、バグがなくならないのである。
つまり、
「インテリジェンス・自立型・変化に強い」 = 「間違い(バグ)」
なのである。
つまり、「バグ」をなくすためには、事前に決められた動きしかできない「仕様」をつくるしかないのだ。
残念ながら、事前にすべての動きの「ケース」を決めるのも経済的にも「不毛」である。
結果、「インテリジェンス・自立型・変化に強い」が求められる。
では、間違った「反応(バグ)」にはどうやって対応していけばいいのだろうか?
どうも非同期処理というのはめんどくさい。
そして、やはり、ちょっと考え方にくせがある。
今回は、そんな例の1つ。
同期型関数、つまり、すぐに値を戻す必要がある関数の中で、
非同期処理を行って値を返さなければならない場合にはどうしたらいいの?
というお話。
この説明だけでは???がいっぱいだと思う。
基本的には非同期型関数を使っている場合には、結果が取得できてから、その後の処理を行っていくに方がいいのだが、
あれは同期型関数で、これは非同期型関数と決まってしまっている中でどうにもならないということも。
そうすると、どうもこのような矛盾したことを言いたくなってしまう。
まずは、サンプル。
やっている事は、get labelというボタンを押すとすぐに、
[please wait 2 seconds ...]
という文字が出力されます。
この文字は、同期型関数として返している値です。
その約2秒後に本当のデータである、
[--done--]
という文字が返ってきます。
全体のソースはサンプルの右クリックから参照してほしいのですが、
ボタンが押されると動く関数を抜粋しますと
protected function get_item(index:int):Object{
var item:Item = new Item();
item.label = " please wait 2 seconds ... ";
var objectProxy:ObjectProxy = new ObjectProxy(item);
// 何らかの非同期処理
// 擬似的に2秒後に実行する処理で代用
var func:Function = function():void{
// 本来の値を設定する
objectProxy.label = "--done--";
// 変更があったことをCollectionに知らせるイベントを発行する
var evt:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
evt.kind = CollectionEventKind.REPLACE;
evt.location = index;
list.dispatchEvent(evt);
};
setTimeout(func,2000);
return objectProxy;
}
このように、本当に返したいオブジェクトを ObjectProxyクラスのオブジェクトでラップしてしまいます。
ここでは、サンプルの為のサンプルとしてのsetTimeoutですが、実際にはここでネットワークを通してデータを取得したり、
私の場合には非同期処理としてのsqliteとしてのデータ取得だったりします。
そして、その非同期処理の中でデータを取得できたら、データが変わったことを通知するイベントをCollectionListの方へ伝えます。
そして、そのデータ群を表示する画面制御はそのイベントを受けて、画面をリフレッシュしていくという訳です。


