2009/12/31

分析

欲しいものはあるが軍資金は有限の資源である。ならば何にどれだけ予算をつぎ込むのか、十分に検討しなければならない。しかし検討するとはいっても、そもそも軍資金としてどこまで使用していいものなのかをはっきりさせなければならない。

今まではそれほど厳重な金の管理をしなくてもやってこられたが、やはり将来を見据えて計画的に消費した方がいいものと思われる。ということで、現状の収入と支出のバランスを調査してみることにした。

とは言っても、ちまちまとレシートを集めて帳簿につける気力はない。そもそも今から情報収集を開始していたのでは遅すぎる。何とかして既存のデータを元に傾向を把握するようにしたい。

利用可能なデータは限られている。履歴として残っており参照可能なのは銀行の入出金明細と給与明細だけである。無論、給与明細をいくら眺めてみたところで収入の構成が分かるだけで支出の構成は分からない。そうなると銀行の入出金明細だけが頼りとなる。

入出金明細には、口座引き落としのものはそのものズバリで記録が残されるが、現金で引き出したものやカードで払ったものは使途が記録されない。だからそれらについては記憶だけが頼りとなる。だが、いつにいくら引き出したのかが分かると存外内容を覚えていたりもするので、まぁ、実用上は問題ない。

そう言うことで、とりあえず分析してみた。

まず、元データを月別・項目別に一覧表にまとめ、そこから当面無視するデータを除外する。一つに賞与は別管理とするため除外する。次に非定常的な支出は除外する。そもそも、分析の目的は非定常な支出にいくらつぎ込むことができるのかを求める為だからである。さらに、株式投資などの資産配分の変更に伴う入出金は除外し、なおかつ、交通費は会社から支給されるため相殺する。

そうすると、だいたい次のような結果が得られる。
A.収入:約20万
B.定常的な支出:約5.2万
C.思いやり予算:3万
D.通話料:0.4万
E.クリーニング代:0.6万
F.検定受験料:0.2万

恣意的にいくつかの外乱要因を除外しているため安全とは言い難いが、だいたいの傾向としては間違っていないはずである。

上記のうち、定常的な支出に分類したものは食費や書籍代などであり、多分に削減の余地があるものである。しかし、とりあえずここは将来にわたって減少することはないものと考えた場合、余剰金として利用可能なのは約10万ということになる。つまり、未来があることを想定せず享楽的に生きるのであれば、毎月10万ずつ使っても問題ないという計算になる。

しかしそれはあまりにもリスキーである。そもそも、賞与とそれを当てにした非定常な支出のバランスが考慮されていない。すなわち、この10万という数字を下記の項目に割り当てなければならない。

X.貯蓄
Y.非定常支出準備金(主に大型設備投資)
Z.非定常小口支出(月々出て行く生活費ではない支出)

Yについてはデータが少ないとはいえ分析すれば概算値が出るはずである。となると問題はXとZの配分ということになる。これについては、もう少し考えてみることにしよう。

2009/11/21

職業

おそらく、世の中に存在するほとんど全ての職業について言いうることなのだろうが、俺がどんな仕事をしているのかと言うことを人に理解させるのは容易ではない。特にそれが、コンピュータに詳しくない、インフルエンザウイルスとコンピュータウイルスの区別もつかないような人にとっては、ほぼ不可能なことなのだろう。

俺の仕事はいわゆるSEである。雑用係という方が実態を正確に表してはいるのだが、横文字で言った方がかっこいいからSEと言っている。まぁ、名前はともかくとして、とりあえずSEと言っておけばコンピュータ関係のいろいろやっている人間だという程度には理解してもらえるものと考えている。何せ、コンピュータ業界は建築業界に次いで二番目に就業人口が多い業種だと言われているのだ。十分、世の中に浸透した職業だと言っていいはずである。

それなのに俺の母親は、つい最近まで俺の仕事を「鶴嘴を持って地下深くに潜り何かをする仕事」だと思っていたらしい。むろん彼女はそのように理解していたわけではない。ただ何となくそのような心象を抱いていたに過ぎない。いったいどこの地下に潜って、鶴嘴で何をどうすると思っていたのだろうか? 無考えにもほどがある。

最近いろいろあって、俺が何をしているのかを説明してやったのだが、結局最後には「要はパソコンを直す仕事をしているのね」と言われて終わってしまった。

まぁツルハシに比べればだいぶ近づいたのには違いない。だがそれでも大きく外れている。確かに仕事でPCは使うが、それはあくまで文房具に過ぎず目的はそこではない。そもそも、PCを使うのはSEに限らず、事務職をはじめとして世の中の多くの職業でPCの使用は必須となっている。それに俺は一度も「修理」する等とは言っていない。それでどうして「パソコンを修理する」になるのだろうか?

また、俺は一応現時点では正社員として雇用されており、とりあえずは安定した生活を送っている。サブプライムローン問題やリーマンショックの際にもクビを切られることなく無事にやり過ごすことができた。生活に苦しんでいる人から見れば、俺は間違いなく羨ましがられる立場にいると言っていい。にもかかわらず、彼女は俺が日雇いの労働者であると信じている。何度となくそうではないと言い続けているにもかかわらず理解しようとしない。

どうやら彼女の中では、俺は是非とも肉体労働に就いていなければならないらしい。というか、いわゆる差別的な思想に基づくところの被差別階級に属していなければならないらしい。

思えば彼女は俺がガキの頃から俺のことをけなして馬鹿にしておとしめるという習慣があったが、それが未だに抜け切れていないらしい。本当かどうかは知らないが己が腹を痛めて産んだはずの子供に対して、どうしてそういうことができるのか俺には理解できない。まぁ、大方「放蕩息子を持つ不幸でかわいそうなアタシ」を演じていたいのだろう。とりあえず、日々の食事に毒を盛られることなく独立することができたのだから、それでよしとするべきか。

2009/11/03

環境

PCを買い換えた。

もし技術史の試験に合格していたのなら、CPUはXEONのW5580にしようと心に決めていたのだが、残念ながら落ちていたからCore-i7 920で妥協しておいた。

それでも、当然だが以前のマシンと比べれば比較にならないほど高速である。当たり前だが。

現在は新PCで今まで通り開発作業を行えるようにするために環境を整えている最中である。しかし、やることが多すぎていくら時間があっても足りない。とりあえず、画面のデザイン等はおおよそ自分のいいように調整することができ(それでも不満は多いが)。

とりあえず、画面を曝しておく。



Firefoxの後ろに見えているのは、VirtualBoxにより動作させているWindows2000である。XPモードではない。

本来であればこんなものは使う予定になかったのだが、なにぶんVisual Studio 6.0はバージョンが古すぎてWindows 7では動作しないのだから仕方がない。

だったらXPモードにしておけばいいのではないかという考えもあるのだが、いろいろと思うところがあって完全に環境を切り離しておくことにした。

2009/10/31

感慨

PCをリプレースすることになり、今日秋葉原で各種のPCパーツを買いそろえてきた。
今は、今夜で最期になる現行PCからこのblogを書いている。データを移し終わったら、後はバラして捨てるだけだ。

さすがに10年使ってきたPCだから、入れ替えるとなるとやはり感慨深いものがある。

2009/10/26

ファジング

久しぶりに、新しいコンテンツを一つ追加しておいた。ブルートフォース法によるファイルのファジングを行うツールである。

別に、どうしても急遽このツールが必要だったという訳ではない。ただ何となく、「主筆」で使用しているモジュールの動作を確認してみたくなって自作したに過ぎない。

「主筆」では設定ファイルとしてWindowsでよく使用されるini形式のファイルを使用している。しかし当然だが、Unixではini形式のファイルを読み込む標準のライブラリなどは存在しない。その為「主筆」では自前でini形式のファイルを読み込むモジュールを作成している。いや、正確に言えば「主筆」で使うために作ったのではなく、俺がそれよりも前に作成していたモジュールを流用したのである。

そういう経緯があるため、ini形式のファイルを読み込むモジュールは「主筆」を構成するモジュールの中でも群を抜いて古い。おそらく、俺が作ったプログラムの中で現存している最古のものではないかと思われる。

一般的に言って、古いプログラムというものはバグも少なく安定していると考えられている。つまり、技術的に枯れていると考えられる。だがこの場合は、何分俺が作って俺が使っているだけであるため、到底枯れているなどと言える状態にあるとは思えない。

そもそも、これを作った当時はセキュリティ性なんて微塵も考えておらず、単に動けばいいという程度にしか考えていなかった。だから攻撃を受けた場合に大丈夫なのかどうか全く自信がない。

だったら、自信がないのなら、十分なテストを行い品質を確保すればいい。そういうことで実際に攻撃をやってみようと言うことで作ったのがこのツールである。

まぁ、無論、このツールで生成できる攻撃用のファイルには制限も大きく、大して実用的とは言えないものかも知れない。だが、今後機会があれば拡張してゆく予定である。

2009/10/22

PC

長年使ってきた今のPCだが、ついに入れ替えようと思う。

OSやアプリケーションが変化しない限り、PCの性能が低くても問題はないものと考えていたのだが、やはり、必ずしもそういうわけにはいかないようだ。ウイルス対策ソフトにしろ、周辺機器にしろ、ブラウザで見るWebページにしろ、どうしても求められるPCのスペックは年々向上して行き、ついに俺も耐えきれなくなってきた。まぁ、CPUがK6-IIIの450MHzであることを考えれば、よくがんばった方だといってもいいだろう。

