コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

『EM Meetup 特別会 〜EMこそソフトウェア設計を学ぼう〜』に行ってきたよメモ

EM Meetup 特別会 〜EMこそソフトウェア設計を学ぼう〜』に参加してきたのでそのメモです、

各発表の感想


開発組織の戦略的な役割と設計スキル向上の効果

感想

  • IT開発が事業の中核になりつつあり、事業の高業績にどう関われるようにするかというお話
  • 事業の変化に対応できるようになっていることが大事で、中核を対応可能になっていないと高業績をつくる足かせになるというのは本当に肌で感じる
  • 特に差別化要素に関しては丁寧に説明されており、マイケル・ポーター差別化戦略を読んでみたくなった。
  • 逆に中核はなにか、事業として中核でない部分まで自らの手で作ろうとしてないか?というのは常に考えておきたいトピック
    • 内製開発やっているとなんでも作りがちになるので、SaaSに委ねて問題ない部分はどんどんアウトソースするべき

関連リンク


ワークショップ

「事業理解から始めるソフトウェア設計道場」の導入部分に関して体験させてもらいました。

levii.co.jp

自社が持つ特性、特に差別化できるような要素を考えみようというものだった。自分が置かれているプロダクトでもセールスポイントとしておいているものとは別にどのようなところが差別化要素なのだろうと考える機会になった。

本題とは関係ないのですがBalus というツールがモデリングのために特化したツールですごく面白かった。miroでもできるが、miroではやれることが多いので削ぎ落とされているあたりが差別化なんだろうなと感じた。


OSTの感想

OST自体初参加だったのでわたわたしながらも参加しました。

私は「ドメイン知識の他人への橋渡し、どうしてる?」というテーマでOST参加しました。

オンボーディング的な話もあったのですが、興味深かったのが「ドメイン知識としてわからなかったことや解決したいことの内訳を書いて、それを解決したことをPullRequestで表現し、最後にそれを生成AIにドキュメント化してもらう」というもの。

何かしらのシステムやプロダクトに手を入れる瞬間にドメイン知識が欲しくなり、それを踏まえて手直しを加えるので、そこで得た教訓をサマリーにしてまとめてもらうのは瞬間の記録としては優秀だなと思いました。おそらくこれを貯めていくことで整理された情報も出力されそうでうまいなーと思いました。

全体を通しての感想

  • 増田さんの話が面白そうだったのもあり聞きにいったのですが、OSTも面白く大変参考になりました。
  • 各社生成AIはガシガシ導入しているので、もっと効果的に使いたいなと思わされました。
  • 私自身最近直接EM的な業務はやっていないのですが、みなさんが考えていることはAI時代でもそこまで劇的に変化していないので色々な意見交換ができてよかったです。

Railsで大文字が連続するクラス名をつけるときは統一感を損なわないように気をつける

すごい抽象的なタイトルだが実際困った事があったのでメモ

例えば拡張現実(Augmented Reality)のモデルを表現するクラスを作るとする。そうするときにar_model.rbというファイル名で、中身を以下のように書く。

class ARModel
  include ActiveModel::Model

  attr_accessor :name, :type

end

ただ、以下のようにもかける

class ArModel
# 後略

これはクラス名だけではなくモジュール名でも同じことが起きるので、ディレクトリ設計やファイル命名では気をつけること。

起きうる問題

例えば

  • app/model/ar_model/tree.rb
  • app/model/ar_model/house.rb

などとおいた場合に class ARModel::Treeclass ArMode::House というような書き方が混在可能なので、一見するとわかりにくい問題を生む。ただちに実害はないが、コードが成長するにつれてわかりづらさは増すので最初のうちにどちらで実装するかは決めておくほうがよい。

参考リンク

マネジメントをすることで不安を感じたときに見たい資料「Two Blades, One Journey: Engineering While Managing」

リーダーとしても、プレイヤーとしても動きたくなったときに見返したいのでメモとして

対象のスライド

speakerdeck.com

みどころ

マネジメントレイヤーが訪れる、不安に関しての言語化とそれに対する登壇者なりの解があるところがみどころ。かなり多くの人が遭遇するであろう不安に対してのヒントになりそうな部分はあり、私は少なからずここから色々と思い返す部分が多かった。

