マイペースなRailsおじさん

Ruby、Ruby on Rails、オブジェクト指向設計を主なテーマとして扱います。だんだん大きくなっていくRuby on Rails製プロダクトのメンテナンス性を損なわない方法を考えたり考えなかったりしている人のブログです。

Active RecordとNull Objectパターン

Active RecordでNull Objectパターンを使うことはできるのか考えてみました。

RubyでNull Objectパターン

RubyでもNull Objectパターンを使えます。下記の記事を御覧ください。

ytnk531.hatenablog.com

Active RecordとNull Objectパターン

どんなときに使いたいか

アソシエーションを張っているレコードがない場合の処理を書きたいときに、Null Objectパターンを使えたら便利そうです。

実装

class Customer < ApllicationRecord
  has_one :actual_license, class_name: 'License'

  def license
    actual_license || NullLicense.new
  end
end

class License < ApplicationRecord
  belongs_to :customer
end

class NullLicense
end

このようにすれば、アソシエーションしているLicenseレコードが無い場合はNullLILicenseを渡すことができます。実際のlicenseとの関連はCustomer#actual_licenseを呼び出すことになります。

実装のポイント - has_oneのclass_nameオプションを使ってLicenseを取得するメソッドの名前を変更する - licenseメソッドのゲッタを作ることでNullLicenseのインスタンスを返せるようにする

困りそうなポイント

NullLicenseのほうに値の無い処理が書けるようになりましたが、その代わり、構造上のややこしさを生み出しました。

  • ライセンスのない場合の処理を外部に書きたいとき、Customer#license.nil?のような判定をすると意図していない結果になる(NullLicenseが取得できるため)
  • licenseかlicense_actualかを呼び出し側で考慮しないと行けない部分が出てくるかもしれない

といったところです。2点目の回避策としては、NullLicenseの方にLicenseインスタンスが外から呼び出されるメソッドを実装してしまうという方法があります。例えばLicense#destroyが呼ばれる場合、このようにしてダミーのメソッドを作ります。

class NullLicense
  def destroy
  # 何もしない
  end
end

この方法は、NullLicenseの方に値がないときの処理がまとまる利点がありますが、構造の把握をややこしくしてしまうという欠点もあります。

Active RecordでNull Objectパターンはややこしいコードを生んでしまうかも

Null Objectパターンを使うためにアソシエーションの張り方を歪めているので、新たな問題を生んでしまう可能性があります。

このあたりのデメリットを許容した上で、値がないときのややこしい処理がビューやコントローラーに散ってしまうことの対策として使うのがよさそうです。

RubyのNull Objectパターン

Rubyの場合はNil Objectパターンと呼ぶことになるんでしょうか?

Null Objectパターン

Null Objectパターンは、値が存在しない場合の処理を共通化したい場合に使えるデザインパターンです。

こちらの解説がわかりやすいです

Nullオブジェクトパターンの紹介と正体 - ベインのブログ

NullObjectパターン - Qiita

Rubyで実装

CutomerクラスとLicenseクラスを使って、CustomerのLicenseのname要素を表示することを考えます。CustomerがLicenseを持っているとします。Licenseは空でも良いです。

class Customer
  attr_reader :license

  def initialize(license=nil)
    @license = license
  end
end

class License
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

Coustomerの持っているLicenseの名前を表示したいときは、次のようなコードを書くことになります。

driving_license = License.new('運転免許')
customer = Customer.new(driving_license)
puts customer.license.name # => 運転免許

ここで、免許が無いときは、「免許なし」と表示したいとします。 おそらく最も単純な方法は、表示時に分岐を作ることです。

driving_license = License.new('運転免許')
customer1 = Customer.new(driving_license)
customer2 = Customer.new
puts customer1.license? ? customer1.license.name : '免許なし' # => 運転免許
puts customer2.license? ? customer2.license.name : '免許なし' # => 免許なし

このコードをいろいろな場所から使おうと思うとき、下記の懸念点があります。

  • Customerを利用する場所では、lisenceが設定されていなかった場合の分岐を書かなくては行けない
  • lisenceが設定されていなかった場合にどのような処理が走るのかは、利用する側のコードを見ないとわからない

こういう問題を解消したいとき、Null Objectパターンが有効に働くことがあります。 Nullオブジェクトパターンの紹介と正体 - ベインのブログ