そうすると問題は、次はどんな奴にするのかという事だ。

SPECの値を俺なりに分析すると、以下の傾向があることが判った。
 ・純粋な1スレッドあたりの処理速度という観点からすれば、Core2Duoが一番早い。
 ・複数スレッドによる処理を考慮に入れた、CPU単体の処理速度という観点でいくと、XEONのW3580やCore-i7 965がほぼ拮抗していて最高速。XEONの5500番台は必ずしも一番早いと言うわけではないが、その差はわずかである。
 ・性能の値を価格で除したコストパフォーマンスで分析すると、Phenom II x4が群を抜いて一番いい。Core-i7 920は二番手集団に位置している。XEON、特に5500番台のコストパフォーマンスは著しく悪い。

また、これはSPEC intやSPEC floatのベンチマークの性質によるのだろうが、HTはほとんど性能向上に寄与していないらしい。それどころか、むしろスレッド数を増やした方が性能が劣化しているという結果が多数散見され、向上しているデータは少ないように見える。まぁ、Intelの誇大広告ですらHTによる性能向上は25%だというのだから、実際にはどれだけ早くなるのか、推して知るべしということなのだろう。

CPUの選定に関わる重要な要素は二つあるものと考えている。一つは性能である。これには、コストパフォーマンスの概念も含まれる。そしてもう一つは、男の沽券である。Core-i7やPhenom等といった民生用の軟弱なCPUでいいのか、それとも、男らしくXeonやOpteronにするのかという問題である。

OpteronはなぜかCPUそのものが売っていない。マザーボードも手に入りにくいようだ。そうすると、Opteronで自作という線は消える。そういう意味でのスキルは俺にはない。そうすると、男の沽券を守る方向でいくとなると、Xeinがもっとも可能性が高くなる。しかしこれではあまりにも価格が高くなりすぎる。俺の試算が正しければ、Xeonのマルチプロセッサ構成にした場合、55万から75万は必要になる。

では、安い方向でいくとした場合は、やはりコストパフォーマンスが重視されるから、Core-i7の920かPhenomである。Core-i5やCore-i7の800番台はベンチマークの結果になかったから評価していないが、価格によっては考慮の対象になる可能性もある。いずれにせよ、この方向で進んだ場合は、安ければ10万を下回る価格で手にはいる可能性がある。多少こだわっても、20万がいいところだ。

男の沽券を取るか、金を取るか。

どうにも決められないから、考え方を変えてみる。すなわち、俺の男の沽券の価格が55万円(75万-20万)と解釈してみる。そして、買うべきか否か悩むときには、悩んでいるものを人にその値段で売り払う事ができるか否かで考えるといいという。そのアルゴリズムに従って考えてみると、すなわち、俺の男の沽券を人にくれてやる(あるいは捨てる)代わりに55万円入ってくるという事になる。俺の沽券に55万もの価値があるのだろうか。

だがしかし、男の沽券とはそもそもなんなのだろうか?

2009/08/29

困難

三ヶ月ぶりに着信メールを確認したら、ジャンクメールが多数きていたから全部消してしまった。最も、メールボックスの容量はなぜか知らないが120MBまで利用できるため、あふれると言うことはないのだが。

今現在、「主筆」の文字列データを保持するロジックを開発しているのだが、最近になってようやく文字列をまともに追加/削除できるようになってきた。後は、構文に従って色を設定するロジックと、文字幅から行がされる位置を決定するロジックを作り込むのみである。

しかし、この処理は複数スレッドを回して並列に処理させるつもりである。すなわち、今まで作り込んできた処理の難易度はほんの序の口で、これからが本番だと言える。それぐらい困難な作業になることが予想される。

一応、基本的な考え方やアルゴリズムについては、頭の中ではできてはいるのだが、しかし、それをコードに落とすのがそう簡単にできることとは思われない。とりあえず、スレッドの生成やウェイトを行うための部品を作るところから手を付け始めたが、すでにして難しい雰囲気が十分に漂ってきている。

まぁ、誰に急かされている訳でもないのだから、ゆっくりと進めていくまでの話だが。

2009/07/26

UPS

気がついたら、オーディオ機器に接続するUPSが著しく増殖していた。



別にだからなんだということでもないが。

ついでに言うと、左に見えている黒い板はPioneerのKUROの背面である。でもって、這い回っているケーブルの大部分は電源とLANである。

出火しなければいいのだが。

2009/07/20

同期

主筆」の、テキストデータを保持し、編集する部分の実装を進めてはいるのだが、やはり難しい。とりあえず、文字列の追加と削除を行う処理だけを先に作って、その部分だけでもとりあえず動くようにしようと考えているのだが、それだけでも難しい。

今現時点では、追加・削除の処理を行う部分のコーディングが終わり、少しずつ動かし始めてはいるのだが、どうにも思うように動いてくれない。一つ課題が解決すれば、また次の問題が生じるという状態で、苦しいことこの上ない。いかんせん、アルゴリズムそのものが複雑なのだから仕方がない。

ところで、今頑張って作っているロジックは、ウインドウ幅での行折り返しを実現するということと共に、複数の処理を並列で走らせて、処理効率を向上するという目的もある。とすると、何らかの方法で、スレッド間の排他制御を行い、矛盾が生じないようにしてやらなければならないはずである。しかも、処理効率向上を目的としているのだから、ごく単純に、あるスレッドがデータ構造にアクセスしようとする都度、データ全体に対して排他ロックを掛けると言うような方式を採用するわけには行かない。複数スレッドが矛盾が生じない限り、複数のスレッドが同時にアクセスできるような方式を考えなければならない。

しかしこれはこれで非常に難しい問題である。

直感的に言って、ツリー構造全体にロックをかけてしまうのが野蛮だというのであれば、ツリーの個々のノードに対してロックをかけるようにすればいいような気がし無くもない。そうすれば、少なくとも矛盾が生じることなく、かつ、複数スレッドで同時にデータ構造にアクセスすることができるようになるはずである。

しかし、その方式には大きな問題点がある。まず、各ノード間には複雑なデータの依存性があるという事だ。つまり、親ノードは子ノードに対するインデックスであるため、子ノードの情報を変更した場合はその変更が親ノードに反映されなければならない場合がある。そのため、単純に一つのノードをロックすると言っても、実際に排他をかけなければいけない範囲は、単一のノードよりもはもう少し広いということになる。そのため、ロックをかける範囲がはっきりせず、実装が困難だと思われる。

さらに、個々のスレッドがどのような順番でノードにアクセスするかが決められないため、場合によってはデッドロックに陥る危険性があるという問題がある。各スレッドの処理をACID特性に従ったトランザクションとして実装するのであれば、デッドロックが生じた場合には、それを検出して一方をロールバックするという方法も考えられる。だが、そこまでやるのは明らかに大仰過ぎる上に、処理速度的にも不利になる。だから、処理が途中で失敗したら元に戻せるような実装にすることはできない。すなわち、デッドロックから回復する術がないということであるため、そもそも、デッドロックが発生しないような、何らかの方法を考えなければならない。

デッドロックを防ぐためには、各リソースに対して、ロックをかける順番をあらかじめ決めておいてしまえばいい。そうすれば、理論上デッドロックは発生し得なくなる。しかし、今回はその方式を採用することはできない。

ツリー構造である都合上、同一の高さのノードを左右に移動するようなアクセスはあまり起こらないと考えられる。そうすると、ロックをかける順番を「上から」と「下から」のどちらかに限定しさえすれば、デッドロックを防ぐことができるような気がする。しかし、必ず上(ルート側)から順番にロックをかけるようにする、というルールを決めた場合、それは、アクセスする都度必ずツリー全体にロックをかけるという方式と同じになってしまう。なぜならば、ツリー構造である都合上、アクセスそのものが必ずルートから行われることになるためである。また、下(葉)から順番にロックをかけるというのも、同じ理由で成立し得ない。いきなり葉からアクセスすることはできないからだ。

また、この考えを延長して行くと、二層ロックを採用することも不可能という事になる。ツリー構造にアクセスするためには、まずルートにアクセスする必要があり、そのためにルートのノードに対してロックをかけることになる。その後、自分が一通りの処理を終えるまでずっとルートのノードを押さえ続けていたら、その間ずっと他のスレッドはツリー構造にアクセスすることができなくなってしまう。だから、どうしても処理途中であっても使わなくなったノードは解放してやるようにしてあげなければならない。

そう考えていくと、どうにも八方塞がりの様な気がしてくる。しかし、あまり汎用性のない、アプリケーション依存な方法を使うのであれば、全くやりようがないという事でもないようだ。まず、データ構造にアクセスするスレッドの種類・数・アクセスパターンは、あらかじめはっきりと判っている(何せ自分で作るのだから)。そこから、起こりうる競合を全て洗い出して、各競合に対してどのように対処すればいいかを一つずつ決めていけばいい。そうすれば、高い効率を維持したまま、矛盾やデッドロックを生じさせないようにすることが可能である。

とりあえず、考えた結果については、また今度気が向いたら書くことにしよう。

2009/07/10

時間

