2015年1月31日土曜日

最近のバイクアイテム

今シーズンのマイ・ベストバイ2品。

■RIDEZ Waterproof Case Sサイズ
サイズ展開は数種類ありますが自分はiPhone 4SなのでSサイズです。

RIDEZ(ライズ) Waterproof Caseウォータープルーフケース スマートフォンホルダー Sサイズ 4527625088801
最近ツーリング時に道を間違える事が多いのでナビを導入したいと思うようになってきました。 本当はTabletをナビにしたいと検討していたけどスマートフォン用がリーズナブルだったのでこっちにしました。 iPhoneをナビとして何度か使用してますが安定していて落ちそうになったり等は全くありませんでした。 ホールドはしっかりしているようで安心して使えます。 ケースの上からでも画面を操作できるのも○。色々とはかどります。 因みに自分だけかもしれませんが、最初にホルダーとケースを結合させる時に感触がわからず 不良品だと思ってしまいました。 店員さんにお願いしたら結合しましたが、諦めずに思いっきり結合させる必要有りです。


■SWAT ミリタリーブーツ

SWAT S.W.A.T サイドジッパー ミリタリーブーツ ジャングルブーツ タクティカルブーツ 黒色 ブラック 黒 28.0cm

S.W.A.Tミリタリーブーツのレプリカ(?)。 バイク用のブーツが欲しいが大体1万~ですがこいつは4300円で買えたのでコストパフォーマンスは最高です。 自分の足は27cmなのですが28cmを買ってホッカイロが入るようにしています。 だいぶイメージ通りですがちょっと安っぽいのと足先が分厚い為にクラッチの下に足を入れるのがちょっと辛いです。 足首がだいぶ伸縮するのでクラッチ操作は十分できます。

2014年12月24日水曜日

象本とHadoop MapReduce デザインパターン

Hadoop

Hadoopの導入から基本的なシステムの解説、サンプルコードなどが書いてあった。
javaやlinuxの知識がある程度あれば読むには困らない。と思う。
試しにシステムを構築して実行するまではこれでいける。
私が買ったのは第二版でHadoopを前提にしたPig、Hiveなど
にも触れてくれているのでかなりお得な一冊でした。

私が読んだのは第二版だけれでもすでに第三版が出版され大幅加筆されているとか。

Hadoop 第3版


Hadoop MapReduce デザインパターン

読み終えて、いや途中から内容が高度すぎて今はついていけなかった。。。
この本を完全に理解するには数学、統計学の知識が必要な為、勉強して読み直さないとならない。
単純な集計処理であればこの本を読まずとも前述の本で間に合うと思うが、
高度で専門的な統計業務をするのであればこっちの本の内容が助けになりそう。

Hadoop MapReduce デザインパターン ―MapReduceによる大規模テキストデータ処理



Hadoopに限らず大規模データ分散処理システムは設計、構築、運用も非常にコストがかかる
ものなので今のところ読むに留まる内容であった。

2014年12月2日火曜日

Looking for Lost for TM 反省会

アプリ「Looking for Lost For TM」の開発にはPhonegapを使用しました。
Google Play用、iOS用のどちらも一つのコードで作れると言うのはとても魅力的に感じたので採用しました。
今回は反省会として所感を一回まとめておく事にします。
因みにPhonegapのバージョンは 3.6.0-0.21.29 です。

Google Play アプリ名文字列長制限
Google Play アプリを登録する際にはアプリ名が30バイト以内で無いといけない。
そんなことはお構いなしで「Looking for Lost on the Tokyo Metro」とか名付けたら名前を変更しなければならなくなってしまった。
各種制限については良く確認しておく事。基本です。

誤解の無いアプリ名を付ける
またアプリ名称について。
最初は

 Looking for Lost on the Tokyo Metro

でしたが、最終的には

 Looking for Lost for TM

になった。
iOS用アプリを登録する際にAppleの審査でアプリ名について「on ○○」っておかしいだろ?
といった内容の指摘を受けました。個人的には東京メトロ路線上で使用するという意味を込めた
つもりでしたがそんな説明するのはめんどくさく、かつ、誤解されても困るというのは共感できる
ので名称を変えました。
また、Google Play アプリの文字列制限もクリアする為に the Tokyo Metro も TM へ省略してみました。

