ミルク色の記録

やったこと、やってみたこと

observable-storeとfreezable-storeというのを作ってみた話

きっかけ

ビューを作るのにReactを使っているとpropsで渡すものはなるべくシンプルなオブジェクトにしたいかな...みたいな気分になる。

(雑な例であまり良くないのだけれど)例えば、カウンタアプリケーションで現在のカウントを表示するビューみたいなのを作る時に、propsで渡されるのはCounterモデルのインスタンスで...とかではなくて、単純にcountプロパティを持つオブジェクトってだけにしたい。

// こうじゃなくて
function CounterView(props) {
  const { counter } = props;
  return <div>{counter.getCount()}</div>;
}

// こんな感じにしたい
function CounterView(props) {
  const { count } = props;
  return <div>{count}</div>;
}

propsで渡ってくるのはそういうオブジェクトだよということをPropTypesとかflowで保証して、キー名typoして残念undefined...みたいなのは防いでおく。ビュー側では参照しかしないので、とりあえず構造が合っていればモデルのこと知らなくていいみたいな感じにしたい。

逆に参照ではなくて状態を変えるところ、例えばカウンタのカウントを増やすみたいなのは、むき出しのJSONこねこねします...みたいなのじゃなくて、ちゃんとCounterモデルの操作にしたい。

またしても雑な例にすると、次みたいな感じでincrementメソッド呼ぶみたいにしたい。

const counter = new CounterModel(/* 初期化パラメータとか */);
counter.increment();

で、その辺りひっくるめてちょっと自分なりのやり方探してみようかなーと、モデルとビューの間に入って橋渡しするくんとしてobservable-storeというのを作ってみた。

observable-store

機能は次のような感じ。

  • 状態を保持する。
  • 保持している状態は参照可能にする。
  • 保持している状態は特定の方法でのみ変更可能にする。
  • 保持している状態が変わったらオブザーバーに通知する。

APIはObject.assignと短命に終わったObject.observeの間の子みたいにして、実装にはProxy使ってゴニョゴニョやった。

単純な使い方は次のような感じ

import createObservableStore from '@ushiboy/observable-store';

// observable-storeのインスタンスを生成
const store = createObservableStore({
  count: 0
});

// 保持している状態にはstateプロパティからアクセスする
const state = store.state;
console.log(`count: ${state.count}`); // count: 0;

// 状態の編集はassignメソッドから行う
store.assign({
  count: state.count + 1
});
console.log(`count: ${state.count}`); // count: 1;

// stateプロパティを直接変更しようとするとエラーになる
try {
  state.count = state.count + 1;  // throw Error
} catch (e) {
  console.log(`${e}`); // Error: Should use assign
}

// 変更を監視するオブザーバーの登録はobserveメソッドで行う
const observer1 = () => {
  console.log(`change: count:${state.count}`);
};
store.observe(observer1);

// オブザーバーの解除はunobserveメソッドで行う
store.unobserve(observer1);

当初はモデルを保持してモデルの変更を監視して...とか、参照の時にモデルのtoJSON呼んで...とか色々考えていたんだけど、モデル側の作り方を制限したくなくなってバッサリやめた。

で、これを使ってやりたかった感じにカウンタアプリ作ってみると次のようになった。

カウンタサンプルのソース

Reactと合わせて使う上でのポイントは次みたいな感じ。

  • Applicationコンポーネントでstoreの監視して、変更があったらsetStateして自身に反映する。
  • CounterViewコンポーネントには直接storeは渡さずにstateのみを渡す。
  • ボタンがクリックされた時の処理はモデルの操作をユースケースで包んで置いて直接は行わないようにする。

単純なサンプル過ぎて参考にならないんだけど、とりあえずやりたい感じになったと言えばなった。

ただ、observable-storeはassignが行われた時に保持している状態に変更があるかゴリゴリチェックしているんだけど、ここで頑張らなくてもReactの方に頼ってしまって良いかも...と感じた。

そこで、状態の変更をチェックするのをやめて、assignされたからどこか変わっているかもよ...とオブザーバーに知らせるだけに機能を削ってfreezable-storeというのを作ってみた。

freezable-store

使い方はstoreの生成方法が変わるだけで、他は一緒。

import createFreezableStore from '@ushiboy/freezable-store';

// freezable-storeのインスタンスを生成
const store = createFreezableStore({
  count: 0
});

