最近、他のプロジェクトが忙しくて、短期的に助けに行きました。今、そのチームは Home Loan Calculator を作っています。会社初めての React.js を使う Web App です。最初の二日間はソースコードを読んでん、Gulp タスク、 WebPack を慣れるだけでした。
AngularJS より、React.js のほうが簡単でした。Component の概念をわかったら、もうだいぶどのように HTML をレンダリングするかをイメージできるようになりました。
まず、React.js はただの UI ライブラリです。MVC 中の V または C-V だけです。まぁ、全て Component に Event Handler などを書けば、普通の Web App になるだけ。Reuse の観点から、やはりM(Model)をあったほうがいいです。その C-V と M の間に座るのは Facebook は Dispatcher というものを勧めています。下記のサイトは詳しく紹介しています。
Flux アーキテクチャー
React.js は App をレンダリングには Virtual Dom というものを内部で持っています。DOM 操作をする前に、次なる状態 (props, state) を使って、現在の Virtual DOM をまず比べます。その結果を基づいて、DOM 更新を行います。ここのフィロソフィーは JavaScript は DOM 操作よりかなり速いです。そうすると、Web App 全体が速く実行できます。自分で使ってみたら、Chrome のパフォーマンスツールによると、多分4倍ぐらい React.js ほうが速いです。(React.js 300ms - AngularJS 1300ms)まぁ、Web App の性質にもよりますけど。
また、 UI ライブラリとして、 React.js も Component の状態をコントロールするために、lifecycle 細かく複数のコールバック関数を分けています。下記のサイトをご参考を。
component specs, lifecycle
Flux を使うと、AngularJS と比べたら、機能をどのように入れるかの設計フェーズはちょっと難しいです。ng-controller, service みたいの概念がないから、例えば、Ajax call はどこに入れるかと考えると Action にするか、data store に入れるか、または Component に入れる。。。いろいろ選択しがありますが、今のアプリでは action に入れています。success の call back に Dispatcher を使って、Store をアップデートしてから、その store の中から、Change event を Emit して、UI (Component) を更新するようになっています。
アプリ全体の設計も AngularJS と違って、まず App という体制を作って、その App の中には Header, Inputs, Results, Footer などの Component 入れます。各 Component もさらに細かい、小さい Component を持っています。これをベースに、React.js は Virtual DOM を作ります。
Component は props (properties)、と state が持っています。props は親の App から、attributes に設定したものです。state は component 自分でメインテナンスします。props と state を変わると、React.js は自動的に Render() function を呼び出して、DOM の再レンダリングします。
具体的に、どのように動くかは後日また詳しく。
Code
2015年11月8日日曜日
2015年10月10日土曜日
ASP.NET C# MVC4 に Webapi アップデート
先日、あるプロジェクトを ASP.NET C# Web MVC4 から Web Api に直そうと。以前、MVC4 のプロジェクトでも幾つかの Controller が Json を返しています。それで、今回の機に、もう Web Page を他のプロジェクトに移して、この App との Edge layer も WebApi にアップデートします。
実際やってみたら、普通の Controller から ApiController に直して、IHttpResult か HttpResponseMessage に変更して、全ての Unit Test を通して、完了かと思いました。テストしたら、なぜか幾つかの Acceptance Test が通らなくなった。。。
詳しく調べてみたら、主に下記の二点になります:
1 まず、戻り値について、以前 MVC4 の場合、Json(null) は空の Response body になりますが、WebApi の場合、"null" になります。これで、正しく deserialize できない Json ライブラリがあって、例えば、iOS では、null は間違った Json というエラーになります。ただ、Newton Json では、null 値になります。Android も問題なく、実際の null になります。結局 iOS だけかと思って。。。それで、Controller で null の場合、Ok() を返すように 修正しました。
2 もう一つの問題点は MVC4 では ModelDataBinder を使っていますが、Request headers, query string, body を探して、引数の Object を作成します。WebApi になると、primitive タイプ(int, double など)の場合、query string から、ModelDataBinder を使って、バインドするようになっています。複雑なオブジェクトの場合、Formatter を使って、Body から作ろうと。もし見つからない場合、もうあきらめるので、null になります。このデフォルトを変える場合、[FromUri], [FromBody] という属性を使って、WebApi に”このオブジェクト” はバインド FromUri ですと明白に指定する必要があります。
他には、StartUp.cs を WebApi ものに変えたりして、簡単にできます。将来的にはやはり Api なら WebApi を使ったほうがいろいろ簡単な機能がありますので、使いやすいです。
それでは。また。
実際やってみたら、普通の Controller から ApiController に直して、IHttpResult か HttpResponseMessage に変更して、全ての Unit Test を通して、完了かと思いました。テストしたら、なぜか幾つかの Acceptance Test が通らなくなった。。。
詳しく調べてみたら、主に下記の二点になります:
1 まず、戻り値について、以前 MVC4 の場合、Json(null) は空の Response body になりますが、WebApi の場合、"null" になります。これで、正しく deserialize できない Json ライブラリがあって、例えば、iOS では、null は間違った Json というエラーになります。ただ、Newton Json では、null 値になります。Android も問題なく、実際の null になります。結局 iOS だけかと思って。。。それで、Controller で null の場合、Ok() を返すように 修正しました。
2 もう一つの問題点は MVC4 では ModelDataBinder を使っていますが、Request headers, query string, body を探して、引数の Object を作成します。WebApi になると、primitive タイプ(int, double など)の場合、query string から、ModelDataBinder を使って、バインドするようになっています。複雑なオブジェクトの場合、Formatter を使って、Body から作ろうと。もし見つからない場合、もうあきらめるので、null になります。このデフォルトを変える場合、[FromUri], [FromBody] という属性を使って、WebApi に”このオブジェクト” はバインド FromUri ですと明白に指定する必要があります。
他には、StartUp.cs を WebApi ものに変えたりして、簡単にできます。将来的にはやはり Api なら WebApi を使ったほうがいろいろ簡単な機能がありますので、使いやすいです。
それでは。また。
2015年9月12日土曜日
C# asyn と await の使い方
先週、やっとアプリを App Store にサブミットしました。ついでに、バックエンドの Web Api も Refactoring して、もっと速くなりました。その改善の一つとしては、HttpClient を使って、他の Endpoint からデータを取得する処理を全て async にしました。たとえば、三つの Http Call をするところ、await Task.WhenAll(<TaskList>) を使って、Concurrency になりました。三つ Call を並べたら、500 ms * 3 の処理を、500ms ちょっとでできます。
ただ、一つだけ、最初は Task.Run() を使って、そのタスクを await しようとのコードを発見しました。それは間違いです。なぜなら、Task.Run は Thread pool から一つのスレッドを申請して、そのタスクを実行しようとします。本来、現在のスレッドを await すると、もっと別のリクエスト処理できるのに、逆にもう一つのスレッドを使ったので、async の意味がなくなります。タスクを await すると、IO の処理は実行している間、CPU Heavey の処理が実行できますし、今のスレッドを一時的に手放して、他のリクエストも処理できます。遅い IO 処理が終わったら、また元の Call Context から処理を Resume して、本来のタスクを完成します。
一つの Best Practice としては、async を使うと、Top-Down で全てを async にしたほうがいいです。そうしないと、デッドロックが発生するかもしれない。参考として下記のブログが詳しく説明されています。
async を block しないで
また、ASP.NET で await void を関数をできるだけ使わないでください。こちらは実際問題が起こされて、一つの AWS Box が応答しなくなりました。原因はまだ調査していますが、await void は結構危険です。
それでは。
ただ、一つだけ、最初は Task.Run() を使って、そのタスクを await しようとのコードを発見しました。それは間違いです。なぜなら、Task.Run は Thread pool から一つのスレッドを申請して、そのタスクを実行しようとします。本来、現在のスレッドを await すると、もっと別のリクエスト処理できるのに、逆にもう一つのスレッドを使ったので、async の意味がなくなります。タスクを await すると、IO の処理は実行している間、CPU Heavey の処理が実行できますし、今のスレッドを一時的に手放して、他のリクエストも処理できます。遅い IO 処理が終わったら、また元の Call Context から処理を Resume して、本来のタスクを完成します。
一つの Best Practice としては、async を使うと、Top-Down で全てを async にしたほうがいいです。そうしないと、デッドロックが発生するかもしれない。参考として下記のブログが詳しく説明されています。
async を block しないで
また、ASP.NET で await void を関数をできるだけ使わないでください。こちらは実際問題が起こされて、一つの AWS Box が応答しなくなりました。原因はまだ調査していますが、await void は結構危険です。
それでは。
2015年8月22日土曜日
Event Handler を DOM 要素に Bind する時のテクニック
先週、ついリリースしました。今はアプリの App Store と Play Store の承認を待っています。たぶん大丈夫でしょう。最後のバグは jQuery 関係の Event Handler の Bind です。ある <a> tag のクリックに ScrollTo の jQuery Animation を呼びたかったが、アニメーションが実行されなくて、普通に飛んで行きました。
詳細を調べてみたら、本来すでに Click に Handler を Bind して、 ScrollTo を呼び出しましたけど、チームの新人さんがそれが知らなくて、別の関数で実現しました。しかも stop(true, true) で前のアニメーションを全てキャンセルして、自分のアニメーションを実行していました。考え方としては問題がありません。ただ、stop() の第二の引数 jumpEnd です。true を渡すと、前のアニーメーションの最後までいきなり実行します。これがバグのルートです。ただ、stop(true) を呼ぶと、普通に正しく実行できました。
最初は大騒ぎでしたが、問題はどこにも存在するイベントの Bind です。もし、全ての Bind を各ページに譲って、固定の箇所にしたら、たぶん新人さんでも気づくでしょう。たとえば、jQuery.ready() の中、ページの js ファイルに定義するとか。もし複数のページが同じコードが使うなら、main.js の固定場所に 置くとか。
もう一つはアニメーションの使い方です。むやみに全てのアニメーションをキャンセルするのがどうかと思います。気軽に全てを止めったり、キャンセルしたりすると、思わぬバグに繋がります。
幸い新人さんがすぐ私に聞いたので、コードはよく知ってるので、すぐ直しました。今後、どこで何をするかを一応ドキュメントにも残したいと思います。
後、Back End のデータベース Oracle が AWS で他のチームと衝突したので、SQL Server に乗り換えました。後日また詳細を。
それでは。
詳細を調べてみたら、本来すでに Click に Handler を Bind して、 ScrollTo を呼び出しましたけど、チームの新人さんがそれが知らなくて、別の関数で実現しました。しかも stop(true, true) で前のアニメーションを全てキャンセルして、自分のアニメーションを実行していました。考え方としては問題がありません。ただ、stop() の第二の引数 jumpEnd です。true を渡すと、前のアニーメーションの最後までいきなり実行します。これがバグのルートです。ただ、stop(true) を呼ぶと、普通に正しく実行できました。
最初は大騒ぎでしたが、問題はどこにも存在するイベントの Bind です。もし、全ての Bind を各ページに譲って、固定の箇所にしたら、たぶん新人さんでも気づくでしょう。たとえば、jQuery.ready() の中、ページの js ファイルに定義するとか。もし複数のページが同じコードが使うなら、main.js の固定場所に 置くとか。
もう一つはアニメーションの使い方です。むやみに全てのアニメーションをキャンセルするのがどうかと思います。気軽に全てを止めったり、キャンセルしたりすると、思わぬバグに繋がります。
幸い新人さんがすぐ私に聞いたので、コードはよく知ってるので、すぐ直しました。今後、どこで何をするかを一応ドキュメントにも残したいと思います。
後、Back End のデータベース Oracle が AWS で他のチームと衝突したので、SQL Server に乗り換えました。後日また詳細を。
それでは。
2015年8月3日月曜日
セキュリティ:クッキー
つい先週、最後のセキュリテイチェック、パフォーマンステスト、Non-Functional テストが終わって、開発した Web API が live になりました。そのチェックの中に、クッキーの設定について、指摘がありました。ASP.NET を使ってるので、web.config に下記の設定追加しろうと。
<system.web>
<httpcookies httpOnlyCookies="true" requireSSL="true" />
</system.web>
今回の Web API では、セッションは OAuth を使っていますし、各 Endpoint は完全に Stateless で、クッキーとか使っていません。ただ、念のため、上記の追加しました。
クッキー値の設定では、四つのフラグが あって、この中の二つは httponly と secure です。
httponly を設定すると、JavaScript からそのクッキーの値が見えなくなります。ただ、クッキーは browser の 各 request には存在します。こうすることで、 document.cookie が .ASPXAUTH などのセッション Id が見えなくなるので、ajax でのセッションハイジャックはある程度防げます。
サーバーから Set-cookie の値が以下になります。
Set-cookie: sessionId=abcdef; path=/; HttpOnly
もう一つの requireSSL フラグは secure フラグをクッキー値に設定します。つまり、scheme は Https の場合のみ、クッキーをサーバー側に送信します。http でサイトを見る場合、または http で image などを要求する場合では、そのクッキーが見えません。
サーバーから response での Set-cookie は以下になります。
Set-cookie: sessionId=abcdef; path=/; Secure
こうすることで、ある程度クッキーが保護されます。別にクッキーが使わなくても、フラグを true に設定したほうがいいでしょう。
覚えておこう。
<system.web>
<httpcookies httpOnlyCookies="true" requireSSL="true" />
</system.web>
今回の Web API では、セッションは OAuth を使っていますし、各 Endpoint は完全に Stateless で、クッキーとか使っていません。ただ、念のため、上記の追加しました。
クッキー値の設定では、四つのフラグが あって、この中の二つは httponly と secure です。
httponly を設定すると、JavaScript からそのクッキーの値が見えなくなります。ただ、クッキーは browser の 各 request には存在します。こうすることで、 document.cookie が .ASPXAUTH などのセッション Id が見えなくなるので、ajax でのセッションハイジャックはある程度防げます。
サーバーから Set-cookie の値が以下になります。
Set-cookie: sessionId=abcdef; path=/; HttpOnly
もう一つの requireSSL フラグは secure フラグをクッキー値に設定します。つまり、scheme は Https の場合のみ、クッキーをサーバー側に送信します。http でサイトを見る場合、または http で image などを要求する場合では、そのクッキーが見えません。
サーバーから response での Set-cookie は以下になります。
Set-cookie: sessionId=abcdef; path=/; Secure
こうすることで、ある程度クッキーが保護されます。別にクッキーが使わなくても、フラグを true に設定したほうがいいでしょう。
覚えておこう。
2015年7月30日木曜日
React.js と AngularJS、どっちがいい?
追加:下記は React.js 実際使う前の書き込みです。こちらも:
React.js Vs AngularJS、どっちがいい その2
React.js Vs AngularJS、どっちがいい その3 - React.js 速い!
最近、隣のチームのプロジェクトでは AngularJS がヘビーだから、 React.js にしたと聞きました。最初、そのチームは AngularJS を使って、Demo を作りました。モバイルでテストすると、何かウェブサイトがすこし応答が遅いと思ったそうです。でも、それは AngularJS の問題ではないと思います。実際向こうのデモサイトを見てみたら、$timeout() がいっぱいあったりして、Directive もいっぱい作って、本来計算が終わったら、$apply を使うべきところを全部 $timeout を使ったりしていました。Angular の使い方としては間違ってると思います。Dirty Check はただ Model 変化をチェックする方法の一つです。Getter Setter の中にいろいろ判断するより、Dirty Check は理解しやすいし、重い処理は Framework に譲れたと思われています。
まぁ、そのチームが React.js に乗り換えったら、Flux を使って、プログラム全体の構造は3年前 Backbone.js を使った時とほぼ同じになりました。実際デモサイトと比べると、それほど速いと思われてないし、勉強とか、Cross Browser の対応とか、またいろいろ苦労したそうです。最初デモサイトがモバイルでは重いと思われたことは 300ms Click との関係もなくはないと思います。
しかも、React.js を使ったら、プログラム全体がわかりづらくなりました。Flux の Dispatcher を理解しない限り、どこで、何が更新されたかさっぱりわかりません。。。
逆に AngularJS だったら、Controller, Service とかすぐ見つかるし、Back end の開発者もある程度見ればわかります。
多分、区別はそこだと思います。React.js は Framework というより、ライブラリだと思います。つまり、アプリとみなすには、Flux などイベント Dispatcher、Model などをまた作らなければなりません。それを考えてみると、Polymer のほうが使い易いと思いますし、速度的には React.js の Virtual DOM より、それほど遅くないと思います、どうせメモリ上の比べだから、Dirty Check でも。
将来 AngularJS 2.0 をかなり期待できると思います。Polymer とのシームレスとか、遅延ロードとか、Framework としてはかなりいいフィーチャーになります。
まぁ、まだ React.js を詳しくみてないから、こう思ってますが、実際 React.js を View にして、AngularJS の Framework に組み込んだら、面白いかもしれません。
今のプロジェクト一段落したら、また React.js を使ってみて、AngularJS と比べたいと思います。
それでは。今現在の考えで。
React.js Vs AngularJS、どっちがいい その2
React.js Vs AngularJS、どっちがいい その3 - React.js 速い!
最近、隣のチームのプロジェクトでは AngularJS がヘビーだから、 React.js にしたと聞きました。最初、そのチームは AngularJS を使って、Demo を作りました。モバイルでテストすると、何かウェブサイトがすこし応答が遅いと思ったそうです。でも、それは AngularJS の問題ではないと思います。実際向こうのデモサイトを見てみたら、$timeout() がいっぱいあったりして、Directive もいっぱい作って、本来計算が終わったら、$apply を使うべきところを全部 $timeout を使ったりしていました。Angular の使い方としては間違ってると思います。Dirty Check はただ Model 変化をチェックする方法の一つです。Getter Setter の中にいろいろ判断するより、Dirty Check は理解しやすいし、重い処理は Framework に譲れたと思われています。
まぁ、そのチームが React.js に乗り換えったら、Flux を使って、プログラム全体の構造は3年前 Backbone.js を使った時とほぼ同じになりました。実際デモサイトと比べると、それほど速いと思われてないし、勉強とか、Cross Browser の対応とか、またいろいろ苦労したそうです。最初デモサイトがモバイルでは重いと思われたことは 300ms Click との関係もなくはないと思います。
しかも、React.js を使ったら、プログラム全体がわかりづらくなりました。Flux の Dispatcher を理解しない限り、どこで、何が更新されたかさっぱりわかりません。。。
逆に AngularJS だったら、Controller, Service とかすぐ見つかるし、Back end の開発者もある程度見ればわかります。
多分、区別はそこだと思います。React.js は Framework というより、ライブラリだと思います。つまり、アプリとみなすには、Flux などイベント Dispatcher、Model などをまた作らなければなりません。それを考えてみると、Polymer のほうが使い易いと思いますし、速度的には React.js の Virtual DOM より、それほど遅くないと思います、どうせメモリ上の比べだから、Dirty Check でも。
将来 AngularJS 2.0 をかなり期待できると思います。Polymer とのシームレスとか、遅延ロードとか、Framework としてはかなりいいフィーチャーになります。
まぁ、まだ React.js を詳しくみてないから、こう思ってますが、実際 React.js を View にして、AngularJS の Framework に組み込んだら、面白いかもしれません。
今のプロジェクト一段落したら、また React.js を使ってみて、AngularJS と比べたいと思います。
それでは。今現在の考えで。
2015年7月5日日曜日
Youtube ビデオを responsive にする方法
先週、モバイルの WebView を使って、文章を表示する機能をアプリに追加されました。エディターから一つの要求は youtube のビデオを表示したいです。基本的に文章は Responsive をしているので、コンテンツは問題なく各種のモバイルスクリーンサイズが適応できますが、youtube ビデオは iframe の中にあるし、youtube の JavaScript ライブラリで作成されますので、responsive にするには with と height を 16:9 で固定する必要があります。ただ、iframe のサイズを変更するには JavaScript 以外だったら、すこし難しいです。特に、JavaScript を web page に使いたくない時があります。
調べて見たら、css- trick からcss だけで youtube ビデオを responsive にする方法がありました。まず、ifarme にラッパーに置きます。html は以下の通り:
<div class="video-wrapper">
<iframe width="480" height="270" src="http://www.youtube.com/embed/{youtube-video-id}?rel=0&hd=1" frameborder="0" allowfullscreen></iframe>
</div>
そのあと、css:
.video-wrapper {
position: relative;
padding-bottom: 56.25%; /* 16:9 */
padding-top: 25px;
height: 0;
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
調べて見たら、css- trick からcss だけで youtube ビデオを responsive にする方法がありました。まず、ifarme にラッパーに置きます。html は以下の通り:
<div class="video-wrapper">
<iframe width="480" height="270" src="http://www.youtube.com/embed/{youtube-video-id}?rel=0&hd=1" frameborder="0" allowfullscreen></iframe>
</div>
そのあと、css:
.video-wrapper {
position: relative;
padding-bottom: 56.25%; /* 16:9 */
padding-top: 25px;
height: 0;
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
ここのトリックは padding-bottom です。パーセンテージにすると、width の長さになります。ここ 56.25% を設定すると、width とのアスペクト比は 16:9 になります。
次、iframe を 100%, 100%, position を absolute に設定したら、親要素の中にフル表示されます。
参考にしたページは
css でいろいろできるなと。例えば、これ:
それでは。
登録:
投稿 (Atom)