[IM]バリデーションの実装を再考する

INTER-Mediatorではかなり以前にバリデーションの実装はしたものの、完全ではない状態だったのですが、このところ、手を入れるに従って、いろいろ不具合…というか、「考慮が薄い」ポイントが目立ち始めましたので、改めて、議論を進めたいと考えています。

まず、バリデーションは、「入力チェック」とも言われます。いちばん、根本的なことは何かというと、「正しくない値をデータベースに保持しないようにしたい」という要求があると考えています。「正しくない」の基準は、アプリケーションによって変わりますが、「NULLである」ということかもしれませんし、「正しいメールアドレスのフォーマットではない」ということかもしれません。その場合に、データベースに記録しないようにするということがあります。データベース絡みとなると、いろいろ複雑な問題が出てきますので、これを後回しにして、まずは、アプリケーション利用者レベルからの見方を考えてみます。

開発者や管理者がバリデーションを必要とし、実装しますが、Webアプリケーションフレームワークは、バリデーションに関連したユーザーインタフェースを構築し、ユーザーを惑わせない仕組みの提供が望まれます。そもそも、アプリケーションで、どようにバリデーションが絡み合うのか、5W1H的にまず考えます。

  • When:正しくない値が入力されたとき
  • What:開発者や管理者が望ましくないと考えるデータを検知する仕組み
  • Where:入力可能なコンポーネント
  • Who:ユーザーが生成すると考える
  • Why:単純なミス、さまざまな誤認、テストあるいはインスペクション
  • How:キータイプ、あるいはコピー&ペーストなどのユーザの操作

以上の分析からは、バリデーションの検知と通知が大きな目的であることが出てきます。しかし、一部に例外があって、フィールドの初期値がバリデーション違反という場合もあります。そのとき、上記のWhoは「システム」ということになってしまいます。この初期値が違反している問題は、厳密にはデータベースの定義が正しくないで終わってしまいますが、非常に複雑な事情が絡むので、後ほど議論します。

バリデーションの検知は、INTER-Mediatorではすでに実装しています。onchangeイベントが発生したときに、フィールド単位でのチェックを行います。フィールドをまたがった判定用にも、コールバックされるメソッドの定義があります。最近になって、初期値が違反しているときでもバリデーションが働くように、onblurイベントでも判定をするようにしました。これら、さまざまなニーズはあると思われますが、タイミングと仕様が確定していれば、対処できる範囲かと思います。

一方、バリデーション違反の通知は、さまざまなバリエーションが考えられます。そういうニーズも状況も多様な状況では、プログラムを組んで対処というのはもちろん柔軟な対応ができていい部分ですが、一定の範囲を宣言的な記述でまかなうことで、プログラムを書くことを減らす意図のあるINTER-Mediatorではなんとかしたかったところです。そこで、フィールド単位のバリデーションが違反したら、「ダイアログボックスを表示して促す」「近辺に赤字等でメッセージを出す」という仕組みを定義ファイルの設定だけで実現しました。そして、イベント発生時に違反が検知されれば、雇用な動作をして、フィールドからフォーカスがはずれないようにしました。

しかし、ここまででも、すでに議論のポイントはいくつもあります。

  • バリデーションはいつ行うのか?
    • キータイプごと?
    • カット&ペーストするごと?
    • データベース更新前?
    • 複数のフィールドに対して「書き込み」ボタンがあれば、それを押したとき?
    • ポストOnlyモードとデータベース更新時は動作を違う必要があるのか?
    • 現状は、定義ファイルで指定可能なのはデータベース更新前のみ。
  • 違反通知をどのように行うのか?
    • 現在は、ダイアログボックスとページ上への文字の追加
    • 新しいページを表示したい?
    • 何が間違えたのかをもっと詳しく表示したい?
  • バリデーションに違反したら、その後にどのような操作を期待するのか?あるいは期待されるのか?
    • そのままでいいのか?
    • どこまでロールバックするのか?
    • どこまで既定値的な値を設定するのか?
    • 違反したレコードは削除しなくていいのか?
    • 違反してもレコードは作るのがいいのか?
    • 現在は、そのままにしつつ、正しい値を入力しないとそのページの他の作業をできなくしている。

あらゆるバリエーションに対する答えを用意するのか、それとも、主要な手法以外はプログラミングをしてもらうのか、その辺りが議論のポイントになると思います。いずれにしても、問題を書き出すことは必要でしょう。

データベースエンジンには通常バリデーションの仕組みは含まているので、本来はそちらを使うべきという議論があるでしょう。SQL言語での定義時に記述するため、「難しいから敬遠している」という向きもあるかもしれません。一方、なぜ、フレームワークがバリデーションをサポートするかというと、データベース側でのバリデーション処理は、違反時の状況の取得や、そこからの適切なユーザーインタフェースの構築、さらにやり直しなどの処理の組み立てなど、単純ではないプログラミングを要求されます。また、その対処方法も、データベースごとに違う可能性もあるので、むしろ、フレームワークの内部でバリデーションをサポートした方が、動作上作りやすいということもあるわけです。データベース側のエラー検知は、レイヤーを上下するワークフローをうまく組み立てるようなプログラミングを必要としますし、その結果、アプリケーションサーバーとデータベースということなるソフトウエア間の連携ということも必要になります。結果として、データベースに頼らない方が、フレームワーク内部で完結するため複雑さの一部を回避でき、加えてデータベースごとの事情に左右されないというメリットを生みます。