Phonegap:アプリ名に日本語名がつけられない
私の技術力の限界でもありましたが、そもそもアプリ名がちとダサいのはPhonegapではアプリ名に
日本語を付けるのが私にできなかった為です。
ネットを検索すると何とか日本語名をつけた方もいらっしゃるようですが、私は断念しました。

Phonegap:remote build と local build で出来上がるものが違う
致命的では無いけれども、 remote build と local build で生成されたファイルに違いがある。
phonegap では project を生成するとwww/resというディレクトリが作成され、そこにsplah用の画像やアイコン画像などを入れられるのだけれども、 remote build では入れたファイルが使われるのだけれども local build では全く使われない。
build の方法によって変わってしまうとなると折角一元管理を目指していたのにめんどくさい
事になってしまった。

Phonegap:iOS用ファイルにプラグインが出力されない
今回はphonegapが提供している追加のプラグインを使用していますが、
iOS用のファイルをリリースする為に local build したものをXcodeで開いたらpluginファイルが
ありませんでした。(remote builde は未確認)
phonegapのgithubから直接ファイルをダウンロードしてきてXcode上でファイルを自分で追加する羽目になり、結構悩んだ。ここはどうにかして欲しい。


コード自体はHTMLとjavascriptなので概ねGoogle Play用、iOS用に対して共通のコードで開発できました。
ただ、画像等のリソース管理、コンパイルやストアへのアップロード等でそれぞれ別の問題に突き当たるのは避けられなかった。まぁ避けられないのは仕方の無いことだろうか。
いやーな事が結構書いてますが、あまり複雑な事はしていない場合に日本語名とpluginが出力されないのを我慢できれば Phonegap の採用はありかな。



2014年11月3日月曜日

Looking for Lost on the Tokyo Metro

2015/11/14にこのアプリの公開を停止しました。

現在はこのアプリはご利用いただけません
Looking for Lost on the Tokyo Metroというアプリを開発しました。
この記事はLooking for Lost on the Tokyo Metroというアプリの告知兼サポートページになります。
またこのアプリは東京メトロアプリコンテストへ応募する予定です。

 
これは東京メトロAPIの列車ロケーション情報を使用した電車内に置き忘れた物を探すアプリです。
忘れ物をした時の情報を入力する事により忘れ物をした車両の位置をリアルタイムで探します。
駅係員の方や鉄道会社の遺失物担当者の方へ状況を伝える場合などにご利用ください。
 


使い方

使い方はとっとも簡単です。忘れ物に気付いた際に入力画面で乗降者した列車の沿線、駅名、進行方向、時間を入力 して探すボタンを押すだけです。サーバーへ列車を問い合わせし結果画面へ該当する列車があれば列車の情報が表示 されます。表示された内容をもとに駅係員様へお問い合わせください。

Movie


スクリーンショット




 

2014年10月24日金曜日

PhalconのDB\AdapterをDIへ登録する際の注意点

今まで勘違いしていたので覚えて置く為のメモ。

PhalconでDIへDb\Adapterを登録してtransactionを一元管理するのはできないのだと思っていたら 使い方が間違っていた。
DIへ登録する時にはshared(共有)として登録すれば呼び出し先で同じコネクションのインスタンス を使用してくれる。逆を言うとsharedしないと同じインスタンスを使用してくれないようだ。
具体的には
// 第三引数にtrueを指定
$di->set('db', function() use ($config) {
    return new \Phalcon\Db\Adapter\Pdo\Postgresql(
    $config->database->toArray());
}, true);
本当にトランザクションが制御できているか以下の方法で確認
DBにテーブルを用意する
CREATE TABLE name1 (
  id SERIAL PRIMARY KEY,
  name text
);
テスト登録用処理を実装したモデルクラスを用意する。
class Name1 extends \Phalcon\MVC\Model
{

    public $id;
    public $name;

    public function getSource()
    {
        return "name1";
    }

