2013年7月31日水曜日

ソフトウェアの製造など、一瞬だ!!(誇張)

ソフトウェア設計とは何か?をななめ読みしていたのですが、
自分がいつの間にかSIerに毒されていることに気がつきました。

それはソフトウェアの製造とはどの部分かについてです。

SIer的な見地から言ってしまいますと、
ソースコードを書くコーディング作業は製造にあたります。

そしてよく自分は、
設計と製造は分割できないものであるから分けるなという議論に持っていきます。

でもよく考えてみてください。

分割できないものなのに、
用語では分割して定義している状態は変じゃないでしょうか。

本質的に同じものであるならば、
同じ用語で表現するべきです。

つまりコーディングは本質的に設計なのです。

そして製造とは、
ビルドを実行してからビルドが完了するまでを指すべきなのです。
(インタプリタであれば、毎回製造しているイメージでしょうか。)

これなら明確に設計と製造を分割できます。

実に清々しい、
目からうろこが落ち、
視界が晴れ渡る気分です。

…って、まだ本文をろくに読んでなかったんでした。

では読み進めるとしますかね。

2013年7月30日火曜日

加害妄想の世界へようこそ?

被害妄想という言葉は有名だと思いますが、
加害妄想という言葉もあることを最近知りました。

そして自分の精神を振り返ってみると、
思い当たる事が結構あります。

もしかしたら、
軽い加害妄想を持っているのかもしれません。

(他人が聞いたらドン引きかもしれませんけど)
そこまで致命的な症状でもないので、
ちょっと晒してみようかと思います。

あ、これが加害妄想だっていう確証はありませんよ?

あくまでもそれっぽい事例としてお伝えするだけなので、
「ふ~ん」程度の気持ちでお読みください。



よく発生するのは、
無防備(に見えるよう)な人とすれ違う場合です。

具体的には、
椅子に座って何か考え事をしている時などだと思います。

対象は最低でも顔見知りであることが多いでしょうか。

もうちょっとですれ違うようなタイミングで発生して、
脳内では実際の行動とは違う行動を行う自分の姿が再生されます。

加害の方法は様々ですけど、
すれ違いざまに無理なく行動できる内容に限られます。

思いっきりラリアットしたり、飛び蹴りしたり、
物を持っていたらそれを叩きつけるetc…

映像は実際に行動を起こす直前で止まることが多いですが、
たまに*事*を起こした後の映像も垂れ流されます。

自分で生み出した映像に嫌悪感を覚えていると、
もう現実ではすれ違った後です。

直前に起こった映像に身震いしながらも、
また日常に戻っていきます。



とまあ、加害妄想って言葉を知らなければ狂気と疑う内容です。

自分は狂気持ちなのかなとも思っていましたが、
やはり自分は普通の人間のようです。

そう言えばあまり好きではない人では起こってない気がするので、
その人を傷つけたくないという意識の裏返しなのかもしれません。

ちょっと過激ではありますけどね…



好きな人を傷つけてしまう映像が頭の中で再生されてしまう人がいたら、
どうか不安がらないでください。

それは多分、
あなたがその人を大切に思っている証拠なのですから。

その映像が現実の物とならないよう、
生きていけば良いのだと思いますよ。

(余談:もしその意識がシャドウとして現れるような事になっても、
自分だと認めてあげましょう。)

2013年7月29日月曜日

自我消耗について適当に考える

困ったときはWIREDからネタを引っ張ればいいか…

ということで、
今回は自我消耗について考えてみることにしました。

これより先の文章は、
素人が適当に考えを述べているにすぎません。

こんな考え方もあるのか~程度にお読みください。


まあ自分のイメージを言ってしまえば、
RPGなどでよく登場するMPの概念に近いと思っています。

何らかの決断を行うたびに減っていき、
0に近いときはろくな決断ができなくなってしまい、
寝たりおいしい食べ物を食べると回復するものです。

ここから得られる教訓があるとすれば、
ゲームと同じでMP管理は大事ってことです。


ふ~む、
ではこの自我消耗の最大値には個人差があるのでしょうか?

何らかの精神的成長があれば、
最大値が上昇したりするのでしょうか?

それを確かめるには最大値を測定できれば良いのですけど、
実現は相当難しい気がします。


なぜなら同じ物事での決断あったとしても、
どれだけ自我を消耗するかに個人差が生じてしまうからです。

例えば何度も同じ決断をしていれば慣れが来ます。

最初は全身全霊を掛ける必要があったかもしれませんが、
慣れてしまえば機械的にこなせる作業などは結構ありそうです。

また個人の適正によって、
得意なものなら消費が少ないでしょうし、
苦手なものなら消費は多いことでしょう。

つまりは全てが相対的であり、
客観的に使えそうな絶対値が見当たらないのです。

実用的にある程度数値化するのであれば、
人類の自我消耗の最大値は一律100%としてしまえば良いでしょう。

そしてある行動に対してのその人の消費量を間接的ながらも計測し、
どんな行動や決断で多く消耗するかを調べていくのは有効そうです。

ほとんどの行動に対して消費量が高い人は、
実際に最大値が低いのかもしれません。

しかしその人の得意なものが見つかってないだけかもしれませんし、
経験を積んだ行動は一気に消費量が減って化ける可能性だってあります。

もしかしたら、
誰もが発狂するレベルの事象には踏みとどまれる才能を隠しているかもしれません。

最大値の違いという要素を用意したとこで、
これらについての個性を上手く表現することに成功していません。

実用面に限って言えば、
最大値の差を比べることにあまり意味は無いってことです。


…本当に、
リアルというゲームの分析しているような気分になります。

自分がリアリティ重視のRPGを開発するのであれば、
MPに相当する項目は百分率表記にしてやるとしましょうかね?
(※今暖めているアイデアでは別の項目が百分率のため却下するでしょうけど。)

2013年7月25日木曜日

音が人間に与える影響

Wiredの"超音波を脳にあてて気分を操作"を読みました。

簡単に言ってしまえば、
脳のある場所にある超音波を当てると気分が良くなるというものです。

確かに名曲などを聞けば感情が揺さぶられることはありますが、
これは耳に聞こえない超音波です。

目に全く見えない超音波でここまで劇的な効果が出るなんて、
実はかなり驚くべきことなんじゃないでしょうか。

もしかしたら昔から特別な場所とされていたものの中には、
この超音波のような何かがあったりするかもしれません。
(別に超音波に限らず、目に見えない何かという意味で)


いや、ああなるほど、
携帯電話の電波についての影響が懸念されるのもこういう感じなのかな?

電磁波なら音波よりも脳への影響が強そうですし。

目に見えない*波*によって変わっていく人類…
う~ん、中二病テイストな響きがします。


おっと、話題が逸れました。

あるかもしれない未来に限らず、
今現実にあるものでも既に恐ろしい領域と言えます。