その結果、データベースのスキーマ定義にバリデーションルールが入らないことになり、それによる大きな問題は、初期値がバリデーション違反という状況で、ユーザーの操作に入ることがあります。これをどこの段階で、不正とみなし、どのような方法で排除するか、これが定まらないと、実装が揺らぎます。

ということで、とりあえず、頭にあることを書き出しておいて、議論を進める手掛かりにしたいと思います。

USB-CのVGAアダプタ

新しいMacBookのための、「USB-C VGA Multiportアダプタ」が到着しました。「USB-C Digital AV Multiportアダプタ」については以前に書いた通り[こちら][こちら]です。VGAの方は、どんな風にOS側から見えるかを書いておきましょう。VGAなので「従来通り」です。なお、HDMIに接続しているDELL P2715QはVGA入力がありませんので、以前に購入したBenQ GL2450H、つまり、HD解像度の24インチのものに接続しました。「このMacについて」は次の通りです。

shot2026

「システム情報」だと以下の通りです。USB-CのVGAアダプタが接続されていることがここで見えています。4K解像度だと、「このMacについて」と「システム情報」の解像度が2倍違うのですが、HDの解像度だと同一になっています。

shot2027

システム環境設定のディスプレイは、Retinaではなくドット数を選択する方式が見えています。

shot2028

あまりきれいな写真ではありませんが、HDMIのアダプタと、VGAのアダプタを並べて写真に撮ってみました。VGAの方も、USB、USB-Cがいずれもあるので、幅が広くなるのは仕方ないとして、なぜか、ケーブルも長いです。しかしながら、ディスプレイ端子の位置から、Macに差し込むコネクタまでの長さは同一です。ボックス部分が長方形になっている分、ケーブルが長くなっています。しかし、このVGAアダプタは、微妙な大きさですね。3端子ないとやっぱり不便だけど、かさばる感じがしますね。厚みは、VGAの方が少し多いです。

IMG_0391

買ったばかりのMacBookのUSB-C事情

MacBookは5/17に到着、5/20に「USB-C Digital AV Multiportアダプタ」が到着、注文中の「USB-C VGA Multiportアダプタ」はまだ未着の段階です。DELLの4Kディスプレイで、Retina動作をすることを報告しました。これはある種の「予想外の動作」と言えるでしょう。しかしながら、使うに従って、USB-Cについて、いろいろ試行錯誤が必要になってきました。

まず、Nexus 7のACアダプタ(7Wか10Wだと思う)で、充電できることをFacebookにも書きましたが、場所によって充電できる場合とできない場合があることが判明しました。自宅だと、充電できます。しかし、移動先ではできたりできなかったりします。同一のアダプタ、同一のケーブル(USB-AとUSB-Cのケーブルを購入した)でやっているので、これはおそらくコンセントの段階での電圧の問題ではないかと思います。先日、「充電できる」と思っていたら、「充電できない」という状況に遭遇しました。とはいえ、1日程度はなんとかバッテリーは持ちました。

次にディスプレイアダプタ(USB-C Digital AV Multiportアダプタ)を装着すると、Nexus 7のACアダプタでは、100%充電はできないし、給電もできないことがわかりました。アダプタが電源を食うのか、USBの機材の関係なのか、ともかくNexusのアダプタ経由では充電や給電ができないのです。

しかし、なんと、iPadに付属のACアダプタ(12W)だと、ディスプレイアダプタを経由して、MacBookに給電/充電ができるのです。ということは、持ち歩きはiPadのアダプタでいいということになりますね。iPadは、Nexusのアダプタで使えばいいということで、「予想外の嬉しい組み合わせ」がもう1つ見つかりました。

代替のACアダプタ、つまり、軽いとか、安いのでいくつか買ってあっちこちにキープみたいなことができないかと考えるわけですが、USB出力があって、10Wを超える(つまり、1つのポートで20W)みたいな製品ってAmazonで調べたけど、見当たりませんでした。USB出力のACアダプタは、ほぼ、スマホタブレット向けで、出力が低いのです。20Wと書いてあっても2端子合計だったりするのが普通のようです。iPadのACアダプタは2200円なので、純正品が5800円に対して半額以下であり、大きさも小さいということもあり、ある意味、持ち歩き用としては、買い足してもいい範囲なんじゃないかと思います。

USB-Cのケーブルもまだまだ高いですし、USB-Cの反対側が高出力のACアダプタ向けのものなんてまだ見当たりません。ということで、新しいMacBookユーザが欲しいスペックのブツはどうやらまだまだのようです。要するに純正以外の選択肢が非常にない状態ということです。予測はしていましたが、とにかく乗り切らねば。Facebookでリンクを紹介しましたが、クラウドファンディングで募集しているHub+がまずは新しいパターンの製品ですね。mini Display 端子があるので、Apple純正のディスプレイをつなぐことができます。

ディスプレイアダプタが来て本格的に利用

新しいMacBookは日曜日に来ました。そして、今日水曜日に遅れてUSB-C Digital Multiport Adapterが到着し、やっと大画面ディスプレイと接続ができました。薄っぺらいもののちょっと大きなアダプタですが、3つのコネクタを横に並べるとしたら、やっぱりこのサイズになるでしょうか。USB-Cには本体付属のケーブルで、付属のACアダプタへ接続しています。ディスプレイとは、ディスプレイに付属のUSBケーブルと、購入したHDMIケーブルで接続をしています。

IMG_0383

このMacについてを見てみると、ディスプレイフルの解像度で見えています。4Kということで、4000弱の横ドット数です。

shot2012

