実は深刻な“カミ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問題」の本質

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

iOS 8のデバイスの回転可能な方向の設定

iOSのネイティブアプリケーションを開発するとき、Xcodeのビルドするアプリケーションの設定のDeployment InfoにあるDevice Orientationにあるチェックボックスの設定が重要です。iOS 6以降、この設定がそのままInfo.plistファイルに設定され、アプリケーションはその設定に応じた動きをします。このDevice Orientationは、その方向にデバイスを向けたときに、画面が回転して、画面の上端が実際に上に見えるようになるということを示しています。通常、Upside Downつまり、ホームボタンが上に来る縦長の状態にしたときには、回転は行われないということになっています。つまり、Upside Downの方向にしたときには、写真は90度あるいは180度傾いて見える状態のままになるということです。

shot9897

前の図のDevice Orientationの設定は、iOS 7までは、iPhoneとiPadで別々でした。それぞれで回転可能な方向を決めることができました。iOS 8つまりXcode 6からは、その上のMain InterfaceがiPhoneとiPadで共通になっているので、Device Orientationも共通かと思ったら、Xcode 6.1.1で作ったプロジェクトでは、iPhoneとiPadのDevice Orientationの設定が、別々に定義された状態になっています。以下は、Infoをクリックして見たところで、Supported interface orientationが、iPhone向けの設定であり、General(前の図)で見えている設定です。それに加えて、Supported interface orientation (iPad)もあり、4つの方向がチェックされています。このiPadの設定はGeneralには見えていません。したがって、General側で設定をどう変更しようと、iPadの場合はこのInfoで見えている設定に従うために、すべての方向に回転ができるようになります。

shot9898

ちなみに、iPhoneとiPadの両方の設定が必要なら、Generalのパネルに双方の設定ができるようにすべきです。もしかして、iPadのDevice Orientationの設定は間違えて紛れ込んでいるのでしょうか? ここで、iPad側の設定を削除したいなら、Supported interface orientation (iPad)の項目を選択し、項目名の右に見える、丸にマイナスの部分をクリックします。これで削除できます。

shot9899

ここで、まず、Info.plistに項目が存在するかどうかによって、どのように稼働するのかを見てみます。これを見る限り、既定の動作をさせるには、要するに、これらのInfo.plist項目はそもそもない方が素直な設定の気がします。既定の動作をさせないときに、項目を定義するというのが理にかなっているような気もします。

Supported interface orientation Supported interface orientation (iPad) 回転の動作動作
設定なし 設定なし iPhoneはUpside Down以外が可能、iPadはすべての方向へ可能、つまりデバイス既定の動作
設定あり、要素なし 設定あり、要素なし
設定あり、要素あり 設定なし iPhoneもiPadも、iPhone側の設定に従う
設定あり、要素あり 設定あり、要素あり iPhoneはiPhoneの設定に、iPadはiPadの設定に従う

Supported interface orientationにチェックが入れば、その方向で回転するというのが概略の説明ですが、正しくは1つの場合だけ回転しません。回転しない例が、iPhoneの場合のUpside Downです。つまり、このチェックを入れるだけでは、その方向に回転しないのです。つまり、デバイスの規定値の方が優先順位が高いとみていいでしょう。

では、iPhoneでもUpside Downを可能にするにはどうすればいいか? UIViewControllerにあるsupportedInterfaceOrientationsメソッドにヒントがあり、このメソッドをオーバーライドするのがポイントです。このメソッドは、UIViewControllerであらかじめ定義されており、ビットマスク値を返します。ホームボタンの位置が上下左右のそれぞれに対応する4ビット分のマスク値を返します。UIViewControllerに実装されているメソッドだと、iPadだと4つのビットがすべて1、iPhoneだとUpside Downを除く3つのビットが1になっています。実際に回転していい方向は、Info.plistの設定と、supportedInterfaceOrientationsメソッドの返り値をビットANDをして、残ったビットが回転をしてもいい方向になります。なので、Info.plistの設定で全部にチェックされていても、iPadでは全方向に回転は可能ですが、iPhoneでは、Upside Downはマスク設定で0になっていて、キャンセルされてしまうのです。