「主筆」の文字列を保持するデータ構造の実装を始めてからかなり時間が経つが、まだコーディングも終わっていない。そもそも、テキストファイルの読み込み/文字コードの変換/マルチバイト-ワイドバイトの変換/データ構造への格納/構文強調表示処理/文字の描画位置の確定/画面への文字列の描画という7種類の処理を全て並列に処理させようと言う野心的な目標なのだから、そう簡単に終わるものとは考えていない。その上、ウインドウ幅での行折り返しに対応させるために、いくつかの余分なデータも保持させなければならないのだから、ますます事態は複雑化し混迷を極めている。

しかし、「主筆」の開発を進める一方で技術士の受験勉強もしなければならない。気がついてみれば、試験日まであと一ヶ月を切っている。論文を書く練習なども、このところ少しさぼり気味だったから、また復活させなければならない。時間は限りなく無いと言える。

どうやらこれは、エロ画像の収集に精を出している場合ではなさそうだ。

2009/06/12

共連れ

ビューとドキュメントの分割に手を付けたのは良いのだが、それをやるためにはどうしてもドキュメント部分の内部構造に大幅に手を入れなければならないようだ。

当面の所は既存ロジックを極力残したまま分割だけを先にやってしまおうと考えていたのだが、やはりどうにも構造がクソで流用するのも難しいと判断したのだ。

そういうことで、ここ数日は文字列操作の要となるデータ構造をどうするかということについて死ぬほど考えていた。

データとして保持しなければならないのは、文字そのものと文字の色、文字の幅である。色は構文強調表示で必要となり、文字の幅はプロポーショナルフォントを取り扱う上で必要となる。でもって、下記の操作に対して最悪でもlog(n)の計算量で処理を完了するようにしなければならない。
 ・文字列の追加
 ・文字列の削除
 ・文字の検索

ここで文字の検索といっているのは、何らかの方法で指定された位置に存在する、とある一文字が格納されているメモリアドレスを求める事を言っている。でもって「何らかの方法」というのには下記のような方法が考えられる。
 ・(行折り返しを考慮しない)行番号と、行頭からの文字数
 ・(行折り返しを考慮した)行番号と、行頭からの文字数

先頭から数えた文字数を用いて、配列のようにアドレッシングを行う可能性は低そうである。どちらかといえば、「画面上のココ」という指定をされて、その文字がメモリ空間中のどこに存在するのかを求める事の方が重要であると思われる。

また、表示や編集の処理を考えた場合、アドレッシングを方法を相互変換する機能も必要になるのは明白である。すなわち、
 ・文字を示すメモリアドレスから、行折り返しを考慮しない行番号と、行頭からの文字数を求める
 ・文字を示すメモリアドレスから、行折り返しを考慮した行番号と、行頭からの文字数を求める
 ・行折り返しを考慮しない行番号と行頭からの文字数から、行折り返しを考慮した行番号と行頭からの文字数を求める
 ・行折り返しを考慮した行番号と行頭からの文字数から、行折り返しを考慮しない行番号と行頭からの文字数を求める
という処理である。

上記の処理はいずれも、一見すると難しいような気もするが、計算量を考慮しない限りそれ程難易度の高いものではない。例えば、文字列を単純に配列に格納して、必要な都度文字列の先頭から総ナメにして要求された値を算出するようにしてやれば、よほどの馬鹿でもない限り実装することは可能なはずである。

だが、問題はこれらの処理を、文字数に対してlog(n)の計算量で解かなければならない所に存在する。

現在で主筆で使用しているロジックは、与えられた文字列を改行コードで区切って部分文字列を構築し、それら部分文字列を指し示すポインタを、単純な配列に入れて管理している。

だから、それこそ何の考えもなしに単一の配列に押し込んでいるよりかは幾分マシだとは言え、本質的には計算量はnに比例する。だから、余り大きなファイルを開くと性能が著しく劣化する。更に、一行の長さがあまりに長くなると、それこそ応答が返ってこないという事態になりかねないため、一行の最大長を10KBにするという制約を設けている。よって、これらの問題をここで一気に解消したいと考えている。

では、どういうデータ構造にすればいいのか。というか、計算量がlog(n)などという、言ってみればデータ量が増えれば増えるほど一文字当たりの計算量が減少するなどという、ご都合主義的な方法が存在するのだろうか?

答えから言えば、方法は存在する。存在するからこそ、こうして俺はゴタクを並べてblogを書いている。

方法としては、B+木を用いればいいはずである。無論「一意に識別できる値を使ってレコードを識別する」という処理ではないため、アルゴリズムは多少変則的なものになるが、それでも不可能ではない。というか、以前、こういった問題について考えたことがあり、その結果をこのページに記述している。要は、これと同じ事をしてやればいいはずなのである。

とは言っても、やはりそれが難しい。

とりあえずは、具体的なデータ構造や値の検索・更新の方法について、ある程度の目処が立ったところではあるが、実装はまだ全く手が着いていない。このままでは第21版の公開は、かなり遠い未来のこととなるであろう。

2009/05/26

偽物

「主筆」のビューとドキュメントの分割に手を着ける前に、とりあえずフォルダ構成を見直しておくことにした。現時点でも、現在公開している第20版には存在しない共有ライブラリが増えているし、フォルダ名がいくつか気に入らない奴が有るため、今の内にきれいにしておくことにしたのだ。

また、生成された共有ライブラリと、その共有ライブラリを使用するために必要となるヘッダファイルが、その共有ライブラリを開発するためのフォルダ内に格納されたままだと何かと都合が悪いため、別途includeとlibというフォルダを用意して、コンパイル後にそのフォルダにシンボリックリンクを作成するようにしておいた。

つまり、たとえばTaEdit/FOOというフォルダを作って、その中でlibFOO.soというライブラリを構築するようにしたとする。そうすると、libFOO.soそのものと、それを使うためのヘッダファイル、たとえばfoo.hは、TaEdit/FOOフォルダの中に存在する事になる。となると、そのlibFOO.soを使うプログラムは、コンパイル時にヘッダファイルとライブラリの検索パスとして、TaEdit/FOOというフォルダのパス名を指定してあげなければならなくなる。

とりあえず、使用するライブラリが1つだけであれば、それは大した事ではない。だが、そういったライブラリがだんだん増えてくると、コンパイル時に指定しなければならなくなるパス名が増えてくることになる。まぁ、だとしても、指定すればいいだけの話だと言ってしまえばそれまでだが、やはりそれでは美しくないため、外部に公開する奴は「公開されるためのフォルダ」を作って、そこに格納するようにしたほうがいい。そうしておけば物事がわかりやすくなるから、コンパイルするときにヘッダファイルが見つからないだの、リンク時にシンボルが見つからないだのと言われる可能性を減らすことができるようになる。

フォルダ構成の整理は、基本的にはMakefileをいじるだけだからそう大した話ではない。もっとも、複数人で開発している場合は、逆にほとんど不可能に等しい荒技ということになるのだが。

今現在は、COMの偽物の仕様ついて考えている。WindowsのCOMの様なことをやりたいとはいっても、しかし、COMそのものを作るつもりはないし、COMと張り合おうというつもりもない。ただ、自分が作ったアプリケーションの範囲内だけでつかわれる、それっぽくモジュールを分割できるような仕掛けが有ればそれでいいのだ。

そうすると、もっともストイックな実装としては、ただ、純粋仮想クラスを継承したオブジェクトを生成して、そのインスタンスを返してよこすだけのライブラリというのが考えられる。すなわち、そのライブラリで提供される関数を一回呼び出してやれば、IDocumentとか何とか、そんな感じの純粋仮想クラスのポインタを返す、そういうライブラリにしておくということだ。

だが、それではちょっとありがたみが薄い。どうせなら、そのライブラリのインタフェース仕様(つまり関数の仕様)や、オブジェクトのインタフェースとなる純粋仮想クラスに一定の規約を当てはめ、その規約を強制するようなライブラリを一枚かぶせるようにした方がいい。そもそも、共有ライブラリの動的ロードや実行時に関数を検索する処理など、ライブラリや実装するオブジェクトによらずみんな同じになるのだから、どうせなら処理を統合した方がいい。

とすると、その規約なりライブラリなりで、どこまで何をサポートするのかが問題となる。とりあえず、純粋仮想クラスを継承したオブジェクトを生成するという機能と、ライブラリ自体がエクスポートする関数は完全にC言語の仕様に準拠していること等と言った物事は、そもそもの目的であることからして外すわけには行かない。

だが、IUnknown::AddRefやIUnknown::Releaseといったメソッドにより提供される、インスタンス管理の機能は必要なのだろうか? 難しいことをやりたいわけでもなし、とりあえずオブジェクトを使う側で間違えなければ、わざわざインスタンス管理の機能をここで実装してやる必要はないものと思われる。もし、参照カウンタなりガーベッジコレクタなりでメモリ管理を行う様にしたいので有れば、それは別の機能として実現すればいいまでの話だ。

また、オブジェクトが提供する別のインタフェースを取得する機能も必要ではない。そんなものは適用にやればいい。COMではGUIDによりインタフェースなどに一意な名前を採番するようにしているが、それも簡略化していいはずだ。どうで、1アプリケーションに閉じた世界の話なのだ。世界中で一意にに識別できなければならない必要性などない。