存在しないことを表現するLicenseクラス、NullLicenseを作ります。Customerでは、licenseが参照された際にlicenseがない場合は、NullLicenseのインスタンスを返すようにします。

class NullLicense
  def name
    '免許なし'
  end
end

class Customer
  def initialize(license=nil)
    @license = license
  end

  def license
    @license || NullLicense.new
  end
end

これで、licenseを参照する側で分岐を書く必要がなくなりました。

driving_license = License.new('運転免許')
customer1 = Customer.new(driving_license)
customer2 = Customer.new
puts customer1.license.name # => 運転免許
puts customer2.license.name # => 免許なし

毎回インスタンスを生成しなくて良くする

Customer#licenseは、コールされるたびにNullLicense.newを生成することになるので、無駄があります。NullLicenseクラスの定数として持たせることでこの無駄な処理を行わないようにできます。

class License
  Nothing = NullLicense.new
end

class NullLicense
  def name
    '免許なし'
  end
end

class Customer
  def initialize(license=nil)
    @license = license
  end

  def license
    @license || License::Nothing
  end
end

Null Objectパターンのうれしさ

Null Objectパターンを使う利点は次の通りです

  • 値が無い場合のあるオブジェクトを利用する側で、値がない場合のことを考慮した処理を書かなくて良くなる
  • 値がない場合の処理がNull Objectにまとまる。

デメリットとして考慮する必要があるのは、次のような点です。

  • Null Objectを返す処理が追加されるので、単純なプロパティの返却ではなくなる。単にプロパティを返してほしいだけだったのにインスタンスが生成されていて、パフォーマンスのボトルネックになる、ということがあるかもしれない。
  • インターフェースを共有することになるので、Null Objectを作る対象のインターフェースが追加されたらNull Objectも追従する必要がある

Null Objectパターンは、非常に便利なのですが、オブジェクトの生成のところで少し工夫が必要になります。いろいろなところに分岐が散ってしまいそうなとき有効なパターンです。

n+1クエリの自動テストが書けるgem、n_plus_one_control

N+1問題

N+1問題は、ループ内の処理を通過するたびにSQLが発行されるというパフォーマンス上の問題です。Railsにおいては、includesメソッドを使って、preloadあるいはeager loadを使って回避できます。

こちらの記事がわかりやすいです

【Ruby on Rails】N+1問題ってなんだ? - Qiita

検出方法

N+1問題の検出には、bulletがよく使われます。このgemは、N+1なクエリが発行されるとメッセージを出力してくれます。

n_plus_one_controlを使って自動テストで検出する

n_plus_one_controlというgemは、自動テストで検出することができるようにしてくれます。

Squash N+1 queries early with n_plus_one_control test matchers for Ruby and Rails — Martian Chronicles, Evil Martians’ team blog github.com

だいだいの仕組みは、複数レコードを出力する処理を複数回実行し、発行クエリの差分を見ることで無駄なクエリが発行されていないかをチェックするものです。 bulletでは検出できないパターンも検出できるようです。

n_plus_one_controlを使ってみる

対象のコード

モデル

ユーザーが部署のレコードを持つモデルを用意します(普通逆だけど)

class User < ApplicationRecord
  has_one :department
end
class Department < ApplicationRecord
  belongs_to :user
end

コントローラー

とくにひねりはなく普通に全レコード取得します。

class UsersController < ApplicationController
  def index
    @users = User.all
  end
end

ビュー

user.departmentが複数回走るので、ここで毎回クエリが発行されます。

<h1>Users</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Department</th>
    </tr>
  </thead>

  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.department.name %></td>
      </tr>
    <% end %>
  </tbody>
</table>

テストする

n_plus_one_controlは、複数のレコードを参照する処理を複数回実行するので、任意の数のレコードを生成する方法を知っている必要があります。populateに、任意の数nを受け取って、n個のユーザーと部署レコードを生成するコードを書いておきます。

あとは、テスト対象の処理が走るページを参照する処理をassert_perform_constant_number_of_queries(populate: populate)で囲めば準備完了です。

require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest
  setup do
    @user = users(:one)
  end

  test 'test_no_n_plus_one_error' do
    populate = lambda do |n|
      n.times do
        User.create(
          name: 'テスト',
          department: Department.new(name: 'テスト部署')
        )
      end
    end

    assert_perform_constant_number_of_queries(populate: populate) do
      get users_url
    end
  end