それでは、自分で定義しているUIViewControllerの継承クラスで、supportedInterfaceOrientationsメソッドを実装して、全部のビットが1になっている値を返せばいいではないかと考えるところです。しかしながら、この回転の判断は、いちばんルートにあるビューコントローラで判定されます。Single View Applicationで作ったようなプロジェクトだと、いきなり自分で定義しているビューコントローラのクラスがルートにあるので、そこでメソッドを組み込めばいいでしょう。以下のコードに追加されているメソッドを加えます。しかしながら、Master-Detail Applicationのテンプレートで作ったプロジェクトでは、例えば、MasterViewControllerやDetailViewControllerクラスにsupportedInterfaceOrientationsメソッドを作ってもうまくいきません。これらのクラスのオブジェクトはルートのビューコントローラではないからです。Master-Detail Applicationで作ったプロジェクトのストーリーボードファイルを見れば、ルートはUISplitViewControllerクラスのオブジェクトです。そこで、以下のような、UISplitViewControllerクラスを継承したMyRootViewControllerクラスを定義します。そして、メソッドにはsupportedInterfaceOrientationsだけを定義すれば良いでしょう。returnの後のenum型の値が、すべての方向のビット値が1に設定されたものです。返り値がIntなので、rawValueプロパティを使ったり、Int型に変換するなど、Swiftではちょっとややこしいですね。

shot9900

そして、ストーリーボードのUISplitViewControllerクラスのオブジェクトを選択します。右側のユーティリティエリア上部では左から3つ目のアイコンを選択して、アイデンティティインスペクタを表示して、Classのところで、前の図にあるMyRootViewControllerを選択します。

shot9901

こうしておけば、Master-Detail Applicationで作ったプロジェクトでも、iPhoneでUpside Downの方向でも回転ができるようになります。もちろん、プロジェクトのDeployment Infoの設定にあるDevice Orientationのチェックボックスは4つともオンにしておく必要があります。

NELog.logに大量の書き込みはAdobe Creative Cloudの問題

珍しく、Adobe関連の話題ですが、いつも通りトラブルシューティングです。

ある日、OS X Yosemiteでコンソールを開くと、~/Library/LogsにあるNELog.logおよび「NELog 11-21-2014 02-58-57.log」みたいな日付つきのログが大量にあることを発見しました。しかも、毎分40KBあまりも出力している。1日50MBくらいだけど、消している時間があるので30MBくらい? 日付を見れば、何ヶ月か前からあるようで、数ギガくらい使っていそうな勢いです。しかし、なんでしょうね?このNSLog.logの正体は? 中身を見ると、こんな感じで、ちょっと手がかりがありません。SQLite関連のエラーが目に付きます。