ところが、「システム情報」を見てみると、1920×1080となっており、ディスプレイ自体のちょうど半分の解像度です。これは、Appleの27インチのCinema Displayの解像度(2560×1440)より低い解像度となります。Command+Shift+3で画面ショットを作成すると、3840×2160ドットなので、ディスプレイのフルの解像度を利用していることがわかります。

shot2013

システム環境設定の「ディスプレイ」では、外付けディスプレイも、内蔵ディスプレイと同じように、ドット数ではなく、4段階の選択になっています。つまり、外付けのRetinaディスプレイとして扱っていると考えていいのではないでしょうか。

shot2011

実は直前まで使っていたのはMacBook Airで、RetinaディスプレイのMacは今回購入したMacBookが初めてなんです。もちろん、美しいのは当然ですが、外付けディスプレイまで、Retinaの処理をしているのは知りませんでした。しかしながら、外付けディスプレイの表示結果は、内蔵ディスプレイに比べて「ちょっと大きい」感じがします。27インチのディスプレイの、従来の解像度よりも低い解像度だけに大きく見えるのは当然でしょう。内蔵ディスプレイの内容がやや小さいので、並べると外付け側が大きい感じが出ます。

しかし、最近、視力も落ち気味だけに、ちょうどいいかとも思っています。システム環境設定の「ディスプレイ」で「スペースを拡大」側のいちばん右にすると、さすがに小さすぎます。しかし、これは、もしかして、5Kだったら大きさ感が一致するのかもしれません。もしかして、それが理由で4KディスプレイをAppleは出さない(部品がなくてだせないとか?)のかもとも思ってしまいます。

Yosemiteでdocdiff

以前、2つの文書の比較結果をカラーリングで示せるdocdiffのことをMavericks向けに書きました。Yosemiteで同じようにすると動きませんでした。しかし、gemで簡単にインストールできるようです(松尾さんありがとう)。

sudo gem install docdiff

これで、/usr/bin/docdiffがコマンドとして機能するようになります。そのほかのライブラリファイル群は正しい場所に入っているということで、気にしないで行きます。

さて、svnで使うには、パラメータの組み換えが必要です。そこで、/usr/local/binにdocdiffを作ってそれを実行用にします。もちろん、viでもemacsでもご自由なエディタで編集してください。もし、/usr/local/binが作られていないのなら、mkdirコマンドで作ってください。

sudo nano /usr/local/bin/docdiff

中身はこのように書きます。

#/bin/sh
/usr/bin/docdiff --format=tty $6 $7

そして、もちろん、アクセス権を設定しておきます。

sudo chmod a+x /usr/local/bin/docdiff

こうすれば、以下のようにsvnコマンドを打ち込むときに、docdiffを使って比較を行います。最後のパラメータはファイル名です。

svn diff --diff-cmd=docdiff -r PREV _any_file_name_

もし、パス(echo $PATH で確認できます)が、/usr/local/binに通っていないとか、/usr/binより後にある場合には、上記のパラメータの1つを「–diff-cmd=/usr/local/bin/docdiff」のように指定します。

ということで、docdiffは便利です。

shot2001

ディスプレイをDell P2716Qに置き換えた

Apple LED Cinema Display 27インチは売り先が決まりそうなので、さっそくディスプレイを買い換えました。新しいMacBookにリプレースすると、Cinema Displayへの接続がとりあえずはできない(そのうちできるかもしれないけど)ので、HDMIのあるものに切り替える必要があります。以前のブログ記事のように、BenQの24インチもありますが、もう少しクオリティたかそうなものが欲しいのと、せっかく新しいMacBookなので、4Kにしようと思い、Dell P2715Qに変えました。

しかしながら、まだ新しいMacBookは到着していないので、本体はMacBook Air 2012年モデルのままです。Mini Display Portから直接つないでみましたが、もちろん、つないでほぼ即座に使えました(最初に入力元の切り替えだけ必要)。

IMG_0381

大きさ感はCinema Displayとさほど変わりません。もちろん、筐体のゴージャスさは大きく差がありますが、まあ、それは仕方ないでしょう。MacからはUSBケーブル1本で、ディスプレイ側に接続し、そこから4つのUSBケーブルを接続できます。USBのハブの出力先は1本増えたのは嬉しいところ。ただし、MacBook Airへの電源供給がなくなったので、ACアダプタを自宅でもしばらく使うことになります。

システム環境設定のディスプレイで見ると、本体が4K対応ではないので、2560×1440しか出ません。Cinema Displayだとそれが最大の解像度だったのでくっきり見えていましたが、Dell P2715Qだと、若干「解像度落としてます感」がありますね。まあ、でも気になりません。画質もBeQの24インチより色が自然な感じです。IPSだからというのもあるかもしれません。まあ、3倍くらい高いから当たり前といえば当たり前かもしれません。「プリセットモード」ってのがあるのですね。けっこう色調が変わりますが、とりあえずスタンダードです。

shot0319

システム環境設定の「サウンド」の出力を見ると、DELL P2715Qと見えているのでおや?と思ったのですが、単に項目として出るだけですね。サウンドがないのはもともと知っていました。下手なスピーカーをつけるより、正しい設計だと思います。そういえば、ラインアウトがあるので、つないだら何か出てくるのだと思います。

shot0318

大画面が2枚欲しいと言いながら、実のところ、クオリティ差が大きいこともあって、結局1枚しか使わない状態になりました。ただし、MacBookが来たら、Retinaだし、トラックパッドも新しくなります。ということで、多分、Dellのディスプレイの前にMacBookを置くパターンで作業するでしょうね。ということで、BenQ 24インチはまたまた、使う機会が減ったままです。実は、今ところ、Apple TVとつないで、大画面ラジオ(意味ない〜笑)にしか使っていない状態です。まあ、でも、たまに画面が欲しくなるときもあるだろうから、AirPlayでスタンバイのままで行くでしょう。