いわゆる音響兵器ってやつです。

研究室の中で完結しているお話ではありません。

こっちはとっくに配備が終わっていて、
使用された実績だってあるのです。

しかもそれなりの効果を上げたという報告付きです。

まあ超音波ではないので、
音は聞こえるそうですけどね。


まだまだ音波ひとつでも色々な可能性が眠っていそうです。

2013年7月23日火曜日

怒りは愛情かもしれないが、それが伝わるとは限らない

特に場所は問いませんが、
誰かが誰かに対して怒っているいるシーンを見たことが無い人はいないと思います。


町中で見かけるようなタイプは、
クレームによる怒りが多いでしょうか。

コンビニでタバコの購入にボタンを押す必要が出てきてから、
それに対してアルバイトの方に怒っているシーンを見かけたことがあります。


オフィスで見かけるパターンは、
何らかの失敗に対して上司や先輩が怒るパターンでしょうか。

怖い上司にビクついたことがさらなる失敗につながり、
さらに怒られるというマッチポンプを見たことがあります。
(この例では上司の方が移動となりました。)


どちらにも共通しているのは、
"何らかの希望や期待を裏切られたことによる失望から発露した感情=怒り"でしょうか?

強い怒りの背景には強い希望や期待が込められているため、
これらの怒りは愛情表現として見ることができるのだと自分は思います。


まあそれはいいです。

怒りを向けられたことで成長した事例なんてたくさん出るでしょうし、
そこに異論はありません。

問題はその成長の事例の影に隠れた、
マイナスとなった事例はどれだけあるのかという話です。


学生の頃読んだきりなのでちょっと曖昧ですが、
ブラックジャックに紹介したい話がありました。

生徒をやたら厳しく怒り、叱る教師が登場するのですが、
その教師は単に血の気が多いというわけではありません。

その教師はその叱責をバネに一生懸命勉強欲しいという、
いわゆる生徒への*愛情*でそのような態度をわざととっていたのです。

でも生徒の一人が叱責に耐えられなくなってしまい、
自殺を図ろうとしてしまうというお話です。


フィクションの話ではありますが、
これを起こり得ないと言い切れるでしょうか。

自分にはそう思えません。

例え愛情が根源にあったとしても、
それが伝わらない例なんてたくさんあるのではないでしょうか。


このような一方通行の愛情を何と言うか、
私達は"ストーカー"と呼んでいなかったでしょうか。

自分はこれも、
ストーカーの変種だと捉えています。

ストーカー行為を続けていくと、
結果はどうなるでしょうか。

少なくとも、
ハッピーエンドにはならないのではないでしょうか。



まとめます。

怒りは愛情から発露することはあり得ます。

ですがそれでストーカー行為を働くのはやめましょう。

危険な無意識の制御 その3

前回までの話とカクテルパーティー効果の話は最近の記事ですが、
これはリンクしているのではという考えに至りました。

つまりカクテルパーティー効果が薄いことにより、
自分の出している声・音が自分が出しているものだと気がついていないのです。

音を発生させた当事者であるにも関わらず、
当人には雑音のひとつとして処理されてしまいます。

指摘を受けたときは、
自分が出した音に気がついたりしているわけじゃありません。

自分の直前の記憶を引っ張りだして、
音を出しそうな行動をしていなかったか思い返しているだけなのです。

ただそれがどんな音でどれくらいの音量だったのか、
その時の雑音の大きさぐらいしか判断材料がなく困ってしまいます。

そこで雑音が発生しないよう高級レストラン並の行動基準で動くわけですが、
これを長時間行えるような訓練もしてなければ訓練方法も分かりません。

結局静かにできないか、
身体に悪影響を及ぼすことでしょう。

まあ人間の*間*を近づけすぎると、
こうなりやすいってことです。

音は距離の2乗で減衰したはず(うろおぼえ)なので、
ちょっと遠くなるだけでもだいぶ違うんですけどねぇ…

よし、総集編っぽくなりました。

2013年7月22日月曜日

IVRは嫌われ者なのか

かなり古い話題です。

WIRED読者が選んだ「もっとも迷惑なテクノロジー12選」には、
トップバッターとして電話の自動応答システム(IVR)が挙げられています。

日本では大半の自動応答が電話機のボタンで操作しますが、
海外では音声認識が導入されている事が多いようです。

日本語よりもずっと認識率が高いのではと勝手に思っていましたが、
利用者の視点から見た感じでは芳しくないようです。

では電話機のボタンだけなら良いかと言われるとそんなことはなく、
慣れた利用者ほどオペレーターに繋ごうとするなんて事例はよく見かけます。

引きこもり体質の自分としては、
人間を介さずに済むならそれで良いかとついつい思ってしまいます。

ですが世間は逆です。

さっさと柔軟な対応ができる人間と会話を行い、
人間を介したサポートを望んでいるようなのです。
(統計データ上はね)

その邪魔をするIVRは、
"迷惑なテクノロジー"となってしまうわけです。



比較的音声系にいる自分としては何とかならないものかとも思うわけですが、
これに関してはかなり難しいかもしれません。

もしもこの先を目指すのであれば、
より人間的な対応を可能にする必要があります。

でもこの先には"不気味の谷"が待ち構えています。

IVRが迷惑と思われないようにするにはこれを乗り越えればならないでしょう。

…誰が谷を越えようなんて思うでしょうか?

今IVRを売っている企業で、
本気で谷を越えようと思っている企業が居るようには見えません。



もしもこの谷を超えることがあるとすれば、
電話業界とは離れたところからやってくる技術かもしれません。

そのとき、IVRにイノベーションが起こるのでしょう。

その日が来るまで、
IVRは今しばらく嫌われ者であるようです。

試験仕様書からチケットにしてしまった方が楽なのでは

ただいま試験の真っ最中なのですが、
試験項目の分割に頭を悩ませています。

複数人で試験しているのですが、
なかなか綺麗に分割できないのです。

仕方がないので同じ試験仕様書のExcelファイルを複数用意して、
口約束で項目を分担してから最後にマージするような運用を取っています。

さも当たり前のように行われていますが、
これって相当、非効率的な作業ではないでしょうか。



SIerや(担当者にとっての)厳格な品質が求められるソフトウェアの場合、
(ほとんどExcelの)試験仕様書なるものを書いて試験を行うことが普通です。

危うくスルーしかけてしまったのですが、
これも一種の帳票と言えます。

帳票になにかを出力用であって入力用するのはよろしくないと思う自分にとって、
これは改善を考えなければならないポイントに映ります。

つまりは試験仕様書という形に縛られていることが非効率なことであって、
本質的でない部分がたくさんついて回っているのです。


ではどうするのか。

試験を"バグがあるかもしれないから調べておいて欲しい箇所"の束だとすると、
タスクの一種としてバグトラッキングシステムに入れてしまってはどうでしょうか。

手順はこうです。

