次世代のクライアントサイドフレームワーク Aurelia の開発がどんどん進んでいます

2ヶ月前のブログエントリーAurelia という次世代のクライアントサイドフレームワークについて書きましたが、Aureliaの開発が更に進んでいて、私たちもそれに追随してサンプルアプリケーションの Typescript のバージョンを更新しました。変更個所をご紹介したいと思います。

リポジトリはこちらです。gulp のみで動作し、IDEに依存していません。

Typescript 1.5.0-beta の利用


Typescript 1.5で幾つか新しいフィーチャーが導入されますが、サンプルアプリケーションでは特に以下の2つのを採用しています。


ES7 Decorators 

Typescript では以下のように使っています。

詳しくは仕様を参考にしてください。

ES6 Modules

Typescript 1.4まで独自のモジュールのインポート・エキスポートシンタクスが使われていましたが、1.5から ES6のシンタクスもサポートされています。幾つかの例は以下の通りになります。

インポート・エキスポートシンタクスは結構豊かになりました。詳しくは仕様を参考にしてください。

モジュールのインポート・エキスポート方法が変わったことに伴って、Typescript 用の型の定義のファイル(*.d.ts)の変更も必要となりました。Typescript 対応をしている Aurelia のチームメンバー Mike Graham さんがこの作業を部分的に行ってくださったので、今回も彼の Aurelia 用の *.d.ts ファイルを使わせていただきました。

ちなみに、彼が Typescript で Aurelia というブログエントリーを書いているのですが、コメントに面白い議論がありました。 Aureliaはもともと JavaScript で書かれたフレームワークですから、 *.d.ts ファイルを手動で作る必要がありますが、この作業は結構大変で、また間違いやすいものです。*.d.ts ファイルを自動で作成するために、幾つかのオプションが提案され、ブログの読者に向けて投票のお願いがありました。オプションの中に、Aurelia 自体を Typescript で書き換える(こうすると、Typescript のコンパイラが *.d.ts をおまけで作ってくれます)というオプションもあって、読者のコメントを読むと、このオプションが圧倒的に人気があることがわかります。実現されたら、Aurelia のソースは Typescript で管理されることになります。

Angular 2.0 も Typescript で実装されることが確定しているようなので、大きいフレームワークのソースを Typescript で管理する方針が明らかになっています。ますます、Typescript 自体の人気も上がっています。

フレームワークは Typescript で実装されていても、もちろんアプリケーションを作るときに、普通に JavaScript を使うのは大丈夫です。この機会にTypescript を採用してみてはいかがでしょうか?

次世代のクライアントサイドフレームワーク Aurelia のご紹介

弊社がエンタープライズ向けのプロジェクトで利用したDurandalフレームワークの作者 Rob Eisenberg さんがこの間次世代のクライアントサイドフレームワークAurliaを発表しました 。

Get Started を和訳しました


ベースの技術が変わりましたが、Durandal の後継者だと言われているフレームワークですので、早速社内で試してみました。可能性を感じたので、Aurelia の Get Started セクションを和訳しました。興味がある方は是非参考にしていただきたいです。(pull requestを送ってマージされました。訳がおかしいところがあればお知らせください!)

Get Started 日本語版


また、サンプルアプリケーションをTypeScriptに変換しました


Aurelia のサンプルアプリケーションは ES6 で実装されていますが、弊社ではクライアントサイドの開発に TypeScript を使っているので、早速 TypeScript に変換しました。

TypeScriptで実装されたサンプルアプリケーションのリポジトリ

元々のサンンプル同様にGulp を使っていて、Visual Studio 等のIDEに依存していませんので、気軽に試していただけます。メインソース、ユニットテスト、結合テストが全て TypeScript に変換されています。

ソースマップも出力されているので、ChromeでTypeScriptのままデバッグができます。



サンプルのREADMEも和訳してありますので、参考にしていただけると幸いです。

Knockout.js + Json Patch でモデルの差分検出/適用


