まえおき
最近、仕事をしていて「つまらない、もうやめたい」って思ったときってどんなときだったっけ?と振り返ってみた。
モチベーションが下がりまくりな仕事の一因として、「パターンが多い」ってのがあると思った。
function handleWebHook(event) { if (event.type == "Liked") { if (event.source == "Article") { handleArticleLiked(event.data); } } else if (event.type == "Comment") { if (typeof event.data["bot_id"] != "undefined") { handleBotMessage(event.data); } } else if ( ... ) { ...
重厚長大なif文は、テスト書くときにも死ぬほどパターンを用意しないといけなくて、とにかくストレスがたまる。
こんな感じのコードが300行くらい続いたら、確実に集中力が切れる。てかキレる。
"else if" よりも、クラス分割?
であれば、分割すればいいやん?というのは自然な発想。
ここでいきなりPythonっぽいサンプルコードになるけど、
class LikeHandler(BaseHandler): def shouldHandle(event): return event.type == "Liked" def handleEvent(event): if event.source == "Article": handleArticle(event.data) class CommentHandler(BaseHandler): def shouldHandle(event): return event.type == "Comment" def handleEvent(event): if "bot_id" in event.data: handleBotMessage(event.data) ... eventHandlers = [ LikeHandler, CommentHandler, ... ]; def handleWebHook(event): for handler in eventHandlers: if handler.shouldHandle(event): handler.handleEvent(event)
Pythonに限った話ではなくて、JavaでもRubyでもだいたいこんな感じで分割するのはぱっと思いつく。分割することで、テストもクラスに応じて1つずつ書いていけるし、ストレス値は一気に減る。
でも・・・
- 毎度
def shouldHandle
とかevent.type==
とかdef handleEvent
とか書かないといけないのってだるいよね def handleEvent
って結局どういう処理するのかって、ソースのコメント書かないと、メソッド名ではぱっと読めないよね- 多くのhandlerは event.typeで判定するんだろうけど、ほんとにそうなの?ってのが全部のhandlerみないとわからない
というところが今度は地味なモチベーション低下要因になってくる。
より "else if" の「判断ポイント」を明確にする書き方
Pythonのbottle とかFlask っていうAPIサーバを書くライブラリをみて、ふと思った。
かりに
router = Router() @router.on('Liked') def handleLike(event): likeRouter.route(event.source, event) @router.on("Comment"): def handleComment(event): if "bot_id" in event.data: ... (中略) def handleWebHook(event): router.route(event.type, event)
みたいに書くことができたらどうなるだろう?と。
毎回 event.type== xxx
とか should_handle(event): return xxx
とかを書く手間もなければ、判断基準(event.typeで判定しているという事実)がブレることもない。
直感的に「これだ!」とおもったので、Pythonで適当にライブラリを作ってみた。
Pythonじゃなかったらどう書く?
JSならこんな感じ?
class Route { constructor() { this.routes = {} } on(key, target) { this[key] = target; } route(key, ...args) { if (typeof this[key] == 'function') { this[key](...args); } } } r = new Route() r.on("Liked", (event) => { ... }) r.on("Comment", (event) => { ... }) /////////// r.route(e.type, e);
結論?
else if
を30個くらい書いてて吐き気がするところは、積極的に分割しよう。
Routerっぽいものを実装すると見通しが良くなるかもしれない。