関連リンク

アサーティブコミュニケーションの原典をざっくり整理する

よくわからなかったので色々整理しながらまとめる

アサーションコミュニケーションの原典

アサーティブコミュニケーションの話の祖となっているのはAndrew SalterのConditioned Reflex Therapyとされている。この書籍の中ではアサーティブコミュニケーションというフレーズは登場しないが、概念自体は昨今語られているものに通じる内容となっている。

Salterの考え方

Salter は、人の行動には大きく分けて 「抑制的反応(inhibition)」と「興奮的反応(excitation)」 があると考えました。

反応タイプ 特徴 具体例
抑制的反応 感情や欲求を抑える・回避する 「言いたいけど黙る」「断れない」「自分の意見が言えない」
興奮的反応 感情や欲求を正直に表現する 「私はこう思う」「嫌です」「それは嬉しいです」などを適切に口にする

この興奮的反応を繰り返し訓練して学習することにより、「パブロフの犬」の考え方と同じように意識せずとも条件反射的に行えるようにするというアプローチです。

Salter が提示した代表的な訓練技法

原著からかなり時間が経過しているのですが、当時語られていた技法には以下のようなものがあります

1.アイ・トーク(I-talk)

自分の感情や欲求を「I(私は)」を主語にして表現する。「私は今、疲れているので少し休みたいです」など、「私」をちゃんと入れて喋る。

2.感情の言語化(Feeling-talk)

感じていることをそのまま言葉にする。「それを聞いて、私は驚きました」や「あなたの提案、うれしく感じました」など、感情を“思考”ではなく“体験”として伝えることを促す。

3.表情・身体での表現(Facial-talk・Body-talk)

表情や姿勢など非言語コミュニケーションを行う。感情と身体表現の一致するのが大事なので、ちゃんと意識して行えるようにする。

4.賞賛の受け入れ訓練(Accepting Compliments)

抑制的反応を多くする人は、褒められると否定したり曖昧にするため、それを改善する。「いやいや、大したことないです」ではなく「ありがとう、そう言ってもらえて嬉しいです」というようにし、自尊感情・自己効力感の基礎を作る。

5.即興的対話(Spontaneous Behavior Training)

計画せずに思ったことをその場で言う。即興で話す訓練を多くし、完璧に考えてから話す癖(抑制)を減らし、自然で柔軟な自己表現を促す。

6.宿題(Homework)

これまでに紹介したことを日常的に生活でやることを意識付けることが大事としている。

Salterの訓練で重視された観点

Salterは精神的な不調が「抑制的反応」が強く出てしまうことが要因と考えていたので、そこを訓練する事によって興奮的反応に変えようとするアプローチになっています。

そのため訓練では繰り返しやることで習慣づけ、日常期に取り組み、アイトークとしてやることで責任と主体性をもたせることが念頭に置かれています。

このSalterの考え方をもとに行動療法として整理されていき、のちのアサーティブコミュニケーションにつながっていったとされています。

参考リンク

『Kaigi on Rails 2025』に行ってきたよメモ

Kaigi on Rails 2025に参加してきたので、見た登壇に関しての感想&メモです。

各発表の感想

dynamic!

感想

  • "動的"に関することをテーマにした発表
  • Rubyとしての話、Railsとしての話、開発の話とすべてにおいて"動的"というテーマで結んでくれる話はとてもよかったです。
  • irbの使い心地に感動した話はめちゃくちゃ共感度が高かったです
  • すべてはアジャイルソフトウェア宣言に戻っていく話など、一周回っているからこそ出てくる味のようなものを感じる話でした。

関連リンク


高度なUI/UXこそHotwireで作ろう

感想

  • Reactができた経緯をたどりながら、HotwireとReactを比較しつつHotwireでもかなりのことができることの話
  • 既存のプラグインもHotwireでとりこむ手法もあるのはあまり知らなかったので学び
  • Railsを使っているけど、Reactを一部取り込もうか悩んでいる人は1回見るとよさそうな話でした。