01/12/15 03:28:07:157 | [WARN] | | ANSClient | | NELocalDataManager | | | 9983 | Not able to get the settings from local db for key (KLastNotificationResponseOlderTimestamp). Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:07:158 | [INFO] | | ANSClient | | NEGlobalData | | | 9983 | Unable to get last Notification Response Timestamp. Fetching notifications from server epoch
01/12/15 03:28:07:286 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to get the settings from local db for key (KLastNotificationResponseOlderTimestamp). Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:07:286 | [INFO] | | ANSClient | | NEGlobalData | | | 9984 | Unable to get last Notification Response Timestamp. Fetching notifications from server epoch
01/12/15 03:28:07:287 | [INFO] | | ANSClient | | NEGlobalData | | | 9984 | Mode is online
01/12/15 03:28:08:159 | [WARN] | | ANSClient | | NELocalDataManager | | | 9983 | Not able to get the settings from local db for key (KLastNotificationResponseNewerTimestamp). Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:073 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to insert the settings in local db. Error code - 0, and Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:073 | [INFO] | | ANSClient | | ConfigurationManager | | | 9984 | Unable to save parameters in Database. Default Configurations are set
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to update create new notification in local db. Error code : 0, and Error msg : Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NENotificationsProcessor | | | 9984 | Unable to create notification for notification ID: 8c1f6505-824e-43e9-8a57-15ad8f47ba7c
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEDataFetcherAndProcessor | | | 9984 | Unable to complete Notification process operation
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to insert the settings in local db. Error code - 0, and Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEGlobalData | | | 9984 | Unable to store last Notification Response Timestamp
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to insert the settings in local db. Error code - 0, and Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEGlobalData | | | 9984 | Unable to store last Notification Response Timestamp
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to insert the settings in local db. Error code - 0, and Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEGlobalData | | | 9984 | Unable to store last Notification Response Timestamp
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEDataRequestHandler | | | 9984 | Unable to get Notification Data from the requested timestamps
01/12/15 03:28:09:164 | [WARN] | | ANSClient | | NELocalDataManager | | | 9983 | Not able to get the settings from local db for key (KLastNotificationResponseNewerTimestamp). Error msg - Sqlite Error: The database disk image is malformed

手がかりがまるでないのですが、まず見つけたのはこのドイツ語のBBSです。ドイツ語はよくわかりませんが、これから、Adobe CCが出力することを見つけました。そして、このNELog.logを開いているプロセスをlsofでチェックして、そのプロセスIDからCreative Cloudアプリケーション、つまり、メニューバーにある無限大のみたいなアイコンのアプリケーションであることがわかります。

$ lsof | grep NELog.log
Creative   3443 msyk   66w     REG                1,4   2876129  3280800 /Users/msyk/.Trash/NELog.log
$ ps -p 3443
  PID TTY           TIME CMD
 3443 ??         0:55.59 /Applications/Utilities/Adobe Creative Cloud/ACC/Creative Cloud.app/Contents/MacOS/Creative Cloud

ここまでくると、「adobe creative cloud nelog」みたいに検索ができるわけで、そうすると、ここの先のようなメッセージがあり、そこに書いてあることをヒントにして、解決ができました。要するに設定ファイルのフォルダを作り直させれば良い模様です。手順は次のようなものです。

  1. Creative Cloudアプリケーションを終了します。メニューバーにあるアイコンをクリックしてウインドウを表示し、右上にあるギアのアイコンをクリックして表示されるメニューから「終了」を選択します。
    shot9808
  2. 以下のようにターミナルからコマンドを入力して、設定フォルダを一旦空にします。念のため、現状を別のフォルダ名にバックアップします(別にターミナルでなくてもよく、Finderで作業してもいいです)。
cd "~/Library/Application Support/Adobe"
mv OOBE OOBE_old
  1. アプリケーションフォルダにあるAdobe Creative Cloudフォルダの、Adobe Creative Cloudアプリケーションをダブルクリックして起動します。

これで大量のログ吐き出しはなくなりました。NELog.logは1分ごとに数行程度の出力をしていますが、まあ、それは無視していいくらいかと思います。なお、記憶しているAdobe IDは消えてしまうようで、その再入力は必要です。

なお、Creative Cloudは他にoobelib.log、ACC.log、PDApp.logというログもけっこう大量に吐き出しますが、まあ、NELog.logほどではありません。こちらは、アプリ起動時に大量のログを書き出します。数ヶ月で100MB程度ですが、これらについても日付のついたファイルは不要と思います。

[IM] 2015年に向けての組織化を考える

INTER-Mediatorの開発を始めてから、ちょうど丸5年くらいが経過しました。いろいろあったものの、一貫して、新居雅行個人のプロジェクトのような形態だったのですが、エミックさんをはじめとしていろいろな展開が始まっており、そろそろ個人プロジェクトではなくそうかと思っています。かといって会社作るということではありません。こうしたプロジェクトは組織そのものも、プロダクツに見合ったものをコミュニティプロセスで発見的に開発しないといけないと考えています。

