、東京メトロ オープンデータ活用コンテストがありました。 そのとき私が応募したアプリのソースコードを公開します。
概要
東京メトロの駅の中から行き先を決めてくれるアプリです。 家にいたくないけれど行き先が決まっていないときに使えます。 Android Wear とも連携し、 Android Wear で行き先や周辺スポットを見ることもできます。
理想
開発に使える時間の制約などから、単純に「行き先を決めてくれるアプリ」になっていますが、次の機能も実装したいと思っていました。
- 気学を用いて運勢のいい方角のなかから行き先を決める。
- 運勢のいい方角と現在地をマップ上で見られるようにする
- 行き先を決める中で、そのときの気分を考慮する。
- 行ったことのある東京メトロの駅を記録し、全駅コンプリートしたらなにかを出す。
- 目的地の駅や乗り換えの駅に接近したら、 Android Wear に通知を出す。
- 複数人で出かけるときの設定項目を考える。
- タップだけでなく、 シェイク して行き先を決められるようにする。
要するにパーソナライズして本当におすすめの駅を探すということです。
振り返って
初めて作った Android アプリ にしてはそれなりによくできたのではないでしょうか。
class の名前などは知識不足もあり、 修正した方がいいものもあります。
pik といえば、 windows で使える ruby の複数バージョン管理ツールです。 記事執筆時点で pik は github で No longer maintained
と書かれていまが、 私は使い慣れた pik を使います。
落とし穴
Windows 7 32bit で検証済み。
msi インストーラ を実行して windows にインストールするのですが、 そのままでは使えません。 ある意味バグが残っているので一部修正して使います。
まずは インストーラのページ から 記事執筆時点での最新版 pik-0.3.0.pre.msi をダウンロードして実行し、そのままインストールします。
設定を変更していなければ C:\pik
に pik に関するファイルがインストールされます。 その中の C:\pik\pik.bat
の 7行目 で %HOME%
になっているところを %USERPROFILE%
に変更します。
|
@ECHO OFF "%~dp0pik_runner.exe" "%~f0" %* IF "%PIK_HOME%"=="" ( IF EXIST "%USERPROFILE%\.pik\pik_run.bat" (call "%USERPROFILE\.pik\pik_run.bat") ) ELSE ( IF EXIST "%PIK_HOME%\pik_run.bat" (call "%PIK_HOME%\pik_run.bat") ) |
Windows では %HOME%
という環境変数は定義されていません。 (インストール先ディレクトリ から考えて) %USERPROFILE%
に変えればうまくいきます。 Windows 8.1 でも同じです。
FuelPHP で複数データベースへ migration を行うやり方を説明します。 FuelPHP 1.7.2 を想定しています。
FuelPHP では php oil g model item name:string
などのようにすると、 model と migration のためのコードが生成されます。 php oil g scaffold ...
とやった場合にも migration のコードが生成されます。 ここで生成される migration コード に手を加えることで 複数データベースに対応させることができます。
変更前のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<?php namespace Fuel\Migrations; class Create_items { public function up() { \DBUtil::create_table('items', array( 'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true), 'name' => array('constraint' => 255, 'type' => 'varchar'), 'created_at' => array('constraint' => 11, 'type' => 'int', 'null' => true), 'updated_at' => array('constraint' => 11, 'type' => 'int', 'null' => true), ), array('id')); } public function down() { \DBUtil::drop_table('items'); } } |
変更後のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<?php namespace Fuel\Migrations; class Create_items { public function up() { \DBUtil::create_table('items', array( 'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true), 'name' => array('constraint' => 255, 'type' => 'varchar'), 'created_at' => array('constraint' => 11, 'type' => 'int', 'null' => true), 'updated_at' => array('constraint' => 11, 'type' => 'int', 'null' => true), ), array('id'), true, false, null, array(), 'db_config_key'); } public function down() { \DBUtil::drop_table('items', 'db_config_key'); } } |
db_config_key
というのを付け加えました。 このパラメータでデータベースを指定できます。 具体的には config/db.php
内 のキーになります。 たとえば 'default'
なんてのが入ります。 何も指定がなければ 'default'
が採用されます。
このようにして複数データベースに対応させることができます。 migration の コードごとに データベースを書き換えればいいですからね。
Model の コードを活用した書き方
Model を利用してやってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<?php namespace FuelMigrations; class Create_items { public function up() { DBUtil::create_table(Model_Item::table(), array( 'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true), 'name' => array('constraint' => 255, 'type' => 'varchar'), 'created_at' => array('constraint' => 11, 'type' => 'int', 'null' => true), 'updated_at' => array('constraint' => 11, 'type' => 'int', 'null' => true), ), Model_Item::primary_key(), true, false, null, array(), Model_Item::connection()); } public function down() { DBUtil::drop_table(Model_Item::table(), Model_Item::connection()); } } |
Model_Item
が Orm
を使っているという前提の話ですが、 データベースの指定に Model_Item::connection()
を、 テーブルの指定に Model_Item::table()
を、 主キーの指定に Model_Item::primary_key()
を使っています。 このようにすると、 model の中に書いておけば migration のコードを変更しなくても済みます。 (ただし 既存テーブルについて model の テーブル名や $_connection
を変更する場合には注意が必要になります。)
DIxAOP ってなんだ? と思っていたら、 ある人が紹介してくれました。 DIxAOPについてはわかりやすく書かれているそうです。 パラパラっと見てみましたが、 EAA や DDD などのアーキテクチャを一通り知っている人が書いた本に見えます。 今回は第1章をじっくり読んでみました。 Spring フレームワーク の前書きみたいな内容で、 Spring を使ったことのない私にはちょうどいいです。
Spring の特徴
Spring の特徴として 際立っているのが DIxAOP だ。 第1章では紹介程度になっているのだが DIxAOP なくして Spring は成り立たないといっても過言ではなさそうだ。
Spring の DIxAOP 設計 は Webアプリケーション が抱える 3つの問題点 を解決する。 以下、簡単にまとめた。
- オブジェクトのライフサイクルの問題
- オブジェクトの生存期間をコントロールする作りこみが困難
- 部品化の問題
- 部品化をするためには実装非依存にする必要があるが、それなりにコストがかかる。 (注: 単にインターフェースを使えばいいという問題ではない。)
- 技術隠蔽や不適切な技術隠蔽
- 高レベルの技術を初級レベルの開発者に利用させて不具合を引き起こしてしまったり、不適切な技術隠蔽をしてその技術の利用が困難になってしまったりすることが開発現場でよく起こる。
Spring では、 上2つの問題を DIコンテナ が、 最後の問題を AOP が解決する。
Webフレームワーク というと Rails や FuelPHP, CakePHP などがあり、 「(アクティブレコードパターンの) 簡単にデータベースが使えるもの」という印象を受けてしまいがちですが、 Spring3 入門 では アーキテクチャ の考え方からしっかりと書かれていて EAAに見られるパターンの説明も(第1章では)随所で行われています。 第1章では特にレイヤの分離の説明が重点的に行われています(フレームワークを使う人には是非ともわかるようになっていてほしい内容です!)。 コードの例もあり、全体的にしっかりした印象を受けます。
以下、第1章の中で私が(個人的に)重要だと思った内容を簡単に書き留めました。
アプリケーションアーキテクチャ
プログラムを作る際には 最低でも 2つの方面からの要件・目標がある。
- ユーザの要件: ユースケースなどで表される機能要求やレスポンスタイムなどの非機能要求
- 開発者・運用者の目標: 開発期間の厳守、変更・機能追加のしやすさ、テストのやりやすさ
この本では 2つ目の 開発者・運用者の目標 からアーキテクチャの重要性が説かれている。
アーキテクチャに求められるもの
- 開発効率
- 意図を把握しやすく、理解しやすい構造
- テストが容易に行える構造
- 柔軟性
- 変更しやすく、機能追加しやすい構造
- 将来の環境の変動に耐えられる頑健な構造
ティアとレイヤ
Web アプリケーション の アーキテクチャ は ティア と レイヤ に分かれている。 ティア は 物理層 を表し、 レイヤ は 論理層 を表す。
ティア
クライアント層、中間層、 EIS(Enterprise Information System)層 の 3つに分かれるのが基本となっている。
各ティアの例
クライアント層 |
パソコン、スマートフォン |
中間層 |
アプリケーションサーバ |
EIS層 |
DB、レガシシステム |
レイヤ
EAA の冒頭あたりにある分類と同じ分け方でレイヤが書かれている(プレゼンテーション層、ビジネスロジック層、データアクセス層 の3層)。 (もちろん異なる分け方もある。) 互いに隣接するレイヤ間では一方向のアクセスのみ許す。
トランザクション処理がどのレイヤに属するのかは迷うところだが、本書ではプレゼンテーション層とビジネスロジック層の境界と説明されている。
Java でコマンドライン引数を扱うサンプルコードです。
続きを読む Java: コマンドライン引数を扱う →
A Life Summary of an Gypsy