微妙なのは、インタフェースを実装するライブラリをどこかに登録しておいて、オブジェクト生成時に、自動的に目的となるライブラリを検索できるようにする仕掛けがいるかどうかだ。COMではインタフェースに割り当てられたGUIDとDLLのファイル名をレジストリに登録しておいて、オブジェクトを生成する際にはDLLのファイル名や物理的な場所については意識しなくてもいいようになっている。だが、今回俺が作ろうとしているものには、そのような機能は必要であろうか?

ビューの方から本物のライブラリ名を指定してオブジェクトを生成させるようにしたところで、あまり実害はなさそうな気がする。だが、ライブラリのファイル名とインタフェース名を事前に何かの設定ファイルに登録しておくようにすれば、アプリケーションでライブラリのファイルを保持する必要が無くなり、何か便利になるような気がする。

だが、それ以上の具体的な利点が見えない。必要だろうか? 不要だろうか? どっちでも良さそうな気がするが、きめなきゃ物事が進まない。どうしようか。

2009/05/22

一刀両断

正規表現の最適化なんか考えている場合ではない。技術士の勉強をしなければならないはずである。とりあえず、ここ数日は毎日論文の問題を解くようにしてはいる。だが、そもそも正解というものがない論文は、勉強したところでできるようになるものなのだろうか? それに、手元にある問題数が少ないため、もうやるべきものが無くなってしまった。 とりあえず、漢字の勉強でもしておいた方が良いのだろうか?

「主筆」のウインドウ幅で文字列を折り返して表示する対応に、そろそろ手を付けたいと考えている。だが、それをやるためには文字列の編集と表示という、最もコアな部分に手を入れなければならない。

大変残念なことに、文字列の編集に関わる処理や文字列の表示に関する部分は、「主筆」の中でも最も古いコードに類し、かなりいい加減な作りになっている。特に気に入らないのは、文字列の操作や編集を行うモジュールと、画面の表示を行うモジュールが強く結合していることだ。つまり、ビューがドキュメントの内部構造に立ち入った様な処理になっているということだ。

どう考えてもおかしいこの作りは、開発当初、モチベーションを維持することを目的に、とにかく動作するものをでっち上げようとしたことに起因する。過去の経験から、フリーソフトを作り上げるためにはモチベーションを持続させることが重要だと考え、その為に設計の基本ですら無視した開発を行ったのだ。

その甲斐あってか、とりあえずはテキストエディタとしての体をなしたモノを作り上げることができた。そういう意味ではその戦略は正解だったといえる。だが、今やその目的は消え、当初無視した設計上の不良がここに来てボディブローのように効いてきている。

コアな部分には手を入れずに、塩漬けにしたまま使い続けるのであれば、別に設計がどうであろうが問題はない。しかし、大規模に手を加えようとするとなると、このままではどうにも都合が悪い。だから、そろそろドキュメントとビューをスパッと切断するような大手術が必要になるものと思われる。

できれば、インタフェースを明確に定め、独立した共有ライブラリとして切り出すようにしたい。つまり、Windowsで言うところのCOMコンポーネントのようにしたいと考えている。まぁ、IDLがどうだとかGUIDがどうだのということをやるつもりはない。とりあえず、インタフェースとして純粋仮想クラスを定義し、その純粋仮想クラスを実装するオブジェクトを生成する、という程度のことはやりたい。そうすれば、主筆の本体部分がほぼ真っ二つに切断されることになり、かなり事態が単純化するはずである。

しかし、その為にはまたしてもかなりの作り込みが必要になる。それも相当に難しく、一度踏み出したら容易には後戻りできない危険な迷宮に足を踏み入れることになるものと予測される。それを、技術士の勉強をしなければならないと言っているような、今この時期に始めるべきか否か。

それが問題だ。

2009/05/09

正規表現の最適化2

答えから書いてしまうと、「α{a,b}{c,d}」という正規表現はc(b-a)>=a-1もしくはc=dが成立する場合に限り「α{a*c,b*d}」に変換することができる。

証明といえるような内容になっているかどうか判らないが、俺なりに考えた結果を書いてみる。

まず、そもそも論として、「α{a,b}{c,d}」を「α{a*c,b*d}」に変換できるとはどういう意味なのだろうか?

「α{a,b}{c,d}」というのは、昨日も書いたが「とある正規表現αがa回以上b回以下繰り返す」というものがc回以上d回以下繰り返す、という指定である。また「α{a*c,b*d}」とは、とある正規表現αがa*c回以上b*d回以下繰り返すという意味である。

でもって、「α{a,b}{c,d}」を「α{a*c,b*d}」に変換できるというのは、「α{a,b}{c,d}」が実質的に「α{a*c,b*d}」と同じ、すなわち、「α{a,b}{c,d}」という指定により繰り返されるαの個数が、a*c~b*dの範囲内に収まり、かつ、a*c~b*dの全ての値を取るということを意味している。

例えば、「α{2,3}{4,5}」という正規表現を考えてみる。

αの数が最も少ないパターンでは、内側の繰り返しが全部2回で、かつ、外側の繰り返しが4回の場合、合計で8回繰り返す場合である。つまり下記のようになる場合である。

 αα αα αα αα (半角空白は判りやすくするために入れた)

次に少ないのは、内側の繰り返しが2回の奴が3つと3回の奴が1つ、でもって、外側の繰り返しが4回の場合である。つまり、下記のようなパターンである。

 ααα αα αα αα
    あるいは
 αα ααα αα αα
    あるいは
 αα αα ααα αα
    あるいは
 αα αα αα ααα

同様に、最も多くなるのは内側の繰り返しが全部3回で、かつ、外側の繰り返しが5回になる場合である。すなわち、下記のようなパターンである。

 ααα ααα ααα ααα ααα

こうやって考えていくと、「α{a,b}{c,d}」と指定された場合、全体の繰り返し数の最小は必ずa*c回、最大の繰り返し数はb*d回になると言うことができる。

ということは、「α{a,b}{c,d}」による繰り返し回数が、a*c回~b*d回の全てのパターンを取りうるのであれば、「α{a*c,b*d}」に変換できると言うことになる。

ちなみに、「α{2,3}{4,5}」の取りうる繰り返し回数を列挙すると下記のようになる。

外側の繰り返し回数内側の繰り返し回数合計
42,2,2,28
42,2,2,39
42,2,3,29
42,2,3,310
42,3,2,29
42,3,2,310
42,3,3,210
42,3,3,311
43,2,2,29
43,2,2,310
43,2,3,210
43,2,3,311
43,3,2,210
43,3,2,311
43,3,3,211
43,3,3,312
52,2,2,2,210
52,2,2,2,311
52,2,2,3,211
52,2,2,3,312
52,2,3,2,211
52,2,3,2,312
52,2,3,3,212
52,2,3,3,313
52,3,2,2,211
52,3,2,2,312
52,3,2,3,212
52,3,2,3,313
52,3,3,2,212
52,3,3,2,313
52,3,3,3,213
52,3,3,3,314
53,2,2,2,211
53,2,2,2,312
53,2,2,3,212
53,2,2,3,313
53,2,3,2,212
53,2,3,2,313
53,2,3,3,213
53,2,3,3,314
53,3,2,2,212
53,3,2,2,313
53,3,2,3,213
53,3,2,3,314
53,3,3,2,213
53,3,3,2,314
53,3,3,3,214
53,3,3,3,315


重複はあるが、最小の8回(=2*4)から最大の15回(=3*5)の全ての値を取るため、「α{2,3}{4,5}」は「α{8,15}」と同じであると言うことができる。

では、いかなる条件が成立した場合に、「α{a,b}{c,d}」による繰り返し回数がa*c回~b*d回の全ての値を取るのだろうか?

それを明らかにするために、まずは外側の数量子の値が同じだった場合、すなわち「α{a,b}{x,x}」という指定だった場合について考えてみる。つまり、

 命題:{a,b}{x,x}が指定されたとき、任意のax~bxの繰り返し回数を取りうる

の、証明を試みる。

何か泥臭いが、帰納的に証明する。

まず、x=1の場合、すなわち{a,b}{1,1}の場合にa~bの任意の値を取りうるか否かについて考える。{a,b}の指定は、a~b回の任意回の繰り返しであることを示すのだから、{a,b}{1,1}がa~bの任意回の値を取れるのは明らかである。

次に、x=2の場合、すなわち{a,b}{2,2}の場合について考えてみる。

x=2つまり外側の繰り返し回数が2回なので、内側の(a~b回)を2回繰り返す、すなわち、

 (a~b回)+(a~b回)=(2a~2b回)

が成立することを考える。

ここでまた泥臭いが、1回目の内側の繰り返し回数が、a回からb回に変化するのを順番に追っていってみる。

 (a+0回)+(a~b回)=((a+0)+a~(a+0)+b回)=(2a~a+b回)
 (a+1回)+(a~b回)=((a+1)+a~(a+1)+b回)=(2a+1~a+b+1回)
 (a+2回)+(a~b回)=((a+2)+a~(a+2)+b回)=(2a+2~a+b+2回)
  ・・・
 (b-2回)+(a~b回)=((b-2)+a~(b-2)+b回)=(a+b-2~2b-2回)
 (b-1回)+(a~b回)=((b-1)+a~(b-1)+b回)=(a+b-1~2b-1回)
 (b-0回)+(a~b回)=((b-0)+a~(b-0)+b回)=(a+b~2b回)