まず、INTER-MediatorがMIT Licenseであり、オープンソースである点はそのままにしますが、クレジットは「INTER-Mediator Development Project」にしようと考えています。加えて、その開発そのものをマネージメントしている「INTER-Mediator Directive Committee」が存在するという形態にしたいと思います。人数少ない中、組織ばっかり作るかという話もありますが(笑)、先々の方向性を決めるINTER-Mediator Directive Committeeがあって、実際の開発はINTER-Mediator Development Projectがやっているという状況とみなすのです。本来は、さらにINTER-Mediator利用者としての開発者やシステム開発を行うエンドユーザもいるのですが、今のところはこれらのみなさんに対する「組織」は作らないで、時機が来るのを待ちたいと思っています。

「INTER-Mediator Development Project」のミッションは、INTER-Mediatorの継続的な開発を進めることです。これは明確ですね。コードに書くクレジットはこれになります。また、GitHubの主体も「INTER-Mediator Development Project」にするつもりです。GitHubは現在新居のアカウント上にありますが、「組織」という仕組みがあるので、それに移行するつもりです。「INTER-Mediator Development Project」のメンバーは、Contributor、Special Thanks、そしてcloneやforkした皆さんというゆるい定義にしたいと思います。つまり、集まっている方々はプロジェクトに関わっているというみなしをするという組織であり、言い方を変えれば求心力はないものの影響力はあるというところでしょうか。今の所、動いている唯一のコミュニティであるFacebookのグループは、「INTER-Mediator Development Project」の活動の一貫であるということにします。

「INTER-Mediator Directive Committee」のミッションは、INTER-Mediatorの継続的な発展を促す活動を行うということです。こちらは、立候補や推薦と同意などを含めて、メンバーが誰であるのかということを明確にします。したがって、入会と退会を明確にする必要があります。「INTER-Mediator Directive Committee」は役割を明確に定めることと、必要に応じて担当者を設定するものとします。役割は、次のようなものです。

  1. INTER-Mediatorの今後の開発計画を立てて、方針を示す(例えば、半年に1度、ドキュメントをリリースする)
  2. Webサイトを運用する
  3. GitHubでのpull requestに対処する
  4. 普及のための活動(勉強会やもくもく会など)を主催、あるいはリードする
  5. トレーニングマテリアルを整備し、提供する

5についてはすでに私自身がお金をいただきながらやっていることですが、位置付けは普及活動になるかと思います。2についても私がやっていますね。1については、Project側の意見も吸い上げないといけませんが、決定して声明を出すのはCommiteeの役目と考えています。

現在のWebサイトは3つのドメインで同じものを表示していますが、以前に松尾さんから想定されていたように、.orgはCommitee、.infoはマニュアル、.comは総合的な紹介サイトということにしようと考えています。人や作業が増えた時に、分割されていると、作業分担がしやすいのではないかと思っています。この作業は、さっそく、2015年前半の作業プランに入れるべきかもしれません。

そういうことで、大きな意味では「Committeeを作り、名乗ります」ということになりますし、それだけといえばそれだけですね。会則とかややこしいことは初期段階では不要かと思います。私がChairmanですということでもいいのですが、役割分担ではないroleの割り当ては、Committeeの人数が増えてからにしようと思います。

Committeeメンバーについては、松尾さんには入ってもらいたいと思っています。エミックさんではFM Publisherを開発して提供しており、INTER-Mediatorの動向は自社ビジネスに少なからず影響するわけですから、言い換えればコントロールする側に立つ意味もあるかと思います。また、立候補、推薦等も受け付けますが、本人が嫌がった場合には当然ながらメンバーとは言えないかと思います。みなさんの中でも立候補される方はご連絡ください。もちろん、開発関係の方の参加が想定されますが、開発に関係ないもののこうしたコミュニティにより深く関わってみたいという方の参加も歓迎します。

言語ごとのiOSシミュレータを用意する