などと書きながら考えて、こういうセッティングにしてみました。右側のBenQ 24インチの後ろに、PromiseのPegasus R4とMac mini Serverがあります。なんとなく、スタンドの位置は夜になって悩む気がしますが、MacBookが来るまでの2、3週間はこの体制かなと思いっています。右の方の机は、もちろん片付けます(笑)。

IMG_0382

第三者を介在せずに「抽選」を行う方法

Facebookに記事を書いたように、機材の販売先を決める抽選が必要になりそうです。第三者に立ち会ってもらって公正にするということは可能でしょうけど、それでも不正の確率は0になりません。頼まれた方もいい迷惑(笑)。なんかいい方法がないか考えました。こんなのはどうでしょう。

基本的な手法

  1. 当せん決定者は、何か1文字を思い浮かべるが、公表しない
  2. 複数の抽選参加者は、何か1文字を思い浮かべて公表する
  3. Unicode のエンコードで、決定者の文字に一番近い参加者が当せんとする

しかし、いろいろ問題があります。決定者が、参加者の公表よりも後になって、思い浮かべた文字を変えてしまうということをしても検出する方法がありません。つまり、決定者は、誰かが当せんするように、意図的に文字を思い浮かべ、それを事前に思い浮かべたものとしてしてしまうと不正が成立します。

では、決定者が文字を思い浮かべた時点で、第三者に伝達する方法があります。しかし、これは決定者と第三者、あるいは参加者と第三者が、裏で結託していると、やはり不正が成立します。

不正を防止する手段

しかしながら、以下のような、ダイジェスト(あるいはハッシュ)を利用する方法をすれば、第三者の介在なしに、不正ができないと考えますがどうでしょう。

  1. 当せん決定者は何か1文字を思い浮かべる:その文字をcとする
  2. 当せん決定者は、別の適当な文言を思い浮かべる。何文字かは公表しない:文章をsとする
  3. s+cのダイジェストd1を求めて公表する
  4. sのダイジェストd2を求めて公表する

こうして2つのダイジェストを求めますが、当然ながら、決定者はファイル等で、sとcを残しておきます。これらのファイルや文字列が、最終決定までに漏えいしないことが前提です。

2つのダイジェストを公表したのちに、参加者は、期限までに「自分が思い浮かべた1文字」を公表します。他人の表明を見ての変更もありとしてもいいかと思います。

最初cのダイジェストを求めればいいかと思ったのですが、Unicodeで1文字程度なら、全部チェックで比較的短時間でわかってしまうという懸念があります。もちろん、公表から10分以内という手もありますが、セキュリティホールの確率が下がるだけです。そこで、不定長の文字列と組み合わせることを考えつきました。

データの作成例

以下は、具体例です。sha1は、「openssl sha1 (ファイル名)」で得られます。公開/非公開は、参加者の表明が終わるまでの間の扱いです。

s="サンプルテキストです:"(非公開)
c="A"(非公開)
sのsha1→34591a094e22f43fb1ba99426265383993599c96(公開)
s+cのsha1→1c19e4ce3a0d49b6dff756e2bf62bdd605355051(公開)

ここで、公表するのはsha1のダイジェスト値のみです。従って、この2つのバイナリデータから、「A」を推測するのは難しいです。cのダイジェストならば数万回程度の試行で元の文字列が分かるかもしれないけど、上記のd1とd2は「不定数の文字列のダイジェスト」なので、ブルートフォース攻撃の必要アタック数は桁違いに高くなります。決定者がAないしはsを変えてしまって、同一のダイジェスト値を得るのは、ほぼ無理と考えれば、不正が入る余地はありません。もちろん、sha1ではなく、sha512などを本番では使うべきでしょうね。

sもcも決定前には未公開なので、参加者は偶然に当ててしまった場合でも、当たったかどうかは分からないはずです。

なお、抽選者が3人以上の場合、「文字コード上で一定以上の距離を空ける」というルールは必要でしょうね。例えば、ある人が「F」と言ったとします。別の2人が「E」と「G」と宣言して、最初の人の当せん確率を限りなく0にすることが可能です。つまり、別の2人が結託している状況です。まあ、これは監視されている上なので、普通はやらないとは思いますが、厳密にはそのルールが必要かと思います。

抽選者にとって、確率は同一になるかどうか? ここはアイデアが固まっていません。抽選者にとってはcは未知なので、Unicodeのコード空間上、どこにあるかは分からないという点では均一なのかもしれません。しかし、cが空間の端の場合とど真ん中の場合で抽選者に影響はあるのかどうかという点も気になります。cを複数設定して、参加者の1文字は一番近いcを採用するといったようなランダム化は必要なのかもしれません。しかし、この問題は、ちょっと難しそうなので、cは1つということにします。

いかがでしょうか?

VirtualBoxのVMのディスク容量を増やす

INTER-Mediatorの試用や学習用にVMでの配布を始めていますが、INTER-Mediator以外にもこのVMは便利に使えています。サーバアプリケーションを動かしたいけど、サーバを立てるほどのこともないといった用途はよくありますよね? そんなときはVMで動かせばいいわけです。今年になってから、Railsで作られたアプリの稼働用、それから古いMoodleを動かす環境というように、2回もVMを作りました。しかし、作ったドライブの容量が少ない場合に、容量をアップするという方法がなかなか完了せず苦労したので、やり方を書いておこうと思います。以下、VirtualBoxはVer.4.3.26です。

