真にエレガントな設計は動作しない

ちょっと前に見たテレビ番組に為末大が出演していて、子どもや後進へアドバイスしている場面が映っていた。

そのときの為末曰く、

走る競技で、”うでを良く振れ”とか”ももを上げろ”というのはナンセンスだ。

走る競技は最終的に早い者が勝つルールなのだから、「速く走る」ことが重要なのであって、身体を振り回すことが目的じゃない。

本当の目的を忘れて、ひたすら「腕を振れ」「ももを上げろ」と教えるのはあまり良くない。

(という内容を意訳した。)

ということらしい。

 

オブジェクト指向の設計も同じだなあ、と。

名前が重要だとかクラスが重要だとか強調しすぎるせいで、何でもかんでもクラスを作って見通しを悪くしたプログラムが多すぎる。

品質に影響しないなら、クラスは少ない方がいいし、抽象化もしないほうがよろしい。

バカの一つ覚えでインターフェイスを定義するのは、未来についての思考停止だ。

 

現代のソフトウェアは多かれ少なかれOSとランタイムに依存しており、それらは過去のしがらみを大量に引きずっている。

したがって、真にエレガントな設計は、そういったものと相容れないし、ちゃんと動作することはない。

エンジニアリングの目的は動作するものを作ることであって、ただ美しいだけのものを作ることではないね。

コミュニケーションを密にするというディスコミュニケーション

情報共有できていないという問題への解決方法として「コミュニケーションを密にする」というのを見た。

矛盾

それは、勉強ができない生徒に勉強をさせるのと、お金が貯まらない人に節約させるのと変わらない。つまり、問題を逆に言っただけ、あるべき姿のひとつを表現しただけで、解決法としては正しくない。

「コミュニケーションを密に」を殊更におかしく思ったのは、そう言っている人自体がコミュニケーションを取れていないという再帰的な問題であるから。もし「密に」という人が、問題領域を詳しく知ろうとするなら、安易な「密にする」などの一般論的解決方法はでてこないからだ。

問題構造

組織がコミュニケーション不全になっているとき、その理由には下記のようなものがある。

  • メンバがコミュニケーション方法を知らない
    → コミュニケーションの質が低下して、情報伝達チャネルとしての価値がなくなる。
    → 報連相など、コミュニケーションが必要なタイミング、仕方を教える。
  • メンバがビジネスのコミュニケーション義務を知らない
    → コミュニケーションが「個人的な厚意」としての扱いになり、組織的役割がなくなる。
    → コミュニケーションは仕事の一部であると教える。
  • 情報を展開するべき人間が、その義務を認知していない
    → 上司/リーダーなどにマネジメントを教える
  • 情報を展開するべき人間のコミュニケーション品質が悪い
    → 情報を正確に伝達するスキルを身につけさせる(主語の明確化、客観/主観の区別など)
  • 情報を展開するべき人間の可処分時間が不足している
    → 展開業務を分担する
  • コミュニケーションのコストが非常に高い
    → 情報種ごとに、情報共有を支援するようなシステムを導入する(ボード、Wiki, ITSなど)

ようは、コミュニケーション不全になっている原因はさまざまであり、対処法も原因によりけりだ。安易に「コミュニケーションを改善しよう」などと言ってはいけない。

遠隔操作ウイルスで気になるところ

前回は無視したんですが、メソッド名などの他に気にしている点があります。前回の補遺になりますから、技術的な興味がある方だけ参考にしていただければと思います。

公開資料が不完全

まずは簡単な指摘から。警察庁のPDFには Main メソッドがありません。ということは、エントリポイントを変更するという謎設定をしてない限り、あの資料はそもそも不完全ということです。(なお、通常であれば、Visual Studio が Program クラスと Main メソッドを自動で生成します。)

不完全なものになってしまった原因を推測してみたいと思います。

  1. private メソッドを記載しなかった。
    Main メソッドは自動生成では private ですし、Program クラスは Main しかないので、資料から取り除かれた説。
    しかし、hbTimer_Tick などのVS自動生成メソッドは private で生成されますが、載っています。したがって、この説の妥当性は非常に低いです。
  2. static メソッドを記載しなかった。
    この場合、Common クラスなどの(記載されている)メソッドはインスタンスメソッドということになります。あれらは static であるほうがより良いので、もしそうであれば開発者のスキルに多少疑問符がつきます。
  3. Main なんて当たり前だから警視庁判断で記載しなかった。
    技術情報の取り扱いについてのセンスがないと思います。
    「上記の情報は、合同捜査本部において、特定の手法により分析した結果ですので、別の手法を用いた場合には、細かい点について異なる場合があります。」なんて言い訳している余裕があったら、誠実に公開すればいいのに。もしくは「特定の手法による分析」とやらを明記するとか。