最近手がけたプロジェクトではクライアントサイドとサーバーサイドのモデルを同期させるときの通信量を削減するために、JSON Patch RFC6902 を採用してみました。JSON Patch の簡単な説明とサーバーサイドの実装方法について、以前に紹介しましたが、今回はKnockout.jsを使ったクライアントサイド用の実装方法と利用パターンをご紹介したいと思います。


JSON Patch とは


簡単に前回の記事を振り返ると、JSON Patch は以下の2つのメイン機能を想定しています。

  • モデルに変更を適用するためのオペレーションの定義。
  • モデルに変更があったとき、その変更内容の検出と表記方法(オペレーションオブジェクト)。

一つのオペレーションオブジェクトの簡単な例です。

このオペレーションをモデルに適用すれば、モデルの age プロパティが 20 に設定されます。

逆にモデルの age プロパティが 20 に変わったら、変更前と変更後の差分の表記方法として、同じオペレーションオブジェクトが使えます。


利用パターン


変更の適用、変更の検出が可能になると、色々な利用パターンが考えられますが、今回のプロジェクトでは以下の機能を実装しました。

  • サーバーから JSON Patch データを受け取り、モデルを更新
  • モデルを更新するダイアログウインドウとメイン画面の間のモデルの差分の通信
  • モデルに対する変更の検出

具体例としてKnockout.js を元にした実装方法を紹介したいと思います。


実装方法


※ これから説明するコードはこちらの gist にまとまっています。
※ 試していただくための jsfiddle も用意しています。

キーポイント

実装の観点から、2つのキーポイントがあります。

  • プロパティに対する変更の適用と検出
  • モデル(のインスタンス)に対する変更の適用と検出

この2つのキーポイントの実装方法を順番で説明します。

プロパティに対する変更の適用と検出

変更の適用と検出を可能にするためには、プロパティが以下の3つの機能を持っている必要があります

機能概要 用途 サンプルコードで
の対応メソッド
変更前の値の保持と現在の値との比較 変更の検出 _getChanges
変更前の値を現在の値にリセット 変更の検出の結果を空にする _resetChanges
現在の値の変更 JSON Patch による変更の適用 _applyChanges
今回は、Knockout.js を使っているので、プロパティは Knockout.js の observable になっています。Knockout.js の extender を利用して、observable に上記の3つのメソッドを定義します。

extender を作成する前に、考慮しなければならない点が一つあります。observable が保持している値のタイプによって、_getChange_resetChange、_applyChange メソッドの実装が異なるので、以下の3つのタイプに合わせて、専用の extender を用意する必要があります。

observableの値のタイプ extender名
プリミティブ track
モデル trackObject
モデルの配列 trackObjectArray
track


trackObject


根本的に、プリミティブ用の extender の実装と同じですが、2つの細かい違いがあります。
  • JSON データから新規のインスタンスを生成するために、コンストラクタを使っていること
    コンストラクタは extender のパラメータとして渡されます。
  • 各メソッドが内部でそれぞれ koPatch.getChangeskoPatch.resetChangeskoPatch.applyChanges というメソッドを呼び出していること
    モデルに対する変更の適用と検出をするための専用のメソッドです。このメソッドの実装方法は"モデルに対する変更の適用と検出"で説明します。

trackObjectArray


モデルの配列の場合、以下の2つの要素を考慮しなければなりません。

  1. 配列のエレメントの追加、削除、置き換え
  2. エレメント自体に対する変更の処理
1. の処理を行うのに、Knockout.js のネイティブの配列変更監視機能を採用しています。エレメントの追加・削除・置き換えのときに、その変更内容が observableArrayChanges 変数に保持されます。

また、_getChanges_resetChanges_applyChangesが呼ばれたときに、配列の各エレメントに対して、それぞれkoPatch.getChangeskoPatch.resetChangeskoPatch.applyChanges を呼び出し、2. の処理を行います。

コード2、3、4で定義した extender を登録します。


モデルのサンプル

tracktrackObjecttrackObjectArray の extenders を利用して、モデルを作成します。

基本的に以下のようにモデルとプロパティの定義ができます。


しかし、直接 ko.observable(...).extend({ track: true }) シンタクスを使うと、エラーが起こりやすく、冗長な書き方になってしまうので、以下の3つヘルパーメソッドを使います。


