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

Active Recordから考える次世代のRuby on Railsの方向性 / Directions for the next generation of Ruby on Rails: From the viewpoint of its Active Record

B8e501d93b98a553abf0b5cee0c33503?s=47 yasaichi
January 29, 2021

Active Recordから考える次世代のRuby on Railsの方向性 / Directions for the next generation of Ruby on Rails: From the viewpoint of its Active Record

January 29, 2021 @ 銀座Rails #29

B8e501d93b98a553abf0b5cee0c33503?s=128

yasaichi

January 29, 2021
Tweet

Transcript

  1. Active Record から考える 次世代の Ruby on Rails の方向性 Yuichi Goto

    (@_yasaichi) January 29,2021 @ 銀座 Rails #29
  2. self.inspect Yuichi Goto(@_yasaichi) ピクスタ株式会社 執行役員 CTO 「パーフェクト Ruby on Rails【増補

    改訂版】」 共著者(Part 5 担当) 2
  3. [PR] ピクスタはクリエイティブプラットフォームを創る会社です 画像出典: https://pixta.co.jp/business 3

  4. 本発表の背景と目的 4

  5. さかのぼること 2 年 2019 年 3 月に Railsdm というイベントで「Ruby on

    Rails の正体と向き 合い方 [1]」というタイトルで発表を行い、当時それなりの反響があった その後もいくつかの発表・エントリで引用していただいた(一部抜粋) 発表: Ruby (off|with) the Rails [2]、Fat Model の倒し方 [3] ブログエントリ: Smart UI パターンが再評価される世界 [4] 5
  6. 前回の発表後に起きたこと: フロントエンドの進化 1. Next.js の現在の主要機能が v9 で概ね実装され、React フレームワーク としての確固たる地位を築く(2019 年

    7 月 [5]~ 2020 年 7 月 [6]) 2. Next.js と Prisma 2 をもとに作られた Rails インスパイアのフルスタック フレームワークである Blitz.js がリリースされる(2020 年 4 月 [7]) 3. JavaScript のフルスタックフレームワークで Rails を置き換えられるの ではないか、という機運が高まる(e.g. Frontend 領域を再定義する [8]) 6
  7. 本発表における問題意識 JavaScript のフルスタックフレームワークで Rails を置き換えられると仮定 したとき、次の問題があると考える。 Prisma 2 などの JavaScript

    の ORM で Rails の Active Record と 同等の開発生産性を実現しようとした場合の課題に関する議論が少ない その前提となる Active Record が果たす役割に関する議論も少ない 7
  8. 本発表の目的とアプローチ 目的: Rails の Active Record が果たす役割を明らかにする 明らかにした内容をもとに 次世代の Rails

    の方向性を考察する ことで、 未来の有益な議論に繋げる アプローチ: ソフトウェアアーキテクチャのパターンを起点とした考察 8
  9. 以降の構成 1. 第一部: Rails の Active Record の正体 2. 第二部:

    次世代の Rails の方向性 3. まとめ 9
  10. 第一部: Rails の Active Record の正体 1. レイヤードアーキテクチャ 2. ドメインレイヤー以下のアーキテクチャ

    3. Rails の Active Record が果たす役割 10
  11. レイヤードアーキテクチャとは 「Pattern-Oriented Software Architecture,Volume 1,A System of Patterns [9]」(※)における定義は次の通り。 アプリケーションを適当数のレイヤーで構造化し、これらを積み重ねたもの

    あるレイヤーにおいて、その構成要素は同一抽象レベルで作業を行う あるレイヤーの提供するサービスは、隣接する下位レイヤーが提供する サービスを利用して実現される ※ 以下、POSA と呼ぶ 11
  12. レイヤードアーキテクチャの概念図 各レイヤーはクラスや関数として 実装される 画像出典: POSA(p. 35) より著者作成 12

  13. Web アプリケーションにおけるレイヤリング One of the most common ways to modularize

    an information-rich program is to separate it into three broad layers: presentation (UI), domain logic (aka business logic), and data access. So you often see web applications divided into . . . On the whole Ive found this to be an effective form of modularization for many applications and one that I regularly use and encourage. ― Martin Fowler (2015) [10] “ “ ※ 太字強調は引用者によるもの 13
  14. Web アプリケーションを構成する主要なレイヤー Fowler 氏の著書「Patterns of Enterprise Application Architecture [11]」(※)では、次の 3

    つのレイヤーが挙げられている。 プレゼンテーション: ユーザーからのコマンド(例: HTTP リクエスト)を 下位レイヤーの呼び出しへ変換、ユーザーへの情報の表示 ドメイン: 入力データの妥当性確認、入力・格納データにもとづく計算 データソース: データベース、メッセージングシステムなどとの通信 ※ 以下、PoEAA と呼ぶ 14
  15. 第一部: Rails の Active Record の正体 1. レイヤードアーキテクチャ 2. ドメインレイヤー以下のアーキテクチャ

    3. Rails の Active Record が果たす役割 15
  16. ドメインレイヤーのアーキテクチャパターン PoEAA で紹介されているパターンのうち、利用する言語・フレームワークに 関係なく採用できるものは次の通り。 トランザクションスクリプト: プレゼンテーションレイヤーからの 1 つの 要求を処理する手続き ドメインモデル:

    アプリケーションが対象とする問題領域(ドメイン)から 抽出された概念をオブジェクトとして定義したもの 16
  17. ドメインレイヤーの分割とサービスレイヤー ドメインレイヤーはドメインモデルとその上位レイヤーの 2 つに分割される ことが多く、後者を PoEAA では「サービスレイヤー」と呼んでいる サービスレイヤーは複数のドメインモデルやデータソースを協調させて、 プレゼンテーションレイヤーからの要求に応える役割を担う 文脈によって同レイヤーを指す呼び名が変わるため注意が必要

    (例: クリーンアーキテクチャの同心円の図では「ユースケース」と呼ぶ) 17
  18. 2 つのパターンの主な違い: ドメインの複雑化に伴う機能追加の労力の変化 トランザクションスクリプトは単純なドメイン では有効だが、複雑になると重複ロジックを 単に抽出した関数が増えて見通しが悪くなる 単純なドメインでドメインモデルを 利用しても設計が面倒なだけだが、 複雑になるとその労力が報われる 画像出典:

    PoEAA(p. 29) 18
  19. データソースレイヤーのアーキテクチャパターン PoEAA において、データストアが RDB の場合に利用できるパターンとして 紹介されているものは次の通り。 (テーブル|行)データゲートウェイ: RDB 内の(テーブル|レコード)への 操作をカプセル化するオブジェクト

    アクティブレコード: ドメインロジックを実装した行データゲートウェイ データマッパー: ドメインモデルと RDB 内のレコードを相互変換するもの ※ Rails の Active Record との混同を避けるため、ここでは意図的に訳本のパターン名を用いている 19
  20. 2 つのレイヤーのアーキテクチャパターンの関係 ドメインとデータソースのアーキテクチャパターンは互いに独立ではなく、 次の組み合わせで利用されることが多い(理由は後述)。 A. トランザクションスクリプト + (テーブル|行)データゲートウェイ B. ドメインモデル

    + アクティブレコード C. ドメインモデル + データマッパー 以降の議論には関係しないため、 こちらの組み合わせは紹介に留める 20
  21. 各組み合わせの実装例 次の正常系のフローからなる「ニュースレター登録機能」を、前ページの組み 合わせ A,B で実装した例を示す。 1. ユーザーは、フォームにメールアドレスを入力して「登録」ボタンを押す 2. アプリケーションは、メールアドレスの形式が正しいことを確認する 3.

    アプリケーションは、メールアドレスとその存在確認用のトークンを DB に 記録して、ユーザーに確認メールを送信する 21
  22. DB = Sequel.connect("connection_url") class SubscribeToNewsletter Result = Struct.new(:errors, :subscription_id, keyword_init:

    true) def self.call(email:) unless URI::MailTo::EMAIL_REGEXP.match?(email) return Result.new(errors: ["Email is invalid"]) end values = { email: email, confirmation_token: SecureRandom.uuid } DB.transaction do id = DB[:newsletter_subscriptions].insert(values) EmailConfirmationMailer.deliver(values) Result.new(subscription_id: id) end rescue StandardError Result.new(errors: ["Something went wrong"]) end end A. トランザクションスクリプト + テーブルデータゲートウェイ ドメインロジックは スクリプト内にべた書き 22
  23. class SubscribeToNewsletterService Result = Struct.new(:errors, :subscription_id, keyword_init: true) def self.call(email:)

    unless URI::MailTo::EMAIL_REGEXP.match?(email) return Result.new(errors: ["Email is invalid"]) end subscription = NewsletterSubscription.new(email: email) subscription.set_confrimation_token NewsletterSubscription.transaction do subscription.save! EmailConfirmationMailer .deliver(subscription.slice(:email, :confirmation_token)) Result.new(subscription_id: subscription.id) end rescue StandardError Result.new(errors: ["Something went wrong"]) end end B. ドメインモデル + アクティブレコード with サービスレイヤー 23
  24. 第一部: Rails の Active Record の正体 1. レイヤードアーキテクチャ 2. ドメインレイヤー以下のアーキテクチャ

    3. Rails の Active Record が果たす役割 24
  25. Rails の Active Record とは MVC パターンを採用している Rails におけるモデルに相当するもので、 Rails

    を構成する gem の 1 つである activerecord にその実体がある 各アプリケーションでは、この gem が提供する ActiveRecord::Base という 基底クラスを継承して固有のモデルを定義する 名前からも明らかなように、この基底クラスは PoEAA のアクティブレコー ドの実装になっている [12] 25
  26. PoEAA のアクティブレコードにはない機能 基底クラス ActiveRecord::Base は PoEAA のアクティブレコードにはない次の 代表的な機能を持っている。 バリデーション: データベース操作の実行前にモデルの状態を検証できる

    ようにするもの(例: ある属性が空でないかの確認) コールバック: データベース操作の実行前後に任意のコードを実行できる ようにするもの 設定したコードはデータベース操作と 同一のトランザクション内で実行される 26
  27. class NewsletterSubscription < ActiveRecord::Base validates :email, format: { with: URI::MailTo::EMAIL_REGEXP

    } before_create :set_confrimation_token after_create :send_email_confirmation_instructions private def set_confrimation_token self[:confirmation_token] = SecureRandom.uuid end def send_email_confirmation_instructions EmailConfirmationMailer.deliver(slice(:email, :confirmation_token)) end end NewsletterSubscription.create(email: "test@example.com") 2 つの機能を利用すると「ニュースレター登録機能」がモデルで完結する 27
  28. 「ニュースレター登録機能」の各実装例のアーキテクチャ上の違い クラスとして実装されていた複数のレイヤーは Rails ではモデルとそのメソッドに対応する 28

  29. Rails の Active Record が果たす役割 次の方法で ドメインレイヤー以下をモデルクラスだけで構築できるように して、コードの記述量を減らす ことで、高い開発生産性を実現している。 アクティブレコードを採用して、ドメインレイヤーとデータソースレイヤーを

    1 つのクラスで実装できるようにした バリデーションとコールバックを導入して、サービスレイヤーのロジックを モデルクラスの DSL やインスタンスメソッドで実装できるようにした 29
  30. コードの記述量を減らすその他のアプローチ コードの記述量を減らして開発生産性を向上させるために、Rails は次のアプ ローチを Active Record と併用している。 Convention Over Configuration:

    Rails の規約に従うと、アプリケー ションの設定に関するコードの多くを記述しなくてすむようにした リソースベースのルーティング: REST に則った URI 設計を行うと、多くの コードを自動生成できるようにした 30
  31. Rails のアプローチの構造的な限界: 暗黙の 1:1 対応が崩れるとき プレゼンテーションレイヤーからのある要求に特化 したバリデーションとコールバックが問題となる 31

  32. 限界との向き合い方 データベースレベル: イベントエンティティ(※1)を見落としていないか 確認して、もしあれば対応するモデルに問題のロジックを移動する コードレベル(※2): 新たにサービスレイヤーを導入して、こちらに問題の ロジックを移動する アーキテクチャレベル(※2): ドメインを最初から小さくする、後から分割 して小さくすることで問題を発生させない

    プレゼンテーションレイヤーからの要求と イベントエンティティの生成は 1:1 対応 している場合が多く、問題になりにくい ※1、※2 詳しくはイミュータブルデータモデル [13]、Ruby on Rails の正体と向き合い方 [1]をそれぞれ参照のこと 32
  33. 第一部完 33

  34. [PR] 会社で「texta.fm」という Podcast を運営しています この Podcast でピクスタの技術顧問である和田卓人 (@t_wada)さんと議論した内容が本発表の下敷きに なっています。改めて感謝申し上げます。 画像出典:

    https://anchor.fm/textafm 34
  35. 第二部: 次世代の Rails の方向性 1. 2 つの方向性 2. フロントエンドからのアプローチ 3.

    バックエンドからのアプローチ 35
  36. フルスタックフレームワークのあるべき姿 この後の議論を展開するために、本発表ではフルスタックフレームワークの あるべき姿を次のように定義する。 定義: Web アプリケーションのあらゆる領域で、そのフレームワークを 利用した方が常に高い成果を得られるという状態を実現するもの Rails における高い成果の例: バックエンドの汎用的な機能をすぐに実装

    できる、特に何もしなくても一定のセキュリティ対策が行われるなど 36
  37. ここ 10 年でのあるべき姿の変化 いくつかの理由により(※)、Web アプリケーションの利用を通じて得られる ユーザー体験の重要性が年々高まっている これに伴い、ユーザーと Web アプリケーションの界面であるフロントエンド 領域が確立され、前ページの「あらゆる領域」に加わった

    2021 年 5 月から Google の検索順位の決定にユーザー体験指標(Core Web Vitals)が導入予定のため [14]、直近ではより関心が高まっている Rails が登場したのは 2004 年であることに注意 ※ 例えば、ソフトウェアが企業の業務支援のための手段からビジネスそのものに変化したから、という理由が挙げられる 37
  38. Rails の現状 バックエンドでの高い開発生産性を実現するための仕組みと比較すると、 ユーザー体験を向上させるための仕組みはあまり充実していない 例: Largest Contentful Paint(※)において改善余地のある事項 Turbolinks の実装の都合上、デフォルトでは全ての

    CSS ファイルが application.css に連結されて <head> 内で読み込まれること Sprockets が画像に対してデフォルトでは何の最適化も行わないこと ※ Core Web Vitals の構成指標で、ユーザーがページ内の最も有意義なコンテンツをどのくらい早く見れるかを表す 38
  39. 差分を埋めるアプローチ = 次世代の Rails の方向性 1. フロントエンドからのアプローチ Next.js のような質の高いユーザー体験を実現するための仕組みの中で、 バックエンドを

    Rails と同等の生産性で開発できるようにする 2. バックエンドからのアプローチ Rails のバックエンドでの高い開発生産性を実現するための仕組みの中で、 Next.js などと同等の水準のユーザー体験を実現できるようにする 39
  40. 第二部: 次世代の Rails の方向性 1. 2 つの方向性 2. フロントエンドからのアプローチ 3.

    バックエンドからのアプローチ 40
  41. 重要な要素: Prisma v1 は任意のデータストアに GraphQL を被せるサーバーの実装だったが、 2020 年 6 月リリースの

    v2 [15] では単なる TypeScript の ORM となった 主な特長として、独自スキーマで定義したデータモデルをもとにした自動 型生成とマイグレーションの実行機能がある Blitz.js,RedwoodJS といった新興のフルスタックフレームワークの多くで 採用されているため、次世代の Rails を語る上で重要な要素である ※ 以降、バージョン番号なしで Prisma と表記した場合、 Prisma 2 のことを指すものとする 41
  42. const prisma = new PrismaClient(); // Create const createdUser =

    await prisma.user.create({ data: { email: 'test1@example.com' }, }); // Read const user = await prisma.user.findUnique({ where: { id: createdUser.id } }); // Update const updatedUser = await prisma.user.update({ where: { id: user!.id }, data: { email: 'test2@example.com' }, }); // Delete await prisma.user.delete({ where: { id: updatedUser.id } }); Prisma におけるデータベース操作の例 各データベース操作はRDB内の テーブルに対応するオブジェクトの メソッド呼び出しに対応する 42
  43. Prisma は PoEAA のどのパターンを実装しているか 公式ドキュメントでは、"Prisma is a new kind of

    Data Mapper ORM" と 述べられている [16] 前ページで示したように、Prisma は POJO(※)と RDB 内のレコードを 相互変換しているので、広義のデータマッパーと言えなくもない しかし、この POJO にドメインロジックは実装できない(レコードの表現で しかない)ため、テーブルデータゲートウェイの実装と言った方が正しい ※ Plain Old JavaScript Objectの略。素のJavaScriptオブジェクトのこと。 43
  44. ドメインレイヤーのアーキテクチャ選定に働く重力 ドメインレイヤー以下をドメインモデル + Prisma で構築する場合、 Prisma の返す POJO のデータをドメインモデルに詰め直す必要がある 特にアプリケーションの実装初期段階では、ドメインモデルと

    RDB 内の テーブルが 1:1 対応することが多いため、この作業は手間なだけである 結果として、ドメインモデルを利用せずに ドメインレイヤー以下をトラン ザクションスクリプト + Prisma で構築する方向に重力が働く p. 21の理由のひとつがこちら 44
  45. import { Ctx } from "blitz" import db from "db"

    import { hashPassword } from "app/auth/auth-utils" import { SignupInput, SignupInputType } from "app/auth/validations" export default async function signup(input: SignupInputType, { session }: Ctx) { // This throws an error if input is invalid const { email, password } = SignupInput.parse(input) const hashedPassword = await hashPassword(password) const user = await db.user.create({ data: { email: email.toLowerCase(), hashedPassword, role: "user" }, select: { id: true, name: true, email: true, role: true }, }) await session.create({ userId: user.id, roles: [user.role] }) return user } 実際にトランザクションスクリプト + Prisma に帰着した例(Blitz.js) 出典: blitz/examples/custom-server/app/auth/mutations/signup.ts [17] 45
  46. Prisma を採用するフレームワークが抱える課題 Prisma を採用するフルスタックフレームワークがバックエンドで Rails と 同等の開発生産性を実現しようとしたとき、現時点では次の課題に直面する。 Rails の高い開発生産性を実現している仕組みは、アクティブレコードの 採用が前提であるため再現できない

    こと(別のアプローチが必要) ドメインレイヤーは自ずとトランザクションスクリプトを採用することになる ため、 ドメインが複雑になると開発生産性が急落する性質を持つ こと 46
  47. Prisma 以外の ORM はどうか JavaScript には次のような著名なアクティブレコードの実装が存在するが、 TypeScript 周りで Prisma に劣るため、現時点では甲乙つけがたい。

    Sequelize: 約 10 年の歴史を持つこともあり機能面では充実しているが、 TypeScript 対応が弱く、それなりの量の型宣言を書く必要がある [18] TypeORM: Decorator により Sequelize の問題が緩和されており、機能 面でも十分だが、多くの場面で Prisma よりも型安全性が低い [19] どちらもバリデーションと コールバック機能を持つ 47
  48. Prisma の将来はどうか we re planning to over time (1) add

    more features on a Prisma level that help you express data-related business logic (e.g. extended validation rules) and (2) provide callbacks/hooks for you to make it easier to implement business logic . . . I strongly encourage you and everyone else to share your use cases and feature requests . . . as this helps us to prioritizing and designing upcoming features! ― Johannes Schickling (Founder of Prisma,2019) [20] “ “ ※ 太字強調は引用者によるもの 48
  49. フロントエンドからのアプローチの成否 次のいずれかの展開により、 ドメインレイヤーでの開発生産性の問題が 解消されるかどうかが鍵になる のではないか。 Prisma またはフルスタックフレームワーク側が Prisma の返す POJO

    に ドメインロジックを実装する仕組みを提供する(≠ アクティブレコード化) アクティブレコードを実装する他の ORM の TypeScript 周りが改善される 現状のままでも問題ないとわかる、またはそう考える人が多数派になる 49
  50. 第二部: 次世代の Rails の方向性 1. 2 つの方向性 2. フロントエンドからのアプローチ 3.

    バックエンドからのアプローチ 50
  51. 重要な要素: Rails 7 次の DHH 氏の言動から、Rails 7 ではフロントエンドに大きな変更が加わる ことが予想されるため、ここではその方向性について考察する。 2020

    年 12 月に SPA を構築するための新しいアプローチ「Hotwire」を 発表、同時に Rails 向けの実装である hotwire-rails を公開した [21] 2021 年 1 月に出演したある Podcast で、「Rails 7 では Hotwire を導入 してデフォルトで有効にしたい」という旨の発言をした [22] 51
  52. フロントエンドでのもう 1 つの試み: 脱 Webpack Hotwire と並行した次の取り組みにより、DHH 氏は Rails での

    Webpack の 利用を必須ではなくそうとしている [23] [24]。 ブラウザの ES Modules サポートを前提に Import Maps(※)の shim を 利用して、JavaScript のビルドなしで hotwire-rails が動くようにする Tailwind CSS でスタイリングできるようにして、Tailwind CSS 自体以外の CSS のビルドをなくす(この実装が tailwindcss-rails ) 未使用クラスの除去は Sprockets で行う ※ import foo from "foo" をブラウザで実現する議論中の仕様。詳しくは WICG の GitHub [25] を参照のこと 52
  53. 背景にある DHH 氏の問題意識 次の発言から、 現代のフロントエンドは問題に対して解決策が必要以上に 複雑になっていることが多い と DHH 氏は感じているのではないか。 “You

    start super stupid simple and then you just pay as you go for the complexity that you use and no more.” [26] “I also agree that apps that don t want or need that [Webpack] shouldn t have to wrestle with something this complex.” [27] 53
  54. バックエンドからのアプローチの成否 現時点では、Rails 7 において起こるだろうフロントエンドでの大きな変更は 開発生産性の向上が主な目的のため、次の事項が鍵になるのではないか。 DHH 氏がユーザー体験の向上に対して問題意識を持つ(現時点では優先 順位が低いだけで、既に問題意識がある可能性は大いにある) コミュニティ(※)側から、ユーザー体験の向上に関するフィードバックや プルリクエストを送っていく

    ※ 私と本日お集まりいただいた皆さんのことです! 54
  55. 第二部完 55

  56. まとめ 56

  57. 第一部: Rails の Active Record の正体 Web アプリケーションは、プレゼンテーション、ドメイン、データソースの 3 レイヤーから構成されることが多い

    Rails の Active Record が果たす役割は、アクティブレコードの採用、 バリデーションとコールバックの導入によって、ドメインレイヤー以下を モデルクラスだけで構築できるようにすることである Active Record や CoC、リソースベースのルーティングによってコードの 記述量を減らすことで、Rails はその高い開発生産性を実現している 57
  58. 第二部: 次世代の Rails の方向性 フルスタックフレームワークのあるべき姿を実現するアプローチを次世代の Rails の方向性としたとき、そのアプローチと課題は次の通り。 1. フロントエンドからのアプローチ: JavaScript

    の ORM のアーキテクチャ などに起因するドメインレイヤーでの開発生産性の問題の解消が課題 2. バックエンドからのアプローチ: Rails 7 で起こるだろうフロントエンドでの 変更が現時点ではユーザー体験の向上が主な目的でないことが課題 58
  59. ご清聴ありがとうございました 59

  60. 参考文献 60

  61. 参考文献 1 1. Yuichi Goto "Ruby on Rails の正体と向き合い方",URL: https://speakerdeck.com/yasaichi/what-is-ruby-

    on-rails-and-how-to-deal-with-it↩ 2. Shinpei Maruyama "Ruby (off|with) the Rails",URL: https://speakerdeck.com/shinpeim/ruby-off-with- the-rails↩ 3. toshimaru "Fat Model の倒し方",URL: https://speakerdeck.com/toshimaru/how-to-deal-with-fat- model↩ 4. Takafumi ONAKA "Smart UI パターンが再評価される世界",URL: https://onk.hatenablog.jp/entry/2020/11/11/024531↩ 5. Vercel,Inc. "Next.js 9",URL: https://nextjs.org/blog/next-9↩ 6. Vercel,Inc. "Next.js 9.5",URL: https://nextjs.org/blog/next-9-5↩ 7. Brandon Bayer " Announcing Blitz.js: Rails-like framework for full-stack React apps — built on Next.js". URL: https://dev.to/flybayer/announcing-blitz-js-rails-like-framework-for-full-stack-react-apps- built-on-next-js-g1o↩ 61
  62. 参考文献 2 8. mizchi "Frontend Study #1: 基調講演 - Frontend

    領域を再定義する",URL: https://zenn.dev/mizchi/articles/c638f1b3b0cd239d3eea↩ 9. Frank Buschmann,Regine Meunier,Hans Rohnert,Peter Sommerlad,and Michael Stal (1996) Pattern- Oriented Software Architecture,Volume 1,A System of Patterns: Wiley.↩ 10. Martin Fowler "PresentationDomainDataLayering",URL: https://martinfowler.com/bliki/PresentationDomainDataLayering.html↩ 11. Martin Fowler (2002) Patterns of Enterprise Application Architecture: Addison-Wesley Professional.↩ 12. "Active Record – Object-relational mapping in Rails",URL: https://github.com/rails/rails/tree/6-1- stable/activerecord#label-Philosophy↩ 13. kawasima "イミュータブルデータモデル",URL: https://scrapbox.io/kawasima/イミュータブルデータモデル↩ 14. Jeffrey Jose "Timing for bringing page experience to Google Search",URL: https://developers.google.com/search/blog/2020/11/timing-for-page-experience↩ 62
  63. 参考文献 3 15. Nikolas Burk "Prisma 2.0: Confidence and productivity

    for your database",URL: https://www.prisma.io/blog/announcing-prisma-2-n0v98rzc8br1↩ 16. "Is Prisma an ORM?",URL: https://www.prisma.io/docs/concepts/overview/prisma-in-your-stack/is- prisma-an-orm↩ 17. "blitz/signup.ts at v0.29.3 · blitz-js/blitz",URL: https://github.com/blitz- js/blitz/blob/v0.29.3/examples/custom-server/app/auth/mutations/signup.ts↩ 18. "TypeScript - Manual | Sequelize",URL: https://sequelize.org/master/manual/typescript.html↩ 19. "Prisma vs TypeORM",URL: https://www.prisma.io/docs/concepts/more/comparisons/prisma-and- typeorm#type-safety↩ 20. "How will prisma2 handle business logic? · Issue #353 · prisma/specs",URL: https://github.com/prisma/specs/issues/353↩ 21. DHH on Twitter,December 23 2020,1:27 AM,URL: https://twitter.com/dhh/status/1341420143239450624↩ 63
  64. 参考文献 4 22. "Remote Ruby | Hotwire, Rails NEXT, and

    the DHH Stack™ with David Heinemeier Hansson",URL: https://share.transistor.fm/s/336e93f9↩ 23. DHH on Twitter,January 14 2021,11:18 PM,URL: https://twitter.com/dhh/status/1349722504483500041↩ 24. DHH on Twitter,Dec 26 2020,7:26 PM,URL: https://twitter.com/dhh/status/1342778751575347200↩ 25. "WICG/import-maps: How to control the behavior of JavaScript imports",URL: https://github.com/WICG/import-maps↩ 26. "Full Stack Radio | 151: DHH – Building HEY with Hotwire",URL: https://share.transistor.fm/s/152b6067↩ 27. "Webpacker presents a more difficult OOB experience for JS Sprinkles than Sprockets did - A May Of WTFs - Ruby on Rails Discussions",URL: https://discuss.rubyonrails.org/t/webpacker-presents-a-more- difficult-oob-experience-for-js-sprinkles-than-sprockets-did/75345/31↩ 64