Repositoryの後ろにネットワーク越しのシステムがあることの是非からRedux的世界へ

twitterで言ってたことを少し修正してまとめ。MVVM + Layered Architectureの文脈です。

最近、Repositoyとして抽象化しておけばそのデータがメモリ上にあるかそれともDB上にあるかネットワーク越しにあるか意識しなくていい、というのは嘘だと思ってる。パフォーマンスの観点除いても。


というのは、リポジトリが「非同期クエリ」を受け付け始めると、ReadStackの複雑性が跳ね上がるというのがあるからなんだけど、そもそもRepositoryへのクエリは必ず非同期であるというインターフェースにすればこれは問題にならないのかな


リポジトリを基本非同期に設計してもいいんだけど、そうすると同期的な表示を求めてくるUIプラットフォームと相性悪くなるんだよな


たとえばMVVMで考えると、モデルのイベントを購読して、イベント来たらクエリ投げてモデル以下にある状態を読み出してきて、自分のデータストアに書き戻すとデータバインドでViewが更新される、ってことすると思うんだけど、クエリが非同期だと、「イベント来たら非同期な操作投げる」ってなって、複雑さを増すと思うんだよ


そうなると、WebAPIは外部システムとみなして、WebAPIからデータ持ってくる操作は「外部システムからローカルのシステムにデータを取り込むコマンド」と考えてやったほうが全体的にシンプルになりやすい気がする


で、それやっていくと基本的に「状態の更新は常に同期操作」になって、なんとRedux的な世界観が近づいてくるんだよな。で、じゃあ非同期をどこで吸収するですかって話になったときに、middlewareっていう仕組み必要とするかアプリケーションサービスで吸収するかって話がある


わたしがRedux触ってみて良いと思ったのはsingle source of truthと、読み出しと書き込みが強制的に分離させられることと読み込みが常に同期的な操作であるって部分で、嫌だったのがmiddleware、ってのはこういうことです


Vuexのほうが好きな理由も同じです。ちゃんと非同期吸収ポイントが納得できる場所にある


あと、ReduxとかVuexはState更新したよってイベント購読管理しなくていいのが楽。けどそのトレードオフでStateの作り方をフレームワークから制約受ける。この制約を「良い制約」と思えるかどうかってのはあると思う。


これ単方向データフローを守ったMVVM前提で考えるからこういう結論になるんだなって思い至ってる


MVPならそもそも非同期であろうがなんだろうがそのタイミングでP呼び出すだけだもんな


ここで、ninjinkunさんと話した「MVVMは難しいパターンですよね」を思い出すのであった


あと単純に、Repositoryの後ろにネットワーク隠蔽しちゃうとAPIのレスポンス複数のVMから参照したいときとか、キャッシュをちゃんと制御したいときにも困る(リポジトリで透過的にキャッシュ?それ一時期web系ではやった"アンチパターン"だよね)


このへんのこと考えて設計した結果がBackLoggerのコードです。

github.com

今思うと、これ、RepositoryがいわゆるStateのポジションにいる、という考え方をしていると見て取れる。少なくともBackLoggerではこの考え方はかなりよく回ったと思っている。

追記:さまざまな反応

VuexとかReduxの制約が生きるシチュエーションについて

@shinpei0213: vuexとかreduxだとstateの作りに制約受けるの嫌なんだけど、InitialStateを外から与えてアプリをbootstrapしたいというようなことが起こる場合は良い制約だと思う

Repositoryってそういう責務かなあという話

@shinpei0213: そうですね。なので、記事では最後に「RepositoryをStateと見なすような感じ」という感じになっています。もしかしたらStateというのを生やして、RepositoryからStateに読み込む、みたいにすると用語の混乱がなくていいかなあと思ってるところです


@shinpei0213 ただ、同期で読み書きできる永続化層ならそれはStateとしてあつかっても不利益ないな(BackLoggerのSettingRepositoryの実装がそうなってる)というのもあり、「名付けをどちらに寄せるか」という問題かなと。


@shinpei0213 「このプロジェクトにおけるRepositoryの責務はこれです」が一貫しており、メンバーに共有するという制約付きですが


@shinpei0213 というかこの話実はイミュータブルドメインモデルと状態のライフサイクルの話と繋がっていて、かなり射程が深いので是非NDSで議論しましょう

Vue.js + Scala.js + Electron でMac用backlogクライアントを作りました

backlogというのは一般名詞のほうのbacklogではなく、ヌーラボさんのプロダクトのほうのbacklogです。

www.backlog.jp

だいたい土日の2日間でできたのでよかった。