そして以下のようにモデルを定義します。


※ 使われる環境、言語(CoffeeScript、TypeScript等)によって、モデルの定義方法を調整してください。

モデルに対する変更の適用と検出

プロパティに対しての変更の適用と検出の方法について説明しましたが、次はモデル自体に対して同じ処理を行うメソッドの実装方法を説明します。

同様なメソッドを実装します。
  • getChanges
  • resetChanges
  • applyChanges

上記メソッドは、パラメータとしてモデルを受け、モデルの各プロパティに対して、それぞれ  _getChanges、 _resetChanges、 _applyChange メソッドを再帰的に呼び出し、変更の適用や変更の検出を行います。


使い方のサンプル


コード9で定義したモデルを利用して、使い方のサンプルを紹介します。

このサンプルでは、ユーザーのプロフィールを編集し、DBに保存する操作をイメージします(実際のAJAXのやり取りは省略)。

上記のコードを実行すると、以下のアウトプットになります。


終わりに


モデルのフィールドが多く、そのまま送ると転送量が多くなるような場合に、JSON Patch を利用して転送量を減らすことができます。レスポンスタイムの短縮につながりますので、モバイル、デスクトップのウェブアプリケーションのユーザーエクスペリエンスの向上ができます。今回ご説明したように実装は簡単です。皆様もぜひ検討してみてください。

著者について
グリシン キリルは、11年前にロシアから来日し、2013年からエンラプトでウェブアプリケーションの開発に従事する。Functional Reactive Programmingに夢中で、クライアントサイドの開発を簡単に、より確かにするための研究を行う。

TypeScriptラムダ式のライブラリ(jQuery、Knockoutjs)での利用

前回、TypeScriptとthisのおさらい という記事で TypeScriptでラムダ式を使った場合の this の留意点について簡単におさらいしました。

実際の開発現場では、色々なライブラリと一緒に使った場合に考慮する事があるでしょう。 弊社が経験した TypeScript と組み合わせたライブラリ( jQuery、Knockoutjs )での考慮点を、簡単なサンプルとともに紹介していきたいと思います。

TypeScriptとthisのおさらい

今回はAltJsとして弊社がよく利用するTypeScriptにおけるthisについておさらいします。

基本的にはJavaScriptと変わらない、、、のですが。
TypeScriptとJavaScriptの違いとして、関数の定義方法によるところがあります。

  • アロー関数式
    • ()=>{} 
    • ラムダ [lambda]式でも通じるかと思います。
      • 当記事では「ラムダ式」と記載します。
  • 従来function式
    • function(){}

それぞれJavaScriptのfunctionと同じように使えます。


このラムダ式ですが、略記以外に重要なポイントがあります。
TypeScriptのラムダ式ではthisの扱いが異なるという所です。(ハンドブック参照)

[Java] Bean validation 1.1(JSR303, JSR349)の拡張

Javaでオブジェクトをバリデーションする仕様にBean validationがあります。
デフォルトのBean validationでは、”nullでないこと””桁数が9桁以上であること”など、最小単位のバリデーションしか用意されていませんので、ある程度複雑なアプリケーションを開発する場合、独自のバリデーションを追加する必要に迫られます。
この記事ではBean vaidationを使った独自のバリデーションを作る方法を紹介します。

Bean validation 1.1(JSR303, JSR349) とは

以下に仕様がまとめられています。

リンク先より抜粋
  • アノテーションでオブジェクトの制約を表現できる
  • 独自の制約を追加することができる
  • オブジェクト(ネストしたオブジェクトを含む)をバリデーションするAPIを提供している
  • メソッド、コンストラクターの引数、戻り値を検証するAPIを提供している
  • (ローカライズされた)バリデーションエラーを取得できる
  • Java EEに統合されている(Java EE以外でも使える)

例: コード1


作ったバリデーションはどのF/W(Java EE, Spring, Hibernate, ...etc)からでも共通的に使うことができます。

まずは、サンプルとしてSpringからBean validationを使った例でBean validationの用法を確認した上で、独自のバリデーションを定義していきます。


