Code

2015年6月28日日曜日

RESTful API データが見つからない場合の処理

 今 RESTful API をベースに iOS や Android のアプリにデータを提供するシステムを作っています。基本的になんでも json を返します。それで、HTTP メッソードを使ったり、 HTTP Response コードを使って、フロントエンドとやりとりをしています。
 HTTP メッソードの方は特に決まってるので、Read (Get), Create (Post), Update (Put または Patch), Delete (Delete)特に問題が起きてませんでした。まぁ、たまに Read を Post メッソードを使う API もありますけど。(GET には HTTP body がルールとして使わないので、複雑なオブジェクトをバックエンドに送る時、例えば、複数検索条件とか、Post も使ったりします。)
 戻り値は HTTP Response コードなので、200 OK, 201 Created, 202 Accepted とかは理解しやすいです:Get (200 OK), Post (201 Created), Put/Patch (200 OK), Delete (200 OK) 一見ですぐわかりますので、唯一考えるべきコードは 404 Not Found ですね。
 私見ですが、データが見つかってない場合、404 ではなくで、空の データ body を返すべきです。なぜなら、404 には url が存在しない場合もサーバーから返すので、意味が紛れ易いです。
 一般的に JSON を扱うライブラリでは空の配列や []、オブジェクト {} など空のデータに deserialize しますが、空の body の場合、null に deserialize します。それで、Front End が null かどうかチェックすればいいのです。
 404 が返す場合、これは HTTP Request がエラーになったと同じ意味なので、違うルートになります。だからコードには
   if (response.StatusCode == 404) {...}
みたいなコードがあっちこっち出てくるかもしれません。そうすると、全体的にエラーの扱いが難しくなります。
 データはデータなので、見つからない場合は、200 OK, null body を返したら Front end もすぐわかります。
 もう一つは Java, Objective-C, C# などは全て Strongly typed 言語なので、JSON を deserialize する場合、一般的に一つの Class を定義しますが、データの角度から見ると、処理に合わせて、たまに Dictionary<string, object> にしたほうがやりやすい場合もあります。
 例えば、JSON オブジェクトの中に、どのプロパティの値が null かをチェックする場合、Reflection を使うより、直接 Key-Value pair にしたらい、Iteration メッソードを使えば、速いし、その後の処理も楽になるはずです。
 それでは。ここまで。

2015年6月14日日曜日

祝 Polymer が 1.0 になりました

 先日、つい Polymer JS が Product Ready (1.0) になりました。
 https://www.polymer-project.org/1.0/

 これは Web の Future と言って、なかり使いやすいです。
 また、将来 AngularJS 2.0 ではシムレスに Polymer の要素を Directive と使えることができます。

 PS: React.js はどう見ても、FaceBook など表示に重点をおいたサイトでは使いやすいかもしれませんが、Interactive の重いアプリではやはり AngularJS のほうがいいと思います。
 後日また。

なぜ RESTful API になったのか

 おととい、チームの iOS Dev といろいろディスカッションしました。彼はまだ古い API のイメージ持っておらず、なんでもサーバー側でやると考えているようです。それで、現在の API は iOS だけではなく、Android, Web などいろんなチャンネルで共通で使う物だと、RESTful API だから、リソースを操作すると考えようといろいろ話しましたが、まだまだ受け入れてなかったそうです。
 以前、3 年前ぐらいまで、iOS デバイスなど、JavaScript の性能がボットルネックだった時代では、サーバー側で計算したり、ソートするなどをやらなければならなかった。当時の Front End はそれほど遅くなかったと言っても、パフォーマンスにいろいろ真剣に取り組まないと、すぐ遅いと感じてしまいました。それで、自分たちのラブラリを作ったり、速く見せるため、ユーザーの動作を予測して、先にデータをロードするなど、工夫していました。
 今 RESTful API になってから、抽象したデータなどをリソースと考えて、HTTP Method をマップして、CRUD -> Get, Post, Put (Patch), Delete を使って、Front end から直接操作できるようなイマージにしないといけないと思います。だから、API はデータを提供するだけ、データの操作はデバイスか Web Site で処理します。
 前では URI や Controller の名前は RegisterDevice など、動詞+名詞でしたが、RESTful API になると/devices と名詞のみなりました。それで、HTTP Get で全部のデバイスを取得したり、 HTTP Post でデバイスを作ったりします。
 GET /devices?pageNo=0&pageSize=20  -> 全部のデバイスの配列を取得
 GET /devices/{deviceId} -> 一つのデバイスを取得
 POST /devices -> デバイスを作る。データは HTTP Request Body から
 PATCH /devices/{deviceId} -> デバイスを更新
 Delete /devices/{deviceId} -> デバイスを削除

 また戻りますが、Front End は一回要求するデータはそれほど多くないので、ソートも時間のかかる処理ではなくなりました。Http Request の時間はまだ考えなければなりませんが。
 結論としては、もう新しい時代ですので、表示ロジックを Front End であるべきです。
 それでは。