作ったやつどこにおいてあるか

アプリ

BackLogger-darwin-x64_v0.1.1.zip - Google ドライブ

ソースコード

github.com

スクリーンショット

f:id:nkgt_chkonk:20170911103251p:plain

タイトルの通り、Scala.jsとElectronで作られています。

なぜ Scala.js と Electron で作ったのか

  • Scala.js がどれくらい実用的に使えるのかを知りたかった
  • Electoron の得意なこと、苦手なことを触ってみて検証したかった

というまっとうな理由と、

  • 来年のScalaMatsuriに応募するためのネタがほしいな〜
  • 「で?なんか偉そうに設計の話してるけど、お前はそれで何作ったの?」って言われたときにちゃんと答えられるもの一個くらいあったほうがよさそう

という邪な理由があります。

なぜバックログクライアントなのか(GitHubIssuesじゃねーのかよ!)

わたしが仕事で使ってるからだよ!

どうせ作るなら自分が便利になるもの作りたい。

アプリの仕様設計

とにかく自分のユースケースに絞って作ってあります。

バックログは、とにかく高機能で、非プログラマなディレクターにもわかりやすい素晴らしいプロダクトだと思っています。

しかし、高機能でいろいろできすぎるがゆえに、

  • 自分にアサインされてる課題の中から、未完了のものを一覧で表示して、
  • 次に片付けるやつ見繕ってそれを「処理中」にして
  • 開発して
  • backlogに戻ってそれを「処理済み」にして
  • 場合によっては自分で「完了」する

という一連の流れがちょっと面倒です。

というか、今書いていて思ったのですが、これはバックログのせいというより、部屋が汚い人間はブラウザのタブを開きっぱなしにする傾向があるという例のやつのせいで、「一覧表示してたタブどれだっけ」「わータブばっかりだーしょうがない新しいタブ開いて課題一覧また開こう」「あ、検索条件また入れなきゃ」「あ、またタブ開いちゃった」「開かれたタブの数が5000兆になった」となるわたしが悪い気がしてきた。

まあそれはそうとして、そういう問題で課題のclose漏れ起こして同僚に迷惑かけたりしていたので、

  • 「パッ」と自分がアサインされている課題一覧にアクセスできる
  • 「パッ」と課題の状態を変更できる
  • ソレ以外のことがしたい場合はブラウザでやってもらう(そのために各画面へのリンクだけ提供しておく)

という思想で作られています。

技術上の課題

まだ設計上甘い部分があって

  • APIから降ってきた生jsonをモデルにマッピングするTranslatorくん作りたい
  • テスト書きやすくできてるとは思うんだけどテスト書いてない
  • リリースが手動

とかそのへんを余裕があればやりたい

仕様上の課題

ぱっと思いつくのは3つ。

とにかくデザインがひどい。スクリーンショット見てもらったらわかると思うんだけど、いかにも「プログラマが片手間でやりました!!!」って感じ。だれか助けてくれ……

Windows対応。自分がWin持ってないので、Winで使いたいというひとがいれば考えるかもしれない程度の感じです。ただ、今後仕事でElectron使う場合はwin対応必須だろうからどっかで試してみたいかも。

マルチスペース対応。自分が必要になったらやるかも。

しばらく自分でも使ってみて、「これあったほうがいいな〜」って機能は追加していくつもりです。もし使ってくれる奇特な方がいらっしゃったら「この機能欲しい」みたいなのを

@

か、普通にIssueにヒョっと書いていただけると対応するかもしれません。

Nekogata Drum SequencerをScala.jsに移植した

Vue.js + CleanArchitectureのサンプルとしてNekogata Drum Sequencerを書いたのは今年の3月のことでした。

解説記事(README)を改めて貼っておきます。

そんな折、最近はScala.jsの調査をしていまして、実験としてこのシーケンサーScala.jsに移植する試みを行いました。つまり、 Vue.js + CleanArchitectureをScala.jsでやってみる、という試みですね。

ソースコードGitHubに上がっています。

github.com

デモはGitHubPagesから。

Nekogata Drum Sequencer written in Scala.js

で、実際に書いてみてどうだったのかとか、どう考えてこういう形になっているのかなどをToKyoto.js ― Kyoto.js in Tokyo - connpassでLTするので、来る人はToKyoto.jsでお会いしましょう。ToKyoto.js終わったらまたスライドをアップロードします。

わたしがあまりHMR(Hot Module Replacement)を好まない理由

JavaScriptニュービーです。ニュービーなので界隈のHMRに対する評価がどんな感じなのかよくわかっていないのですが、個人的には採用しない理由のほうが多いと感じています。