Bean validationの用法紹介: Spring Controllerの引数を検証するために使う

例としてDocumentオブジェクトを保存するAPIを用意します。
(前提: SpringとBean validationは事前に使える状態になっていること)

コード2: DocumentController.java

コード3: Document.java


上のコードの説明
Validアノテーション(Bean Validationが提供)
このアノテーションを付与すると、引数 doc に対してバリデーションが実行されます。

BindingResultクラス(Springが提供)
BindingResultを引数に指定しておくと、Springがバリデーション結果(エラーのあったフィールド名、満たせなかった制約、エラーメッセージ)をこのオブジェクトに設定して渡してくれる。もし、BindingResultを引数に指定しなかった場合、例外(Springの場合: MethodArgumentNotValidException.class)がThrowされるので、Springの@ExceptionHandlerとかを使ってハンドルすれば共通的にバリデーションエラー時の挙動を記述できます。

CustomConstraintアノテーション(独自に定義)
このプログラムに合わせてカスタマイズしたバリデーションを実施します。
(* 後ほど説明します)

NotNullアノテーション(Bean Validationが提供)
textに設定された値がnullの場合にバリデーションエラーになります。

⑤ ネストしたオブジェクト(配列、Listに対しても付与可能)に付与したValidアノテーション(Bean Vaildationが提供)
Validアノテーションを付けるとネストしたオブジェクトに対してもバリデーションが実施されます。

利用側からするとアノテーションを付与するだけになるため、コード簡潔に保つことができています。この例でいうと、CustomConstraintという独自のアノテーションを使っていますがこのようなアノテーションを共通的に用意しておけばバリデーションロジックを汎用的に用意しておくことができるため開発の効率化に繋がります。

それでは次にDocumentオブジェクトのidフィールドに対して、独自の制約(CustomConstraintアノテーション)を導入してみましょう

独自の制約を作成する

上のコード3にある@CustomConstraintアノテーションを作ります。
これから見ていくサンプルを簡単に説明すると、CustomConstraintアノテーションのpayloadフィールドにバリデーション内容(Validatorインターフェースの実装クラス)を指定しておくとそのバリデーション内容が実行されるというものです

コード4: CustomConstraint.java

コード5: CustomValidator.java

コード6: Validators.java
コード7: Validator.java
コード8: Message.java

コード9: WebConfig.java
上のコードの説明
独自の制約を作るときにはConstraintアノテーションを付与したアノテーション(コード4)を用意します。バリデーションロジックは、ConstraintアノテーションのvalidateByに指定したクラス(コード5)に記述します。

またこのアノテーションには、以下3フィールドを定義しておく必要があります。

  • message 制約に違反したときにこのメッセージが返されます。このメッセージにはローカライズ等の変換処理が施され返されます。変換に関する仕様はこちらに書かれています。 仕様ではResourceBundleにあるValidationMessages(ValidationMessages.properties)がメッセージの変換に使われますが、独自のメッセージ定義を使いたいときには、Springの場合、コード9に記載のあるようにWebConfigurerAdaptor#getValidatorをoverrideし独自の設定をすることでこれが実現できます。
  • groups groupsを指定した場合、バリデーションする/しないを任意の単位で分割することができます。 例えば、「あるAPI Aではバリデーションしたいけど、別のAPI Bではバリデーションしたくない」といったときにAPI Aグループと、API Bグループをつくり、バリデーションするときにこのグループを指定すれば、指定したグループ単位のバリデーションが実施されます。(* Springでグループ単位のバリデーションをするには、javax.validation.Validアノテーションの代わりに、org.springframework.validation.annotation.Validatedアノテーションを使います)
  • payload 制約アノテーション(e.g. NotNull)を付与するときに、制約に対して更に情報を付与したいときに使用します。 例えば、フィールドA、BにNotNullアノテーションを付けていて、フィールドAがnullのときはエラーとして扱い、フィールドBがnullのときは警告として扱いたいといったときに、フィールドAには@NotNull(payload=sample.Error.class)、フィールドBには@NotNull(payload=sample.Warning.class)を指定することで、バリデーションエラー受取側では、このpayloadに設定された値によって挙動を変えることができます。