INTER-Mediator搭載のVM

INTER-Mediatorを組み込んだVMは、Ubuntu 14.04 Serverをベースに、Apache2、PHP5、MySQL、PostgreSQL、SQLiteを組み込み、即座にサンプルを動かしたり、あるいはコードを入れてみたりということができるものです。こちらのページからダウンロードできます。ページに記載の通り、「仮想アプリライアンスのインポート」を行い、ネットワークアダプタをホストオンリーネットワークが使える状態にしておくことで、原則として即座に利用できます。

VirtualBoxのVMディレクトリ(OS Xだと~/VirtualBox VMs)にINTER-Mediator-Serverフォルダが作られ、その中にあるINTER-Mediator-Server-disk1.vmdkというのが、OSなどがインストールされたディスク装置のファイルということになります。

このディスクは6.3GBです。INTER-Mediatorの試用では、別に少なくなることはまずないと思いますが、ここにいろいろインストールしたり、データを入れたりするとする、もっと大きくしたいと考えます。

ボリュームの容量アップの流れ

ボリュームサイズをアップするには、全体に定期には次の3つの作業が必要かと思われます。かなり試行錯誤しましたが、この流れで行けそうです。

  • 作業1:ディスク装置のファイルの増量
  • 作業2:追加した領域をデバイスに組み込む
  • 作業3:デバイスに組み込んだ領域をOSで使えるようにする

もし、もっと、違うやり方があるのなら知りたいのですが、これだけの作業が必要になる模様です。

作業1:ディスク装置のファイルの増量

ディスク装置のファイルは、VirtualBoxで見ると、たとえば8GBなどのサイズが見えています。この上限サイズは越えられないサイズなのですが、それをまずもっと大きな値にしたいと考えます。ここで、VirtualBoxはさまざまな形式のディスク装置ファイルをサポートしていますが、vmdkファイルはサイズの変更ができません。やろうとしてもエラーになります。そのため、まず、vmdkファイルをvdiファイルに変換します(サイズ変更可能な別の形式でもかまいません)。VirtualBoxを使って行うには、「ファイル」メニューにある「仮想メディアマネージャー」を利用して、INTER-Mediator-Server-disk1.vmdkと同じフォルダに、INTER-Mediator-Server-disk1.vdiファイルを作れば良いでしょう。コマンドラインであれば、以下の様に入力します。カレントディレクトリを移動してコマンドを入れます。VirtualBoxコマンドがきちんと通るはずです。

cd ~/VirtualBox\ VMs/INTER-Mediator-Server
VBoxManage clonehd INTER-Mediator-Server-disk1.vmdk --format vdi INTER-Mediator-Server-disk1.vdi

この後、次の様なコマンドを入れて、ファイルのサイズを50GB程度にしておきます。このコマンドはすぐに終わります。–resizeはメガバイト単位のサイズを記述します。

VBoxManage modifyhd INTER-Mediator-Server-disk1.vdi --resize 51200

その後、ツールバーの「設定」をクリックするなどして、該当するVMの設定を変更します。ダイアログボックスのツールバーで「ストレージ」を洗濯して、「コントローラー: SATA」の下位にあるディスクを、INTER-Mediator-Server-disk1.vdiに切り替えます。右側の「属性」のポップアップメニューのさらに右にあるアイコンをクリックして、「仮想ハードディスクファイルの選択」を選択し、そしてファイルを選択すれば良いでしょう。SATAコントールの分類に、INTER-Mediator-Server-disk1.vdiが追加されればいいのですが、ダイアログボックスが小さくて確認できないのがちょっと難点です。「仮想的なサイズ」が50GBになっていることで、まずはディスク装置のファイルのレベルでサイズがアップしていることを確認します。

shot0008

作業2:追加した領域をデバイスに組み込む

ここまでの作業では、50GBのサイズのファイルの中に、6.3GBのボリュームがあるという状態です。未使用領域を、ボリューム領域として利用するために、作業2を行います。ここで、対象ボリューム自体のマウントを解除して作業するために、別のボリュームで起動します。ここでは、Ubuntu GNOMEのライブCDを使って起動しました。ダウンロードはこちらのページから行いました。

そして、そのライブCDのイメージをVMにマウントします。「設定」のダイアログボックスの「ストレージ」にある「コントローラ: IDE」の下位の項目が「空」になっているので、選択した上で、属性のポップアップメニューの右側のアイコンをクリックして「仮想CD/DVDディスクファイルの選択」を選択し、ダウンロードしたライブCDのイメージを選択します。規定値では、SATAよりもIDEにある起動可能なボリュームが優先されるので、この状態で起動すればライブCD側のシステムで稼働します。なお「Live CD/DVD」のチェックは入れなくても使えました。

shot0009

 

ライブCDで起動すると、最初に次の様な画面になります。ここで、左側の「Ubuntu GNOMEを試す」をクリックします。マウスも、特に何もせずともきちんと動作しています。

shot0010

しばらく待つとデスクトップ画面になります。左上の「アクティビティ」をクリックして少し待ちます。

shot0011

続いて、左側のアイコンが出てきます。一番下の「アプリケーションを表示する」の部分をクリックします。

shot0012

 

続いて、アイコンがたくさん出てくるので、Gpartedをクリックします。

shot0013

パーティションを変更するツールが起動します。最初、少し時間がかかります。最初から、該当ボリュームが選択されていますが、選択されていない場合には、ツールバー右端にある部分でボリューム選択ができます。