    /**
      * 引数のコネクションと関数内で生成したコネクション
      * でそれぞれ登録
      *
      */
    public static function insertTest($src_db){
        $name = new \App\Mvc\Model\Name1();
        $db = $name->getDI()->get("db");
        for($i=0;$i<5;$i++){
            $name = new \App\Mvc\Model\Name1();
            $name->name = 'FFFFF' . sprintf("%05d", $i);
            $name->create();
            $result = $db->query("INSERT INTO name1(name) VALUES(
                '" . "DDDDD" . sprintf("%05d", $i) . "')");
            $resulta = $src_db->query("INSERT INTO name1(name) VALUES(
                '" . "EEEEE" . sprintf("%05d", $i) . "')");

        }
    }
}
DIのsharedをtrueにしたものとしないものの両方で以下の処理を実行する。
具体的にはコントローラー、生成したモデルのテスト用関数で登録処理が行われ、例外を意図的に 発生させてrollbackを行う。
try{
   
    $this->db->begin();
    for($i=0;$i<5;$i++){
        $name = new \App\Mvc\Model\Name1();
        $name->name = 'AAAAAA' . sprintf("%05d", $i);
        $name->create();
                
        $result = $this->db->query("INSERT INTO name1(name) VALUES(
            '" . "BBBBB" . sprintf("%05d", $i) . "')");
    }
    \App\Mvc\Model\Name1::insertTest($this->db);
            
    throw new \Exception("trnsaction test");
    $this->db->commit();
}catch(Exception $e){
    if($this->db->isUnderTransaction()){
        $this->db->rollback();
    }
    throw $e;
}

sharedした場合の結果は
test=# select * from name1;
 id | name 
----+------
(0 行)

しなかった場合、インスタンスを別で取得して登録した分が残ってしまう。
test=# select * from name1;
 id |    name    
----+------------
 12 | DDDDD00000
 15 | DDDDD00001
 18 | DDDDD00002
 21 | DDDDD00003
 24 | DDDDD00004
(5 行)
一元管理したい場合はsharedをする事で可能になる。一番起きそうなのは一元管理するつもりだったのに sharedしないで登録してしまいtransactionがめちゃくちゃになってしまったという事故。

connectionのインスタンスはDB回りのクラスで管理されるものと思い込んでいたのでDIでやる発想が無かった。 こんな方法もあるんだな。

2014年10月14日火曜日

Google Play アプリ開発で参考にした本

Google Play版のPocket Trumpetterも無事リリースに至りました。

アプリ開発ではもはや名著「初めてのAndroid 第3版」を参考にしています。

初めてのAndroid 第3版

javaの基本的な知識は必要ですが、シンプルなアプリの開発ならこの本の例を作る過程で身につく
と思います(少なくとも私は身についたと思っています)。
強いて惜しいと思われるのは、内容はちょっと古いんじゃないかと思っています。
サンプルで使用されたライブラリや関数が非推奨になっていたり、Fragmentについては触れられなか
ったりと。まぁこんなものは大したマイナスではないと思いますが。

2014年8月31日日曜日

Phalconで強引なSubmodule

ここ最近、自称最速PHPフレームワークを謳っているphalconというのを
使っています。早い根拠はコアな部分をC言語で実装している為だそうです。
(SQLをログに出力すると意図しないクエリーをDBに流しているように見受けられ、遅くならないか? と心配になるが今回の趣旨とは異なるのでこれ以上触れません)

Laravelもチラ見したたけれども、最近のフレームワークはmoduleというくくりがちょっと 大きい単位になってしまっている気がしていまいち自分の意図と合わない。
個人的には関連するcontrollerやviewなどをある程度纏めた単位をsubmoduleとした構成にしたい。
かなり強引だけどnamespaceを使って実現してみる事に。
phalconのインストールからmodule構成まではphalconの公式ページを探せば見つかるので これまたここでは触れません。

先ずファイル構成はこんな感じ