1つめの式により、2a回からa+b回の任意の繰り返し回数が生成できることが判る。また、それ以降の式の最大繰り返し回数が、a+bから2bまで1つずつ順番に増加して行くことから、結果として、2a回~2b回の任意の繰り返し回数を取ることができることが判る。すなわち、(a~b回)+(a~b回)=(2a~2b回)は成立する。

次に、x=3の場合、すなわち{a,b}{3,3}の場合について考えてみる。

x=3つまり外側の繰り返し回数が3回なので、内側の(a~b回)を3回繰り返す、すなわち、

 (a~b回)+(a~b回)+(a~b回)=(3a~3b回)

が成立することを考える。

ここで、(a~b回)+(a~b回)=(2a~2b回)が成立することを利用して、上記の式を下記のように変形する。

 (a~b回)+(2a~2b回)=(3a~3b回)

ここでx=2の場合と同じように、1回目の内側の繰り返し回数が、a回からb回に変化するのを順番に追っていってみる。

 (a+0回)+(2a~2b回)=((a+0)+2a~(a+0)+2b回)=(3a~a+2b回)
 (a+1回)+(2a~2b回)=((a+1)+2a~(a+1)+2b回)=(3a+1~a+2b+1回)
 (a+2回)+(2a~2b回)=((a+2)+2a~(a+2)+2b回)=(3a+2~a+2b+2回)
  ・・・
 (b-2回)+(2a~2b回)=((b-2)+2a~(b-2)+2b回)=(2a+b-2~3b-2回)
 (b-1回)+(2a~2b回)=((b-1)+2a~(b-1)+2b回)=(2a+b-1~3b-1回)
 (b-0回)+(2a~2b回)=((b-0)+2a~(b-0)+2b回)=(2a+b~3b回)

x=2の場合と同様である。1つめの式により、3a回からa+2b回の任意の繰り返し回数が生成でき、また、それ以降の式の最大繰り返し回数が、a+2bから3bまで1つずつ順番に増加して行くことから、結果として、3a回~3b回の任意の繰り返し回数を取ることができることが判る。すなわち、(a~b回)+(a~b回)+(a~b回)=(3a~3b回)は成立する。

一般化してn回の場合も同様に、

 (a~b回)1+・・・+(a~b回)(n-1)=((n-1)a~(n-1)b回)

が成立することから、

 (a~b回)1+・・・+(a~b回)n=(na~nb回)

は、

 (a~b回)+((n-1)a~(n-1)b回)=(na~nb回)

となり、今までと同じように、

 (a+0回)+((n-1)a~(n-1)b回)=((a+0)+(n-1)a~(a+0)+(n-1)b回)=(na~a+(n-1)b回)
 (a+1回)+((n-1)a~(n-1)b回)=((a+1)+(n-1)a~(a+1)+(n-1)b回)=(na+1~a+(n-1)b+1回)
 (a+2回)+((n-1)a~(n-1)b回)=((a+2)+(n-1)a~(a+2)+(n-1)b回)=(na+2~a+(n-1)b+2回)
  ・・・
 (b-2回)+((n-1)a~(n-1)b回)=((b-2)+(n-1)a~(b-2)+(n-1)b回)=((n-1)a+b-2~nb-2回)
 (b-1回)+((n-1)a~(n-1)b回)=((b-1)+(n-1)a~(b-1)+(n-1)b回)=((n-1)a+b-1~nb-1回)
 (b-0回)+((n-1)a~(n-1)b回)=((b-0)+(n-1)a~(b-0)+(n-1)b回)=((n-1)a+b~nb回)

となり、(a~b回)1+・・・+(a~b回)n=(na~nb回)が成立する。

以上のことから、「α{a,b}{x,x}」は、常に「α{a*x,b*x}」に変換できると言うことができる。

次に、外側の繰り返し回数に幅がある場合、すなわち「α{a,b}{c,d}」の場合に、ac~bd回の任意の繰り返し回数を生成できるか否かについて考えてみる。

ここで、以下のような複数の変換について考えてみる。

 「α{a,b}{c+0,c+0}」を「α{a(c+0),b(c+0)}」にする
 「α{a,b}{c+1,c+1}」を「α{a(c+1),b(c+1)}」にする
 「α{a,b}{c+2,c+2}」を「α{a(c+2),b(c+2)}」にする
  ・・・
 「α{a,b}{d-1,d-1}」を「α{a(d-1),b(d-1)}」にする
 「α{a,b}{d-0,d-1}」を「α{a(d-0),b(d-0)}」にする

つまり、外側の繰り返し回数を固定にして、一つずつ増やしていった場合について、それぞれの変換について考えてみる。上記の変換は、外側の繰り返し回数が同じであるため、今までの証明から全て成立するということができる。

ここで、変換後の「α{ac,bc}」「α{a(c+1),b(c+1)}」・・・「α{ad,bd}」の繰り返し回数の範囲が互いに重複しているのであれば、「α{a,b}{c,d}」の繰り返し回数が、ac~bd回の全ての繰り返し回数の値を取ることができると言うことができるはずである。

数直線で書くと、こんな感じになるだろうか。



式で書くと、b(c+0)+1>=a(c+1) かつ b(c+1)+1>=a(c+2) かつ ・・・ かつ b(d-1)+1>=a(d-0) という条件式になる。表現を変えれば、下記のようになる。



上記の式は、下記のように書き換えられる。



ここで、iは必ず正の値であり、かつ、単調増大であること、及び、aとbの値は変わらないことから、iがもっとも小さいとき、すなわちi=cの場合にi(b-a)>=a-1が成立すれば、iがcからdまで変化する場合の、全ての場合について成立すると言うことができる。

以上のことから、c(b-a)>=a-1が成立する、あるいは、c=dが成立するならば、「α{a,b}{c,d}」=「α{a*c,b*d}」が成立すると言うことができる。


と、こんなもんでどうだろうか? あっているだろうか?

2009/05/07

正規表現の最適化1

下らないことを考えてみた。

正規表現で、繰り返しを表す記号(数量子とか言うらしい)には、*とか、?とか、+とか、{a,b}とか、いろいろある。また、その中にも最長一致とか最短一致とか強欲なマッチとかいろいろな種類がある。

とりあえず、最長・最短・強欲の種別は無視するとして、*・?・+・{a,b}の指定に関して、正規表現を最適化することについて考えてみた。

*は0回以上の繰り返しを表す。すなわち機械的に{0,}に置き換えることができる。同様に、+は{1,}に、?は{1,0}に置き換えることができる。また、{a,b}の形式でbが省略された場合は、bに十分大きな値(例えばINT_MAX)が指定されたと考えれば、全ての数量子は{a,b}の形に正規化することができる。

そこまではいい。問題はここから。

α{a,b}{c,d}と指定されたら何が起きるのか、ということについて考えてみる。この指定の直接的な意味としては、正規表現αが、最低a回・最大b回繰り返し、かつ、それが最低c回・最大d回繰り返すということになる。つまり二重の繰り返しになるということだ。

だが、素直に考えるとこれは無駄である。例えば、α{0,1}{0,INT_MAX}と指定された場合は、内側の{0,1}の指定は全く意味が無くただの無駄以外の何物でもない。すなわち、α{0,INT_MAX}と最適化してあげるのが妥当である。

同じように、α{2,3}{4,5}と指定された場合にはα{8,15}としてあげることができるはずである。そうすれば、マッチを行う際の処理効率が大幅に向上するはずだ。(まぁ、元よりこんなアホな指定をする人間が悪いという考え方もあるのだが)

そう考えると、一般的にα{a,b}{c,d}と指定された場合は、α{a*c,b*d}と変換してあげることができるような気がする。

しかし、よく考えるとこの変換には無理がある。例えば、α{20,21}{2,3}という指定について考えてみる。この場合、先の変換公式に従うとα{40,63}という形になるのだが、実はα{20,21}{2,3}とα{40,63}とは等しくないのである。

すなわち、α{40,63}とした場合は、正規表現αが最低40回・最大63回繰り返すと言うことを意味しているのだが、α{20,21}{2,3}とした場合は、αが40回・41回・42回・60回・61回・62回・63回のいずれかの繰り返しになると言うことを意味する。よって、この変換は成立しない。

よくよく考えると、ある特定の条件が成立した場合だけα{a,b}{c,d}をα{a*c,b*d}に変換できるということに気がついた。だが、その条件については、今日はもう疲れたからまた今度書くことにする。

2009/05/01

あな

スーツを新調した。

別に、この年になってから性に目覚めておしゃれに気を遣うようになったためでもなければ、季節の変わり目だからという訳でもない。単に、スーツのズボンに穴が空いたためである。

いつも人に笑われるが、俺は外出する際には常に鞄は肩から提げるようにしている。典型的なオタク臭の漂うあのスタイルである。それは通勤の際も同様であり、必ず鞄は肩にかけている。その都合上、鞄の生地とスーツの腿のところがこすれて、気を付けてないとズボンに穴が空いてしまうのだ。

俺的には穴が空こうがズボンをはいていなかろうが、別にどうでも良いとしか思っていないのだが、しかし、曲がりなりにも客商売である以上、最低限まともな格好をしている必要がある。例えよれていようが型が古かろうが、最低限、穴や破れの無いスーツっぽい布きれでチンコとすね毛を隠さねばならない。これはサラリーをもらう社会人として必須である。