ここで、一覧を見て明らかなように、/dev/sda5が、実際のボリュームになっていて、その上位が/dev/sda2のファイルシステムとういことになります。ここで、鍵のアイコンがあるのは、利用中であることを示します。ここで、マウンドの解除などの作業をするのですが、/dev/sda2の方は何もメニューが選択できません。一方、/dev/sda5の方は、右ボタンクリックすると、「Deactivate」という項目があるのでそれをクリックします。これで、設定の変更ができる状態になると言えばいいのでしょうか。

 

shot0014

Dectivateすれば、今度は、/dev/sda2の方を右クリックして、「リサイズ/移動」を選択します。

shot0015

 

次の様なダイアログボックスが表示されます。ここでは、シアンカラーのボックスが全体の中の利用であり、シアン色の線のうち右側をドラッグすることで、右端の位置を広げれば、/dev/sda2の死サイズを50GB近くまでアップできます。ドラッグして広げたら「リサイズ/移動」ボタンをクリックします。

shot0016 shot0017

次は、/dev/sda2の内部にある/dev/sda5です。こちらが、OSで見えているボリュームの実態と言えばいいでしょう。こちらの項目を右ボタンをクリックして、「リサイズ/移動」を選択します。ダイアログボックスで同様に、最大まで幅を広げて「リサイズ/移動」ボタンをクリックします。

shot0018 shot0019

 

こうして、領域を広げ終わったら、ツールバーにあるチェックマークをクリックします。これは、設定作業が終わり、実際のディスク関連作業に進むことを意味します。

shot0020

設定変更の確認をします。最初のダイアログボックスでは「適用」をクリックします。作業が終了するとその旨を表示するので、「閉じる」ボタンをクリックします。

shot0021 shot0022

LiveCDを終了するには、画面右上の電源ボタンのような箇所をクリックして表示されるパネルで、やはりMac等で見られる電源ボタンのアイコンをクリックします。その後に「電源オフボタンをクリックします。ただし、実際には電源オフの状態にならないので。VMを適当に止めます。

shot0023 shot0024

 

ここで、「設定」の「ストレージ」で、コントローラー: IDEの方のライブCDをマウントする設定を「空」にします。項目を選択して、属性のポップアップメニューの右のアイコンに表示されるメニューから、「仮想ドライブからディスクを削除」を選択します。

作業3:デバイスに組み込んだ領域をOSで使えるようにする

VMを起動して、ルート権限が可能なユーザでログインをします。以下は、行頭の$がプロンプトで、太字が実際に入力するコマンドです。最初、dfコマンドでサイズを見てみますが、6.5GBとなっています。まだ、実際にボリュームとして使えるサイズは変化ありません。ここで、デバイス名が「/dev/mapper/inter–mediator–server–vg-root」であることをチェックします。引き続くコマンドでこのデバイス名を指定します。そして、lvextendコマンドを使って、サイズを可能な限り大きくし、resize2fsコマンドを使って実際にサイズを変更します。その後にdfコマンドを見れば、48GBまでサイズが増加しました。

$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/inter--mediator--server--vg-root 6.5G 2.1G 4.2G 33% /
none 4.0K 0 4.0K 0% /sys/fs/cgroup
udev 487M 4.0K 487M 1% /dev
tmpfs 100M 436K 99M 1% /run
none 5.0M 4.0K 5.0M 1% /run/lock
none 497M 0 497M 0% /run/shm
none 100M 0 100M 0% /run/user
/dev/sda1 236M 66M 158M 30% /boot
$ sudo lvextend -l +100%FREE /dev/mapper/inter--mediator--server--vg-root
 Extending logical volume root to 48.76 GiB
 Logical volume root successfully resized
developer@inter-mediator-server:~$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/inter--mediator--server--vg-root 6.5G 2.1G 4.2G 33% /
none 4.0K 0 4.0K 0% /sys/fs/cgroup
udev 487M 4.0K 487M 1% /dev
tmpfs 100M 436K 99M 1% /run
none 5.0M 0 5.0M 0% /run/lock
none 497M 0 497M 0% /run/shm
none 100M 0 100M 0% /run/user
/dev/sda1 236M 66M 158M 30% /boot
$ sudo resize2fs /dev/mapper/inter--mediator--server--vg-root
resize2fs 1.42.9 (4-Feb-2014)
Filesystem at /dev/mapper/inter--mediator--server--vg-root is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 4
The filesystem on /dev/mapper/inter--mediator--server--vg-root is now 12782592 blocks long.

$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/inter--mediator--server--vg-root 48G 2.1G 44G 5% /
none 4.0K 0 4.0K 0% /sys/fs/cgroup
udev 487M 4.0K 487M 1% /dev
tmpfs 100M 436K 99M 1% /run
none 5.0M 0 5.0M 0% /run/lock
none 497M 0 497M 0% /run/shm
none 100M 0 100M 0% /run/user
/dev/sda1 236M 66M 158M 30% /boot

参考にしたサイト

以下のサイトを参考にさせてもらいました。

  1. http://www.virment.com/extend-virtualbox-disk/
  2. http://qiita.com/niwashun/items/f71b0b805a6f97b514ec
  3. http://nori3tsu.hatenablog.com/entry/2013/11/23/114400

3つ目のサイトには、ここでの作業1〜3が書かれていますが、最初に見たときには手順2については意味がわかりませんでした。手順2については、上記の1のサイトが詳しく書かれていますし、手順1については上記の2のサイトが詳しくかかれています。

Swift: アウトレットを含めたプロパティで Optional “?” を積極的に使う