テキストでもXMLでもJSONでもなんでも良いので、
試験項目の一覧を作成します。

次に作成した試験項目をバグトラッキングシステムにインポートします。

そして通常通り試験を行い、
インポートしたチケットをこなしていくわけです。

新たに追加したい試験項目、
試験で見つかったバグ、
再試験したい項目あれば、
チケットの状態を変化させるなり新規に発行してしまって構いません。

まあただ付け加えるとすれば、
後でエクスポートするのでタグか何かの属性を付与することをオススメします。

試験が完了したら、
エクスポートしてExcelにまとめます。

バグトラッキングシステムのデフォルトの書式が気に入らないなら、
自分でプラグインなりアドオンなり書けばいいんです。

これで帳票を入力に使うという事態は回避され、
より柔軟な試験の対処が行えるようになります。



まあ問題があるとすれば、
バグトラッキングシステムを使っていないような環境では馬に念仏ってことと、
インポートとエクスポートのスクリプトを書くこと自体を許容して貰えるかってことです。

良い案だと思うのですが、
ダメですかねぇ?

2013年7月20日土曜日

簡単になったとしても、素人に任せるべきじゃない

よくソフトウェア開発においては、
「◯◯を使えば素人でも簡単に開発できるようになる。」
なんて文句を聞くことがあります。

実際に使ってみると、
10必要だった手順が3~4くらい省略できたりして、
確かに簡単に開発することができるようになっています。

しかし*素人でも*という部分はどうなんでしょうか。

ユーザーに対して必要な前提知識が減るのは素直に喜べるのですが、
開発者に対しては話が別です。

それは病院に最新の機器が入ったからという理由で、
素人でも簡単に診断ができるようになると言っているようなものです。

医者は医師免許のおかげでそんな事態にはならないのですけど、
プログラマーにはそんなものが無いためホイホイ引っかかってしまいます。

そして素人はその◯◯でスパゲティコードを書いてしまい、
やっぱりダメだったということが繰り返されてしまうわけです。

大抵この手の◯◯は、
用途を限定化させるか抽象化レイヤーを1層作ることによって効率化しています。

しかしそれは、
別に開発者の無能さを隠せるわけではありません。

依然として開発者自身の抽象化技法は要求されています。

ただそれに気がつくまでのタイミングが限定化・抽象化によって遅くなったに過ぎません。

だからちゃんとしたソフトウェア会社は面接時にコードを見るのであり、
それはプログラミングの本質が覆らない限り続くのです。

2013年7月19日金曜日

残業があるかもしれないということ

興味本位でFogCreekの募集要項を覗いてみたのですが、
その中の項目に面白い一文を見つけました。
May involve work after normal business hours, and being on-call
意訳すると、
「残業が出来て、営業時間外の呼びかけに応じられること 」でしょうか。

日本ではあまりに普通すぎてスルーしてしまいそうになりますが、
わざわざ記載が必要だという点が非常に興味深いです。

つまり海外(まあ少なくともニューヨーク)では、
日本と同じ社員の運用をするには要件に載せる必要があるってわけです。

日本の非常識を垣間見えたと思う人も居るかもしれませんし、
よそはよそ、うちはうちと思う人も居るかもしれません。

自分としてはちゃんと記載していることに大変好感が持てるのですが、
皆さんはどのような感想を抱いたでしょうか。


2013年7月18日木曜日

危険な無意識の制御 その2

自分が無意識にやっている行動が、
何やらうるさいらしい。

しかし自分には自覚症状が無いため、
タイミングを見て自制することも難しい。

前回は呼吸量を意識的に半分に落とすことで、
自分が無意識にやっている動作を意識できる領域に戻そうとしました。

しかし慢性的な酸素不足は非常に危険なものなので、
代案を探していました。
(実際にどんどん頭が痛くなってきました。これは本当に危険です。)


要は意識の分配を極力外に出せればいいわけです。

道具を使わずに、
意識を外に向け続ける方法は無いものでしょうか…


そこで新たに考えたのは、
「常に腹筋へ力を入れ続ける」です。

意識が自分の身体に対して向け続けられるので、
自分の身体の制御の大部分を意識下に置くことができるのではないでしょうか。

酸欠よりも、
腹筋が筋肉痛になるほうが幾分ましというものです。


今日それを試しているわけなんですが、
やはり欠点がありました。

呼吸量の制御以上に苦しく、
作業効率そのものが無視できないレベルまで低下しています。

それに加え、
必ずしなければならない呼吸よりも継続に意思が必要になります。

ちょっと気を抜けば力が抜けてしまうので、
精神力の消耗も早いようです。

自分はお腹周りが気になる体型なので、
力を入れている間はベルトに腹が締め付けられるようにしてそれを軽減しています。


それでも辛いですが…


自分のようなタイプの人間は、
人間の"間"に必要な間隔が長めの人間なのかもしれません。

これも個性…なのか…

カクテルパーティー効果の個人差

ある大人数での飲み会での話です。

自分もそこに参加することになったのですが、
乾杯の挨拶から耳を突き抜ける歓声に思わず耳を塞いでしまいました。

その後も各所でものすごいトークの嵐です。

自分も知人に引っ張られて適当なグループの輪に入りましたが、
ほとんど話を聞き取ることができませんでした。

自分が返答を要するものだと感じたときは、
尋ね返して耳をかなりそばに立てて聞かなければなりません。

居ることそのものはそこまで問題ではありませんが、
現状ではこの場で会話を成立させるのは難しいという感想でした。



通常、こういった場ではカクテルパーティー効果が働きます。

無意識のうちに雑多な音の中から必要な音声を聞き分けるのです。

しかしこの効果はどうにも個人差があるようで、
聞き分けがまるでできない人間も中には居るようです。

こういったタイプの人間には、
賑やかな会場は雑音の洪水のように感じられます。

聴覚から意識を逸らして全部カットすることはできても、
話相手との会話の声だけを聞くのは大きな苦痛です。

なぜなら、
その他全部の音声も拾ってしまっているからです。

濁流の中で探しものをしろと言われても、
こちらとしては対処のしようすらないわけです。

対策としてトレーニングしようにもトレーニング方法も不明ですし、
そもそも先天性の問題でどうにもならない可能性もあります。

結論を言うなら、*雑音の中での会話は諦めろ*です。
(処世術として雑談はほとんど聞き流している方もいるそうです。)



結構強烈なハンデキャップに思えるのですが、
認知障害系の記事でそこまで読んだ記憶がありません。
(掲示板のコメントではちらほら)

この件に関してはある程度測定が出来そうな気がしますし、
実験データとか論文とかは無いものでしょうか。

「聴力は問題ないんですけど…」と言うのにはもううんざりなんです。

2013年7月17日水曜日

新しい言葉を使いたがるのは許してやってくれないか

よく新しい言葉を覚えると、
会話の中に積極的に使おうとする方がいます。