2015年5月31日日曜日

Task.Run と Autofac データベース Connection 問題から、サーバー側マルチスレッドの検討

 今開発しているシステムは HTTP を使って、RESTful API です。Front end は iOS から、Android、WebSite 全部サポートしています。デバイスの 3G 回線でも、できるだけ速くロードするために、いろいろ工夫しました。例えば、一つ目のレスポンスに各リソースをリクエストする URL を入れて、実際の作成は後回しして、マルチスレッドを使います。さらに、Task.Run を使って、できるだけ時間のかかる処理を別のスレッドで行うようにします。一方、Oracle DB Connection などは Autofac を使って、 DI の .InstancePerRequest() で各スレッドに配っています。そうすると、Task.Run は Thread Pool に新しいスレッドを申請してので、そのスレッドでは前の Request のスレッドのリソースが使えなくなりました。。。"Invalid operation on a closed object" みたいなエラーが発生したりしています。毎回ではないですが、かなりの確率で発生しています。
 解決の方法としては、Task.Run を使ってるスレッドの中に、自分で Autofac の LifetimeScope コントロールすることです。 まず、LifetimeScope の Provider を作って、RequestLifetimeScopeTag を ILifetimeScope の作成関数に設定することで、この ILifetimeScope は Request Scope として指定できます。ただ、自分で ILifetimeScope を作ったから、Scope の Dispose() 関数を自分で呼び出す必要になります。後日まだどうするかのコードを貼り付けます。
 ここでまず話したいことは Task.Run を使う場合、スレッドの切り替え処理もありますので、一般的に 50 ms 以下のタスクでは別スレッドを使う必要がないのです。
 Task.Run は Back End でファイルを書く場合や、HttpClient を使って、他のスステムに Http Request を発行する場合使ったほうがいいです。一般的な DB アクセスには速度がかなり早いので、20ms ぐらいと言われているので、必要がないと思われています。
 もし Loop を使って、DB 更新を行う場合や、複数のテーブルを更新するが更新結果は Front end に返すする必要がない場合、できるだけ小回りにして、複数回で更新したほうがいいです。この処理は Task.Run を使うより、Hangfire などの Background タスク Runner を使ったほうがいいです。Hangfire は DB を使っているので、Retry 処理もあるし、Task.Run より安全です。
 Front end から見ると、Http API を呼ぶとき、レスポンスが戻ってきたら、 Callback 関数が呼ばれるので、一回の Http Request より、複数の Request を発行して、各 Callback 関数を呼び出して、UI をアップデートしたほうが速いです。Http Request 自体がマルチスレッドでサーバー側で処理するので、それを最大限に使わないと。

 それでは。

2015年5月16日土曜日

iOS ユニバーサルデザイン実践:イメージのセンター揃い

 この Sprint では、チームの iOS Dev が休暇で一ヶ月ほど離れることになりました。あまり Native サイドのコードを触りたくないですが、急いで実現したい機能があったので、一週間ほど Objective-C を使って、 開発をしました。
 まだ iOS の開発では Nib をベースにしていますが、xib フィアルの代わりに StoryBoard が使われるようになりました。さらに、違うサイズのデバイスを対応するために、ユニバーサルデザインという概念が導入されました。これは前と違って、 絶対位置を指定するより、Constraint を使って、相対位置とサイズを指定することで、大きい iPhone 6 plus から、細長い iPhone 5 まで、全てのスクリーンサイズを対応できる layout nib になります。
 さらに、Segue という概念が導入されて、前のように ViewController を push するコードより、もっと具体化になるものです。Ctrl を押しながら、ドラッグして、次画面はどこに遷移するかを指定します。これも面白いです。
 今回の機能は幾つかのイメージをスクリーンの真ん中に表示することです。前なら、イメージビューをプログラムで作成して、addSubView を読んで、画面に追加します。そのあと、Frame を取得して、計算後、位置を指定します。少しは面倒くさいデスけど。
 ただ、ユニバーサルデザインでは、これは変なコードになるので、どうするかを少し調べたら、一番いい方法が見つかりました。
 具体的に、parent view を作って、centre align の Constraint を指定します。同時にこの Constraint をoutlet で view に追加します。Constraint の Constant などのパラメーターが取得できるようになります。
 次、イメージを parent に追加したら、parent view の width を取得して、先ほどの centre constraint に設定します。これで、どうなスクリーンサイズでも、parent view がセンターになります。
 
 Constraint は iOS が各ビューの位置や、サイズを決めるために使ったものなので、さらに面白い使い方がありますね。さらに、こちらの値もアニメーションで使えるので、前のように origin.y を使ったりすることなくても、 view を動かしたりすることもできます。
 それでは。