実際のバリデーションはコード5の①で実施されています。
この例では、payloadに指定されたバリデーター(e.g. Validators.Id)に定義されたバリデーションロジックを実施し、エラーがあればメソッドの引数のConstraintValidatorContextにメッセージを追加します。
以上でBean validationを拡張した独自のバリデーションが完成しました。


Author
Yuki Sanada

[Scala] Unfilteredで簡単ストリーミングダウンロード

本記事では、Scala製のUnfilteredと呼ばれるフレームワーク(後述)を使用し、簡単にファイルをストリーミングダウンロードする方法を紹介します。


Unfilteredとは?

ここでの詳しい説明はしませんが、簡単に説明するとUnfilteredは、Scalaのパターンマッチの機能を使用し、HTTPリクエストを処理するフレームワークです。

詳しい説明は、公式ドキュメントにサンプルとともに記載されてあります。

ResponseBytes

まずUnfilteredには、ResponseBytesと呼ばれるクラスが用意されており、そちらを利用することによりByteデータを簡単に返却することが可能となっています。

しかしながら、ResponseBytesを使った実装では、以下の様な問題が出てきます。

  • ダウンロード対象が大きいファイルの場合、データをArray[Byte]に溜め込んでしまうため、ダウンロード可能なファイルサイズがヒープ容量に依存。
  • ダウンロード時も全てファイルデータを読み込んだ後にファイルダウンロード開始されるため、開始されるまで止まっているように見える。


Channel(Netty)

そこで、NettyのChannelを使い、ストリーミングすることでResponseBytesで起きた問題を解決することが可能となります。

ここで注意すべき点としては、非同期処理を行うため、Planをasync.Planにする必要があります。

以上でストリーミングダウンロードが可能となりますが、Unfilteredフレームワークに限らず、ファイルダウンロードAPIを作成する際は、Channelなどを用いた非同期な実装を検討してみてはいかがでしょうか。

Author
Satoru Takaishi

BEMに基づいたCSS設計手法のメリットについて

BEMの採用でCSSとHTMLの開発プロセスの改善をする


私はCSS/HTMLの開発の際、構成管理をどのようにすれば良いか考える機会がありました。どんなコードベースでも以下の点の改善ができれば、開発のプロセスがもっと早く、もっと簡易に、もっと確かになるためです。
  • 再利用性
  • 拡張性
  • 開発生産性とメンテナンス性

上記の点の改善を可能にするCSSとHTML設計手法のうちの一つにBEMがあります。どのように改善ができるか、詳しく説明したいと思います。

再利用性


BEMにはブロックエレメントいう2つの概念があります。
ブロックとは独立した存在で、デザインの「構成要素」であります。ブロックはコンテキスト(親HTMLエレメント等)に依存せずに、ページのどこの位置に配置されても自分の機能を保つべきものです。
ブロックを組み合わせて、アプリケーションページを組み立てます。
エレメントは、ブロックの一部分であり、特定の役割を果たしています。 エレメントはコンテキストに依存していて、そのエレメントが属するブロックだけで利用されています。
ブロックとブロックの中にネストされたエレメントの例:
ブロックの独立した性質のおかげで、他のブロックと自由な組み合わせでアプリケーションのどこのページにでも簡単に再利用ができます。

拡張性


BEMには更にモディファイヤーという概念があります。
モディファイヤーはブロックとエレメントのスタイルにバリエーションを持たせるためのものです。CSSとHTMLの開発フェーズが終わっていても、CSSのベーシックな知識しか持っていないチームメンバーでも新しいモディファイヤーを追加することで、既存のブロックやエレメントのデザインの変更が簡単にできます。
既存のブロックの背景色を変更するモディファイヤーを追加する例:
また、既存のモディファイヤーを組み合わせたりすることで、新しいデザインが作れます。
既存の二つのモディファイヤーの組み合わせで新しいデザインのボタンを作成する例(ボタンの色とサイズの組み合わせ):