まあ何と言いますか、
よほどドヤ顔で無い限りは許してやってくれないでしょうか。

言葉というのは実際に使って身につくところもあるので、
覚えた言葉を身につける為には有効な行為だと思うのです。

その人のトレンドワードということで、
温かい目で見守ってあげてください。(学生は特に)


自分の場合は最近LLVMが熱いので話して回りたいですが、
使いたいのに相手がいなくて困っています。

というわけでこの場で使ってしまうことにしました。


…それだけ。

※LLVMはいつかgccの完全な代替になるんですかねぇ?

抽象化の最終的なボトルネックは人間ではないか

抽象化について考察を重ねるほど、
抽象化技法は人を選ぶということから目を背けなくなる気がします。


これを保守性に置き換えるとよくわからなくなっていきます。

保守性の高い、
つまり正しく抽象化されたソフトウェアであればあるほど、
保守できる人間が限られてしまうのです。

抽象化が嫌われるのはまさにここで、
一番上の方の抽象化は人類の数%しか理解できないと言っても過言ではありません。

保守しやすいのに保守できる人間が限られる…

でも抽象度を下げると、
(言語のせいってわけじゃないですが)COBOLで作られたソフトウェアと同じです。

属技能性ではなく属人性によって構築されてしまい、
遠くない将来に数%どころか直接関わった数人しか分からなくなってしまいます。


問題をさらにややこしくしているのは、
ソフトウェアが完成した当初は抽象度が低い方が内容を理解している人が多いのです。
(管理者や経営者も含めます。)

まだ技術的負債も膨らんでいないので、
改修にも大きな係数はかかりません。

でも時間が経過していくと技術的負債は大きくなります。

そしてソフトウェア開発に関わっていた人物も徐々に離れていきます。

このあたりで抽象度が高いソフトウェアの保守性が理論上は逆転します。

理論上という表現にしたのは、
まだ長い期間運用されている抽象度の高いソフトウェアが少ないからです。

昔は抽象化技法がまだ発達していなかったので、
これが分かるのは最近開発されたソフトウェアの数十年後の結果となります。

まあ少なくとも、
抽象度の低いソフトウェアの結末は最近のニュースを見ればだいたい分かるでしょう。

それが未来の姿ってわけですね。


たぶんプログラマー的には自明のような話なんですけど、
理解した上で取捨選択しているとはとても思えないのはなぜでしょう。

2013年7月16日火曜日

小ネタは読者のハードルを下げるのか

http://blog.livedoor.jp/dankogai/archives/51870361.htmlより、
"~が添削しといてくだしあ。" 
http://blog.livedoor.jp/dankogai/archives/51876805.htmlより
"脱立体機動がもたらす、~"
後者は微妙かもしれませんが、
引用部分は記事の本質から離れた、
いわば小ネタに相当する部分です。

自分も似たようなことは頻繁に書いているのですが、
これは「読者ホイホイ」なんでしょうか、
それとも「読者バイバイ」なんでしょうか、
はたまた特に影響は無いのでしょうか。

実は使っていながらそこら辺が分かっていないのです。

統計が取れるとも思えないので、
とりあえず自分の考えをまとめてよしとしておきましょう。



記事中のこのような小ネタは、
なんというか、
料理の添え物…いやそれよりも扱いの小さい何かです。

ただそれを知る人(というか書いている本人)にとっては、
少しだけ彩りが豊かになります。

砕けた調子になって真面目な内容も肩の力を抜いたように話せますし、
表現の選択肢の増加は何であれ表現の幅を広げます。

だったら日本語をもっと学べと言われればそれまでですが…



う~ん、それとも一種のフィルタリングなんでしょうか。

小ネタ(自分の趣味)に近いかどうかを判別するための。

ネタが分かる人は集まって、
ネタが分からない人は去っていく。

でもそれを期待してる?いやしてない。



結論:よくわからない

2013年7月12日金曜日

危険な無意識の制御

こころのどこかでありうるんじゃないかとは思っていたのかもしれません。

来たるべき日が来たとも言えます。

私の仕事中の声や物音が、
怒鳴られる事態になるという日がです。
(ちなみにその時の指摘は聞き耳ロールに失敗しているので、直前の行動からの推測です。)

基本的に動けば何かにぶつかるタイプなので、
机や椅子にぶつかるのは日常茶飯事。

体調が悪い時は思いっきり呑気症の症状が出るうえ、
体調が悪いとゲップを出していることに気がつけないおまけ付き。

あくびもかなり大きな声を上げるのが標準なので、
注意を向けるのに失敗すると悲惨なことに。


そこで普通に指摘されるだけならそこから注意はできるのですが、
基本的に効果はその日限りです。

発生したら怒られるのであれば、
発生させない方法にするしかありません。

予防するとなるとこれはかなり厳しい手段を取らざるを得なくなります。


この手の症状に悩まされる方の多くは、
「そんな方法があるなら教えてくれ!」
という方じゃないでしょうか。

でもこの方法はオススメできません。

なぜなら*呼吸量を意識的に半分にする*方法だからです。

これは通常の2呼吸のうちを1回を止めるのでも構いませんし、
呼吸のテンポを半分にしても構いませんし、
呼吸量を半分にしても構いません。

とにかく呼吸を半分にして生命活動を下げ、
さらに息苦しさで自分の身体に意識を向けさせます。

これで普段は無意識で操っている身体のコントロールの一部を、
マニュアルで動かすわけです。

問題となる絶対的な酸素の不足は、
呼吸から意識が逸れるタイミングで呼吸が増えることを期待します。

自分の場合には、
多少の作業効率と多大な精神力との引き換えで成功しているようです。

ただ冗談抜きにつらいです。


これは本来ならば伝家の宝刀(つまり使わない手段)にするべきでしょう。

いざとなれば静かに生活できるという手段を持つことで、
精神を安定させる方に使ってもらいたいです。


自分も病院送りになる前に次の手を考えなければ…

2013年7月11日木曜日

設定ファイルとデータベースの境界

ある程度ソフトウェアの規模が大きくなってくると、
設定ファイルだけではなくデータベースを使うようになります。

しかしデータベースのみを使うかと聞かれればそうではなく、
設定ファイルも継続して使われます。

まあデータベースの接続設定を書くために設定ファイルが必要なんですけど、
実際に見てみるとそれ以外も書かれているような気がします。

またデータベースの中身を覗いてみると、
これをデータベースに保持させるのはないわ~というデータも結構あります。

WebフレームワークのDIなんかは設定ファイル一択ですね。

つまりソフトウェアの規模以外にもどちらを選択するかの判断基準があるわけです。

個々に判断することはできるのですが、
その境界は一体どこにあるのでしょうか?

…って思いましたが、
よく考えればデータベースと設定ファイルには決定的な違いがありました。

データベースはデータを挿入したり、更新したり、削除したりするのでした。