2015年4月29日水曜日

javascript で Native iOS app 開発

 昨日、これを発見しました。
 facebook react-native

 少し見てみましたが、基本的に javascript で、JSX を使って、native ios app を作るというものです。PhoneGap と違って、基本的に javascript コードが objective-c コードに、JSX は NIB ファイルになるような感じです。
 
 react JS ライブラリと違って、これはモバイル向けで、将来は Android, Windows Phone もサポートするそうです。
 すでに App Store に https://itunes.apple.com/app/id964397083 こういうアプリが公開されたそうです。

 まぁ、そんなにパワフルなものではないような気がしてますが、いい試しだと思います。ただ、使う気がない。。。

 最近 Objective-C を使ってるので、swift に比べると、まぁ、幾つか Syntax Sugar 以外、Objective-C のほうがマシだと思ってますが。
 
 再来、facebook から何か出てくるかな。。。

 それでは。

2015年4月19日日曜日

AngularJS Directive の使い方

 おととい別チームの Front End Dev に Directive のオーダーについて聞かれました。そのプロジェクトでは ng-model の隣に、入力値のチェックやフォーマットを全て個々の Directive で行われています。いっぱい Directive が書かれていて、コードを読むにはちょっと大変です。。。それで、問題となってたところは二つ Directive の中に、onblur を使って、入力値をチェックしたり、値を変えたりしてました。ただ、onblur のコールオーダーによりページには変な動作になりました。それで、onblur の handler の呼び順番変えられるかと聞かれました。
 少し、彼らの Directives を見てみると、あまりいいアプローチと思ってませんでした。なぜなら、priority も設定してないし、ng-model の中に formatter と parser キューがありますので、本らなら、それを使って、すぐできる機能なのに、全て onblur の中に書いてしました。
 まぁ、一番大事なのは問題を解決するので、まず、directive に priority という属性がありますので、それを使って、direcitive の link function を実行するオーダーが変更できます。具体的に言うと、AngularJS はまず一つの element に attach した全ての directive を array に入れて、そのあと、priority を使って、Sort してから、link を呼び出してます。それで、directive の onblur を呼ぶ順番は変えられます。
 まぁ、もう一つの方法は $timeout を使って、次の digest circle に実行することです。ただ、これは間違いだと思っています。$timeout はあまりにも使いすぎてる感じがあります。何か動かなかったら、すぐ $timeout を呼ぶとか。。。
 注意すべきところは $timeout では、$rootscope.apply() が呼ばれているので、全てのあたりが一回 digest されます。もし複数の $timeout が呼ばれるなら、ページはずっとリフレッシュされます。。。これは AngularJS が重いと言われた原因の一つだと思います。

 今回なら、ng-model すでに formatter と parser があるので、それを使うべきだと思います。それに、一つの機能を一つの directive に入れるのはあまり良くないです。いっぱい directive になると、さらにその中に jquery などを使って、DOM 操作すると、オーダーが難しくなります。もし、単独の directive を使うなら、カテゴリにより機能をまとめるべきです。例えば、入力値のフォーマットをチェックするなら、全てのチェックの一つの directive にまとめた方がいいです。そうすると、$validate でエラーメッセージを設定には簡単になります。表示の順番も操作しやすくなります。
 
 本来なら、Framework は裏でいっぱいやっているので、その処理を知るべきだと思います。例えば、directive の compile、link function はどのように呼ばれているかとか、angular の bootstrap はどのように実行しているかとか。それを知らないと、パフォーマンスのいいアプリは作れるには難しいです。
 
 それでは。