というのも、「開発効率がちょっとよくなる」というメリットに対して、

  • HMRに対応するために、ユーザーが触るプロダクション環境には関係ないコードを書かなければいけない
  • プロダクション環境で起こり得ないことが起こる仕組みが開発時にのみ入ってくる

というコストを支払う価値が高すぎると思っているからです(あと、リロードで壊れないSPAを作るためには意外とHMR入れてても開発時にリロードする気がする)。

単純にわたしがHMRよく理解できてない or 知識が古い可能性もあるのでその場合は教えてください。

ベストスピーカー賞の是非が話題ですが

わたしの気持ちです。

  • ベストスピーカー賞はあくまで「スピーカー」としての賞であり、プログラマとしての賞ではない
  • 貰った側もベストスピーカー賞好きなひとも嫌いなひともそこを混同しないほうが平和だと思う
  • 「にぎやかし」と「人に響くトークをしたひとへのフィードバック」として、ベストスピーカー賞があってほしい派

にぎやかしという観点で言えば、個人的には(最近あまり見かけないけど)LTでドラ叩く"ドラ娘"は「なぜその役割が"娘"限定なの?」という点で邪悪であるように感じるけど、ベストスピーカー賞にはそういうたぐいの邪悪さがなくていいな〜って思う。

ただ、コンテンツ力が強すぎてカンファレンスの目的を食っちゃうみたいになってくると、本来にぎやかしだったものがメインになっちゃってみんな不幸だよね、って話は結構同意できるところで、「あくまでにぎやかしだよ」ってのが打ち出されるようなベストスピーカー賞の仕組みがあるといいな〜って思います。そのほうがにぎやかしとして素直に楽しめるし。

※この記事は全部、個人の希望であり、そうあるべきだ、という主張ではありません。

#builderscon 2017で「複雑なJavaScriptアプリケーションに立ち向かうためのアーキテクチャ」という発表をしてベストスピーカー賞第三位を頂いてきた

先週開催されたbuildersconで表題の通りの内容をしゃべってきました。発表内容については、スライドもアップしてますが、いつもどおり実況中継シリーズを会社ブログのほうに書きます。ただ、あれ書くのすごい大変なのでもうしばらく時間かかりますすみません。書きました

自分のトークについて

弊社はまだまだメンバーが少なく、わたしもJavaScriptが専門、あるいは専任というわけではないという状況の中で、「なるべくJavaScriptに独特の概念などはプロダクトに持ち込まず、他のプラットフォームにも通用するような考え方ややり方で保守性の高いコードを書く」ということを考えて設計/実装をしています。

その試行錯誤の結果得てきた知見を対外的に発表することで、みなさんに「JavaScriptに限らず有用なトークだった」と言っていただけたのは本当に嬉しいです。

ただ、逆に考えると「JavaScript全振りマン」みたいなひとにとっては「うーんこれJavaScriptの話か?」とか「JSの話として聞くとめちゃめちゃ内容薄いっていうかJS wayじゃないよなこれ」みたいなトークになってしまったかな、ちょっとタイトル詐欺だったかな、と反省しています。

その他発表では触れられなかった話やいただいたフィードバックに対する反応は後で書く予定の実況中継シリーズのほうで触れたいと思います。

ベストスピーカー賞3位をいただいたことについて

buildersconはYAPC::Asia tokyoの流れを汲むカンファレンスですが、YAPC::Asiaの頃から何度か登壇させていただいています。で、この流れを汲むカンファレンスでベストスピーカー賞を取るというのはひとつの悲願で、一時期は「 ベストスピーカー賞狙うぞ!!」とか思ってスライドを練ったりトークを練ったりしていたこともありました。しかし、ベストスピーカー賞を狙いに行っても毎回カスリもせず……。

そんなこんなで、今年は、とにかくベストスピーカー賞のことはあまり考えず「自分が学んできたことをなるべく順を追ってわかりやすく、全体像を描きながら、設計についての情報の海に翻弄されている人の頭が整理されるようなトークをしよう」ということだけ考えてトークを準備していきました。その結果、ベストスピーカー賞をいただけたのは望外の喜びです。

そういう経緯があり、「ベストスピーカー賞は取れないしな」と思っていたので、別の用事を優先してクロージングに出席しないという蛮行に及んだ結果、せっかくの悲願であったベストスピーカー賞受賞の瞬間を逃すというまさかの事態に!!記念にそのときの一連の流れを貼っておきます。

聴いた中で一番印象に残ったトーク

pastak氏の発表が一番印象に残りました。