├─app
│  ├─config
│  │      config.ini
│  │      loader.php
│  │      module.php
│  │      service.php                        # route処理を定義。
│  │                                         # ここでURLとmodule、name
│  │                                         # space、controller、acti
│  │                                         # onを関連付け
│  │
│  ├─frontend                               # frontend module
│  │  │  Module.php
│  │  │
│  │  ├─modules
│  │  │  ├─error                          # エラー処理用 submodule 
│  │  │  │  │                             # コントローラーのnamesp
│  │  │  │  │                             # aceは error
│  │  │  │  ├─controllers
│  │  │  │  │      IndexController.php
│  │  │  │  │      
│  │  │  │  ├─forms
│  │  │  │  └─views
│  │  │  │      └─index
│  │  │  │              app.volt
│  │  │  │              notfound.volt
│  │  │  │              system.volt
│  │  │  │              
│  │  │  └─index                          # index処理 submodule 
│  │  │      │                             # コントローラーのnam
│  │  │      │                             # espaceは index
│  │  │      ├─controllers
│  │  │      │      IndexController.php
│  │  │      │      
│  │  │      ├─forms
│  │  │      │      IndexForms.php
│  │  │      │      
│  │  │      ├─language
│  │  │      │  └─exprss
│  │  │      │          ja.php
│  │  │      │          
│  │  │      └─views                      # index module 専用のテ
│  │  │          │                         # ンプレートをここに作
│  │  │          │                         # 成する。
│  │  │          └─index
│  │  │                  index.volt
│  │  │                  
│  │  └─views
│  │      │  base.volt                      # 共通template
│  │      │  
│  │      └─layouts
│  │              main.volt                  # 共通layout
│  │              
│  ├─library
│  │  └─mvc
│  │          Module.php                     # module用親クラス。sab
│  │                                         # moduleのロード等
│  ├─logs
│  └─plugins
│          
├─cache
└─public
        .htaccess
        index.php
            

}}}
[config/service.php] phalconを実装する多くの場合でdependency injectionの各serviceをここで 定義していると思う。 ここでsubmodule構成の為にrouterサービスを定義。
/**
 * Specify routes for modules
 */
$di->set('router', function () {

    $router = new \Phalcon\Mvc\Router();

    // デフォルトモジュールを frontend に設定
    $router->setDefaultModule("frontend");

    /* frontend/modulesの直下にあるディレクトリ名をnamespaceとして定義
       ここで/foo/var/indexとアクセスがあった場合、以下が設定される
       module     = frontend
       namespace  = foo/Controllers
       controller = var
       action     = index
     */
    $modulesDir = APP_ROOT_PATH . DIRECTORY_SEPARATOR . 'frontend/modules';
    $dir = @opendir($modulesDir);
    if($dir){
        while($dir_name = readdir($dir)){
            // exclude [.],[..],[*.php]
            if($dir_name == '.' || $dir_name == '..'
               || strpos($dir_name, ".php") > -1){
                continue;
            }
            $router->add("/" . $dir_name . "/:controller/:action", array(
                    'module'     => 'frontend',
                    'namespace' => $dir_name . '\Controllers',
                    'controller' => 1,
                    'action' => 2,
            ));
        }
    }

    return $router;
});
もしModuleがfrontend以外にもあるのならそのディレクトリも同じように登録すれば 実現可能。


[library/mvc/Module.php] ここでは特に2つの事を行う。

1つはmodules直下を読み込んでいってnamespaceとしてロードする
    /**
     * Register a specific autoloader for the module
     */
    public function registerAutoloaders()
    {

        $loader = new \Phalcon\Loader();

        $namespaces = array();

        $modulesDir = APP_ROOT_PATH . DIRECTORY_SEPARATOR . 
                        $this->module_name .  '/modules';
        $dir = @opendir($modulesDir);
        if($dir){
            while($dir_name = readdir($dir)){
                // exclude [.],[..],[*.php]
                if($dir_name == '.' || $dir_name == '..'
                  || strpos($dir_name, ".php") > -1){
                    continue;
                }
                $namespaces[$dir_name . '\Controllers'] = $modulesDir . 
                   DIRECTORY_SEPARATOR . $dir_name . DIRECTORY_SEPARATOR .
                   'controllers';
                $namespaces[$dir_name . '\Forms'] = $modulesDir . 
                   DIRECTORY_SEPARATOR . $dir_name . DIRECTORY_SEPARATOR .
                   'forms';
            }
        }
        
        $loader->registerNamespaces($namespaces);
        
        $loader->register();
    }
