Ractive 0.7.3 と non-POJO のワーニング

# はじめに
[Kii Cloudの開発者ポータル](https://developer.kii.com/?locale=jp)では、そのWeb UI部を[Ractive.js](http://www.ractivejs.org/)というライブラリを主に使って実装しています。
React.jsと名前が似ていますが、あくまでRactive.js。シンプルなテンプレートUIライブラリといったところです。
このライブラリの概要については他の紹介記事でも参考してもらうとして、本題。

最近Ractiveのバージョンを0.7.3に引き上げたところ、以下のようなワーニングが出力されるようになりました。

> Ractive.js: If supplied, options.data should be a plain JavaScript object - using a non-POJO as the root object may work, but is discouraged

これは何ぞ? というお話です。
![スクリーンショット 2016-07-05 19.04.55.png](https://qiita-image-store.s3.amazonaws.com/0/131614/91fa2f25-d08e-416f-6ea0-f532031dadb1.png)

# POJO / non-POJO とは?
ワーニングメッセージ全文に取りかかる前に、人によっては聞き慣れない `POJO` という単語について見てみましょう。
POJO、ポジョ、、スペイン語をかじった身としてはニワトリ(pollo)が脳裏に浮かびますが、これは **P**lain **O**ld **J**avaScript **O**bject の略です。
ようは飾り気の無い普通のJSオブジェクト、 `{}` で生成されるそれを指します。
(注: POJO は元々 Plain Old Java Object の略でしたが、最近は JavaScript にも使用されています)

では、non-POJOとは。
Ractive.jsのワーニングを出しているソースを読むと以下のように定義されています。

~~~~JavaScript
> // Warn if userOptions.data is a non-POJO
> if (data && data.constructor !== Object) {
~~~~

データの [constructor プロパティ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF) が `Object` かどうかで判断している様子。
念のためJSコンソールで以下を叩いてみると `{}` の `constructor` プロパティが確かに `Object` である様子が見て取れます。

~~~~JavaScript
> ({}).constructor
< function Object() { [native code] }

> ({}).constructor === Object
< true
~~~~

# POJOは分かった、じゃあこのワーニングは何か?
ワーニングを訳すとだいたいこんな感じになります。

> Ractive.jsからのお知らせ: options.dataを指定するならプレーンなJSオブジェクトを指定してね。non-POJOなオブジェクトでも動くかもしれんけどオススメしないよ。

つまり、POJO 以外の何かが data に指定されていると、そう警告をしているわけです。
むしろ何を options.data に渡しているのか。
調査してみるとコレには二つのパターンが見つかりました。

## data に CoffeeScript のクラスを指定してた
開発者ポータルではAltJSとして [CoffeeScript](http://coffeescript.org/) を採用しています。
JSに仕込まれた大量のハマりポイントをいい感じにしてくれる、ゆるふわ言語ですね。
あまりに便利なのでついつい `=>` や `class` を連発したくなります。

今回の例で言えば data に何となく `class` なオブジェクトを指定してしまっていたと。
つまりこういうことです。

~~~~CoffeeScript
class Hello
  constructor: () ->
    @ractive = new Ractive({
      el: '#container',
      template: '#template',
      data: new HelloData()
  })

class HelloData
  constructor: () ->
    @name = 'world'
~~~~

上の例では明らかに class を使う意味はないです。
(CoffeeScriptの甘い誘惑に負けてしまったのでしょう)
そして上の例でなくても、実際のところ class じゃないと困る、というケースは、そうそう考えられません。

一方で、読み込みの順序等々の都合で、POJOじゃあ困る、というケースは確かにあります。
例えば上の例のように、 data を class の外に配置した場合、data の評価はこのJSファイルが読み込まれたタイミングとなります。
作りによっては参照エラーなど、思わぬ問題に出くわします。

Ractiveでは **POJOを返す関数をdataに渡す** ことを許可し、この問題を回避しています。
つまりこういうことです。

~~~~CoffeeScript
class Hello
  constructor: () ->
    @ractive = new Ractive({
      el: '#container',
      template: '#template',
      data: helloData
  })

helloData = () ->
  return {
    name: someGlobalReference
  }
~~~~

## data にbackbone.js モデルを渡していた
[Ractive.js の Plugins ページ](http://docs.ractivejs.org/latest/plugins)を見るとAdaptorsの先頭に Backbone.js が鎮座しています。
一世を風靡した [Backbone.js](http://backbonejs.org/) ーMVC構造を提供するライブラリー は開発者ポータルでも一部で、薄く使用されており、さらにその一部は直接 Ractive.js の data へと直接指定されていたのです。

WebクライアントにおけるMVCモデル、Ractive.js の data もいわばコレに当てはめるならば `M` と言えるのではないか、2way binding で RESTful にデータを扱えれば最強なんじゃあないかという考え方。
これについては、今回の話から大きく、とても大きく離れてしまうので、別途機会を設けて詳しく書きたいところなのですが、あえて一言だけ言うならば
**「やめておけ」** と。
いえ、思想の問題(だけ)ではなく、データと描画の不整合や、パフォーマンスの問題を引き起こす可能性があるからです。
Backbone.js を Ractive.js と一緒に使いたいのであれば、data に直接Backbone.js Model や Collection を渡すのではなく、必要に応じて、 data に attributes 値をコピーして受け渡すことをオススメします。

# 最後に
Ractive.js 0.7.3 では他にも親切なワーニングをたくさん出してくれるようになりました。(テンプレートの閉じタグが間違っている等)
古いものを使っている方は是非、最新版に上げてみましょう。
そして、ワーニングには素直に従いましょう。

----
[**Kii株式会社では開発者ポータルを一緒に作ってくれるウェブエンジニアを募集しています！**](https://jp.kii.com/recruit/index.html)