babelやpollyfillという武器を手に入れたわたしたちにとって、ふつうにブラウザ上で動くJSアプリケーションをクロスブラウザ対応することは一時期に比べるとだいぶ楽になりました。

一方拡張機能はどうなのか、と思っていたのですが、「やはり拡張機能を単一ソースでクロスブラウザ対応するのはすごく大変なのだな」ということ、「しかしやりようによってはクロスブラウザ対応もできるかもしれない」という希望の両方が得られる尊い発表でした。

発表後、「各ブラウザ依存のところはファイル分けてしまうみたいなアプローチも考えられると思うんですけど、そういうアプローチはどうなのでしょう?」と質問させていただきました。業務ではそのようなアプローチも取っていると聞けて、現在の状況での実践的なプラクティスと、未来への展望どちらも理解できてとても有用でした。

来年について

最近ずっと「コイツいつも設計の話ばっかりしてんな」って感じだったのですが(最近ずっとその辺を試行錯誤していたから、というのが大きいのですが)、来年は事例紹介的なトークができるといいな、と思っています。できるのか!?(事例がちゃんと成功するか?という壁と、プロポーザル出したとして採択されるのか?という壁がある)

心理的安全性を獲得しにくい個人(は|を)どうすればいいんだろう

心理的安全性ということばはだいぶ浸透してきて、とくに説明なくみんなに通じるような感じになってきているけれど、まあなかなかに難しいものだなあと思う。

組織やチームのまとめ役となる側からすると、心理的安全性が確保できるチームをどのように作っていくか、という点に注目があつまりがちなんだけど、個々人が心理的安全性を獲得するときにも、それぞれの性格によって難易度に差があるよね、ということについて書きたい。言葉を変えると、多くのひとが問題なく心理的安全性を獲得できるような状況やチームであっても、自己肯定感を適切に持つことが難しいようなタイプのひとは、なかなか心理的安全性を獲得できないという問題(問題、というと語弊があるかもしれないけど、problemというよりもissueという意味での問題)があるんじゃないか、というような話だ。

自分にそういうところがあるからこの話をするのだけれど、わたしは「他人が自分をどう評価するのか」「他人が嫌な気持ちになっていないか」ということを過剰に気にする傾向がある。たちがわるいのが、あくまでそれは自己完結した自分の感情であり、この気持が外に向かってコミュニケーションを改善する方向に向かず、自分の中でぐるぐる回って自家中毒を起こすような方向に向かってしまうところだ。

他人は他人であり、それを理解することはそもそもできない。できないからこそ、わたしたちは言葉その他様々な方法で相手にメッセージを送り、それを受け取り、その繰り返しで信頼関係を築いていくわけだ。けど、「他人が自分をどう評価するのか」「他人が嫌な気持ちになっていないか」を過剰に気にしてしまい、しかもその気持ちを適切に外に向けることができないと、「明らかにこれは無限に友好的なメッセージである」と判断できないメッセージを受け取ったとき(つまり大抵の場合)に、「なにかわたしが相手の機嫌を損ねるようなことをしてしまったのだろうか」と不安になり、萎縮しはじめる。結果として、こちらからきちんとメッセージを発信することができなくなり、コミュニケーション不全に陥る。

さらに悪いことに、普段そうやってビクビクしているからこそ、逆に「このひとはわたしにとって安全だ」となってしまうと、そこに甘えて雑なコミュニケーションを行ったり「言わなくてもわかってもらえるよね」みたいな感じになってしまう(そうして、結果としてせっかく良い関係を築けていたところを自分からぶちこわしてしまう)。こっちの問題については最近思うところがあって、ちゃんと努力して実際改善しつつあるとは思っている(まだがんばっている途中)んだけど。

で、本題に戻ると、こういうタイプのひとは、上述のような流れで、自分にとって「判断不能」なメッセージをひとつ受け取ると、その解釈不能性が自家中毒を起こしはじめる。そして、たったひとつの、ほかの人からしてみたらなんてことないメッセージだけで、おおいに心理的安全性が脅かされるということになりがちだと思う。自分がそういうタイプであるとき、あるいはメンバーがそういう問題を抱えているときに、どうやったらこれを改善あるいはサポートし、健全なコミュニケーションを取り戻すことができるのか、ということを最近よく考える。

とはいえ、まず自分の問題を解決しないことには他人の問題を解決することはできないわけで、まずは自分のこの問題とどのように付き合っていくのかについて、なんとかしないといけないよなあと思っているのであった。自分の問題を確認するために言語化したかっただけで、結論はまだない。