関連リンク


そのpreloadは必要?──見過ごされたpreloadが技術的負債として爆発した日

感想

  • N+1を防ぐためのpreloadを使った際の落とし穴の話
  • preloadを使うのは定石だが、ちゃんと使いどころを考えないとよくないことが起きる事例として、とても学びがある話だったと思う。
  • なんでもできるオブジェクトを作ろうとすると起きがちなので気をつけたい

関連リンク


Railsアプリケーション開発者のためのブックガイド

感想

  • Webアプリケーションを作るうえでの血肉になる書籍の紹介
  • 「チームが変わっても一貫したものを作る柱として文化が必要」「ドキュメントは時間を超える」など染み入るフレーズが多かったです。
  • 自分も読んだことのない書籍もあったので、積めるものは積んでいきたいなと思いました。

関連リンク


Web Componentsで実現する Hotwire とフロントエンドフレームワークの橋渡し

感想

  • Angularのコンポーネントをラッピングして使うためにWebComponentを使った事例の話
  • WebComponentを使うと良くも悪くも外界と遮断しやすいのでなるほどなーと思って聞いていました。
  • 実際のレンダリング速度がどうなるかは気になりつつも、手法としては知っておいて損はなさそうでした。

関連リンク


5年間のFintech × Rails実践に学ぶ - 基本に忠実な運用で築く高信頼性システム

感想

  • 社内の運用事例大紹介、のような発表
  • 日々の運用で手が届かないところの改善ができていてすごくいい環境だなと感じました。
  • 同時にこれらの運用の解決策は割と環境によっても変わるので、事例としてもとてもいい話でした。

関連リンク


2分台で1500examples完走!爆速CIを支える環境構築術

感想

  • いろいろなテクニックでCIの時間を短くする話
  • 並列化の過程などはなるほどと思いつつ、最後は物理だったのはちょっと意外でした
  • ネタ的な部分もありつつもクラウドよりも物理の話はときたま聞くので、考えさせられる部分はありました。

関連リンク


Railsによる人工的「設計」入門

感想

  • 教わる側の世界観を通じて設計のノウハウを継承するための話
  • 初学者の解像度が高く、なるほどこういう発想になるのかという学びが多かったです。
  • 個人的には、キャリアの初期に画面遷移図からアプリケーションを作ることが多かったので、設計が身につきやすかったのかもしれないなどしみじみ思いました。

関連リンク


今改めてServiceクラスについて考える 〜あるRails開発者の10年〜

感想

  • Serviceクラスの成り立ちと現在の向き合い方に関する話。
  • 個人的にはもととなったQiitaの記事を見てServiceクラスを作ったりしていた時代を経験しているので色々心打たれるものがあった
  • DDD文脈がわからないと理解できないかも、とも思いつつ良い資料だったので折を見て見直したい

関連リンク


2重リクエスト攻略HANDBOOK

感想

  • 2重リクエスト防止に関するパターン集
  • すぐに思いつくものから、HTTPの仕様的なものまで話していたので何かあったときに見返したい資料でした。
  • 取捨選択のパターンも話されていて、とてもよい発表でした。

関連リンク

全体を通しての感想

  • 1日目はかなり自由時間があったので、色々見て回ったりしましたが、2日目は自社のブースにいたので発表はあまりみてませんでした。
  • moroさんとjokerさんの話が本当に良くて、1日目だけでもすごくいいものが見れたなという気持ちになりました。
  • 最近正しくRailsを使える場面がないので、得たものをうまく咀嚼しつつ取り組んでいければなと思っています。

RailsでのActiveRecordへのfreeze, readonly, strict_loading の違いをざっくり整理する

「引数にActiveRecordを渡したいが、そこから操作されてほしくない」というようなときにどういうアプローチがあるかが気になったので、ざっくりまとめ。

検証した環境

$ bin/rails -v
Rails 7.1.2
$ ruby -v
ruby 3.2.1 (2023-02-08 revision 31819e82c8) [aarch64-linux]

例示に使うモデル

今回は BookAuthor というモデルを例示に使う。定義は以下。