end

実行結果

$ rails test
# Running:

F

Failure:
UsersControllerTest#test_test_no_n_plus_one_error [/home/tanaka/n_plus_one_app/test/controllers/users_controller_test.rb:18]:
Expected to make the same number of queries, but got:
  5 for N=2
  6 for N=3
Unmatched query numbers by tables:
  departments (SELECT): 4 != 5

いいかんじに失敗してくれました。n=2のときに、5回クエリが発行されているので、n=3でも5回クエリが発行されることを期待したが、6回発行されたという旨が表示されました。すごい!

なおす

includesを使って解消します。

class UsersController < ApplicationController
  def index
    @users = User.all.includes(:department)
  end
end

これで再度テストします

$ rails test
Running via Spring preloader in process 7072
Run options: --seed 18633

# Running:

.

Finished in 1.235619s, 0.8093 runs/s, 0.8093 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

テストが通るようになりました。

大事なところで使うといいかも

n+1クエリって、改修の中でいつの間にか生まれていくという印象が強くあります。大きな機能追加のときは気をつけるんですが、細かい改修だと見落としてしまったり…。なので、この手の自動テストが書けるというのは非常に役立ちそうです。

n+1をどれだけ徹底して潰すかにもよりますが、パフォーマンスに気を使う処理の場合は、このようなテストは大変有効に働くのでは無いでしょうか。逆に、あまりどこでも使ってしまうと「早すぎる最適化」に陥ってしまうかもしれません(「早すぎる最適化は諸悪の根源」について - Qiita)。

用法用量に気をつけて、少しずつ使う機会を探っていこうと思います。

Railsの設計について思うこと

Railsと設計

Railsは、Active Recordを中心に据えてコードを書いていきます。そうなると、自然とテーブル設計に強く依存したアプリケーションになって行くので、アプリケーションが複雑になっていくとツライ!となることがあります。こういった、Railsアーキテクチャそのものに対する議論はたびたび話題に上がります。

RailsとDDD

RailsでDDDした人の話

最近、ミノ駆動さんのDDD(ドメイン駆動設計)に関する発表が界隈で話題になりました。

ドメイン駆動設計は、アプリケーションの中心にDBなどのデータストアではなく、ドメインを持ってくるという設計方法です。ヘキサゴナルアーキテクチャを使って実装されることが多いようです。長期開発を主眼においた設計手法で、大規模プロジェクトではよく使われる設計手法です。

ミノ駆動さんは、Railsの300KLOCを超える大規模なモノリシックなアプリケーションをDDDでリファクタリングするというとてつもない問題に取り組まれています。尊敬します。実際どんなアーキテクチャにしているかについても記事を書かれているので気になる方はぜひ。

ドメイン駆動設計の比類なきパワーでRailsレガシーコードなど大爆殺したるわあああ!!! - Qiita

ミノ駆動さんの主張のうち、私がRailsの設計を考える上で重要だと感じるのは次の2点です。

  • 初めからRailsでDDDをやるのはおすすめしない
  • コアドメインに対して部分的にDDDを導入すると良いのではないか

hanami

では、rubyでDDDをやりたい人はどうすればいいのでしょうか? hanamiというrubyフレームワークがあります。railsからこちらに乗り換えるべきでしょうか?

hanamirb.org

ここで、一度立ち止まって考えたいことは、いきなりDDDにゆくべきか?という点です。

偉い人はなんていっているか

エンタープライズアプリケーションの大家Martin Fowlor先生は、Railsのようなアクティブレコードを使った(所謂)犠牲的アーキテクチャと、Springのようなデータマッパーを使ったヘキサゴナルアーキテクチャはどっちがいいんだ?という議論を2014年に公開しています。時間が経ってはいますが、議論されているの対象となるRailsの性質は変わっていないため、現在でも十分聞く価値があります。

www.martinfowler.com

ものすごくざっくり要約すると下記のようなことを言っています。

  • データマッパーとアクティブレコードの間にはトレードオフがある。データマッパーは複雑だがDBとの依存を低くでき、アクティブレコードは単純だがDBに強く依存する。
  • ドメインが複雑で、アプリケーションとDBを分離する必要があるならヘキサゴナルアーキテクチャを使うべき
  • ドメインが単純ならばActive Recordが有効に働く
  • 判断基準となるのはドメインの複雑さであって、コードの量やテーブルの数ではない。ThoughtWorksで1000テーブル以上を扱うRailsアプリケーションが開発され、うまくいっていた。