それもソフトウェアが起動している最中に、頻繁に。

対して設定ファイルは基本的に起動時に読み込んでそれっきりです。
※キャッシュしないような設計にしない限りはですけど。

ならこう言い換えればいいのかな?
  • 設定ファイルはソフトウェアの起動時に使うデータを置いておく。
  • データベースはソフトウェアの起動後に使うデータを置いておく。
もちろん例外はあるでしょうけど、
これを基本方針としていいの…かな?

2013年7月10日水曜日

帳票は出力であって入力には不利なのではないか

仕事上、何らかの帳票との連携を行うソフトウェアを見ることがあります。

そのたびにいかにも使いにくそうなGUIに顔をしかめてしまうのですが、
それがどうにも帳票の発想から来ているのではないかと感じるようになりました。

一番顕著だと思うのは、
固定サイズのウインドウにこれでもかとボタンやテキストボックスを詰め込むデザインです。

その見た目は背景色さえ変えればいかにも帳票そのものです。

確かに、
画面の大きさに対しての情報量はこの方が多いと言えます。

しかしそれは読むときの話であって、
何か入力しなければならないときは逆に窮屈に感じます。

例えば可変の件数でデータ入力する必要があったとしたら、
画面枠の都合で3件までしか入力できないなんてことが起こります。

そして4件以降も入力可能にする必要が発生したとき、
画面をぐちゃぐちゃにいじってねじ込まなければいけません。

ここら辺はExcelでも同じでしょうか。

画面の枠ではなくてページの枠に切り替わりはしますけどね。

まあ何が言いたいかといいますと、
帳票はPDFとかあまり編集が効きにくい形式で出力することにして、
その他の部分で帳票を匂わせる設計はあまり行わない方が良いということです。

入力と出力(帳票)は別!
切り離して考えろ!
※帳票の要件が極めてシンプルな場合を除く

2013年7月9日火曜日

構造化プログラミングを購入しました

日本語版は品質をちょっと上げただけで値段が2万近くに達するので、
英語版で良いかとアメリカのAmazonで購入しました。

配送代で数千円飛びましたが、
5000円以下で済みました。

まあ内容はおおよそEWD249なわけですけど、
pdfで読むよりかはやる気もでるでしょう。

それに、3部構成の残り2部がありますしね。

…あれ?これもネットで公開されていたりするのかな?

な、ないよ!きっと!
探してないけどないよ!

 
追記:記事書いた後の10分で見つけたよ…読みたい人はこちらでどうぞ。
 

2013年7月7日日曜日

クォーターパウンダーゴールドリングのレポ

ネタのひとつとして食べに行ってきました。

まず購入のときなんですが、
渡される際に説明を受けました。

食べるときに使う持ち手用の紙があって、
それを使わないと崩れてしまうかもしれないからご注意くださいとのこと。

なるほど、あれだけの具材を入れたら確かに不安定にもなります。

そして渡されたのは何とも大層な紙袋。

1000円分のうちのどれだけがこの包装に回っているんでしょうね。

でまあ家に帰って食べてみた訳ですけど、
パイナップルはやっぱり人を選びそうですね。

自分は好きでしたけど、
嫌いな人も相当数でそうかな。

値段通りの価値かと言われると…
まあ同じ値段以下で佐世保バーガーに手が届きますからね~

マクドナルドの設備で、
ちゃんとしたグルメバーガーに勝つのは難しいでしょう。

個人的には、
どれだけグルメバーガーに迫れるかの勝負ではないかと思っています。

その辺りを基準にご判断いただければと、
ではでは。

・専用の紙袋
 
・中身の箱、バーガーを持つ用の紙、バーガーのパンフ(!?) 

 
・ゴマがたっぷりのバンズ
 
 
・色々とはみ出している中身

 

2013年7月5日金曜日

今のSIerはファーストフード店のメタファーが一番合う…気がする

この説明は…いける!?

つい最近、今のSIerの現状を説明する機会がありました。

そのときにSIerの組織形態をファーストフード店に例えると、
今まで自分がSIerについて発言したことを見事に説明できました。

これは使えるかもと思い、
文章として整理してみる運びとなった次第です。


オーダーメイド型のファーストフード店

ただ一点だけファーストフード店のメタファーでは馴染まない店があります。

それは提供する商品です。

ファーストフード店ではいくつかのメニューを大量生産して売りさばくわけですが、
SIerではそうもいきません。

現状では全てが一品物のオーダーメイドです。

ハンバーガーに例えるなら、
どのバンズにして、どのパティにして、トマトを入れたりレタスを入れたり、
あ、チーズを挟むのも全て自由に選択できます。

ただ自由に選択できるがゆえに、
お客様が具材に餡やシメサバを指定したらその通りとなってしまいます。

それで幽体離脱する事態になったとしても、
それはお客様が望んだことなのです。

気の効いたアルバイターは注意してくれるかもしれませんが、
お客様がその忠告を聞いてくれることは少ないようです。

その上でオーダーメイドの分料金がかさみます。

まあだから色んな方が文句の一つも言いたくなるんです。


パッケージ型ソフトウェア会社は高級レストラン(でも安い!)

SIerに対して、
メニュー通りに作ったものを大量に売って収益を得るソフトウェア会社も存在します。

よくパッケージ型とか言われていたと思うのですが、
こちらには高級レストランのメタファーを適用します。

実際の高級レストランと違うのは、
逆にオーダーメイド率が下がっていく点です。

そして高級レストランであるにも関わらず、
その値段は手頃です。

ここが面白いところで、
会社の組織形態が高級レストランに近づいていけばいくほど、
販売する商品の形態はむしろファーストフード店に近づいていくのです。

その店に目をつぶれば色々と符号する点が見えてきます。

一度ソフトウェアの品質を向上させると、
その後は(いやそれ以前に買ったお客様も)ずっとその恩恵を受けることができます。

これはソフトウェアには変動費がほとんど無いことが原因です。

真の意味で売れば売るだけ得なのです。

ならばとソフトウェアの品質を向上させて、
大量に売れるように努力するように力が働きます。

その為に、
一流のシェフ(プログラマー)を雇って品質の向上を行うわけです。

評論家が料理(ソフトウェア)の品評をしているので、
買う前からある程度味(品質)が分かるのも特徴でしょうか。


ファーストフード店にシェフはいない(いらない)!

対して、SIerはそうもいきません。

こちらは全てがオーダーメイドなので、
たまたま品質が良いハンバーガーが出来上がっても次がそうとは限りません。

シェフを雇っても毎回レシピを考えさせたら回転が止まってしまいます。

よってアルバイトを大量に雇って、
大した経験が無くてもハンバーガーが作れるように手順を整備します。

シェフはフライパンや鍋や包丁や鉄板やオーブンで様々な料理を作ることが可能ですが、
アルバイトはハンバーガー専用の機器が必要となります。