そういうことで、手取りが少なくなり、ますます生活が苦しくなりつつあるこの状況下でありながらも、思い切ってスーツを買ってしまった。

だがそもそも、穴が空かなければ無駄な支出を削減することができるのだから、例の腐臭漂うスタイルをやめればいいのではないかとも思うのだが、しかしこれはそう簡単な問題ではない。あの格好はいろいろな条件を勘案するともっとも安全であるという結果が導き出されるスタイルのなである。

まず第一に楽である。わざわざ手で鞄を持つ必要がないため、疲れにくい。第二に、置き忘れる心配がない。手で持っているとついどこかに置きたくなるが、そうすると置き忘れる危険性がある。手放さなければ置き忘れる心配はない。第三に、痴漢に間違われるリスクを軽減することができる。電車内で、鞄で股間を護り、両手を上に上げていることで、あらぬ言いがかりを付けられるスキをなくすことができる。

というか、むしろ鞄を手に持って満員電車に乗っている奴らの方が不思議である。あれはわざとやっているのだろうか? 鞄を手に持ち下におろしていると、ちょうど手がケツの部分にあたる。それを判った上で、女のケツを触るべくしてわざとそうやっているのか、さもなくば著しく頭の働きが鈍く、現実が認識できていないのか、そのどちらかとしか思えない。そういった連中がいる限り、世の中から痴漢が無くなることはないだろうし、同時に、痴漢の冤罪が無くなることもないだろう。

いずれにせよ、いろいろな意味でのセキュリティ的観点から言って、鞄は手に持つものではなく肩に提げておくべきものであるという結論が導き出される。

だがこのスタイルにはいくつかの重大な欠点がある。まず、先にも書いたがスーツに穴があくという問題が挙げられる。ジーンズの生地ですらこすれて薄くなり、ついには貫通するぐらいなのだから、スーツのペラペラな布きれなどたちどころにやられてしまう。次に、このスタイルは自ら公衆に対してオタク・マニアの類、すなわち、被差別階級の所属であることを公言しているようなものだということである。大多数の人は、おそらくこのレッテルを背負うことを恐れ、忌み嫌うのだろうが、俺はもはやそのような問題は超越している。マニアは、他者からマニアであると蔑まれることは気にしない。

しかし、余分な出費が嵩む現実は残る。合理性を妥協するつもりはないが、穴が空く問題には何らかの対処が必要であろう。

2009/04/23

経歴

努力の甲斐あって、技術士の試験の受験申し込み手続きが完了したようだ。とりあえず、申し込みを受理したとか何とかそういった内容のメールが来た。これは、受験ができるという解釈で間違いないのだろうか? いずれにせよ、受験票が来る頃になってみれば判るだろう。

提出した業務経歴だが、これは当然の事ながら素直には書いていない。何せ、入社してから今年の3月末でちょうど7年なのである。入社直後には当然の事ながら研修が行われ、その間はもちろん仕事なんかしていない。配属後だって、右も左も判らないような新人に何ができるわけでもないし、さらには、しばらくの間仕事を離れて研修漬けだった期間もあるわけで、それを単純素直に書いたら「技術士にふさわしい業務の経歴が7年以上」という制約条件を満たすことができない。

だから、入社直後の期間については、そのころやっていた開発プロジェクトの名前を適当に書いておいた。まぁ、全く何も知らないものを書いて、変な突っ込みを受けてボロを出すわけにも行かないから、ある程度話ができるような物を挙げておいたのだが。また、しばらく研修で仕事をしていなかった時期については「○○の研究」ということでごまかしておいた。まぁ、内容の程度は別として、嘘は言っていない。

最近のものにしたって、普段はノーマルな受注開発を行っているノーマルな雑用係に過ぎないのだから、それをそのまま実体通りに書いても制約条件を満たすことはできない。受験要項を見ると「科学技術に関する事項についての計画・研究・設計・分析・試験・評価」をやっていることとある。だから、なんとしても語尾を「計画」「研究」「設計」「分析」「試験」「評価」のいずれかにしなければならない。しかしこのうち、「計画」「分析」「試験」「評価」というのは、ちょっと余りにも実体とかけ離れた感がある。とりあえず「設計」であればあながち嘘ではないので、全部これにしておいた。

順序にしたって、当然の事ながらオーバーラップする部分はあるはずで、それをそのまま書くことはシステム上の制約からして不可能である。だから、多少は実体とずれている部分がある。いや、はっきり言おう。かなりずれている。だが、こればかりは仕方がない。何せ、入社してから7年でパッツンパッツンなのである。期間を短くすることはできない。明らかに怪しいが、みっちり「設計」と「研究」に明け暮れていました、という内容にしておいた。

内容が何であれ、それを証明する「公印」は取ってきたのだし、問題は無かろう。経歴を証明する手だてもなければ、それを確認する術もないのだ。後は、(筆記試験に受かったらの話だが)口頭試問でボロが出ないようにすれば良いまでの話だ。まぁ、それが難しいのだが。

2009/04/17

公印

技術士の2次試験の申し込みが終わった。

技術士の2次試験は実務経験を求めており、業務経歴書を出さなければならない。俺の場合、1次試験に受かったのがついこの間の事なので、「7年以上の実務経験」という奴についての業務経歴書が必要になる。

とりあえず、今年の3月末で入社してから丸7年になるため、何とか適当なことを書いて業務経歴書を書き上げることぐらいは不可能ではない。入社1日目から研修もなくいきなり実務に携わっていました、というかなり無謀な経歴書ではあるが、書くだけならなんとでもなる。

しかし問題は、その業務経歴書には「会社の公印」というのが必要になるということだ。

そもそも「公印」というのが何なのかが判らない。gooの国語辞典を調べても、「公の印」としか書かれていない。これでは何の説明にもなっていない。まぁ、受験申し込みの要項をみると「所属部課の責任者の印」とあるから、課長か部長ぐらいの印があればいいのだろうと勝手に考えていた。しかし、だとしてもどんなハンコをもらえばいいのか? 要項には「無職の場合や自分が会社の社長の場合には、本人の私印を押せ」と記載されていることを考えると、少なくとも認印ではないものと考えられる。では、一体何なのか?

締め切りは4月20日で、その前の日は土日で会社が休みであることを考えると、時間は限りなく無いに等しい。仕方がないから、ヤケクソで総務の人に電話して訊いてみたら、どうやら「公印」として使える事業部長名の印鑑があるという。とりあえず、それをもらってくれば間違いないようだ。

困った。

事業部長というのは、俺から見れば上司の上司の上司の上司の上司である。はっきり言うが、顔を見たこともなければ口をきいたこともない。名前を知っているかどうかというレベルの人だ。課長か部長であれば、多少内容がいい加減であったとしても、なぁなぁで承認してもらうこともできるだろうが、こんなエンもユカリもないおっさんを丸め込むことができるのだろうか?

できるもできないも無い。やるしかない。この時点ですでに申し込みも受験料の支払いも終わっているのだ。受験料1万4千円を無駄にしないためにも、なんとしても印を取ってこなければならない。それも、日程的にはその日の内にやらなければ間に合わない。

そして俺はやった。成し遂げた。かなり無理のある経歴書の内容も受験申込書も、一言一句直すことなく認めさせた。出してしまった後だからいうが、受験申込書に書いた会社の部署名が間違っていたが、それも含めて認めさせた。というか、気づかれる前に印を取ってきた。

まぁ、受験の申し込みだけで、そう大した書類ではないから、ほとんど何のチェックも入らなかっただけなのではあるが、それでも内向的な俺が即日で公印を取ってきたいうのは、大変なことである。俺的には、これを片づけただけですでにおなかいっぱいである。

だが、試験自体はこれからである。そもそも、まだ書類を提出したばっかりで、受験できるかどうかも判らない。とりあえず、受験が認められることを神に祈りつつ、筆記試験の勉強でもすることにしよう。

2009/03/22

げんこうといっしょ

2月半ばほどから微妙に忙しかったのだが、3月に入ってからは本格的に苦しいことになってしまった。「現行システムと同じことをするプログラム」なる物を作っていたのだが、その現行システムというやつが何をどうしてそういう結果になるのかが理解できない酷い代物であるため、開発に苦労したのだ。

たとえ既存部分のプログラムが見苦しい代物であったとしても、業務処理がはっきりとしていれば、「現行システムと同じ処理をするプログラム」と作ること自体は不可能ではない。なぜならば、既存部分を全く無視して業務用件から仕様を導き出せばいいのだから。しかし、そもそもの業務用件が複雑怪奇な場合はそうもいかなくなる。

なぜならば、業務処理内容が複雑だと、その仕様を理解している人間が存在しなくなってしまうのだ。つまり、客に「この処理はどうすればいいのか」と聞いても「よくわからないから、それは現行と同じようにしておくように」と言われるだけで、何をどうすればいいのかについて教えてもらえなくなるのだ。

いわゆるレガシーという奴である。

しかし、どうしてそういうことになるのだろうか? そもそも、業務システムという奴は、元々人間が手でやっていた仕事を機械でやらせるようにしただけの代物のはずである。ということは、もとはそれほど複雑な物ではなかったはずなのである。それなのになぜ、奇っ怪な化け物になってしまうのだろうか?