Reactと合わせてやる分にはこれでも良いかもなーという印象。

今のところの感想

試しに作ったのがカウンタアプリ程度で扱う状態が単純すぎてなんともなーみたいな感じだけど、状態が複雑になってくるとassignのところとかヤバイかなーどうかなーみたいな感じ。とりあえずもうちょっとドッグフーディング

Proxy使ったの初めてだった。

PhinxでマイグレーションしつつEloquentのモデルのテストをする方法

PhinxでDBのマイグレーションしているけど、モデルにはIlluminate\Database\Eloquentを利用していて、 PHPUnit単体テストするときにSQLiteのオンメモリでやりたいなと思ったのでソース見ながら方法探してた。

やり方まとまったのでメモしておく。

こんな感じのモデルを用意して、

こんな感じにテストする。

ポイントはテストのsetUpで、 Illuminate\Database\Capsule\Managerのインスタンスを作って各種設定をしたあとにPDOのインスタンスを取り出して、 それをPhinx\Migration\Managerのインスタンスにセットしてマイグレーションを実行する。

DB設定は一応phinx.ymlから参照するようにしたけど、どうせSQLiteの:memory:しか使わないのであればベタ書きで良いかも。

サンプルコードはこちら。 github.com

Y8 2017 spring in Shibuyaに参加してきた

y8-2017-spring.hachiojipm.org

去年に引き続き、今年も参加してきた。

f:id:ushiboy:20170528191115j:plain:w480

そして今年は、2nd season(懇親会)の方で猫型さん(@neko_gata_s さん)と「春だ!webフロントエンド開発を語り尽くすぞ!!」というタイトルで漫談してきた。

トークを聴いて

苦労話とか、知らなかった話とか、ためになる話があってなるほどなーという感じで良かった。

  • hyperapp – 1kbのビューライブラリ
    • ソース読んで見たらすごいコンパクトでびっくりした
  • ScalaでウェブAPIを書いている人が設計や実装やその他について話そうか
    • 猫型さんがScala.jsでドメイン全部書きたいって言ってた理由がなんとなくわかった
  • V8 for フロントエンドデベロッパ
    • JavaScriptを書くときにV8の気持ちを考えるのに参考になった

辺りが特に印象に残った感じ。

漫談したこと

勉強会とかで発表した経験が浅い自分にとって、漫談とはいえ大勢の前でやるのは難易度高すぎて、 最初に猫型さんに誘われた時は、正直「いやいやいやいや…」って感じだったけど、 やっぱり何かしら挑戦しなければと常々思っていたので、良い経験になった。

緊張しまくってたけど、夜の部で懇親会中ということもあり、始まってしまえばそれなりに気楽になった。 だんだんフリーダムになって事前に打ち合わせしていた内容の半分くらい喋らなかったのはご愛嬌。

漫談中のアドリブもそうだけど、漫談後に色々な方にせっかく話しかけて頂いたのにイマイチうまく話すことができなくて、 「なんでもっとうまく話せなかったんだろう…」と一夜明けてからずーっと悶絶しているけど、 「そういうのを次に活かしてサイクル回すと良いよ」というアドバイスを頂いたので、頑張りたい。頑張ろう。

猫型さんは「ニュービーなので…」などと言いながらフロントエンドのツールやライブラリをちゃんと使いこなしつつ、 複雑なSingle Page Applicationの設計をものすごく研究している人なので、 「純粋にWebブラウザでどこまでのアプリケーションが作れるのか」が大好きな自分にとって、 すごく勉強になるし、漫談の打ち合わせで話しているだけでも本当に楽しかった。

自分の関心のある話を誰かと濃く話せるというのはすごい楽しいんだなーと思った。 なので、もっとそういう話をできる人とお近づきになりたい(とういか師匠が欲しい)。

まとめ

主催の@uzullaさん、運営スタッフ、発表者、参加者の皆様ありがとうございました。 今年も楽しい体験をさせて頂きました。

一緒に漫談やってくれた猫型さん、見守ってくれた@hayajoさんありがとうございました。 数年前のあの日、hayajoさんに誘っていただいて行った居酒屋での出会いは自分に確かな影響を与えています。

【NDSiN#12×Niigata.js×C4N】JavaScript 2017春に参加した

nds-meetup.connpass.com

久しぶりのNiigata.js絡みのイベントに参加して、「SPAのルーティング」の話をしてきた。