というかそれしか店には置いてないので、
アルバイトの中にシェフが混じっていても同じ機器を使わざるを得ません。

「料理(プログラミング)の腕を振るえると思ったのに…」

シェフ(プログラマー)は現実を悟り、
SIerから離脱していきます。

それでも難しいオーダーメイドが成立することがあるのは、
シェフの個人的な調理器具を置いておける程度には寛容な店もあるからです。

調理難度が高い注文が来たときは、
手持ちのフライパンと包丁で片付けてしまいます。

ただこれが評価されることは少ないです。

ファーストフード店(SIer)の評価基準は、
店の器具(SIerの手法)を上手く使えたかどうかの評価です。

フライパンや包丁を上手く扱えるようになることは、
始めから評価項目に入っていないのです。

店の機器を使った場合は平均的なのであれば、
きっと平均的な評価となるでしょう。

ここでもシェフ(プログラマー)は現実を悟り、
SIerから離脱していきます。

調理難度が高いオーダーメイドが成功するかどうかは、
運良くシェフが居残っている幸運にかけるしか無いのです。


こんだけ文句言いつつも

でもそれでSIerが潰れることは無いでしょう。

高級レストランはオーダーメイドには消極的なので、
対決する相手は同じSIer同士なのです。

結局値段も質も五十歩百歩、
お客は損をしている実感もないまま購入を続けることでしょう。

どこで買っても*大差ない*んですから。

今までのSIerが潰れる日があるとすれば、
ファーストフード店のメタファーが通用しないSIerが、
世間一般(大口の顧客)に認知されるようになってからでしょう。

2013年7月4日木曜日

InternetDateFormat for RFC3339

Java isn't supported RFC3339.

Because I made InternetDateFormat class.

But it hasn't tested very much.

If you use this class, you need a few test.

package org.mericle;

import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * InternetDateFormat is supported RFC3339.
 * e.g. "1937-01-01T12:00:27.87+00:20"
 * Because SimpleDateFormat can't parse or format to RFC3339.
 * InternetDateFormat not invoke performance tuning, perhaps it is slowly.
 * @version 1.14
 * @author Bladean Mericle
 */
public class InternetDateFormat extends DateFormat {

    /** Auto generated serialVersionUID. */
    private static final long serialVersionUID = 1223084646264103173L;

    /** Date/time formatting with time offset. */
    private boolean offset = true;

    /** Fractional seconds digits. */
    private int fractionalSecondsDigits = 0;

    /**
     * Default constructor.
     * Output time offset, and not output fractional seconds.
     */
    public InternetDateFormat() {
        super();
        setCalendar(Calendar.getInstance());
        setNumberFormat(NumberFormat.getInstance());
    }

    /**
     * Constructor.
     * @param zone the given new time zone.
     * @param aLocale the given locale.
     */
    public InternetDateFormat(TimeZone zone, Locale aLocale)  {
        super();
        setCalendar(Calendar.getInstance(zone, aLocale));
        setNumberFormat(NumberFormat.getInstance(aLocale));
    }

    /**
     * Constructor.
     * @param anOffset date/time formatting with time offset
     * @param aFractionalSecondsDigits fractional seconds digits (0-3)
     */
    public InternetDateFormat(
            boolean anOffset,
            int aFractionalSecondsDigits)  {
        this();
        setOffset(anOffset);
        setFractionalSecondsDigits(aFractionalSecondsDigits);
    }

    /**
     * Constructor.
     * @param zone the given new time zone.
     * @param aLocale the given locale.
     * @param anOffset date/time formatting with time offset
     * @param aFractionalSecondsDigits fractional seconds digits (0-3)
     */
    public InternetDateFormat(
            TimeZone zone,
            Locale aLocale,
            boolean anOffset,
            int aFractionalSecondsDigits)  {
        this(zone, aLocale);
        setOffset(anOffset);
        setFractionalSecondsDigits(aFractionalSecondsDigits);
    }

    /**
     * Tell whether date/time formatting with time offset.
     * The offset is used only format method.
     * @return true is formatting with time offset; false otherwise.
     */
    public boolean isOffset() {
        return this.offset;
    }

    /**
     * Specify whether or not date/time formatting with time offset.
     * The offset is used only format method.
     * @param anOffset true is formatting with time offset; false otherwise.
     */
    public void setOffset(boolean anOffset) {
        this.offset = anOffset;
    }

    /**
     * Gets the number of fractional seconds digits.
     * The digits is used only format method.
     * @return fractional seconds digits (0-3)
     */
    public int getFractionalSecondsDigits() {
        return this.fractionalSecondsDigits;
    }

    /**
     * Sets the number of fractional seconds digits.
     * Digits range is 0 to 3.
     * If digits over range, this method throws IllegalArgumentException.
     * The digits is used only format method.
     * @param fractionalSecondsDigits fractional seconds digits (0-3)
     */
    public void setFractionalSecondsDigits(int aFractionalSecondsDigits) {
        if (aFractionalSecondsDigits < 0 || 3 < aFractionalSecondsDigits) {
            throw new IllegalArgumentException(
                    "Fractional seconds digits range is 0 to 3. ("
                    + aFractionalSecondsDigits
                    + ")");
        }
        this.fractionalSecondsDigits = aFractionalSecondsDigits;
    }

    /**
     * Formats a Date into a date/time string.
     * @param date a Date to be formatted into a date/time string.
     * @param toAppendTo the string buffer for the returning time string.
     * @param fieldPosition keeps track of the position of the field within the returned string.
     */
    @Override
    public StringBuffer format(
            Date date,
            StringBuffer toAppendTo,
            FieldPosition fieldPosition) {
        Calendar formatCalendar = (Calendar) getCalendar().clone();
        formatCalendar.setTime(date);
        if (isOffset()) {
            int formatedOffset = formatCalendar.get(Calendar.ZONE_OFFSET);
            toAppendTo.append(String.format(
                    "%1$tFT%1$tH:%1$tM:%1$tS", formatCalendar.getTime()));
            toAppendTo.append(formatFractionalSeconds(formatCalendar));
            toAppendTo.append((formatedOffset >= 0) ? "+" : "-");
            toAppendTo.append(String.format(
                    "%1$02d:%2$02d",
                    Integer.valueOf(formatedOffset / (60 * 60 * 1000)),
                    Integer.valueOf(formatedOffset % (60 * 60 * 1000) / 1000)));
        } else {
            // Correct offset
            formatCalendar.add(Calendar.MILLISECOND, -formatCalendar.get(Calendar.ZONE_OFFSET));
            toAppendTo.append(String.format(
                    "%1$tFT%1$tH:%1$tM:%1$tS", formatCalendar.getTime()));
            toAppendTo.append(formatFractionalSeconds(formatCalendar));
            toAppendTo.append("Z");
        }
        fieldPosition.setBeginIndex(0);
        fieldPosition.setEndIndex(toAppendTo.length());
        return toAppendTo;
    }