Xcodeでシミュレータが見えなくなるトラブルが発生しましたが、復旧過程で「機種ごとだけでなく、言語ごとにデバイスを用意する」ということができることに気づきました。その方法を紹介しましょう。

いろんなバージョンのXcodeを行き来しつつ、ユーザも切り替えながら使っていることもあるせいなのか、ある日、XcodeでiOS向けのプロジェクトで、iOSシミュレータがまったく選択できなくなりました。現在は、Ver.6.1.1が公開されている中で最新ですね。

shot9502

ここで見えるシミュレータは、WindowsメニューのDevicesで確認できます。やっぱりみんな消えています。なぜかはわかりません。

shot9503

シミュレータを追加するには、左下の+部分をクリックします。すると、次のようにシートが表示されて、名前や機種、iOSのバージョンなどを指定してシミュレータを追加できます。全部消えてしまっても、もちろん、こうして追加すればOKです。

shot9504

ここで、ふと「同一の機種は追加できるのか」と思ってやってみたらできました。そこで、さらに思いつきました。たとえば、iPhone 4sを2つ登録して、それぞれで、シミュレータの言語を「日本語」と「英語」にしておけば、言語の切り替えがポップアップからできるようなものではないだろうかということです。

以下のように、iPhone 4s-EnとiPhone 4s-Jaの2つのシミュレータを追加登録します。どちらもDevice TypeはiPhone 4sを選択しています。

shot9509

Xcodeでは、このように、指定した名前(Simulator Name)のポップアップメニュー項目が出てきます。

shot9506

それぞれのシミュレータでアプリケーションを起動するなどして起動し、「設定」アプリケーションで言語を日本語と英語に設定しました。そうすれば、以下のように、もちろん、それぞれの言語でシミュレータが即座に立ち上がります。シミュレータ側でのHardwareメニューのDeviceでは、名前でなくデバイスタイプが出るようで、ちょっと不便ですが、まあ、Xcode側で選択できさえすればいいので、これで、Xcode側から言語を指定したシミュレータの呼び出しができるということです。

shot9508 shot9507

ちなみに、XocdeからプロジェクトのRun等をしないでシミュレータを起動するには、Xcodeで、XcodeメニューからOpen Developer ToolのiOS Simulatorを選択すれば良いでしょう。

shot9505

以下の書籍ではこの話題は入れられませんでした。こちらの書籍もよろしくお願いします。

ios_programming_cover1

[IM] MySQLでエンコードにはまったとき

INTER-Mediatorの話題です。こういうことがあるかどうは微妙かもしれませんが、私の郵便番号検索のサイトで、以下のような状況になりました。

  • 郵便番号検索のアプリケーション(A)はmysql_Connectで稼働している(あー、5.5ではついに書き直さないといかんなー)
  • UTF-8で動いているつもりだったが、MySQLで、エンコーディングの指定をしないままに動かしてしまっていた(これは失敗、でも、UTF-8でなんとなく動いている)
  • その上に、INTER-Mediatorで作った、書籍販売サイト(B)を動かす。これも、なんとなく動いている。郵便番号とは別のデータベースを作ったので、独立しているから問題なかった。
  • INTER-Mediatorでの郵便番号検索ページ(C)をいくつかの理由で立ち上げて、郵便番号データを読み込んでいるデータベースを利用して検索しようとしたら、文字化けた。

とまあ、要するに、2項目目が失敗なのですが、なんとなく動いているという状況下気づかなかったものの、最後の項目ではちゃんとやろうとして失敗に気づいたということです。my.cnfに、エンコードとしてUTF-8をつけると、(C)はきちんと動きました。それから、(A)もきちんと動きました。はいおしまいと思っていたら、(B)が文字化けます。つまり、(A)(B)(C)、同時に動かなくなったのです。なお、(C)の後追加した「character_set_client=utf8」が問題(かどうかも問題)のようで、これはmy.cnfから削除しました。(C)の発覚後、「character_set_server=utf8」も追加しましたが、最終的にはこれは残してあります。