まあ、私の主観では 3 です。Main の他にも InitializeComponent という自動生成メソッドがあるはずなのにありませんし。あとキーロガーとか画面キャプチャに Win32 API を使わないのかな? 使っているとしたら export されたメソッド定義があるはずです。

フィールドの情報がない

ところで、メソッドは公開されているのに、フィールドは公開されていません。どういうことですかね。hbTimer_Tick というのがあるのですから、十中八九 hbTimer というインスタンスフィールドはあるはずです。

もしかしたら、警察のサイバー現場が上層部に掛け合って、ようやく引き出した公開範囲が「クラス名とメソッドの一部」なのかもしれません。某踊るなんとか的な想像ですが。

あの規模ならメソッドとフィールドの情報から振る舞いをおおよそ推測できますから、ちょっと残念です。

クラスが少ない

さて、公開の仕方については以上として、今度は再び中身についてです。

ウイルスに含まれるクラスは、 Form1, Common*, Fileman (File Manager?), Operec (Operation Recording?) とされています。

ただちに分かるのは、Form1 以外すべて機能分解的なモジュールであって、オブジェクト指向的なクラスがないということです。

これから次の妥当な推論ができます。

  1. ほとんどのロジックが Form1 にあり、機能的モジュールを中央集権的に制御している。
  2. Form1 内部では各種データをバラバラの変数で扱っている。抽象データ型を利用していない。これは、オブジェクト指向設計(OOD)ではありません。機能分解による設計です。

順に見ていきます。

メソッドの粒度が大きすぎる可能性がある

まず1についてです。

Form1が主制御を実装しているとすると、そこには遠隔操作コマンドを実行するロジックがあるはずです。

探してみると、runIns, doUrl が怪しい。ですが、たとえば doSuica とか、「あるコマンドを実行する」というメソッドがありません。とすると、runIns か doUrl の中にはすべてのコマンドのロジックが含まれている可能性があります。これは”一般的には”良くない設計です。(一般的には、と断る理由は下記。)

良くない設計は何を意味するのか

そして2と、設計についてです。

犯人からのメールでは「一から作った」となっていますから、全体設計には開発者の設計力が反映されていると思います。しかし、設計がOODではないことイコール開発者のスキル不足とは限りません。その理由を説明します。

ソフトウェア開発のセオリーでは、まずオブジェクト指向分析・設計 (OOA/OOD) なりでソフトウェアの輪郭を描き出せとされています。OOなんとかで開発を進めるので、この場合は出来上がりもOOっぽくなります。しかし、「このOOなんとかで行え」の前提は、要件定義を行える状況にあるということで、それは暗黙的に「要求仕様を把握している誰かがいる」ということです(普通は、曖昧にせよ顧客が要求を持っている)。

ところが、本件ウイルスのように「誰も正しい作り方を知らない/聞けない」という開発の場合、難しいのは「何を」開発するのか決めることです。「なにができれば遠隔操作ウイルスとして成り立つの?」に対する答え探しともいえます。

これはコロンブスの卵で、事後には簡単に見えるけど当事者には難しい問題です。正解はありませんが、答えを見つけるよい方法にプロトタイプの作成があります。遠隔操作ウイルスも、プロトタイプとして作られたと思います。

プロトタイプは良い設計を備えるべきか

ながながと書きましたが、要点は下記です:

  1. 遠隔操作ウイルスはプロトタイプである。(反論は少ないと思う。)
  2. プロトタイプの目的は実証であり、設計は二の次である。

そうすると、プロトタイプである遠隔操作ウイルスが「あまり設計されていない」ことは、実は開発者の賢さの現れとも捉えられるのです。いわゆる “premature optimization is the root of all evil” です。

そうすると、遠隔操作ウイルスにクラスが少ないことは、次のどちらにも考えられます:

  1. オブジェクト指向に対する理解が浅い。
  2. プロトタイプでの過剰設計を避けた。

プロファイリングにおいてこれをどう評価するかは難しいので、クラス構成に基づいた論評は避けました。

リファクタリングすべきか

ここまで書くと「リファクタリングして当然」という反論が思い浮かぶので、あらかじめ書いておきます。

現状として遠隔操作ウイルスが所望の機能を果たしているのであれば、リファクタリングのみを目的としてコードを改変するのは愚かなことです。「コードをきれいにしたい」という欲求に突き動かされて目的を見失うのは二流だと思います。(とはいえ、遠隔操作ウイルスの構造が、開発者のそういう自制の結果かどうかは分かりません。)

上位20%