    /***
     * Formats a Date into a fractional seconds string.
     * @param formatCalendar be formatted date
     * @return fractional seconds string
     */
    protected String formatFractionalSeconds(Calendar formatCalendar) {
        String fractionalSeconds = "";
        int digits = getFractionalSecondsDigits();
        if (digits != 0) {
            Integer milllisecond = Integer.valueOf(formatCalendar.get(Calendar.MILLISECOND));
            fractionalSeconds = "." + String.format("%03d", milllisecond).substring(0, digits);
        }
        return fractionalSeconds;
    }

    /**
     * Parse a date/time string according to the given parse position.
     * @param source The date/time string to be parsed
     * @param pos the parsing position
     * the position at which parsing terminated, or the start position if the parse failed.
     */
    @Override
    public Date parse(String source, ParsePosition pos) {
        try {
            Calendar parseCalendar = (Calendar) getCalendar().clone();
            parseCalendar.set(Calendar.YEAR, parseNumber(source, pos, 4));
            checkSeparator(source, pos, "-");
            parseCalendar.set(Calendar.MONTH, parseNumber(source, pos, 2) - 1);
            checkSeparator(source, pos, "-");
            parseCalendar.set(Calendar.DAY_OF_MONTH, parseNumber(source, pos, 2));
            checkSeparator(source, pos, "T");
            parseCalendar.set(Calendar.HOUR_OF_DAY, parseNumber(source, pos, 2));
            checkSeparator(source, pos, ":");
            parseCalendar.set(Calendar.MINUTE, parseNumber(source, pos, 2));
            checkSeparator(source, pos, ":");
            parseCalendar.set(Calendar.SECOND, parseNumber(source, pos, 2));
            if (source.substring(pos.getIndex()).startsWith(".")) {
                pos.setIndex(pos.getIndex() + 1);
                parseCalendar.set(Calendar.MILLISECOND, parseFractionalSeconds(source, pos));
            } else {
                parseCalendar.set(Calendar.MILLISECOND, 0);
            }
            String next = source.substring(pos.getIndex());
            if (next.equals("Z")) {
                pos.setIndex(pos.getIndex() + 1);
                // "Z" equals 00:00
                parseCalendar.set(Calendar.ZONE_OFFSET, 0);
                return parseCalendar.getTime();
            } else if (next.startsWith("+")) {
                pos.setIndex(pos.getIndex() + 1);
                parseCalendar.set(Calendar.ZONE_OFFSET, parseOffset(source, pos));
                return parseCalendar.getTime();
            } else if (next.startsWith("-")) {
                pos.setIndex(pos.getIndex() + 1);
                parseCalendar.set(Calendar.ZONE_OFFSET, -parseOffset(source, pos));
                return parseCalendar.getTime();
            }
            pos.setErrorIndex(pos.getIndex());
            return null;
        } catch (IndexOutOfBoundsException e) {
            pos.setErrorIndex(pos.getIndex());
            return null;
        } catch (NumberFormatException e) {
            pos.setErrorIndex(pos.getIndex());
            return null;
        }
    }

    /**
     * Parse number, and increment parse position.
     * @param source A String whose beginning should be parsed.
     * @param pos the parsing position
     * @param length parse length
     * @return parsed number
     */
    protected static int parseNumber(
            String source,
            ParsePosition pos,
            int length) {
        int index = pos.getIndex();
        int number = Integer.parseInt(source.substring(index, index + length));
        pos.setIndex(index + length);
        return number;
    }

    /**
     * Check separator string is valid.
     * If separetaor is invalid, this method throws IndexOutOfBoundsException.
     * @param source A String whose beginning should be parsed.
     * @param pos the parsing position
     * @param separator separator string
     */
    protected static void checkSeparator(
            String source,
            ParsePosition pos,
            String separator) {
        int index = pos.getIndex();
        int length = separator.length();
        if (!source.substring(index, index + length).equals(separator)) {
            throw new IndexOutOfBoundsException();
        }
        pos.setIndex(index + length);
    }

    /**
     * Parse fractional seconds.
     * @param source A String whose beginning should be parsed.
     * @param pos the parsing position
     * @return parsed fractional seconds
     */
    protected static int parseFractionalSeconds(
            String source,
            ParsePosition pos) {
        String milliSecond = source.substring(pos.getIndex()).split("\\D")[0];
        int number = Integer.parseInt((milliSecond + "000").substring(0, 3));
        pos.setIndex(pos.getIndex() + milliSecond.length());
        return number;
    }

    /**
     * Parse offset.
     * But it is not include "+" or "-".
     * When this method is called, these operator have to be already parsed.
     * @param source A String whose beginning should be parsed.
     * @param pos the parsing position
     * @return offset millisecond
     */
    protected static int parseOffset(
            String source,
            ParsePosition pos) {
        int hour = parseNumber(source, pos, 2);
        checkSeparator(source, pos, ":");
        int minute = parseNumber(source, pos, 2);
        return (hour * 60 + minute) * 60 * 1000;
    }
}

e.g.
try {

    InternetDateFormat format = new InternetDateFormat();

    System.out.println(format.format(new Date()));
    System.out.println(format.parse("2013-07-04T19:52:42+09:00"));

    format.setOffset(false);
    System.out.println(format.format(new Date()));

    format.setFractionalSecondsDigits(2);
    System.out.println(format.format(new Date()));

} catch (ParseException e) {
    e.printStackTrace();
}

FYI:Japanese Edition

2013/07/31: Update detail.
2013/12/16: Bug fix "parseFractionalSeconds".
2017/09/18: Bug fix "parse" (Thanka comment!)

2013年7月2日火曜日

どうでもいいリスク回避

お仕事で朝から現地集合なんてことはまれによくあります。

それが行き慣れた場所なら良いですが、
初めて行く場所は少しだけ厄介です。

迷う可能性もありますし、
集合場所を間違うかもしれません。

かと言って、
あんまり早く来てもしょうがありません。

ならば朝食を現地で食べればリスクを吸収できるのでは?

…あ、当たり前すぎる。

寝ぼけているからこんな記事を書くんでしょう。

まあ寝ぼけているので、
このまま投稿してしまいます。

2013年7月1日月曜日

なぜ抽象化しなければならないのか

とにかく抽象化は大事なんだよJK

プログラマーにとって、
"抽象化技法を身につけた方が良い"というのは自明の話です。

構造化プログラミングしかり、
オブジェクト指向プログラミングしかり、
◯◯(好きな用語を入れよう)プログラミングしかりです。

あまりにも自明すぎて、
この事実の重要性を伝える段階になって困ってしまいます。

重要とだけ叫んでも理解されないのはこれまた自明なのですが、
でも実例を紹介してもやっぱり理解されない気がします。