結局どうしたか? (A)は、実は、「SET NAMES utf8」というSQLコマンドを発行して、うまく動かしていたのです。つまり、これを動かさないとうまく行かない大昔の状況のまま運用していて、エンコードの指定が適切でなかったことに気づいたわけです。(A)(B)(C)全部を動かすために結局何をしたかというと、INTER-Mediatorのアプリケーションで「SET NAMES utf8」を実行するようにしました。クエリーするたびにまず、このコマンドを実施して、SELECTを出すようにしました。これも、定義ファイルの設定でできます。こんな感じの定義ファイルです。scriptというキーワードは、FileMakerではよく使いますが、すべてのデータベースで利用可能です。

IM_Entry(
    array(
        array(
            'name' => 'postalcode',
            'view' => 'pcode',
            'records' => 50,
            'maxrecords' => 50,
            'paging' => true,
            'script' => array(
                array(
                    "db-operation"=>"load",
                    "situation"=>"pre",
                    "definition"=>"SET NAMES utf8"
                ),
            ),
        ),
    ),
    null,
    array('db-class' => 'PDO'),
    false
);

そういうことで、あっさりトラブル解決できました。まあ、でも、郵便番号サイトは、今シーズン終わったら、PHP 5.5か5.6で動くように、全面改修だな。

[IM]ページ上のオブジェクトに機能を割り付ける

データベースの内容を一覧するときに、検索結果を適用するという仕組みを一切プログラムを書かずに実現するために、ボタンやテキストフィールド、あるいは一般的なノードに対して機能を割り当てるという考え方を導入しました。要素のdata-im属性を利用して、ローカルコンテキスト(名前は「_」)に特別なキー名でバインドすることで、機能が割り当てられます。今の所、検索ページを作るための以下のものが利用できます。抽象的に記述してもわかりにくいと思いますので、具体的なタグのテキストともに紹介します。

検索条件の付加

テキストフィールドを「_@condition:….」のローカルコンテキストへバインドさせると、そのテキストフィールドに入れた文字列が検索条件になります。また、Enterキーで、コンテキストの更新が実行されます。

 <input type="text" data-im="_@condition:postalcode:f3,f7,f8,f9:*match*">

@以降は、コロン(:)で4つのセクションに分かれます。

  • 第1セクション(例:condition):この文字列
  • 第2セクション(例:postalcode):コンテキスト名
  • 第3セクション(例:f3,f7):フィールド名。複数の指定も可能
  • 第4セクション(例:*match*):演算子

最初の2つはいいとして、3つ目のフィールドは複数指定も可能です。複数指定をすると、それぞれのフィールドに対して同じ値の検索条件をORで与えます。演算子は、一般的なものに加えて「*match」「match*」「*match*」の3つが用意されています。データベースエンジンに関わらずに、部分一致や前方一致などをこの演算子で記述します。

上記のテキストフィールドに、例えば「新宿」と入れてEnterキーを押すと、以下の検索条件がコンテキストに付加されて、再度検索を行い、そのコンテキストのエンクロージャー内が更新されます。

(f3 LIKE '%新宿%' OR f7 LIKE '%新宿%' OR f8 LIKE '%新宿%' OR f9 LIKE '%新宿%')

表示件数の制御

以下のポップアップメニューを選択すると、レコードの表示件数をポップアップの選択肢で指定でき、選択と同時にコンテキストが更新されます。「limitnumber」が決められた名前で、コロンより後にはコンテキスト名を記述します。changeイベントにより、コンテキストの更新します。

<select type="text" data-im="_@limitnumber:postalcode">...</select>

コンテキストの更新ボタン(検索ボタン)

以下のボタンをクリックすると、指定したコンテキストが更新されます。つまり、「検索」ボタンとして機能するということです。「update」が決められた名前で、コロンより後にはコンテキスト名を記述します。clickイベントにより、コンテキストの更新します。

<button data-im="_@update:postalcode">search</button>

並べ替えフィールドの指定

