はじめに
こんにちは。アプレッソ開発部の土岐と申します。
DataSpiderに不可能はない! ということをテーマに、 さまざまな要件にDataSpiderで答えていくことをチャレンジしています。
今回は「DKS」です!
DKS、その起源について
DKSとは?
DKSについて説明するには、その起源から話す必要があります。
弊社内のパーティで、景品の抽選会を行う機会がありました。
様々な経緯によりその司会担当を務めることになってしまった私は、
「まあ定番のビンゴゲームかな」
「あのよく景品で使うガラガラ回すやつ(調べたら”ガラポン”という正式名称でした)とかあったら面白いな」
とか考えつつ、
「果たして技術者としてそれでいいのか?」
という葛藤を抱えたわけであります。
技術者は、技術でもって人にサプライズを与えるのが使命なはず・・・。
それを出来合いの技術を使って楽をして良いのであろうか・・・。
とそのとき、気付いたのが「我々にはDataSpiderがある!」ということです。
DataSpiderを作っているアプレッソ社員の運命を決めるのは、やはりDataSpiderが最適なのではないか?
そして思いついたのが、DataSpiderでくじ引きを行うソリューション、
「DataSpider Kujibiki Solution(DKS)」であります!
・・・と大袈裟に書いてしまいましたが、まあ要するに「DataSpiderのスクリプトでくじびき処理を作ってみました」ってだけです。
しかしこれは同時に「DataSpider、そして自分に対する挑戦状」でもあります。
「くじ引きがしたい」という無茶な要件にどこまでDataSpiderが応えられるか、
そしてDataSpider技術者として、私がその要件に応えるスクリプトを作ることができるか。
そのような使命感を持って、DKSの開発に取り組みました。
ということで、そのスクリプトを作るにあたって悩んだところや工夫したところ等を紹介していこうと思います。
DataSpiderでスクリプトを作成したことのある方は、「自分だったらどう作るか?」ということをご想像いただきながらお読みください。
DKS仕様概要
というわけでいきなり結論に行ってしまいますが、出来上がったのがこちら。
デザイナ画面ドン」!
かなり複雑になってしまいました・・・。
すべてを説明すると長大になってしまうので、コンパクトに何をやっているかを説明します。
まず今回行いたいくじ引きの要件としては以下となります。
1) 対象者は50人程度
2) 50人の中から、当選者を景品ごとに無作為に抽出する
3) 1つの景品につき当選者は1~3人
4) 一度景品が当たった人は対象者から除外する
5) 景品は20個程度
この要件に応えるために、考えた仕様は以下です。
1) 「対象者の名前+改行」を書き出した「対象者ファイル」を作成し、その行数をインデックスとする
2) 2桁の数値をランダムに生成し、そのインデックスに該当する対象者を当選者とする
(ア) もしその2桁の数値に該当するインデックスが無い場合、再度生成する
3) 複数の当選者が居る景品の場合、再び2)の処理を行う
4) 当選者がすべて決定した場合、その名前をテキストファイルに書き出し、外部アプリケーション起動処理で表示する
5) 当選者のインデックスに該当する対象者名を「対象者ファイル」から削除する
という感じで、このスクリプトにおいてメインとなる「くじ引きエンジン」は、
ランダム2桁インデックスを生成
→該当するインデックスの行数が対象ファイルに無い場合は再度生成
→該当したらそのインデックスが当選者のインデックス
という処理になります。
苦悩のランダム
とここまでは順調にできたのですが、「どうやってランダムな2桁の数値を作るか」ということで悩みます。
残念なことに、DataSpiderではランダムな数値を作成するMapperロジックやアダプタがありません。
皆さんお気づきとは思いますが、アダプタSDKを使ってそのようなアダプタを作れば、このような要件には簡単に応えることができます。
が、ここはDataSpiderへの挑戦。
あえて標準機能を使って、ランダムな数値を作ることにチャレンジしてみました。
ということでそのMapperでの処理がこちら。
数学的に厳密なランダムまでは必要ないのであくまでも擬似的なものです。
「現在日時」の「分」と「秒」を基に、乗算・加算を重ねて数値を作成し、その結果を使用しています。
正直作りはテキトーではあるんですが、まあ「そこそこランダム」くらいの値になるように、定数などを調節しながらなんとか作ってみました。
とりあえず、何とか出来上がったのが稼動前日の夜。
テストデータで何度か確認し、いざ、と社内パーティの日を迎えたのであります。
意外な結末
そして本番稼働。
意気揚々としてスタートしたくじ引き。
DKSの存在は極秘プロジェクトとして行われていたので、なかなかのサプライズとなっていたようです。
まずは軽めの景品から当選者を決定していき、なかなかの盛り上がり!
いける!
しかし・・・
3度目くらいのくじ引きで、ある疑惑が発生します。
そもそも前提として、今回は弊社社員のご家族も参加のパーティだったので、以下のような名簿から、ランダムで数名ずつを当選者とすることになったんですね。
1 山田太郎 (社員)
2 山田一郎 (ご家族)
3 山田洋子 (ご家族)
4 田中邦夫 (社員)
5 田中幸子 (ご家族)
6 佐藤大介 (社員)
7 佐藤貴子 (ご家族)
・・・
こんな感じで、家族が並んでいます。
なぜか、この中で、
1 山田太郎 (社員)
2 山田一郎 (ご家族)
3 山田洋子 (ご家族)
が同時に同じ景品に当選。
次は、
6 佐藤大介 (社員)
7 佐藤貴子 (ご家族)
が同時に同じ景品に当選。
というように、連番の人が同じ景品にあたってしまうという状態に。
4度目のくじ引きで、その疑惑は決定的になりました・・・。
やばい!
一度中断し、緊急にサポートチーム・QAチームが集まり(本当に)、緊急MTGが始まります。
「スクリプトを修正してはどうか?」
「いや、原因がはっきり判明しない以上、場当たり的な修正はさらなる不具合を招く」
「スクリプトの複雑さから、原因究明の時間は無く、影響範囲も不透明」
「一人だけの当選者なら、ランダム性は確保されている模様」
ということで結論。
「一度の抽選での当選者を一人にするという運用で対応しよう!」
というスピーディな対応により(って自分が招いたんですが・・・)
なんとか全部の景品の抽選を終え、本番を乗り切りました。
この不具合対応も含めて、ドキュメンタリーっぽくて良かっ・・・・良くない!
そして反省へ・・・
あとで調査してみて、原因はわかりました。
先ほどのMapperでのランダム値の取り方に問題がありました。
「現在時刻」を元にしてループで当選者インデックスを算出しているため、
「1秒以内」にループが回ってしまうと、同じインデックスが当選者となってしまうのです・・・・。
なんてこった!
しかし、プログラムに不具合は発生しうるもの。
なぜこんなイージーな不具合に気付かなかったか?
それを分析すると、以下のようになります。
1) テストデータが不適当
ある人名リストをテストデータとして使用していました。
それが、なんとなくネットでみつけた某球団の選手一覧だったのが原因の1つです。
テスト中に、この選手一覧でも連番であたっていたのですが、特に馴染みのないリストだったため、まったくそのことに自分が気づいていませんでした。
2) テスト不足
本番稼働前日に完成したスクリプト。
テストをしたのが開発者本人。
これが、ちゃんと余裕をもって開発者以外がQAをしていたのならば、この問題を発見できたはず・・・
3) 必要以上に複雑なスクリプト
妙な気負いをもってスクリプトを複雑に作りこみ過ぎたのも原因でした。
そのため、不具合発生時の切り分けに時間がかかってしまいました。
「求められている要件」と「実装する機能」のバランスについて、設計時にもっと検討するべきでした。
そして未来へ・・・
というわけで、失敗しながらもなんとか役割は完遂することはできました。
しかし、DataSpiderのポテンシャルはこんなものじゃない!
というか、リベンジさせてくれ!
というわけで、密かに「DataSpider Kujibiki Solution ver 2.0」へ向けてのロードマップを組み立てている昨今です。
それと同時に、「こんなことDataSpiderでできる?」という無茶な要件をなんとかやってみる、ということの面白さにも目覚めました。
その中で見えてくる、DataSpiderのポテンシャルや弱点、またDataSpiderを使った開発の工夫すべきところや、失敗しがちなところ、そういうものをDataSpider自体の開発にも活かしていければ、と考えています。
これを読んでいただいた皆様からも、
「こういうことできる?」
「自分だったらこうやる!」
みたいな意見も随時募集しておりますので、ぜひご意見をお聞かせください!