# == Schema Information
#
# Table name: authors
#
#  id         :bigint           not null, primary key
#  name       :string(255)
#  created_at :datetime         not null
#  updated_at :datetime         not null
#
class Author < ApplicationRecord
end

# == Schema Information
#
# Table name: books
#
#  id         :bigint           not null, primary key
#  title      :string(255)
#  author_id  :bigint           not null
#  created_at :datetime         not null
#  updated_at :datetime         not null
#
class Book < ApplicationRecord
  belongs_to :author
end

本記事で扱う3つのアプローチ

ActiveRecordオブジェクトの変更を制限する方法として、以下の3つを検証します。

  1. freeze - オブジェクトの変更を完全に禁止
  2. readonly! - データベースへの保存を禁止
  3. strict_loading - 関連レコードの遅延読み込みを禁止

各メソッドごとのざっくりまとめ

freezeとは

freezeはRubyのObjectクラスに定義されているものであり、オブジェクトの変更を禁止するもの。定数などではよく使われるが、ActiveRecordにも適用できる。

例えば以下のように、Bookが持つattributeは更新できなくなる。

irb(main):001> book = Book.last
  Book Load (0.3ms)  SELECT `books`.* FROM `books` ORDER BY `books`.`id` DESC LIMIT 1
=> #<Book:0x0000ffffb14fd808 id: 1, title: "hon", author_id: 1, created_at: Sat, 25 Oct 2024 03:44:36.248348000 UTC +00:00, updated_at: Sat, 25 Oct 2024 03:44:36.248348000 UTC +00:00>
irb(main):002> book.title = "test"
=> "test"
irb(main):003> book.freeze
=> #<Book:0x0000ffffb14fd808 id: 1, title: "test", author_id: 1, created_at: Sat, 25 Oct 2024 03:44:36.248348000 UTC +00:00, updated_at: Sat, 25 Oct 2024 03:44:36.248348000 UTC +00:00>
irb(main):004> book.title = "test2"
/usr/local/bundle/gems/activemodel-7.1.2/lib/active_model/attribute_set.rb:59:in `write_from_user': can't modify frozen attributes (FrozenError)
irb(main):005> book.save
/usr/local/bundle/gems/activemodel-7.1.2/lib/active_model/attribute_set.rb:59:in `write_from_user': can't modify frozen attributes (FrozenError)

なお、メソッド自体に関してはObject#freeze (Ruby 3.4 リファレンスマニュアル)を参考のこと。

なお、関連付けられたオブジェクト(例:book.author)まではfreezeされないので、個別にfreezeする必要がある。

readonly!とは

ActiveRecordのメソッドの一つであり、更新作業をできない状態にするもの。

例えば以下のように代入は可能だが保存はできない状態にできる。

irb(main):001> book = Book.last
  Book Load (0.3ms)  SELECT `books`.* FROM `books` ORDER BY `books`.`id` DESC LIMIT 1