いろいろ理由はあるのだろうが、俺が思うに、システムというのは使われ出すと、仕様の元となった業務自体に影響を与えるからなのだと思う。つまり、業務を元にシステムの仕様が決められたはずなのに、システムが逆に業務に影響を与えるのではないかと思うのだ。(というか、そういう話をどこかで聞いたことがある気がする)

システムを使う側はシステムの中身については一切知らない。ただ、入力と出力が見えるだけである。そして、とにかくそれを使って仕事をしなければならない。そうなると、システムにあわせて人間が業務処理を変えてしまう可能性が出てくる、というか確実にそうなる。

そして、そうなると今度は、人間が業務処理を変えたのにあわせてシステム側が改修される。改修されたらまたそれに合わせて人間が仕事のやり方を変える・・・。そういったことの繰り返しで、長年の間に誰にも仕様が把握できない怪物が育ってゆくのである。

そうなるとその怪物には誰にも手が出せなくなる。手が出せないからそのまま放置しておく。するとますます怪物が成長する・・・。悪循環の繰り返しである。

おまけに、その悪循環を断ち切るべくシステムを作り直したとしても、システムを作るときには決してビジネスフローが見直されることがないため、新規にできた物は結局現行と同じ複雑怪奇な怪物だったりするためたちが悪い。

おそらく、「できた物」が「元となった仕様」に影響を与えるという問題は、元の仕様が人間そのものである限り、決して根本的には解決できない問題なのだろう。しかし、だとしても設計書やその他の文書として「どんな処理を行っているのか」について、ちゃんと書いておけばこんな苦労はしなくて済むはずである。なぜ、そんな当たり前のことができ無いのだろうか?

不思議だ。

2009/03/02

事例

世に言われている通り、業務システムで作られるプログラムには、時に常軌を逸して酷いものがある。正直言って、どこの素人が書いたのかと言いたくなるほどいい加減なものもある。

例えば、メモリを解放し忘れてたり、エラーが発生するとメモリの二重解放が起きてプロセスが落ちたり、ハンドルを閉じ忘れていたりする。だがまぁ、それはまだ可愛い方だ。とりあえず、結果オーライで動いているのだし、それに、間違えやすいポイントであり、必ずしも理解できないわけではない。

だが、中には作った奴の正気を疑いたくなるような記述もある。例えば、次のようなプログラム。

/* ↑ファイル名を取得する */
r = GetPrivateProfileString( ・・・ );


今時GetPrivateProfileStringを使うなと言う突っ込みではない。また、「ファイル名を取得する」等という、明々白々ことをコメントに書くなと言う突っ込みでもない。俺が怒っているのは、明らかに矢印の向きが間違っているということなのだ。

一体これは何を意図した記述なのだろうか? これを書いた奴は矢印の向きを間違って覚えているのだろうか? それとも、正真正銘の気違いなのだろうか?



/***************************************************
* 日付をする処理
***************************************************/
int ProcessDate( ・・・ )
{
 ・・・
}


ユーザが入力した日付の入力チェックを行う関数の前についていたコメント。「日付をする」って日本語として成立してネェし。


/* ↑日付のニューメリックチェック */
int d = atoi( strDate );
if ( d < 101 || d > 1231 ) {
/* ↑エラー */
・・・
}


atoiで文字列を数値に変換してもニューメリックチェックにはならないと思うのだが、気のせいだろうか? 値の範囲のチェックぐらいはできるだろうが、その間にある不正な値、例えば「0231」とかのチェックはできてないし。

ついでに言うと、この無意味な処理の後で、上記の「日付をする処理」を呼び出して、詳細な入力チェックを行っていた。


long wlong1[1000];
long wlong2[1000];
long wlong3[1000];
char *area;
char *area2;


データの並べ替えを行うための作業用の領域らしいのだが、変数名からはそういったことが読み取れない。変数名がwlongでは、long型の作業用領域だと言うことしか判らない。変数名で言うべき事は値の型ではなく、それが何のために使用されるのか、何の値が格納されるのかということを言うべきである。

当然、同じ事がareaにも言える。areaでは、何が入るのか全く想像もつかない。

また、long型配列に格納された整数値を並べ替える処理を自分で実装するな。それも、なにやら奇妙でトンチンカンなソート処理を作っているんじゃない。qsort関数ぐらい使え。というか、そんな暇があったのなら、コメントをちゃんと書け。


/***************************************************
* ファイルを検索する処理
***************************************************/
int MakeEnv( ・・・ )
{

}


「MakeEnv」という関数では、不要になったファイルを削除する処理を行っている。にもかかわらず、コメントには「ファイルを検索する処理」。何も言うことはない。


「前向き」に解釈すれば、作っているときにテンパッてこうなってしまったのだと、考えられなくもないが、しかし、余りにも酷いのではないだろうか? 常軌を逸したコメントを見ていると、本当に書いた奴の知能のレベルが低かったのだと思わざるを得ない。

2009/02/26

錠前

世の中には不思議なことをする人間がいる。

よく、扉の鍵を閉めた後に、ノブを回して扉を前後に動かしてみるという行為をする人がいるが、あれは一体何を目的とした行動なのだろうか?

当然の事ながら、鍵を閉めた後なのだから、扉には鍵がかかっている。その扉を無理に開けようとしても、当たり前だが扉が開くことはない。そんな当たり前なことを確認して、一体何が嬉しいのだろうか?

どうやら、本人としては「鍵を閉め忘れていないかどうか」を確認したいがための行動であるらしい。しかし、鍵を閉めた後に扉を開けてみるという行動では、決してその目的が達せられることはないはずである。

なぜならば、鍵を閉め忘れた時には、扉を無理に開けるという確認もし忘れるはずだからである。

すなわち、扉を無理に開けるという行動によって確認できるのは、錠前が期待通りに正しく動作しているか否かという事だけであり、自分が鍵をかけ忘れたか否かという意味では、全く何の確認にもなっていないのである。

それなのに、その行動を執拗に繰り返す人間がいるのが不思議でならない。俺の隣近所に住んでいる奴が、特に著しい。朝、鍵を閉めた後にガチャガチャと数分間に渡って扉をこじ開けようとし続けている。それもかなりの勢いでやるから、音が周囲に響いて著しく不快である。

錠前の動作を疑い、その確認をするのは本人の考え方の問題であり、ましてや、それを何回行おうが他人の知ったことではないはずである。しかし、それは他人に迷惑をかけていない場合の話であり、その行動により少なくとも一人以上、不快に感じている人間がいるのだから、控えるべきだと思う。特に、その行動に余りにも合理性が無い場合には、周囲の人間をいらだたせるばかりだから、なおさらである。

別に、錠前の動作確認をするなとはいわない。だが、せめて静かにやってくれ。うるさいから。

2009/02/21

ログ

主筆」の文字列処理を変更する作業で、プログラムの全体に渡って手を加えた。そのため、今度はデバッグが大変なことになっている。

全く動かないというわけではないのだが、やはり、変更したからには動作を確認する必要がある。しかし、変更箇所が多く全てを確認するのは大変だ。

まぁ、業務用のアプリケーションなら一も二もなくテスト漬けにして品質を担保するのだろうが、所詮ロハで公開しているフリーソフトである。そこまでする気力はない。とは言っても、とは言っても、やはり品質は気になる。

そういうことで、横着しつつも品質を向上できるような方法をいくつか取り入れることにした。

ひとつはassertを大量に埋め込むことである。今までも使ってこなかったわけではないのだが、それでも使用方法は限定的だった。だがこれからは、もっと積極的に導入することにした。

次に、ログ出力機能の追加である。ログを出力させることで、内部の処理が正しく行われていることを確認しようと言う訳だ。ログを出したからとて、直接的に品質向上につながるわけではない。しかし、それでも内部の状態を確認することにより、プログラムの正しさが(一面的ではあるが)確認できるので、まぁ、ある程度の効果はあろうというものだ。

だが、ログ出力機能を付けると言うことは、またしてもプログラム中の至る所に手を加えると言うことになる訳で、逆に状況が悪くなるのではないかという気がしなくもない。

だがまぁ、いいか。

2009/02/05

文字列処理の変更

このところ、自分で使うためのソフトいくつか作っていたのだが、そろそろ「主筆」の開発に戻ることにした。

かなり前にもここに書いた覚えがあるが、今現在取り組んでいるのは、「主筆」内部で取り扱う文字列をワイドバイト文字列で統一する作業である。

「主筆」内部では、基本的には文字列はワイドバイト文字列(すなわちwchar_tの配列ないしstd::wstring)で取り扱うようにしているのだが、一部そうでない部分がある。正確に言えば、ファイル名は全てマルチバイト文字列(すなわちcharの配列ないしstd::string)で取り扱っている。

だが、移植性や互換性といったプログラムの品質といったものを考えた場合、文字列は全てワイドバイト文字列で取り扱うのが正しいように思われる。しかし、Solarisはシステムコールやライブラリ関数がワイドバイト文字列に対応していないことが多く、酷く厄介である。

Windowsの場合、ほとんど全ての関数に対して、マルチバイト文字列(実装上はShift-JIS)を取り扱うバージョンと、ワイドバイト文字列(実装上はUCS-2、すなわちサロゲートペアの無い16ビットのUnicode)をおり扱うバージョンとか用意されており、かつ、それらをコンパイル時に切り替えられるようにするたの関数とか用意されている。