公式サイトにもModuleのautoloadersの実装方法があるが、少し変化させて今回の目的に対応できるようにした。
modulesの直下にあるnamespace用ディレクトリの直下にcontrollersとformsというディレクトリを用意して、 それぞれnamespaceとして定義してローダーに登録している。
modules/indexを例にすると以下のようになる
  └─index
      ├─controllers                # namespaceはindex\Controllers
      │      IndexController.php    
      │      
      ├─forms                      # namespaceはindex\Forms
      │      IndexForms.php
      │      
他にこのnamespaceの単位に組み込みたいものがあれば(modelを追加したい場合はあるかもしれない) ここで定義すれば追加可能。

2つ目はviewの定義。各ファイルはnamespaceを使う方法に依って相互に認識しあえるようにできたが、 viewがちょっと異なる。controllerなどのphpファイルはnamespaceが利用できたが、viewのテンプレートは PHPのクラスで無い為にnamespaceに頼る事が出来ない。
(他の多くのフレームワークでもそうだと思うがテンプレートは通常のファイルとして扱っている)

Moduleでserviceを登録できる方法が提供されているので、viewをここで定義する。
レイアウトとメインのテンプレートは共通のディレクトリを使い、各アクションに依存した画面テンプレートは modules以下を使うようにしたい。

    public function registerServices($di)
    {
        $module_name = $this->module_name;

        //Registering the view component
        $di->set('view', function() use ($di, $module_name){
            $config = $di->get("conf");
            $view = new \Phalcon\Mvc\View();
            $view->setViewsDir(APP_ROOT_PATH . DIRECTORY_SEPARATOR . 
               $module_name . $config->application->viewsDir);

            // レイアウトディレクトリとメインは共通のディレクトリを示
            // すように定義
            $view->setLayoutsDir('../../../views/layouts/');
            $view->setMainView('../../../views/base');
            
            $view->registerEngines(array(
                    ".volt" => 'volt'
            ));

            // change view directory by namespace
            $eventsManager = new \Phalcon\Events\Manager();
            $eventsManager->attach('view', function($event, $view)
               use($module_name) {
                $dispatcher = $view->getDI()->getShared("dispatcher");
                $nName = $dispatcher->getNamespaceName()
                if ('beforeRender' == $event->getType()) {
                    // レンダリング前にviewのディレクトリを
                    // modules/namespace/views になるように設定。
                    $view->setViewsDir(APP_ROOT_PATH . DIRECTORY_SEPARATOR . 
                      $module_name . DIRECTORY_SEPARATOR . 'modules' . 
                      DIRECTORY_SEPARATOR . substr($nName, 0, 
                      strpos($nName, '\\', 0)) . DIRECTORY_SEPARATOR . 
                      'views' . DIRECTORY_SEPARATOR
                    );
                }
            });
            $view->setEventsManager($eventsManager);
            
            return $view;
            
        });

        $di->set('volt', function($view, $di) use ($module_name) {
        
                    $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
                
                    $volt->setOptions(array(
                            "compiledPath" => APP_ROOT_PATH
                               . "/../cache/volt/" . $module_name
                               . DIRECTORY_SEPARATOR
                    ));
            return $volt;
        }, true);
            
    }



[frontend/modules/index/IndexController.php]
/index/index/indexでアクセスされた場合にrouterによって紐付けされるように実装する。 注意する点はnamespace。routerとModuleで定義した内容とマッチするように定義する
namespace index\Controllers;

class IndexController extends \Phalcon\Mvc\Controller
{

    public function indexAction()
    {
    }
}


どうしてこうなったのか?

色々考えた結果、phalconのフローの関係で今回挙げた処理は前述の箇所となっり、このスタイルに 落ち着いた。デフォルトのModuleの単位をこのレベルに引き落とす方法も見当したが、エラーハンド リングがどうしても共通で行う方法にしっくりくる物が無かった。
routerの定義、namespaceの登録とロードはdispatchがされる前で、viewサービスはdispatch後に実行 されるようなのであのような形になった。


もっと良い実装方法 or 実はphalconの機能で実現する方法が存在するかもしれない。
今のところはこんな方法だろうか。