Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実際のところHanamiってどうなんですか?という話

E1c383c7cd14e26ca7be1e561ce271b8?s=47 Yuta Tokitake
December 11, 2019

 実際のところHanamiってどうなんですか?という話

LegalForce Ruby MeetUp #1 (https://legalforce.connpass.com/event/154895/) でのHanamiについての発表です。
LegalForceではHanamiフレームワークを用いてAPI開発を行っています。これまでHanamiでの開発を行ってきて溜まってきた知見や、取り組みについての話をしました。

E1c383c7cd14e26ca7be1e561ce271b8?s=128

Yuta Tokitake

December 11, 2019
Tweet

More Decks by Yuta Tokitake

Other Decks in Programming

Transcript

  1. 実際のところHanamiって どうなんですか? という話 2019/12/11 LegalForce Ruby Meetup #1

  2. ࣌෢ ༎ଠ גࣜձࣾLegalForce औక໾CTO 2014年 Πϯλʔϯͱ͍͔ͯͭ͘͠ͷWebαʔϏε։ൃΛܦݧ 2016年 DeNAʹ৽ଔೖࣾɺεϚϗΞϓϦͷ։ൃʹैࣄ 2017年 LegalForceʹࢀըɺݱ৬

    2019年 CTO of the year 2019ड৆ ౦ژେֶେֶӃ ৘ใཧ޻ֶܥݚڀՊ ଔۀ
  3. https://jp.techcrunch.com/2019/11/22/cto-night

  4. LegalForceとは

  5. 弁護⼠が作った会社です

  6. ⾓⽥弁護⼠ (CEO) ⼩笠原弁護⼠

  7. でも、お堅くありません

  8. None
  9. None
  10. None
  11. 契約書レビューシステム を作っています

  12. ܖ໿ॻ

  13. ࢴͱϖϯͰ

  14. ͻͱͭͻͱͭ੺ೖΕ

  15. None
  16. 2019೥ 4݄ 5݄ ໿ 180ࣾ 6݄ 7݄ 8݄ 9݄ 10݄

    導⼊顧客数 100ࣾಥഁʂ
  17. 技術に⼒を⼊れています

  18. 京都⼤学との共同研究 共同研究者兼技術顧問 森 信介 京都⼤学学術情報メディアセンター 京都⼤学情報学研究科 知能情報学専攻 教授 技術顧問 末永

    幸平 京都⼤学⼤学院情報学研究科 通信情報システム専攻 准教授
  19. 技術顧問 まつもとゆきひろ プログラミング⾔語Ruby開発者 ⼀般財団法⼈Rubyアソシエーション理事⻑ ほか肩書多数 Matzを技術顧問として招聘

  20. コミュニティへの貢献

  21. https://rubykaigi.org/2019/

  22. None
  23. 2019年のスポンサー 3⽉ ⾔語処理学会第25回年次⼤会 (NLP2019) Rails Developer Meet Up 2019 4⽉

    RubyKaigi 2019 8⽉ NLP若⼿の会 (YANS) 第14回シンポジウム 9⽉ WebDB Forum 2019 11⽉ RubyWorld Conference 2019 ICPC 2019 Asia Yokohama Regional
  24. アジェンダ 話すこと • Hanamiは実際のところどうなのか • Hanamiをどんな感じで使っているのか 話さないこと • Hanamiのコンポーネントそれぞれについての詳細

  25. なぜHanamiなのか

  26. 興味 • Clean Architectureよさそう • キレイに書けそう • フレームワーク名気に⼊った

  27. 話題性 • RailsやSinatraとは違う⽬新しさ • Railsに疲れてきた、飽きてきたエンジニアに訴求できそう • 技術発信すると注⽬されそう

  28. で、実際のところどうなの?

  29. 保守性 • あのロジックどこにあるっけ?はRailsより少ない(気がする) • ビジネスロジックがapp間で共有できるのは便利 • Fat ControllerやFat Modelは形成されにくい •

    アーキテクチャへの知識は多少なりと要求される
  30. パフォーマンス • Railsよりは薄いのでその分速い(書き⽅にもよる) • Railsよりメモリ消費量少なめ

  31. 開発速度 • 最初期の基盤構築はRailsより⼤変だった • ⼀度構築終わればあとはRailsと⼤差ないイメージ

  32. カスタマイズ性 • ほぼVanilla Rubyなのでカスタマイズを⼊れやすい • ActiveSupport的な便利機能はHanami::Utilsモジュールにある • カスタマイズしすぎると理解不能になりそう。。

  33. キャッチアップ • さすがにRailsと⽐べるとガイドは充実していない • ⽇本語での解説記事はほとんど無い • Railsを使いこなせる⼈であれば数週間程度で把握できる

  34. 実際のところ Hanami Ruby on Rails 保守性 ◎ ◦ パフォーマンス ◎

    ◦ 開発速度 ◦ ◎ カスタマイズ性 ◎ △ キャッチアップ △ ◎
  35. Hanamiといえば

  36. Clean Architecture

  37. https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

  38. View Action Interactor Result Interactor Interactor Input Flow of control

    Actions Interactors Entities R epositories View s rack sequel ER B
  39. Actionの⾃動⽣成

  40. Action • ユーザーからのHTTPリクエストを扱うレイヤー • HTTP paramsからInteractorへのInputを整形する • Interactor ResultをViewへ渡せるように 整形する

    View Action Interactor Result Interactor Interactor Input Flow of control
  41. Action class Web::Users::Create include Web::Action params do required(:name).filled(:str?, max_size?: 20)

    required(:gender).filled(:str?, included_in?: ["man", "woman", "other"]) required(:age).filled(:int?, gteq?: 0, lteq?: 100) end def call(params) result = UsersCreateInteractor.new.call(params) halt_by_error(result.errors) if result.failure? self.status = 201 self.body = UsersCreateResponse.create(result.output) end end
  42. Action class Web::Users::Create include Web::Action params do required(:name).filled(:str?, max_size?: 20)

    required(:gender).filled(:str?, included_in?: ["man", "woman", "other"]) required(:age).filled(:int?, gteq?: 0, lteq?: 100) end def call(params) result = UsersCreateInteractor.new.call(params) halt_by_error(result.errors) if result.failure? self.status = 201 self.body = UsersCreateResponse.create(result.output) end end パラメータバリデーション ← Interactor呼び出し ← エラーハンドリング ← レスポンス作成
  43. なんか⾃動⽣成できそう

  44. OpenAPI (Swagger)

  45. None
  46. OpenAPI • スキーマにバリデーションが付けられる name: type: string maxLength: 20 gender: type:

    string enum: ["man", "woman", "other"] age: type: number minimum: 0 maximum: 100
  47. OpenAPI name: type: string maxLength: 20 gender: type: string enum:

    ["man", "woman", "other"] age: type: number minimum: 0 maximum: 100 required(:name) .filled(:str?, max_size?: 20) required(:gender) .filled(:str?, included_in?: ["man", "woman", "other"]) required(:age) .filled(:int?, gteq?: 0, lteq?: 100) Hanami
  48. Actionの⾃動⽣成運⽤を 検討してます。が

  49. まだ達成できてません。。 誰か助けて!

  50. DIコンテナの利⽤

  51. 依存性逆転の原則 (DIP) • モジュールの依存関係は抽象だけを参照すべきである • 抽象は具象に依存せず、具象が抽象に依存すべきである

  52. https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

  53. Hanamiでよくあるコード user_repo = UserRepository.new book_repo = BookRepository.new payment_repo = PaymentRepository.new

    interactor = HogeInteractor.new( user_repo, book_repo, payment_repo ) interactor.call(params)
  54. DIコンテナ導⼊後 class HogeInteractor include Hanami::Interactor extend DIContainer include modules( :user_repository,

    :book_repository, :payment_repository ) def call(params); end end HogeInteractor.new.call(params)
  55. DIコンテナ導⼊後 • include modules部分を⾒るだけで依存モジュールが明確に • SomeClass.newのコードが減って可読性アップ

  56. マルチデータベース問題

  57. Repositoryについて

  58. Repository • データの永続化ロジックを実装したレイヤー MySQL PostgreSQL MongoDB UserRepository #where(name:) #find(id:)

  59. Repository ActiveRecord (Rails) users = User.where(age: 20).order(created_at: :desc) Hanami users

    = UserRepository.new.where(age: 20).order { created_at.desc } ほぼ⼀緒では…?
  60. Repository ActiveRecord (Rails) users = User.where(age: 20).order(created_at: :desc) Hanami users

    = UserRepository.new.where(age: 20).order { created_at.desc } ⾮推奨
  61. Private Queries クエリの発⾏ロジックをRepository内でカプセル化する class UserRepository < Hanami::Repository def most_recent_by_age(age) users.where(age:

    age).order { created_at.desc } end end UserRepository.new.most_recent_by_age(25)
  62. Private Queries クエリの発⾏ロジックをRepository内でカプセル化する ↓ • Repositoryの内部実装を知らずに使える • どこでメソッドが使われているか探しやすい • 可読性が⾼い

    • テストしやすい
  63. LegalForceはマルチテナンシー • 1社につき1つのMySQLデータベース+共有データベース Amazon Aurora 共有 テナント1 テナント2 テナント3

  64. Hanami::ModelはマルチDB⾮対応 • Railsはバージョン6からマルチDBが正式対応されたので、 今マルチDBを検討するならRailsのほうがつらくないかも

  65. どうやってるのか • DBスイッチロジックを⾃前で書いてます DB Container DB Container request Interactor Repository

    MySQL
  66. マイグレーション問題 1テナント1データベース、ということは

  67. None
  68. マイグレーションヤバい!

  69. おや、どこかで⾒覚えが…?

  70. https://tech.smarthr.jp/entry/2018/04/06/100000

  71. Citusへの移⾏も検討中です 誰か助けて!

  72. こんな感じで ぼちぼちやってます

  73. ⼀定のHanami運⽤知⾒は たまってきたものの

  74. 開発・改善するところ まだまだあります…!

  75. None