以下のSPANタグ内の▲をクリックすると、f3フィールドの昇順で並べ替えを行います。同一のコンテキストに対する「addorder」の機能を持った要素は連動します。たとえば「f3で昇順」の後に「f9の降順」を選択すると、「f9の降順」を最優先とし、続くキーとして「f3で昇順」を設定します。最後に設定した条件が最優先になるようになっています。このバインドはclickイベントに対応しており、クリックすれば指定したコンテキストが更新されます。

<span style="cursor: pointer" data-im="_@addorder:postalcode:f3:asc">▲</span>

@以降は、コロン(:)で4つのセクションに分かれます。

  • 第1セクション(例:addorder):この文字列
  • 第2セクション(例:postalcode):コンテキスト名
  • 第3セクション(例:f3):フィールド名。1つのみ
  • 第4セクション(例:asc):昇順ならasc、降順ならdesc

Yosemiteのウインドウの緑ボタンは最大化でなくフルスクリーン

Yosemiteのウインドウのタイトルバーにある左側のボタンがすっかりデザインが変わりましたが、もっと重要な違いがあります。緑のボタンをクリックすると、今までは最大化されましたが、Yosemiteではフルスクリーンモードになります。

スクリーンショット 2014-10-17 17.49.05

一方、タイトルバーをダブルクリックするか、あるいはoptionキーを押しながら緑のボタンをクリックすることで、従来の「ウインドウ最大化」と戻しができます。ただし、Chromeではタイトルバーをダブルクリックでは最大化されないので、アプリケーションの実装によりできない場合もあるかも。

緑のボタンを押してフルスクリーンにしてしまうと、メニューはでなくなります。また、タイトルバーの右端にあったフルスクリーンから戻すボタンもなくなってしまって一瞬慌てます

shot1110-1

元に戻すには、ポインタを画面上部に移動させます。すると、メニューも出ますし、緑色のボタンも出てきます。再度緑のボタンを押せば、元に戻ります。他には、「フルスクリーンを解除」のメニュー項目を探すのもいいでしょう。さらに、トラックパッドであれば、3本指スライドで、別のアプリケーションに移動するという方法もあります。もちろん、この方法は、フルスクリーンのままに、別の画面に切り替わります。

shot1111-1

ちなみにMavericksではこうでした。フルスクリーンにしたら、ウインドウの右側に戻すボタン領域が作られていましたが、Yosemiteではそれがなくなりました。

スクリーンショット 2014-07-28 2.50.37

 

Yosemiteのmanは2本指スライドでスクロールするぞ!!

Yosemiteを入れた方、ターミナルを起動して、たとえば、「man diskutil」と入れてください。長いmanをスクロールするのは、えーっとcontrlなんだっけ〜と思う前にトラックパッドで2本指でスライドさせてください。なんと、manがスクロールします。Linuxマシンにつないでもできますよ。

ということで、manというより、Terminal.appの動作がトラックパッドに最適化されたってことですが、わかりやすいタイトルをつけてみました。

[IM]ContributorとSpecial Thanksの定義

ReadmeなどにINTER-MediatorのContributorとSpecial Thanksの項目があって、ともかく英語で書いてありますが、この区分をいちおうきちんと定義しておきます。もちろん、状況に応じてルールの増減はあります。

Contributor

  • コア部分に関連するソースコードをコミットあるいは提供した
  • レポジトリにまとまったサンプルを提供した
  • 開発進行において重要な決定を下し、それを遂行した
  • Webサイトを主体的に編集した。あるいはWebサイトにまとまったページを作成した
  • 貢献順。たとえば、コードの行数など。判断はとりあえず新居が行う

Special Thanks

  • バグレポートを具体的にコミュニティに公開した
  • イベントやサイト運用などのコミュニティ活動を支えた
  • 順番は姓のアルファベット順、Contributorになればこちらのリストからは落とす
  • 通常は氏名のみ、つまり組織名は書かないが、希望があれば書きますよ

こんなところかと思いますが、ご意見ありますでしょうか?