開発生産性とメンテナンス性


ブロックはコンテキストに依存しない存在であるため、ブロックを組み合わせることでページの作成が可能になります。
CSSとHTMLの作成を外部デザイナーに依頼する場合、アプリケーションページの全体の作成ではなく、必要なブロックだけの作成を依頼すれば、あとは基本レベルのCSSとHTMLの知識を持つチームメンバーでもブロック利用して、アプリケーションページの組み立てができます。
2つのブロックの簡単な組み立ての例:

簡略化されたBEMへのアプローチ


BEM自体は結構大きなフレームワークです。CSS設計ルールだけではなくて、専用のテンプレートエンジンやビルドツールやJavaScriptを取り扱う方法などが含まれています。このフレームワークの全ての要素を導入するには、相当な努力が必要でしょう。
幸いなことに、ブロック、エレメント、モディファイヤーというコアコンセプトを有効に使うのに、全体のフレームワークを取り入れる必要はありません。BEMに基づいたCSS設計ルールだけを採用しても、BEMをはじめることができます。
弊社では、こういうCSS設計ルールセットを用意しております。この設計ルールセットのメインの部分を紹介したいと思います。

BEMに基づいたCSS設計ルール


  1. クラスのネーミング

    概念的に、クラスのネーミングルールはBEMのものと同じですが、ブロック、エレメント、モディファイヤーの区切り用のエレメントを自分の好みにあわせています。
    各ブロックの定義は個別のファイルに納めることで、ブロック名の衝突を避けています。
  2. カスケードセレクターを利用しない

    コンテキストに依存してしまい、ブロックの再利用が困難になるため、カスケードのセレクターを利用しません。
    エレメントの場合も同じです。理由は2つあります。
    • セレクターのspecificity(詳細度)が上がってしまうので、CSSルールが特殊になり、モディファイヤーでのスタイルの上書きが難しくなります。
      Specificityというのは、CSSルールの優先順位のことです。複数のCSSルールが同じHTMLエレメントの同じ要素をコントロールしているとき、specificityが高い方が優先されます。基本的に、カスケードのあるセレクターのspecificityがカスケードのないセレクターより高いので、以下の例でテキストの色はredのままになり、モディファイヤーが効かなくなります。
      だめな定義の例:
      セレクターのspecificityが同じ場合、後から定義された方が優先になります。
    • クラスのネーミングルールによって、エレメントのクラス名にすでにブロック名が入っているため、他のブロックのエレメントのクラス名との衝突はおきません。
  3. タイプセレクターを利用しない(セレクタにタグ名が使われているセレクターのこと)

    • カスケードセレクターと同じように、specificityが上がるので、モディファイヤーでのスタイルの上書きが難しくなります。
    • 定義された以外のエレメントでの利用が不可になります。
  4. セレクターにIDを利用しない

    IDを使ってしまうと、そのブロックをページ内で一回しか使えなくなるために、再利用が不可になります。
以上が設計ルールセットのメインの部分の紹介になります。

簡単なブロックのCSSとHTMLのサンプル


以下に簡単なブロックとモディファイヤーの定義と利用方法のサンプルを紹介します。

結果


まとめ


最近手がけたエンタープライズ向けプロジェクトでも上で説明したCSS設計手法を採用しています。その感想を簡単にシェアしたいと思います。
  • 今回のプロジェクトではブロックのCSSとHTMLの作成を外部デザイナーに依頼していました。作成していただいたブロックを組み立て、合計で50以上の画面を作りましたた。ブロックの再利用が本当に簡単で、画面作成にかかるコストを大幅に減らせた印象があります。
  • デザイナーからブロックのCSSとHTMLが納品された後でもデザインの多少の変更がありましたが、CSSの再設計を依頼せずに、モディファイヤーを利用することで既存のブロックの拡張が簡単にできました。
著者について
グリシン キリルは、11年前にロシアから来日し、2013年からエンラプトでウェブアプリケーションの開発に従事する。Functional Reactive Programmingに夢中で、クライアントサイドの開発を簡単に、より確かにするための研究を行う。

Popular Posts