これまでのすべての論点について、技術的バランスをとった妥当な判断の結果としての遠隔操作ウイルスなら、開発者は上位1%未満の「非常に優れたスキル」と思います。しかし、すでに述べたように、開発者がそういう優れた判断をしているかは個別の事象からは分からないことが多いです。ですから、メソッド名だけだと分からんなあ……と思ってしまいます。

ですから結局おおざっぱに言えば「実装している」「運用している」「目的をほぼ達成している」という点からの上位20%評価です。

ソフトウェア技術者の客観的評価

ソフトウェア設計における判断は、個別評価が難しいので、優れた技術者ほど第三者評価が低い可能性もあります。なぜなら:

  1. ソフトウェア技術者の能力を正確に評価するには、私の経験では、その技術者以上の能力が必要です。
  2. 優れたソフトウェア技術者ほど、正確に評価される可能性が少なくなります。
  3. 優れた判断の中には、単体では未熟さによるものと見分けがつかないものもあります。
  4. したがって、普通の技術者は、優れた技術者をなかなか見分けることができません。

ちょっと暴論ですが、私はこんなふうに思っています。

上位20%というのは、そこらへん(賢さと未熟さの混同)も考慮したうえでの、まあなんとなくの数字です。

遠隔操作ウイルス開発者のプロファイリング

世の中を騒がせてますね。素人が専門家にぼろ負けしてるという印象です。問題は素人が権力を持っていること?

ウイルス自体が手に入ると良いのですが、どこにもないので、警視庁のページを見てみました(PDFのコピー禁止設定とか、情報提供する気あるのかって思う……)。

資料まとめ

iesys.exeに対するコマンド

これによると、まずiesys.exeに対するコマンドは下記であるとされています。

  • ファイルのアップロード、ダウンロードなどに関する命令
    cd, del, dl, dltext, send
  • キーロガー、画面キャプチャなどに関する命令
    framecnt, kloff, klon, scrcap, scrcap_auto, scrcap_auto_stop
  • 掲示板の設定、アクセスに関する命令
    newuser, updatesv, bm, nm
  • iesys.exe自身の動作などに関する命令
    restart, exit, wait, fsuspend, force_, run, stat, suica, update, ver
  • ブラウザ機能に対する命令
    wbback, wbcap, wbclick, wbdef, wbget, wbpost, wbset, wbset_p, wbsubmit, wbtryselect

iesys.exeのクラス名・関数名

次に、クラス名・関数名です。

  • Form1
    fetchMyThreadId, makeNewUser, parseInstructions, waitTimer_Tick, runIns, startBurstMode, endBurstMode, selectDOM_point, selectDOM, _getElementById, _getAllElems, _getElementsByTagName, ins_end, ins_end_force, wb_DocumentCompleted, hbTimer_Tick, checkInsTimer_Tick, timerNewUsr_Tick, kakikoMyThread, kakikoMyThread_noEnc, fetchNewIns, kakikoMyThread_retrymode, kakikoRetryTimer_Tick, connection_emergence, decodeEscaped, uploadBitmap, snapTimer_Tick, startAutoSnapMode, endAutoSnapMode
  • Common
    GetUnixTime, getMyDir, setAutorun, rmAutorun, SaveSjisTextFile, exitAndDel, exitAndDel_p, exitAndUpdate, exitAndUpdate_web, getDefBrowser, targetSanitize
  • Common_Crpt
    EncryptString, DecryptString, GenerateKeyFromPassword, uidToPwd, uidToEndMark_S, uidToEndMark_E, uidToInterceptMark_S, uidToInterceptMark_E, encByUid, cutEncodedStr, decByUid, decByUid_partial, eraseIntercept, addKaigyo, removeKaigyo
  • Common_TCP
    asyGetRequest, getRequest, asyDoUrl, doUrl, sendFileMethodPost, asySendStreamMethodPost, sendStreamMethodPost, makeShitarabaThread, kakikoShitaraba, getShitarabaThreadListStr, getShitarabaThreadList, getShitarabaThreadDat, binDownload
  • Fileman
    runCmd, getCDName, getCDList, getFile
  • Operec
    isLogging, startLogging, stopLogging, getRawLog, getLog, clearLog, globalKeydown, globalMousedown, convLogToStr

感想

容疑者が誰かは置いておいて、これを日本人が作ったとすると、それなりにスキルは高そうという印象です。

  • 英単語の語彙が下位技術者のレベルではない。
    fetch, parse, instructions, burst, force, snap, generate, encrypt/decrypt, intercept, exit, partial
    hbTimer = hibernationTimer?
    sanitize (無毒化)などはそもそも高度な概念と思うけど、最近は違うのかな。
  • 英単語の微妙な使い方が正しい。
    instruction*s*, start*Logging*, get*Log*, Auto*r*un
  • 短縮語は大文字にするという几帳面な命名
    DOM, TCP, CD
  • 英単語の対応関係が明確
    start/end, set/rm, add/remove, start/stop
  • 固有名詞の扱いが妥当
    kakiko, shitaraba

