Tokyo Rubyist Meetup で Hanami について発表してきた。このコミュニティは日本にいる外国人エンジニアや彼らと交流したい日本人の集まりなので、英語が公用語となっている。発表も英語でする。
11/29 で「いいにく」の日だったから、ご飯が豪華だった。でも発表していたからそんなに食べられてない...。残念。 会場は cookpad のオフィスだったのでキッチンが充実していて、料理も美味しかった。ローストビーフが特によかった。
僕の発表: The Pragmatic Hanami
発表資料:
発表内容は以前 Rubyist Magagine に寄稿した るびま と同じく Hanami のアーキテクチャの説明などをしたあと、多少実際に開発をする時必要となるTipsを紹介した。
英語で発表するのが初めてだったので、台本用意してそれを読み上げていたんだけど、ずっと下向いて発表するから聞いてる人の反応を見ることが出来なくて、そのへんが辛かった。 普段日本語で発表する時は意識してないけど結構聞いてる人の反応を見て話ししてるんだなと思った。
Hanamiと発表に関しては、わりと基本的な話が多かったせいか、質疑応答で色々と聞かれた。 僕の英語力は技術文章のリーディングが一応できる程度しかないので、なかなか返答できなくて困った。 質問してくれた人はゆっくり喋ったり簡単な単語使ったり、だいぶ気を使ってくれていたと思う。ほんと、申し訳ねぇ。。。 普段、 google 先生に頼り切りなので、スライドと発表原稿はほぼ全部 google 翻訳で書いていた。
google home を通訳代わりに持っていっていたんだけど micro usb ケーブルを忘れたせいで起動できなかった。最近忘れ物が多い...。
聞かれた質問 (たぶん。英語聞き取れてないから内容違うかも) を覚えている範囲で。あと回答(これは会場ではうまく言えなかったこと):
- Hanami に Rails Engine 的な機能はある?
- ない。Routes で別の Rack Middleware にリクエストを投げるか、Hanamiの中で Rack Middleware を取り込んで動かすとかはできるけど、Rails Engine 的なものはない。僕としては Rails Engine は人類には早すぎる技術なので使わないほうが良いと思う。
- 既存の Rails のコードをコピペして Hanami にリプレイスしていけるか?
- 出来なくはないかもしれないけど、やめたほうが良いんじゃなかろうか。Hanami は Rails じゃない。そういう既存のRailsシステムにDDDを導入するなら Hanami より Trailblazer を使ったほうが良い。ただ、Hanami は Pure Ruby なので Rails の中で Hanami を動かすことはできる (View の部分を hanmi-view に変更するとか) ので、そうやってちょっとずつリプレイスするのは、もしかしたらありかもしれない (全部作り直したほうがはやいと思うけど)。
- サードパーティ gem が少ないと思うけどどうしてるの?
- 自分で書いてる。あるいは Rack とか Sequel 関係の gem や Pure Ruby で動く gem は使うことができる。これに関しては Rails の方が便利に思えるかもしれないけど、そもそも Rails は gem を使い過ぎなので Hanami の場合そんなにたくさん gem いれなくても良いと思う。Sinatra や Padrino のおかげなのか、最近は結構 Rails 依存じゃない gem も多くなってきている。
- Rails と比べて Hanami を使う優位性? (これだいぶ聞き取れなかった)
- まぁなんていうか...。アーキテクチャの説明を聞いてもそこを疑問に思うなら別に無理して Hanami 使わなくても良いんじゃなかろうか。別のことを聞かれていたような気もする。「Rails でも DDD できるじゃん」という意図の質問だったなら、それは単に Rails Way が強すぎて辛いってだけ。Rails は Rails のレールに乗るのが一番平和なので、それに乗らないなら Hanami みたいに別の方法を使うほうが良いよね、という気持ち。一緒に開発するエンジニアにいちいち僕が書いたコードを説明するのが面倒臭すぎて嫌なのだ。「DDDの方がメンテしやすいのはなぜか」って質問だとしたら、アーキテクチャが疎結合で、各レイヤーで単一責任の原則を守りやすいから、という感じ。小規模な開発ならRailsの方がいい。Rails は MVC のレイヤー構造をもっているくせに、レイヤーやクラス毎の責務はまとまっていなくて、ロジックが分散するのがすごく嫌だ。
僕としては設計の話は「自分がどのようにコードを書きたいか」でしかないと思うから、「Interactorを使わずにControllerにロジック書いたらダメなんですか?」みたいなことも聞かれたけど、それは別にそうしたいなら書けばいいし、単純なロジックならそのほうが読みやすいケースもあるし、でも僕は単一責任の原則が大事だと思うからあまりそういう書き方はしないよってだけ。ポディショントークみたいになりがちだから、不毛な気がするのであまりこういう話はしたくない。プログラムはただの表現であって、正解があるとは思えない。選択があるだけ。エレガントなコードも汚いコードもあるけど、コンパイルが通って仕様どおり動くならそれは正しいコードだと思う。もちろん、汚いコードはきれいにするべきだが。 僕はアーキテクチャ設計が好きだから「こういう設計のやり方があるんですよ」って話はするけど、それのどのへんが良いのかみたいな部分は、自分で考えれば良いんじゃなかろうか。自分の中で良いと思えないなら、おそらく使わないほうが良い。
まぁ、それに Hanami は(少なくとも現状では)、プログラミング初心者に親切なフレームワークではない。ドキュメントよりコードを読まないと使い方がわからない機能もあるし、Ruby やアーキテクチャ設計に詳しくないとうまく使えない部分もある。Railsみたいに「とりあえずgemいれたら動いた」みたいなのはあまりない。そこら辺に不安を感じるなら、RailsとかLaravel(PHPのフレームワーク)とか使えばいいと思う。
The Ruby Module Builder Pattern
Chris Salzberg 氏の発表。だいたい次の話。
まず、「Module 内で mix-in する側の class の変数なりメソッドなりを呼び出すようなコード(つまり closure みたいなコード)を書くと、変数・メソッド名が共通でなければその module を使うことが出来なくて柔軟性がさがるよね」という課題を解決するために Module Builder Pattern がある。 Module Builder Pattern を使うと、同じ処理だけど単に呼び出すメソッド名が違うというケースでも同じ module を使って mix-in できるようになる。
で、これを実現する方法がなかなか巧妙なんだけど、
class AdderBuilder < Module def initialize(*keys) define_method :+ do |other| self.class.new(*(keys.map { |key| send(key) + other.send(key) })) end end end class LineItem < Struct.new(:amount, :tax) include AdderBuilder.new(:amount, :tax) end l1 = LineItem.new(9.99, 1.50) l2 = LineItem.new(15.99, 2.40) l1 + l2 #=> #<LineItem:... @amount=25.98, @tax=3.9>
こんな感じで Module を継承したクラスを作るというもの。この発想はなかった。
AdderBuilder
は Module
のサブクラスのインスタンスだから、他のクラスやモジュールで include
できるし、オブジェクトで extend
もできるんだよ!、という力技。いや、ほんとすごい。天才か。
その他、思ったこと。
発表が終わったあと、直接話しかけられて「Hanami の Repository や Rails の Model が fat になる問題をどうしているか?」と聞かれて「Refinement で DCI してメソッドをクラスから分離している」と答えたんだけど、これが伝わらなかった。この説明も割りと毎回やってる気がするので、そのうち記事にしよう。パターンを名乗ってしまえば良いのかもしれない。 Refinement は Ruby の最も不思議な機能で、なんとかうまく使ってやりたくなる機能で、一番使い所が難しいものでもあるけど、僕は DCI と簡易的な Template Method Pattern として使うことが多い。
あと、Trailblazer や dry-rb の知名度が相変わらずいまいちっぽい。まぁ別にいいんだけど。ActiveModel で消耗するよりはマシな気がするので、Railsつらい人たちはとりあえずこのへんからやってみたら良いんじゃなかろうか。
まぁ、もう僕はこの手のRailsの設計話はつかれたから Hanami とか Clojure に移ろうとしているわけだけど。Rails でもきれいな設計はできるし、複雑なフォームを作ることはできる。ただ、それはレールを外れているから面倒なことが多いよってだけ。Webpackもそんなに良いものだとは思えないし、 Webpacker という方向性はちと疑問だ。必要なのは Laravel-mix みたいなやつで、 Webpacker じゃないだろうと思う。