Railsは、主に初期開発時のスピードをつけるために大変有効に働きます。設計が複雑になるからと言ってその利点をすんなり諦めてしまうのはもったいないように感じます。

スケールする設計

成功したプロダクトでは、長期的に見るとソフトウェアはこのような扱いを受けます。

  1. 立ち上げる
  2. 拡張する
  3. リプレイスする

Railsは、1. のフェーズにおいてはとても有効に機能します。 私がRailsのプロジェクトに関わっていて感じるのは、2. のフェーズをうまく過ごすことができれば、いきなりDDDを導入してアーキテクチャをごっそり入れ替えるみたいな大規模な回収を入れずに済むのではないか?ということです。

DDDにすれば解決する?

ヘキサゴナルアーキテクチャやDDDが良い、とされているのはアプリケーションの複雑さをアーキテクチャで吸収することでコードが単純になるから、と私は考えています。大げさに言うと、コードが単純になる代わりに、クラス設計や依存するライブラリの方に複雑さを寄せているに過ぎない、という考えです。

であれば、最初から複雑でないアプリケーションを構築するために、冗長なコードを書く必要があるのでしょうか?もちろん、最初から大規模だったり複雑になることがわかっていて、お金と人員が豊富なことがわかっているプロジェクトであればDDDを導入すべきだと思います。

管理が辛いのはRailsのせい?

Railsは、アーキテクチャに関する選択はプログラマーに委ねられている部分が少なからずあります。コントローラーとモデルの間に、どれたけクラスを配置しようが自由です。究極的には、Active RecordをDDDでいうRepositoryの実装として扱えば、Active Record、ひいてはDBへの依存を取り除き、ドメインをDBから隔離することもできます。

アプリケーションが複雑になってきたら、部分的に冗長なクラス構成に拡張していく、というようにスケールしてやればRailsでも大規模かつ複雑なアプリケーションを十分構築可能なのではないか、ということです。

最強のRailsの設計とは、自分達のアプリケーションにとっての最適を目指すこと

Railsは、普通に使っていくと柔軟性が低い。でも、最初のうちはそれでいい。アプリケーションが複雑になってきたら、その複雑さを吸収できるようなアーキテクチャに少しずつ変えていけばよいのでは、というお話でした。

Ruby on Railsがわからないときに見る場所

RailsSQLからJavaScriptまで広い範囲を扱えるため、詰まりポイントが非常に多いです。私がRailsに慣れなかったころに確認していたことを振り返ってまとめてみます。

どこがつまりポイントになるか

Railsが扱う要素技術は非常に多いので、初心者にとってはそれら一つ一つがつまりポイントになります。よくよく調べてみると、意外とRails自体で詰まることは少ないかもしれません。Railsでは、主に下記の要素技術を扱います。

たぶんもっとありますが、これら一つ一つがそれぞれ奥深い技術です。うまく動かなくてもめげずに根気よく向き合って行きましょう。

Railsの使い方がわからないとき

あまりひねったことはせず、公式のガイドとリファレンスガイド、ソースコードを見るのがわかりやすいです。Qiitaや技術系ブログの記事もわかりやすくて良いのですが、私の場合は変なつまり方をしてしまうことがあったので、できるだけ確実な一次情報を当たるようにしていました。

慣れていない機能を使うときは、まずガイドで大まかな使い方を把握します。やりたいことができそうなことが確認できたら、使いたいメソッドについてリファレンスガイドで詳しい説明を確認します。引数の渡し方や、ガイドには書いていない便利な機能、あるいは制約が書いてあることがあるので、注意して確認します。

ソースコードの方は正直かなり巨大なので、細かく読むことはめったにありませんでした。RailsActionView、ActiveModel、ActiveRecordといったモジュールに分かれていて、それらをRailtieというモジュールでつなぎ合わせています。ソースコードでは、各モジュールのREADME.mdを読んで、モジュールの担当範囲を把握したり、主要なクラスの継承関係、依存関係を把握します。この構成がわかっているとリファレンスガイドから知りたい情報にたどり着くのが圧倒的に早くなります。