ひとつふたつならともかく、この程度のきめの細かさでコーディングできるプログラマは少数だと思います。「俺は出来る」という自称プログラマなども、パターンなどうわべの知識だけで実際のコーディングは微妙ということが多いのに、なかなかのセンスに見えます。

技術的にもみるものがあります。

  • thread と asy がある。
    スレッドは有名な並列処理の方法ですが、最近は非同期呼び出し (asynchronous call) が主流です。上記を見ると、命名からスレッド処理なのか非同期処理なのか判別できますし、それらを使い分けていることも分かります。非同期については識別子の先頭にasyを付けるという開発者の固有ルールがあるのでしょう。優秀なプログラマには当たり前の特徴です。
    (追記)はっと気がつきましたが、thread は掲示板スレッドの意ですね。”My”が気になっていましたが、そりゃそうだ。よくよく考えられた名前だと思います。
  • Java言語も使える可能性が高い。
    C#もそうですが、Microsoft 系の言語の一般的な命名規則ではメソッドは大文字で始まります。一方、Javaは小文字です。上記はほとんどが小文字開始ですから、元々Java出身の技術者である可能性があります。もしくは私のように、privateな要素については小文字(もしくは大文字/小文字を気にしない)というルールかもしれません。その場合はより繊細なコーディングをしていることになります。
    略語がすべて大文字なのもJavaの流儀です。C#では、略語であっても二文字目以降を小文字にします(例外は名前空間)。
  • 記事やネットでは「いまどき通信でどうこうするプログラムは難しくない」という論調ですが、C#のような汎用記述言語で一からコーディングするにはかなりのスキルが必要です。また、実際に動くのは未知の環境下ですから「手元で動けばOK」という認識は通用しません。また、10分間隔できちんと動作することの確認など、実際問題としての課題はそれなりにあります。
  • 暗号化などもコピペのようで、巷では「そんなに難しくない」という評価のようですが、普通のプログラマであればまず「暗号化しよう」という発想に至りません。たとえコピペだろうとも、スクラッチプログラムでそれが実装され、期待通りに動作するというのはそれなりにすごいことです。

これらを総合すると、下記のような推論ができます。

  • まず除外できるのが、素人がほとんどのコードをコピペで作成したケース。新種ウイルスとして登録されていますし、全体コピーはないでしょう。開発者はスクリプトキディのような素人ではありません。
  • また、断片を寄せ集めて統合したケースも可能性は低いです。経験的に、コードスニペットを寄せ集めるタイプのエンジニアは「動けばよし」です。未知の環境で動作するネットワーク越しのアプリとして完成度を高める能力はありません。また、内部を理解しないのでリファクタリングすることができないため、コードに統一感がありません。今回のは、完璧に整ったとは言えないものの、寄せ集めという感じはあまりしません。
  • したがって、特別な記述が必要な暗号部分などを除いて、基礎部分は独自に開発されたとみて良いのではないかと思います。(暗号部分などは難しい割に使い回しが難しいので、私もよくコピペします。)
  • すでに述べたような特徴を持ったプログラムを一から開発できるのであれば、几帳面で、行動力と知識があり、5〜10年程度の実践的な実装経験があると思います。その技術者のスキルは上位20%に入っていると思います。
  • しかしながら、報道記事などによるとエラー処理が甘く落ちたりするらしいので、通信系の職業プログラマではないとは思います。通信系の職業プログラマであれば、基本処理と同じくらいエラー処理が重要であることを知っていて当然だからです。したがって、前述の実装経験は、エラー処理など異常系を考慮しなくてよい立場・環境で培われたものだと思います。

これまでの推論をまとめると、職業プログラマよりも、むしろたとえば学生や研究者、日曜プログラマのような技術者が開発者ではないかと思います。Web技術については、その分野の専門家というより、近代プログラミングの教養として身につけていた程度ではないですかね。エラー処理の甘さと対照的な、高度概念の導入などがそう思わせます。

ブログ迷走

はてなブログは AtomPub に対応してなくて、使えない。

Blogger はインポートがうまくいかなくて、いちいちCAPTCHAを要求されるのも面倒。

結局、ちょっと垢抜けなくてもはてなダイアリーを使い続けるのが良さそうだ。

はてなブログのテスト

はてなブログに乗り換えてみようかと。

しかし、いつも使っている Windows Live Writer からはてなブログに投稿したい。

でも、AtomPubのURLは d.hatena.ne.jp でいいのかな……。どうみてもはてなダイアリーに投稿されているとしか思えないんだけど。

自動でブログの方にも反映されるのかな?というテスト。