JavaScriptでcompose可能なCommandとして諦めてPromiseを使うことにしようとした話
手頃なInteractorが見つからずほとほと困り果てた
Clean Architecture を読んで以来、依存の方向はともかく1Interactor が気になって気になって仕方なかったので、ずっと調べてたんだけど、どーにも JavaScript で手頃なものがなくて困っていた。
そのものズバリとしては
vadimdemedes/interactor: Organize logic into interactors
なんだけど、残念ながら Node.js 上では動くけどブラウザに持ってきたら動かなかった。
ここから放浪の旅が始まる。
大きく Interactor や Command Pattern で調べると数年前にリリースしたきりみたいなのが多い。
angeloashmore/cleanroom: Compose your business logic into commands that validate input.
こういうやつ。どれも自分用に作ってみました感が強くて、乗っかるには躊躇する。
business logic方面
business logic で調べるとどうなるかというと、
- peasy/peasy-js: A business logic micro-framework for javascript
- jamiepine/pulse: ✨ Pulse is an application logic library for reactive Javascript frameworks with support for VueJS, React and React Native. Lightweight, modular and powerful, but most importantly easy to understand.
辺りなんだけど、割と多機能かつちょっと DSL 感が出てくる。もっとシンプルなのでいいんだけど。
あと
こんなのも見つけて、へー面白いとは思ったものの、なかなかオーバーキルだなって感じ。
functional programming方面
command を compose できるくらいでいいんだよなーとこじらせてたら functional programming でいんじゃね説が出て来て ramdajs とか lodash/fp とか目移りし始めた。特にこれは面白かった。
Future は Promise よりも Lazy に扱えて、Fluture は functional な flavor も乗ったもの。とても面白いんだけど、明らかに語彙が増えすぎて目的から外れるのでやめた。
Promiseでいんじゃね説
まーとにかく右往左往したが、Promise で Promise の結果をまとめるのでいいんじゃねーの? というところに戻って来た。例えば以下のようにすると
function p1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('reject p1')
}, 50)
})
}
function p2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('reject p2')
}, 20)
})
}
p1()
.then(p2)
.catch((err) => console.error(err))
普通に p1 で止まる様子が console で確認できる。極めてフツー。ただし、これだと command 失敗した際に実際どうするかを catch の中だけでうまいことやるのは難しい。
もちろん工夫はあって、
function exec() {
const eventId = ulid()
pubsub.publish(`start ${eventId}`)
p1(eventId)
.then(() => p2(eventId))
.catch((err) => pubsub.publish(`fail ${err}`)
}
みたいなことをすると eventId とともに記録を外に出せるので、rollback とかあれこれ対処はしやすくなる。こんな感じの base class があると楽かもしんない。
あとは
辺りを入れるともうちょっと使い勝手もよくなるかも。
参考
- 脱フレームワーク依存!JSのビジネスロジックを抽象化するpeasy-jsとは - WPJ
- 5 Reasons To Use Bluebird for Promises – Cory House – Medium
たぶん普通は逆で、みんなめっちゃ依存の方向、レイヤーの切り方の記事が多い ↩