=> #<Book:0x0000ffff8970d8a0 id: 1, title: "hon", author_id: 1, created_at: Sat, 25 Oct 2024 03:44:36.248348000 UTC +00:00, updated_at: Sat, 25 Oct 2024 03:44:36.248348000 UTC +00:00>
irb(main):002> book.title = "test"
=> "test"
irb(main):003> book.readonly!
=> true
irb(main):004> book.title = "test2"
=> "test2"
irb(main):005> book.save
/usr/local/bundle/gems/activerecord-7.1.2/lib/active_record/persistence.rb:1281:in `_raise_readonly_record_error': Book is marked as readonly (ActiveRecord::ReadOnlyRecord)
irb(main):006> 

こちらも関連オブジェクトはreadonlyにはならないので、気をつける。

strict_loadingとは

Rails6.1から導入された機能で、N+1を抑止するための機能。あらかじめオブジェクトがロードされていない状態で関連を取ろうとするとエラーになる。

例えば以下のように includes などでオブジェクトを取得していない状態だと、関連レコードの情報を取ろうとするとエラーになる。

irb(main):001> book = Book.first
  Book Load (0.3ms)  SELECT `books`.* FROM `books` ORDER BY `books`.`id` ASC LIMIT 1
=> #<Book:0x0000ffff7d9ef7f0 id: 1, title: "hon", author_id: 1, created_at: Sat, 25 Oct 2025 03:44:36.248348000 UTC +00:00, updated_at: Sat, 25 Oct 2025 03:44:36.248348000 UTC +00:00>
irb(main):002> book.author
  Author Load (0.4ms)  SELECT `authors`.* FROM `authors` WHERE `authors`.`id` = 1 LIMIT 1
=> #<Author:0x0000ffff7dd8bb70 id: 1, name: "suzuki", created_at: Sat, 25 Oct 2025 03:43:52.517291000 UTC +00:00, updated_at: Sat, 25 Oct 2025 03:43:52.517291000 UTC +00:00>
irb(main):003> strict_book = Book.strict_loading.first
  Book Load (1.2ms)  SELECT `books`.* FROM `books` ORDER BY `books`.`id` ASC LIMIT 1
=> #<Book:0x0000ffff7dca2d08 id: 1, title: "hon", author_id: 1, created_at: Sat, 25 Oct 2025 03:44:36.248348000 UTC +00:00, updated_at: Sat, 25 Oct 2025 03:44:36.248348000 UTC +00:00>
irb(main):004> strict_book.author
/usr/local/bundle/gems/activerecord-7.1.2/lib/active_record/core.rb:230:in `strict_loading_violation!': `Book` is marked for strict_loading. The Author association named `:author` cannot be lazily loaded. (ActiveRecord::StrictLoadingViolationError)

ちゃんと取得していればエラーにならない。

irb(main):001> strict_book = Book.strict_loading.includes(:author).first
  Book Load (0.2ms)  SELECT `books`.* FROM `books` ORDER BY `books`.`id` ASC LIMIT 1
  Author Load (0.2ms)  SELECT `authors`.* FROM `authors` WHERE `authors`.`id` = 1
=> #<Book:0x0000ffffadc2da50 id: 1, title: "hon", author_id: 1, created_at: Sat, 25 Oct 2025 03:44:36.248348000 UTC +00:00, updated_at: Sat, 25 Oct 2025 03:44:36.248348000 UTC +00:00>
irb(main):002> strict_book.author
=> #<Author:0x0000ffffae99dbb8 id: 1, name: "suzuki", created_at: Sat, 25 Oct 2025 03:43:52.517291000 UTC +00:00, updated_at: Sat, 25 Oct 2025 03:43:52.517291000 UTC +00:00>
irb(main):003> 

なお、追加でのクエリ発行を抑制するだけなので、保存や代入のブロックは行わない

関連リンク

RailsのActiveRecordで主キーの配列を取りたい場合はidsメソッドで取得できる

pluck(:id) を使っていたのでメモ程度に。

動作環境

$ bin/rails -v
Rails 7.1.2

実例

Authorというモデルがあった場合、以下のように取得できる

Author.ids
# => [1, 2, 3]
Author Ids (0.6ms)  SELECT `authors`.`id` FROM `authors`
# => Array

こちらはModel側で主キーを別のものに指定している場合でもよしなに該当カラムを引き当ててくれるので、その点ではpluck(:id)よりも親切

実コード

実際のコードは以下の通り、再帰的なことをやっているのでわかりにくいが primary_key を使って取得している

def ids
  primary_key_array = Array(primary_key)

  if loaded?
    result = records.map do |record|
      if primary_key_array.one?
        record._read_attribute(primary_key_array.first)
      else
        primary_key_array.map { |column| record._read_attribute(column) }
      end
    end
    return @async ? Promise::Complete.new(result) : result
  end

  if has_include?(primary_key)
    relation = apply_join_dependency.group(*primary_key_array)
    return relation.ids
  end

  columns = arel_columns(primary_key_array)
  relation = spawn
  relation.select_values = columns

  result = if relation.where_clause.contradiction?
    ActiveRecord::Result.empty
  else
    skip_query_cache_if_necessary do
      klass.connection.select_all(relation, "#{klass.name} Ids", async: @async)
    end
  end

  result.then { |result| type_cast_pluck_values(result, columns) }
end

参考リンク