つまり、Windows上でプログラムを作る場合は、文字列は全てCStringないしTCHAR型配列として実装すればよく、ライブラリの非互換性などの問題は時々気にしてやればいいだけである。しかしSolarisの場合、外部の関数を呼ぶ場合にはほとんど全ての場合において、文字列のエンコードをマルチバイト文字列に変換してやらなければならない。

例えば、ファイルを開くためにfopen関数を呼ぶにしても、ワイドバイト文字列のバージョンは用意されていないため、ファイル名をマルチバイト文字列に変換してからファイルを開くということをしてやらなければならない。

面倒なことこの上ない。しかも、処理が遅くなりそうで気に入らない。だから「主筆」では、ファイル名などの一部のデータはマルチバイト文字列のままで処理するようにしていた。しかし最近になって、ワイドバイト文字列とマルチバイト文字列の混在による複雑さが手に負えなくなってきたから、面倒さはあるとはいえ全てワイドバイト文字列で統一することにしたのだ。

プログラム内部の処理方式を変えたからといって、基本的には外部に影響を及ぼすことはない。元より、ユーザがマウスとキーボードで操作するだけのソフトである。文字列の形式など問題とはなり得ない。しかし、今回の対応を行うことにより、一部分どうしても影響を受けざるを得ないものがある。

それはプラグイン関数のインタフェースである。プラグイン関数では引数にファイル名を受け取るものがあるが、そのファイル名がマルチバイト文字列(すなわちconst char*)になっているのである。

互換性のためにはconst char*の引数を受け取る関数を変更するわけにはいかないが、逆に手つかずのままにしておくこともできない。だとすると、const wchar_t*を受け取るバージョンの関数を新たに作って提供しなければならないことになる。

どうにも面倒だが、まぁ、仕方あるまい。

2009/01/25

蝋燭

数日前にyahooのニュースで、電気を止められてロウソクで生活していた人が、火災を起こしたというニュースが流れていた。

電気をとめられた場合、電力会社によって違うかも知れないが、100W程度の電気までならただで使わせてくれる可能性がある。つまり、電流制限器という1Aのブレーカーを取り付けられた上でなら、電気を使わせてくれるサービスを提供している。これは、まさに今回のような事件を防止するために行われている事だ。この事件の場合、電気を止められる際に、このサービスについての説明は無かったのだろうか。

電気代を払わないでいると、当然の事ながら電気を止められることになる。しかし、止められるとは言ってもいきなり供給が絶たれるわけではない。止められるまでにはいくつかの段階がある。詳細は電力会社によって異なるが、俺が知っているある電力会社の場合を例にとって説明してみる。

まず、しばらく滞納していると督促の紙が来る。それを無視していると集金の人が自宅にやってくる。その場で払えば当然の事ながら事なきを得る。しかし、金がないなどの事情で支払いを断ると、いつまでに払えという脅し文句を言って帰っていく。また、集金人が自宅にきたときに相手が留守だったら、いつまでに払えと書いた紙を置いていく。

脅し文句や置いていった紙を無視して、さらに払わないで頑張っていると、またしても集金人がやってくる。そのときには、いつまでに払わないとマジで止めるぞゴルァと言うことが書いてる紙を置いていく。

滞納の前科などによっても扱いは変わるが、長ければその後二回ほど警告の紙を渡される可能性がある。ついでに言うと、その紙には上記の「ちょびっとだけロハで使わせてくれるサービス」についての記載がある。

何回か渡される「止めるぞゴルァ」と書いた紙の文章はその都度内容が異なり、だんだん脅しの程度が強くなってくる。そして、左上に「最終」と書かれた紙を受け取ったら、もう後が無くなる。つまり、この次に集金人が来るときには、具体的に電気を止める作業をしに来ると言うことだ。

電気を止められると、「電気を止めてやったぞ、ざまぁみやがれ。でも金は払いやがれ」と書かれた紙を置いて行く。その状態で金を払えば、また電気が供給されるようになる。

電気を止められてもなお支払いを拒み続けていると、またしても集金人がやってきて、金を払えと言ってくる。それでも払わないで頑張っていると、最後には電気契約を破棄されることになる。しかしそれでも債務が消えるわけではなく、その後も何回か集金人がやってくる。その後どうなるのか、ここから先は俺は詳しいことは知らない。

だが、一般論としてはこのような不良債権は、専門の取り立て屋に売却されるため、時効が成立するか夜逃げに成功するまではずっと取り立てが続くものと思われる。

契約上、三ヶ月ぐらい滞納すると電気を止められる危険が発生するわけだが、しかし、初犯の場合は結構待っていてくれたりもする。この辺りは交渉次第と言ったところだろうか。しかし、常習犯の場合は相手も強行にでてきて、場合によってはいきなり止められるということもあるらしい。だから、全体的に遅らせてキャッシュフローを改善しようなどと言うことはあまり考えない方がいいのではないだろうか。

そもそも、集金の人はその道のプロであり、素人が立ち向かえる相手ではない。サラ金の取り立てではないので、幾分は甘いかも知れないが、それでも取り立て屋である。相手がいると判れば、夜打ち朝駆けを厭わない。平穏無事な人生を送りたければ、払うべきものは払った方がいい。

2009/01/04

対話

主筆」のWebサイトを少しずつ変更している。

この間新規に作ったソフトを公開した以外にも、いくつかのページで採用していた対話形式のページを書き改め、普通のモノローグ形式に変更している。

特に深い理由があるわけでもないのだが、やはり対話形式だと「そういう物」にそれ相当の免疫のある人でないと読むに耐えないのではないかと思ったからだ。端的に言ってしまえば痛いのではないかと。

「痛い」心配は当初からあったのだが、まぁ、どっちみち内容自体が痛いのだしどうでも良いか、それよりかはインパクトが強い方が良いのではないか、そう判断して導入した対話形式なのだが、しかし、やっぱり痛いのではないかという方に最近考えが変わってきた。

俺自身に何があったというわけでもないのだが、ある種、思想の経年劣化なのかも知れない。

とりあえずそういうことで、1ページずつ順番に修正している。現時点で残す所は「主筆プラグインの開発について」のみである。これも気が向いたら、すぐに修正するつもりである。

同時に、Sun Studio 11の解説ページも全部削った。これはまぁ当然か。Sun Studio 12が公開されて久しいのにいつまでも11の話を載せておくわけにもいくまい。ただ、いくつかのページはSun Studio 11には余り関係のない話もあるから、それは焼き直して後日公開する可能性もある。

マルチスレッドの話も少し削った。余り具体性のない俺の妄想を語っているだけのページは、さすがに実がないと判断したからだ。書くのなら、実際にやってみて確認できるような、具体的な内容にしたいと思う。

しかし、こう考えてみると俺のWebサイトの内容は、どうも専門性に欠けるというか、総じて何を言いたいのか判らないようなサイトになってしまっているような気がする。何か一つのことについて集中的に述べる方が良いのだろうが、どうもそうなっていない。

今更抜本的に作り直す勇気はないが、それでも「これだけは他のサイトには負けない」というものを作って行くようにしたいものだ。

2009/01/02

黒箱

長年の逡巡のあげくに、ついにテレビを買った。PioneerのKURO KRP-500A。50インチのプラズマテレビである。安い奴にしようかと思っていたのだが、やはりここは思い切ってよさげな奴を買っておくことにした。60万弱だった。本体はおよそ55万だったが、接続に必要なケーブル類を含めると、それだけでも多少金がかかり、結局60万にちょっと足りないぐらいの金額となった。

まぁ、良いか。

それにしても、なぜD端子ケーブルとHDMIケーブルはあんなに高いのだろうか。5メートルのD端子ケーブルが約4千円、1.5メートルのHDMIケーブルが2千円。この2本のケーブルだけで6千円である。UPSが5千5百円だったことを考えると、高すぎではないだろうか。たかだかケーブルである。ただの導線を束ねただけの代物なのに、なぜあんなに高いのだろうか。

KPR-500Aはメディアレシーバーとかいう黒い箱がついている。これにはチューナー等が入っているらしいのだが、すでにBlu-rayディスクのレコーダーやAVアンプ・スピーカーなどを持っているから、俺には必要ないと思っていた。だが、逆にテレビの本体にはまともなインタフェースはついておらず、メディアレシーバーに全ての入出力が集中しているという構成になっていたため、使わざるを得なかった。

そうすると、このメディアレシーバーという奴をどこに置くのかが問題になる。今現在、AV機器を置いてある棚は4段しかない。しかも、この棚はこれ以上増やすことができない様だ。これは自分で組み立てるタイプの金網の棚だから、サイズが合う棚だけ買ってくれば増やすことができるはずなのだが、いかんせんこれはLuminousやERECTAのような著名なものではなく、安価な無名な奴であるため、同じものがどこで売っているかが分からない。そのため、増やしようがないのだ。

金に余裕があるのなら棚ごと買い換えてしまう所だが、それはいくら何でももったいない。だから、とりあえず一番使用率の低いレコードのプレーヤーをどけて、そこに黒い箱を設置しておいた。

そうすると今度は、レコードのプレーヤをどこに置くのかが問題になる。最近ではレコード自体が余り手に入らないことを考えると、まぁ、押入かどこかにしまってしまっても良いのだが、それは何か負けたような気がして忌々しい。何かうまい方法はないだろうか。