Swiftの特徴として、クラス名のみで示す型では、nil値を許さないことです。一方、?や!でnil値を許す変数の定義などができます。それぞれ、OptionalとUnwrapped Optionalと呼ばれています。

var myLabel1: UILabel = UILabel(frame: ...) // nilを許さないので何か入力しないといけない
var myLabel2: UILabel?
var myLabel3: UILabel!

ここで、アウトレットについて考えてみます。アウトレットは、Interface Builderで線を引くなどして参照先のオブジェクトが指定されていれば、ストーリーボードのロード時などに自動的に参照先が設定されます。しかしながら、オブジェクト生成直後では値が確定しないので、OptionalかUnwrapped Optionalのどちらかにしないといけません。

ここで、Appleのドキュメントでは、Unwrapped Optionalにすべきと書かれており、Xcodeでアシスタントエディタで、Interface Builderのオブジェクトからctrl+ドラッグでコード上にドロップしたときに作られるプロパティは、自動的にUnwrapped Optionalになります。もし、アウトレットをOptionalで定義すると、Optional Binding、つまり、

if let aLabel = myLabel2 {
    x = aLabel.text
}

のように、ifで囲う必要があります。そうなると、Objective-Cで作られたプログラムを移植するようなときに、流れが変わってしまい、作業効率が悪くなるということもあると思います。こうした点を総合して、AppleはUnwrap Optionalをアウトレットの推奨形態にしていると思われます。

しかしながら、Optionalか、Unwrap Optionalかは、仕組みの上ではどちらでも構わないのではないでしょうか。つまり、nil値を許せばいいのです。また、nil値になる状態での不要な処理を避けるという意味では、明示的にOptional Bindingを記述することになるので、不都合はなく、むしろ好都合かもしれません。余分に記述するのが目障りということもあるかもしれませんが、予防的な措置であれば、むしろ歓迎すべきです。これらの点は、個人的な嗜好ではありますが、むしろ評価すべきです。そもそも、Swfitは安全な言語ということが謳い文句だったはずです。であれば、Optionalをもっと積極的に使うべきではないでしょうか。

Optionalにしたら、面倒と思うかもしれません。たとえば、以下はいずれも、エラーになります。tagというプロパティはないとエラーでは記述されています。

myLabel2.tag = 3
let m = myLabel2.tag

しかしながら、若干の誤差を許していただければ、基本的には非常に緩いルールでこれらのエラーは逃れられます。それは、Optionalなプロパティが左辺にあるときには、単に、変数名に?をつけるだけでいいのです。右辺で利用するときには原則としてバインディングを行います。

myLabel2?.text = "aaa";
if let label = myLabel2 {
     let m = label.text
}

これだけのことでいいのです。これだけのことで、より安全になるのであれば、手間をかける価値はあるのではないでしょうか? アウトレットを含めたプロパティは、Optionalで定義する〜このルールでも構わないと考えます。

実は深刻な“カミFileMaker問題”

(2015/2/12 0:28更新:Facebookでの杉原さんの意見も反映させました。2015/2/13 17:00更新:Facebookでの日高さんの意見も反映させました。ありがとうございます。)

ネ申ExcelはExcelだけの問題か?

Excel方眼紙や罫線優先のワークシートなどなど、Excelで作った文書のうち、見栄えを整えることを主眼として作ってしまったことにより後からデータの活用ができなくなってしまった文書などを「ネ申Excel」と総称されています。三重大学の奥村先生の論文にまとめられています。良し悪しの問題は難しいのですが、例えばネ申Excelな記入用紙はWebフォームにすれば、即座に一覧が作られるなど、より利便性が高い代替え手法が明らかに存在するような場合があります。そのようにExcelにこだわる余り、自身の効率化を損なうのはもちろん、入力をするなどの利用者の利便性を著しく損なう状態になるのは避けるべきだと言えるかと思います。

同じような問題は他のソフトウエアにも、サービスにも存在します。ここで、データベースソフトの話をしたいのですが、そうなると、AccessかFileMakerかということになります。自分自身の問題でもあるので、馴染みの深いFileMakerを取り上げ、「カミFileMaker問題」として扱います。あえて、カタカナの「カミ」にしたのは、大昔「ファイルメーカー」と呼んでいたFileMakerへのトリビュートです。FileMakerのレイアウト機能は、帳票を高い自由度で作成できることから、従来の紙ベースで行われてきた業務をそのままデータベース化できる強い動機付けになっています。同じような仕様がAccessにもあることはありますが、プロの開発者からデータベース利用者までがみんなしてテーブルを定義してレイアウトをいじるというのはFileMaker市場の大きな特徴だけに、「カミFileMaker問題」が浮き彫りになると考えられます。

「カミFileMaker問題」とは?

ここで問題の定義として、紙の帳票類をそのままデータベース化してしまうことで発生する問題とします。もちろん、帳票をそのままデータベース化するだけでも、例えば、共有ができることや、印刷を省きパソコンやタブレットで閲覧することでの即時性などのメリットは発生します。最初の帳票ができたとき、「これはいい!」と誰もが思います。だけど、いくつも帳票を作るに従って問題が顕在化します。

紙が画面に変わっただけ?

帳票をデータベース化すると、どうしても従来のワークフローが結果的に踏襲されることになります。むしろ、ワークフローは出来上がっているのだから、それを電子化すればよりスムーズという、あまり根拠のない理屈を信じて突き進みます。その結果、まず、電子化されているのに「転記」という作業や、帳票の生成や破棄、あるいはステータス更新という動作に「手作業」が入ってしまいます。今までは紙だったので、それはやって当たり前でした。しかしながら、電子化するときに、そこでの自動化を深く考えなかったとしたら、同じことを端末を操作してやらないといけません。パソコンを扱うのが弱いとか、ストレスが高い人は、そこでまずはつまずくことになります。