Rubyの使い方がわからないとき

Rubyの方も、同じような方法で調べます。ただし、体系立てて学べる資料がインターネット上で見つけられなかったので、私は書籍から入っていきました。

英語版のリファレンスマニュアルと、日本語版のリファレンスマニュアル(通称るりま)は微妙に書いてあることが違ったりするので、両方確認していました。

Railsが思うように動かないとき

Railsのコードが思うように動かないとき、Railsがわかっていないというよりは、Railsを構成する要素技術の理解が足りないためにうまくいかないというのがほとんどです。

何が悪いのか検討もつかない場合は、フロントエンドからサーバーサイドに向かって、順を追ってどこでうまく行っていないのか確認すると良いでしょう。

DOM要素を確認する

ブラウザの開発者ツールを立ち上げて、HTMLとCSSが意図した状態になっているか確認します。JavaScriptを使っている場合は、コンソールにエラーが出ていないかも確認します。

HTML、CSSJavaScriptについて、下記のことがはっきりわかっていないときは、MDNなどで知識を補いながら確認します。

  • 期待する動作をさせるためには、HTMLはどのようになってればよいか
  • CSSが意図した要素に対して有効か
  • CSSJavaScriptソースコードがページに読み込めているか

f:id:ytnk531:20201028001803p:plain

HTTPメッセージを確認する

こちらも開発者ツールでのネットワークタブから、HTTPメッセージを確認します。

下記、足りない知識があれば補いながら確認します。HTTPについてはMDNの解説がちょうどいい粒度です。

  • HTTPレスポンスボディ、HTTPリクエストボディに意図したデータが書き込まれているか
  • HTTPレスポンスヘッダ、HTTPリクエストボディに見慣れないヘッダが付与されていないか

f:id:ytnk531:20201028002136p:plain

Railsデバッグログを確認する

rails serverを実行したターミナルに、デバッグ用のログが出力されるので、ここから下記のようなことを確認します。

  • 意図したページにリクエストが投げられたか
  • 意図したコントローラーで処理が実行されたか
  • 意図したSQL分が実行されているか

SQLについては、書籍も学習サイトも豊富にあるかと思いますので、お好きなもので学習してください。

Started GET "/" for ::1 at 2020-10-27 07:42:03 +0900
Processing by TopController#index as HTML
  Rendering top/index.html.erb within layouts/application
  Board Load (0.1ms)  SELECT "boards".* FROM "boards"
  ↳ app/views/top/index.html.erb:25
  Rendered top/index.html.erb within layouts/application (Duration: 3.7ms | Allocations: 870)
[Webpacker] Everything's up-to-date. Nothing to do
Completed 200 OK in 15ms (Views: 13.5ms | ActiveRecord: 0.1ms | Allocations: 4993)

Railsのコントローラーを確認する

デバッガーを使って、Railsの動きを止めて、変数に意図した値が入っているか確認いしてみましょう。 デバッガーの使い方はこちらが詳しいです。

Rails アプリケーションのデバッグ - Railsガイド

以下を確認します

  • 変数に意図した値が入っているか
  • request, paramsに意図した値が入っているか

終わりに

Railsは覚えることが非常に多く、エディターの補完も効く範囲が限られているので、気を抜くとすぐに迷子になってしまします。 詰まったらまずは、「自分が理解できていないことは何か」を理解することを心がけましょう。

Rails6 + Webpackerな環境でyarnで入れたbulmaを使う

bulmaは美しいCSSフレームワークです。Railsで使おうとする場合、bulma-railsというgemを使ってもいいのですが、せっかくyarnが入っているので、yarnでインストールすることにしました。

bulma-railsは、本家よりすこし遅れてアップデートが反映されていくので、早く最新版を使いたい場合は、yarnで入れる方にメリットがあります。

環境

特にオプションは指定せずrails newした直後の状態から始めます。

手順

bulmaをインストール

yarnでbulmaをインストールします。

yarn add bulma

stylesheet.scssを設置

Railsからbulmaを読み込めるようにします。

まず、読み込むCSSを確認します。通常、node_modules/bulma/css/bulma.min.cssが配置されているので、これを読み込みます。

$ ls node_modules/bulma/css
bulma-rtl.css      bulma.css
bulma-rtl.css.map  bulma.css.map
bulma-rtl.min.css  bulma.min.css