自分の経験と照らしあわせて実例を噛み砕いて理解しようとするでしょうけど、
理解していなければ自分の経験に適用させることができません。

つまり「自分は使うことはないだろう」という結論に陥ってしまい、
それ以上の学習が止まってしまうのです。

結局、今まで抽象化技法を身につけることができた人達は、
学習の情熱が冷める前に理解できたのだと思います。


n分間待ってやる

今回のお話は、
その情熱が冷めるまでの時間を伸ばすための説明です。

少しでも良いので、
「理解できれば今までよりも少しは良くなるかもしれない」と思わせるのです。

そうして学習を続けてさえもらえれば、
より多くの人が新しい抽象化技法に目覚めてくれる…かもしれません。


抽象化すると何を"ゲットだぜ"できるか

ぶっちゃけた話をしてしまいますと、
レベルの高い抽象化技法を身につけていればこんなことができるようになります。
  • 大きなソフトウェアが開発できる
  • 中~大くらいのソフトウェアの開発速度が向上する
  • 小~大くらいのソフトウェアの保守性が向上する
大きなソフトウェアになると、
もう開発できるかできないかに関わってきます。

色んなブログで、
「優秀なプログラマー少数でやればあのプロジェクトは成功したかもしれないのに…」
的な記事が読めるとおもいます。

これは赤字とかではなくて、
何かの事情でプロジェクト自体が破綻したパターンです。

プロジェクトチームは足並みを揃えるために、
一番レベルの低い人に合わせる傾向があります。

つまり抽象化技法が最低のものしか採用できず、
チーム編成の時点で詰んでいることも珍しくないわけです。


プロジェクトの破綻とまでいかないにしても、
赤字だったプロジェクトが黒字になる可能性は大幅に上がるでしょう。

同じ期間を少数の人数で完成させてしまうことができますから。

つまり一時的とはいえ、
レベルの低いプログラマーを使うこと自体が損失と言えます。

…あ、しまった。

少人数だとしてもプロジェクトの値段が変わらないことが前提です。

これは人月計算の見積もりによる矛盾の話なのでスルーするとしましょう。


そしてソフトウェアは完成した後の方が大変です。

使っているうちにバグが見つかるかもしれませんし、
機能を追加したり差し替えたりしたくなるかもしれません。

その時に適切な抽象化を行ったソフトウェアは簡単に対処することができます。

ちょっとした修正でもえらく時間がかかるソフトウェアがあれば、
それはレベルの低い抽象化しか行なっていないわけです。


利点は認めるけど、自分のプロジェクトには関係ないから…

と説明して分かってもらえれば、
世の中のプロジェクトはもっと成功していることでしょう。

抽象化技法を理解していなければ現行との比較ができないからです。

評価できない、よく分からないものをプッシュされても詐欺師と思われるだけでしょう。

なのでもう一歩引いてみることにします。

「抽象化技法を学ばないなんてありえない!」

ではなく

「抽象化技法を学ぶ価値はあるんじゃないかなぁ?」

くらいを目標に据えて考えなおしてみましょう。

それくらいなら話を聞いてもらえるかもしれませんから。


複雑度が違うのだよ!複雑度が!

目標を決めたところで、
抽象化技法の利点についてもう少し深く掘り下げてみましょう。

そもそも抽象化技法を実施することで、
なぜ様々な利点が生じるのでしょうか。

それは抽象化技法がなぜ生まれたかを知れば簡単です。

抽象化技法は、
ソフトウェアの複雑さに対処するために生み出されたのです。

つまり抽象化技法がもたらす利点とは、
ソフトウェアの複雑さを軽減することによって生じているのです。

ちょっとイメージを表にしてみました。


横軸がソフトウェアの開発規模です。

対数表記なので、
目盛の上昇幅は1、10、100、1000、10000…みたいな増え方をしています。

といってもイメージなので、
具体的な数値は表記されていません。

縦軸はそれに対するソフトウェアの複雑度です。

こちらも対数表記です。

仮に表の上限を突き抜けたら、
保守不能レベルということにしておきましょう。

各色の線は、
採用した抽象化技法の違いを表現しています。

濃いオレンジ色の線は、
ろくに抽象化技法を使っていない状態です。

ループすら使わず、
もうただひたすらに保守不能に向けて一直線です。

構造化プログラミングを採用したあたりが、
薄いオレンジ色の方でしょうか。

ループや関数を記述しなければならない分、
ちょっぴり初期コストが掛かっています。

でもすぐに交点を迎え、
あっという間に構造化プログラミングを採用した方がよくなります。

まあどれだけ使いこなせるかでこの線は簡単に上下してしまうのですが、
それなりに使いこなせていると思ってください。

次の黄色は…オブジェクト指向プログラミングにでもしましょうか。
※実際には構造化プログラミング+オブジェクト指向プログラミングかな。

クラスを作ったりしなければならないので、
初期コストは構造化プログラミングのみより大きくなります。

でもやっぱりすぐに追いぬいて、
オブジェクト指向プログラミングを採用した方がよくなります。

次は…何だか面倒くさくなってきましたが、
緑色はデザインパターンを使いこなしているあたりにでもしましょうか。

さらにさらにぃ!
初期コストはかさみますけどやっぱりすぐに追い抜きます。

たださすがに初期コストが無視できなくなってきました。

状況を見ての取捨選択も必要になってくるあたりでしょうか。

エメラルドグリーンは…
もう何でもいいですがさらなる抽象化技法です。

初期コストはもっともっとかかるでしょうけど、
やっぱりどこかで逆転します。

ものすごーく大きなソフトウェアが開発できるようになりますが、
初期コストも大き~いので、
価値を見出す人も価値を見出す場所もごくわずかかもしれません。


複雑度の交点を探せ!

この話で重要なポイントは、
抽象化技法を選択したことによる複雑度の変化、及びその交点です。

抽象化技法は、
上位のものほど記述的な意味で初期コストが発生します。

その面倒さが報われるのは、
ある程度の大きさのソフトウェアを開発したときになります。

これが一種の初心者殺しで、
例えばオブジェクト指向プログラミングの利点を説明しようにも、
その利点が体感できる規模は参考書のサンプルにするには大きすぎてしまうのです。

そしてもう一つ、
抽象化技法を会得するまで、
複雑度の交点がどこにあるのかは分からないのです。

今までの記述よりも量が増えるにも関わらず、
サンプルで利点も分からず、
目標もよく見えない、
なのでごく短期間に理解できる人間でないと諦めてしまうことが多い。
※もしくは直感的に利点があることまでは理解できるか、かな。

それが抽象化技法の特徴なのではないでしょうか。


結局何が言いたいわけ?

会得しないと利点が分からない性質のものだから、
有名な抽象化技法くらいは頑張ってみたら?

少なくとも、
複雑度の交点が見えるようなるまでは。

え、何が言いたいか分からない?

自分も分からないんです…