www.slideshare.net

SPAのルーティングに関してはあまり話に出てるの見たことがなくて(この前のWEB+DB PRESS 97号で初めて見たくらい)、みんな当たり前のようにやってる事なのかなーと思っていたけど、自分がSPAなアプリケーションとか、SPA用のルーティングライブラリ作った時に結構やらかしたり学んだりしたことがあったので題材にしてみた。

ホントは更にサーバサイドレンダリングと絡めて、ページロード時のサーバサイドのルーティングや初期化データ取得とのViewの生成、ページロード直後のフロントエンドの動きあたりのとこまで踏み込めると、また深みがあるのでそこまで行きたかったんだけど、まだ自分も模索中みたいなところが多すぎて無理だった(その辺りの良いやり方知りたい…)。

他の発表者さんの発表を聴いてて、みんな落ち着いて話してるなーという感じで、自分もっと場数踏まないとだなーと思った。

2016年にフロントエンド開発に使った環境

今年も終わるのでメモしておく。

去年との大きな違いはwebpackの設定を個別ファイルにするのをやめたくらい。 webpackの設定はgulpfile.js内で関数用意して、引数で対象の環境(development, production, testing)を切り替えるようにした。

こんな感じで使う。

他にはbabelのバージョンが上がったことに伴うあたりが変わったくらいで、そんなに大きな変化はなかったかな…と。

以下、package.jsonとか。

2016 development tool

SVGのtext要素でUnicodeのHTML文字参照を使う

意外なやり方だったのでメモしておく。

方法

次のようなsvg#screen1にHTML文字参照を含むコンテンツを持つtext要素を追加したい場合、

text要素をcreateElementNSで生成したらinnerHTMLでコンテンツをセットする。

これで"test@foo"が表示される。

見つけた経緯

レイアウトの調整のために、直接タグを書いていたときには問題なく表示できていた。

<svg width="400" height="20">
  <text x="0" y="16" fill="black">test&#x0040;foo</text>
</svg>

動的に描画するためにtextContentやcreateTextNodeを使ったら、"&"が"&amp;"になるので、"test&#x0040;foo"と表示されてしまった。

直接タグを書いていた時にはできていたので何かあるはずと思って、text要素のインスタンスのプロパティを直接見たらinnerHTMLがあった(SVGの要素なのに)。

気になること

W3Cとかでこのあたりの資料探してみたけどいまいち見つからない...

React.jsの場合

上記のことを踏まえて、dangerouslySetInnerHTMLを使えば実現できる。

確認したブラウザとバージョン

次のブラウザで表示できるのを確認した。

ブラウザ バージョン
Firefox 47.0
Google Chrome 52.0.2743.82
Safari 9.1.2

ソースコード

こちら: SVG Text · GitHub

YAP(achimon)C::Asia Hachioji 2016 mid in Shinagawaに行ってきた

すっかり時間が開いてしまったけど、7月の2日、3日にYAP(achimon)C::Asia Hachioji 2016 mid in Shinagawaへ行ってきたので残しておく。

感想

ベストトーク賞の上位に上がっていたトークはすべて会場で聴いていてどれもこれも良かったのだけど、特に@kamadangoさんの「2人で楽しくサービスやアプリを作る話」がすごく良かった。

そもそもトークの応募リストに上がったのを見た時から、ポッドキャストのdandy.fmでデザイン思考の話聴いてたこともあり、これは絶対聴きに行きたいやつだ...と思ってたので、当日会場で聴いて、デザイン思考のフローに沿ったポイントとか、「ものづくり」する上での大事なこと、ストレスにしないための工夫・気づかいなどなど、予想通り大満足だった。あと、始まる前の突発的な@uzullaさんと@yusukebeさんの平和なエゴの話も良かった。

自分がやりたいのはこういう「ものづくり」なんだよなーと改めて思って、それが自分はできているか?と考えると、遠い目になる...という感じではあったのだけど、個人的に方向性を探るきっかけみたいにはなったかも。

今回、「遠方だから絶対決まってないと死ぬ」枠で2日間申し込んだのだけど、実は申し込む前に「遠方扱いで申し込んでいいものか?」とか思ってちょっとためらった。申し込んで、後日にconnpass見なおしたら「※ 新潟は遠方です。」と追記されてて笑ったし、些細なことかもしれないけれども、嬉しかった。

楽しい2日間だった。