app/javascript/packs/application.scssに下記を記述します。無い場合は作成します。| ~(チルダ)に続けてnode_modulesから見たパスを指定します。

@import '~bulma/css/bulma.min';

viewからapplication.cssを読み込む

application.html.erbに、こちらの記述があることを確認してください。なければheadタグ内に追加します。

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %

以上でRailsからbulmaを使う準備ができました。簡単ですね。

使ってみる

<div class="section">
  <article class="message">
    <div class="message-header">
      <p>こんにちは</p>
      <button class="delete" aria-label="delete"></button>
    </div>
    <div class="message-body">
    bulmaをインストールして使ってみました。
    </div>
  </article>
</div>

f:id:ytnk531:20201027000429p:plain 以上です!

Stimulas、いつつかうん?

Stimulas

Stimulasは、少ないコード量で動的な表現をすることに主眼を置いて開発された、軽量なJavaScriptフレームワークです。DHH率いるBaseCampが公開してます。

主に提供している機能はこの2つです。

  • DOM要素のイベントと、そのイベントにフックするJSのメソッドをHTMLへの簡単な記述で紐付けられる。
  • DOM要素とJSの変数を、HTMLへの簡単な記述で紐付けられる

解説はこちらがわかりやすいです。 JavaScript初心者にもオススメ!クリーンなコードでHTMLを拡張する「Stimulus」とは?|ferret

vs Vue.js, React.js

フロントエンドのフレームワークといえば、Vue.jsReactです。これらと比較するとどうでしょう?

結論から言うと、Stimulasはこれらのフレームワークほど協力ではありません。値を双方向バインディングして自動的にDOM要素を更新するような機能も無ければ、UIパーツをコンポーネント化して使い回すような機能もありません。

例として、Vue.jsではテンプレートの中に変数を入れておくと、その変数が更新されれば自動的にDOM要素の値も更新されます。これをバインディングといいますが、Stimulasにはそのような機能はありません。DOM要素を更新したければ、プレーンなJSを使うときと同様、HTMLのAPIを操作してDOM要素を更新する必要があります。

いつつかうん?

私が考えるのStimulasの使い所は、「フロントエンド専門のエンジニアがいないプロジェクトでJSを書く場合」です。

フロントエンドのエンジニアがいるような環境では、HTMLの共通化や自動生成はVue.jsやReact.jsを用いjてJS側で行われることがほとんどなはずです。 いくらStimulasが軽量のフレームワークで覚えることが少ない、といっても今どきの大抵のフロントエンドエンジニアは、よりリッチなVueやReactを使える人がほとんどです。わざわざ新しいことを覚えて、より非力なフレームワークを使うというのは非効率に感じます。

また、フロントエンドエンジニアが投入されているようなプロジェクトでは、やはりそれらリッチなフレームワークを使うべき複雑なフロントエンドの制御が求められるはずです。そのような場合、Stimulasを使ったからと言って、フロントエンド開発の効率化はあまり期待できません。

逆に、Railsのようなフレームワークを使って、モノリシックなアプリケーションを少人数で作っているような環境では、Stimulasが役に立つかもしれません。 JSにあまり詳しくないエンジニアからすれば、Stimulasは非常にちょうどいいフレームワークです。 きっと、そのような人たちはこのように考えると思います。

  • 生のJSでは、DOM取得と操作がコードの大半を埋め尽くしてしまい、記述が面倒である。
  • フロントエンドで複雑な制御(状態がたくさんあったり、UIパーツをガラッと入れ替えたり…etc.)を必要としない、控えめなフロントエンドの制御が必要な場合に、Vue.jsやReactのようなリッチなフレームワークを活用するのはやりすぎである。

そう思ったとき、Stimulasは、生のJSとリッチなJSフレームワークとのちょうど間をいく、いいかんじのフレームワークなんです。

サーバーサイドからHTML、CSSまで一人で触るような開発をしている場合、サーバーサイドでできること(HTMLの生成)を、わざわざJSに書くのは非効率です。そのため、クライアントサイドでの描画が必要な動的な部分だけを効率よく作りたい、と考えるのは自然なことに感じます。 Stimulasは、サーバーサイドでHTMLの共通化や自動生成を行っているプロジェクトで、JSのコードを記述する量を最小化するのに用いるのが適しているのではないかと考えています。