紙にはなかったリンク情報はどうなった?

それでも仕事をみんなでがんばってこなしたとします。そして、さまざまな帳票レコードが、1つのエンティティに対して複数積み重なることにより、新たな問題が発生します。ある帳票と別の帳票が結びついている場合はよくあります。1対1や1対多ということもあるでしょうし、多対多もあります。紙で作業していると、その結びつきを人間がやっていることがあります。業務上の常識から、誰もが自動的に異なる2枚の帳票に関係がある、関係ないということを判定できるのです。この作業をパソコンの画面上で人間が行うのは非常に面倒です。紙のファイルを何冊か机に並べて対応するものを開けて突き合せるような手軽さは、今のパソコンやタブレットではまだまだ無理です。

もちろん、相手の文書IDを記録するなどすればいいのは当然ですが、気付いた時には遅かったということもあります。また、そのような「リンク」の重要性が、問題が発生しても気付かない、あるいは気付かないふりをするということあるでしょう。かくして、対応する文書の手がかりをかなり強引に引っ張り出すことになります。「同一顧客で、この帳票より前のもののうち、最新のもの」などといったリレーションシップを組むなどします。それでも、運用は可能かもしれませんが、対応が取れなくなる可能性が0ではなく、小さいながらも0%よりも大きくなります。また、業務で発生するイレギュラーなケースを忘れていると、ミスにつながります。ビジネスロジックでほぼ解決できるものでも、より単純な解決法があるのなら、単純な方が安定しているのは言うまでもありません。

矛盾する2つのフィールドの関係

さらにこんな例もあります。紙の帳票から、別の帳票に転記するとき、人間が転記するといいように解釈していたのですが、それを電子化すると、機械的に転記できないような場合が発生します。つまり、それぞれの帳票のスキーマに、論理的な不一致が発生してしまうのです。もっとも身近な例では、入力帳票が「氏名」で、それに対応する別の帳票が、姓名別々のフィールドのような場合です。こうしたスキーマの不一致は、紙の帳票をそのままデータベース化すると、気が付いたら行っていたということになります。また、転記なのか参照なのか、ここの考え所を全部転記することにしてしまったことで、かえって手作業が増えることもあります。

この問題は、突き詰めると、データベースのスキーマを検討するときに必ず必要となるその業務ドメインのモデル化が不正確なのです。フィールドとテーブルを定義すれば良いというのはFileMakerの機能のことで、設計者は他に考えないといけないことはたくさんあります。データ間の連携はもちろんだし、これについてはリレーションシップで定義することになります。しかしながら、FileMakerの機能に見えないこととして、あるデータは転記して見えるようにするのか、参照して見えるようにするのかということを考える必要があります。これは、FileMakerのテーブル設計のダイアログボックスでは明示化されていないものの、極めて重要な設計上の決まりごとになります。

データベースには、データベースに合った設計を

こうした問題は、昔からありますが、FileMakerは手軽だからこそ、陥る罠でもあるといえます。あえて、「カミFileMaker問題」として、問題を浮き彫りにすることで、より多くの方が意識できるようになればと考えました。もちろん、プロの方々もこうした失敗を重ねてきていて、いろいろなノウハウをお持ちでしょうし、長年使ってきた人も同様です。例えば、受託開発のとき、導入経験がないお客さんの要望をそのまま構築すると、「カミFileMaker問題」の宝庫です。プロや熟練者は、そこでしっかりとお客さんの要望を受け入れつつ、問題の発生を抑える手立てを考えないといけません。言われた通りにやればいいというのは間違いで、そのようなやり方を続けてきた結果使われないシステムを納品することになり、信用を落とすことになるのです。この問題を認識し、きちんと説明して方向付けをする必要があるのは、プロや熟練者の皆さんなのです。決して、素人を茶化すための問題定義ではないことは最後に強調したいと思います。

以下にまとめておきます。もちろん、みなさんの意見や表現の向上も大歓迎です。

「カミFileMaker問題」の発生

  • 帳票類をそのままFileMakerのデータベースで再現する電子化

「カミFileMaker問題」による起こりがちな結果

  • 一見すると効率化されたように見えるが、帳票作業とは異なる事務作業等が増えているなど、実は効率化されていない
  • 機械的に行えるデータの連携や解釈などが、データベースの仕様に含まれず、そうした作業も人間が行う必要がある
  • 2種類の帳票でスキーマが異なり、論理的には転記ができず、人間が解釈してつどつど修正しないといけなくなる
  • 紙が減ることの効率性だけに注目した結果、システム運用コストに気が回らず、気が付いたらかえってコスト高になってしまっていた
  • データベーススキーマの設計において正規化という点が考慮されず、データ解析に支障をきたしたり、あるいは解析自体が不可能な、品質の低いデータを蓄積してしまう。

「カミFileMaker問題」の本質

  • コンピュータ作業に最適なワークフローを検討し、転換しないために、結果的にさほどの効率化もされない
  • データ間のリンク構造を記録できないスキーマ上で、ビジネスデータが蓄積され、どうしようもなくなり、最悪はデータ活用に制限が出てきてしまう
  • データベースのスキーマを単に「紙にあった項目」のみで認識することで、ドメイン自体を表現するモデルの精度が低くなってしまう