Railsのトランザクションについて学び直す

Railsのトランザクションって、勘で書きがちで、自分の理解は下記ぐらいだったので、少し真面目に捉えようと思いました。 まずは学ぶことを決めていきます。

今のところの自分の解像度

曖昧な概念(わからないこと)

派生できる概念も含めてこんなところでしょうか

<ActiveRecordの内部実装>

これに関しては指針がほしかったのでClaudeに聞いてみました。

  • https://github.com/rails/rails/tree/main/activerecord 特に lib/active_record/transactions.rb を重点的に

  • Connection Pool の仕組み

  • データベースアダプタの実装
  • 分散トランザクション
  • デッドロックの検知と対策
  • connection.transaction の実行フロー
  • ロールバックの発生条件と挙動
  • データベースへの実際のクエリ発行タイミング
  • トランザクション分離レベル
  • ORMの主要パターン(ActiveRecord, DataMapper, Repository)
  • レコードの読み込み(遅延ロード vs 即時ロード、キャッシュ戦略)
  • 関連の取り扱い(has_many, belongs_toの実装、結合テーブルの処理)
  • コレクションの管理(配列のような操作、バッチ処理)

仕事振り返り その3

簡単な振り返り

  • group_byでは2カラムセットをキーにしてグループ化できる
  • stateful_enumを使ったtransitionはevent名にcanをつけて呼び出すと、対象のインスタンスが遷移可能なステータスなのかを教えてくれる
  • ハッシュに対して、{}.defaultでkeyが無い場合のvalueのセットができる

設計手法について

context変数

人の設計をみて思ったことですが、SeriveClassやFormObjectなどを作るときに、「主責務からは逸脱するものの、処理の都合上必要なデータ」などをcontextというハッシュにまとめてしまう、という手法を見かけましたが、かなり良いなと思いました。

ViewObject

ViewObjectを使ったSVGの描画が良いなと思いました。 SVGって、動的なものをベタ書きしようとすると、かなりごちゃついてしまうので、ViewObjectにすることで、要素を置く位置を計算するメソッドをViewObjectにまとめてしまって、さらに各要素のVIewObjectをその中で生成していくことで、ViewとViewHelperだけでは複雑になりがちなメソッドを要素ごとにまとめることができます。

例えば、飲食店などで席のVIewをレンダリングして、一つ一つの席のObjectはhighlightメソッドを持っている。そこに人が座ったときにクリックすることでhighlightメソッドがtrueを返し、その席が埋まっていることをホームページなどで知らせることができるシステムなどに使えますね。

ストリングス - 既存曲からの学び

既存曲からの学び

横軸

  • 1stVn 白玉系のときに、前後の音の高低差が合った場合、かけあがりフレーズをいれる
  • ノンコードトーンもあり
  • 駆け上がったあとはコードトーンに着地するといい感じになる
  • 1st と 2ndが必ずしも同時になってるわけではない
    • 1stしか鳴ってない部分もある
  • ヴィオラは比較的白玉系
    • 1st 2ndが白玉系のときにヴィオラが反行することもある
  • チェロも当然白玉系だが、ところどころヴィオラに反行したり(1st 2ndに寄せている)、ヴィオラの半分の音価で切り替わることがある
  • 主従関係の交代
  • 駆け上がりは、ど頭ではなく1拍後などにいれるのもあり
  • クロマチックのかけあがり
  • 煽り方

縦軸

  • 上三声において、開離でも密集でもないパターン
    • たとえば2ndVnとヴィオラがコードトーン2音飛ばし以上離れている
      • かといって正当な開離にしても、ヴィオラとチェロの間が12度を超えることはないので、少なくとも理論的な必然性はない
        • 説1・・・MIDIが間違っている
        • 説2・・・単なる例外、まずは正当な開離・密集を意識すればいいので、現時点ではあまり気にしない
    • Drop2とかDrop3とかの可能性もある

      和声/ストリングス

  • 次のコードのテンションになるように前のコードの音を繋留させる

ストリングス打ち込みの学び

意識すべきルール

簡単チェックリスト

  1. 三和音の場合、ルート以外の音が重複してしまっていないか?
    1. 3度が重複すると微妙
      1. そのためのオクターブ配置
  2. 上三声の各声部同士のインターバルが、1オクターヴを超えていないか?
  3. 限定進行音を守れているか?
  4. 禁則は発生していないか?
  5. ビブラートやエクスプレッションなどを適切に使い切れているか

音域

Vn・・・G2~G5(C5以上からプロ奏者じゃないと難しくなってくる)

Va・・・C2~A4

Vc・・・C1~G3

ボイスリーディング(限定進行音)

3rd 2上
7th 2下
♭9th 2下
9th 2下
#9th ♭9thへ
11th 2下
#11th 2上
♭13th 2下
13th 2下

ボイスリーディングにおけるdimについて

パッシングdimはドミナントのルート抜きと考える

例:G#dim7 ⇔ E7(♭9)

禁則

  • 連続8度
    • 2つの声部間で完全8度の関係が連続すること
  • 連続5度
    • 2つの声部間で完全5度の関係が連続すること
    • 減5度→完全5度の進行が生じること
  • 並達5度、並達8度
    • 2声部が並行するときに後続に完全5度、完全8度の関係が生まれてしまう状態(ただし下記条件があるので、ソプラノとバスを反行させておくことで防げる)
      1. 外声間に並達が生じた場合 → ソプラノとバスの間で並達が生じた場合。
      2. ソプラノが跳躍進行した場合 → ソプラノが3度以上の音程で進行した場合。

ボイシング

  • ポップスでは基本的に開離の方が良い
    • また、開離の場合、上三声の隣り合う音の距離が1オクターブ以内に収まるようにする
  • 原則としてコードトーンはすべて鳴らす
    • 例外
      • 限定進行音を守る影響
      • 編成以上の音数がある
        • 省略可能な場合はする
          • 5度の省略
        • ベースがルート以外
  • 第一転回の場合、ベースに3rdが入っているため、3rdは上三声から抜いたほうが安全
    • つまりオクターブ配置になる可能性がある
    • 逆にいうと、オクターブ配置になるのはこの場合のみ
  • バスとテノールは15度以上は離れないほうがいい

横のライン

  • Vcと1stVnが反抗するといい感じになる
  • トップノートだけを動かし続けず、内声もちゃんと動かす
  • メロの重心にリズムを合わせるといいかんじになる

ユニゾンについて

  • 必ずしもコピペで同じ音を弾くというわけではない(という風に捉えるのが良い)
  • 例えばVn2は6度下でハモるなど
  • 目立たせたいフレーズなど

既存曲について思ったこと

  • カウンターメロディ的にトップノートが動くパターン

    • それ以外の声部は必ずしもトップノートと同じようなラインで進まなくてもいい
    • かといって、バラバラな方向に進みもせず、譜割りだけ一緒で音は変わらないなどの停滞をしている
    • 例
      • トップノートはオルタードテンションを含んだつややかなラインをたどっているが、それ以外は譜割りだけ追従して、残りはコードトーン
  • 駆け上がり

    • C4→G5などの跳躍駆け上がりもある
      • おそらく運指的にやりやすい駆け上がり
    • かけ下がりのあとすぐかけあがりもあり
      • Vを描く
    • 駆け上がり×2回でも良い
      • 例:16分3連を2回ずつ
    • 駆け上がりのあと必ずしも駆け上がり時より高い音に到達する必要はない。下がっても良い
      • ただし比率としては駆け上がり時より高い音に到達していることのほうが多い
  • ライン・ボイシング
    • 内声は1stVnと結構おなじ動きをすることもある
    • 必ずしも連続的にコードトーンを鳴らす必要はない
      • 特にフレーズチックなものは柔軟に考える
    • ハモらせすぎるとフレーズ感がなくなってよく聞こえなくなる
      • 逆に、ここフレーズ感をどのくらい明確にするかでストリングスの主役度が変わってくる
    • サブドミナントマイナーなどの部分転調みたいなときは、裏メロでCメジャーにない音を使ってみると立体感が出る
    • メロの重心にストリングスのリズムをあわせてみる
    • コードの内声やテンションを裏メロと捉えると♭5thã‚„#5thなどもストリングスの段階で足してみるのもあり
  • その他
    • C5が限界かなと思いつつF5くらいまである曲はある
    • スタッカートで徐々に音量を上げるなどのとき以外は、Uを描くようなベロシティになっていることが多い
      • Uを描くというのは、例えば5音あったときに
        • 強→少し強い→少し弱い→弱い→少し強い→強いのようなベロシティ構成
    • 強いベロシティが連続することが少なく、上がったあとに落ち着くパターンが多いような気がしてる
    • ベースとトップが同じだと重くなる

打ち込みの話

  • リバーブ
    • 編成の広いものでリバーブを作る
  • 音源が得意とする奏法を多く使う
    • 打ち込みっぽくなる奏法もある
  • セクションの中にソロの音源を混ぜ込む
    • Spitfire
      • Solo
      • Symphonic
      • Chamber
      • すべてを使って生っぽさを出していく
  • Run
    • Run用の音源がある

仕事振り返り その2

hotwireを使った部分遅延ロード

RailsのViewでできたページの一部を遅延ロードする必要があった。 ページの一部表示で重めの計算をしているが、その表示はあまり参照しないので、遅延ロードしたいという意図。

いろいろ調べると、Hotwireを使うとよさそうだったので、調べてみた。遅延ロードに関する記事はあまり出てこなかったが、以下のようにすると良い。

表示親のページ

= turbo_frame_tag 'target_page_name(何かしらの識別値を任意で命名する)', src:  target_page_path do
    .loading 計算中...

表示するページ

%turbo-frame{id: "target_page_name(任意で命名した識別値)"}

以下は通常の記法

Controller

 def target_page_name
    render partial: 'target_page_name'
 end

あとは使いたいインスタンス変数や、通常通りルーティングをセットすればOK

lock!, zipなど

zipメソッド

まぁこれはシンプルに初めて知ったというだけで特筆することはないですが、zipメソッドは競プロの問題に使えそうだなぁとおもいました。

https://docs.ruby-lang.org/ja/latest/method/Array/i/zip.html

lock!メソッド

最近は物流周りのシステムを触っているので、今まで考えもしなかったロック系のことも知る必要があるなと感じました。 実際にソースの中でlock!が出てきたので、一回調べてみようと思った感じです。

  • lock!とwith_lockがあり、with_lockはトランザクションも同時に行う
  • 悲観的ロックという概念がある(きっと競合するだろうという観点でロックすること)
  • 楽観的ロックはデータのバージョンを管理できるカラムを使って、ロックはしないものの、「更新対象取得時と同じバージョンであれば更新する」というもの
  • 悲観的ロックは、UI上からロックを解除できる機能があった方が良い

同じ画面を開いている管理者が同時に同じ操作をするとき、操作対象は最初にバックエンドからとってきたものが画面に出ているはずで、例えば

  1. Aさんが1000個ある在庫のうち、100個の破棄を行う
  2. Bさんが同じことをしようとするが、Aさんが作業中なのでロックされている
  3. ロックが開放されたので、Bさんが同じことをする
  4. 100個でよかったのに200個破棄してしまう

みたいなことは起きないのだろうか、3の時点で、Bさん側の画面には1000個在庫があるように見えないだろうか?Aさんが同じことをしていたということをBさんが知らなければ4みたいなことは起きないだろうか? この辺は運用でなにか回避するか、別のシステム上の工夫が必要な気がしている。

参考

https://qiita.com/NagaokaKenichi/items/73040df85b7bd4e9ecfc

https://qiita.com/kamohicokamo/items/e7c31f61c99c9fc0fe7f

https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

Kaigi on Rails 2022 & 2023

今更ながらKaigi on Rails 2023の気になったものをピックアップして感想を書いていこうかなと思います。 見たら随時追記していきます。

自分のPCの中に2022年のメモが存在したのでそれにも触れておきます。

2022å¹´

before_actionとのつらくならない付き合い方

これは個人的に感動しました。 before_actionというか、コールバック系はなるべく使いたくないなと感じていたものの、「これって自分だけ?玄人はそんなことないのかな」と思ってたので。

とくにRailsのコールバックはクラスの上にまとめて定義するし、複数アクションに適用できるので、どのアクションのときにどのコールバックをつかうか、コールバックの前提条件としてどのコールバックが必要か、みたいな順序を管理しなければいけないですよね。

とはいえ、こういった手法の本質はメリデメの比重にある気がしています。

例えば、「どこで変化してるかを拾いきれないデータの変更を検知してある処理をする場合」など、before_actionを使わなければデメリットが大きいケースなどが実体験としてあったので。(before_actionに限らずafter_commitなどでも)

本質的関心事と横断的関心事の概念は初めて知りました。こういったモヤモヤを抽象度の高い言葉で分類できるとスッキリしますね。

  • 本質的関心事とは、そのメソッドが「やるべきことはなにか」ということ
  • 横断的関心事とは、そのメソッドを含めたいくつかの処理を行うにあたって必要な処理

ということらしいです。Slack通知などは横断的ですね。決済ログとかも。これらはコールバックを使うメリットが上回るんじゃないかなと思います。

今年できたチームの生産性を向上させたプラクティスの紹介

これは当時PMをやっていたので参考にさせていただきました、といいたいところなんですが、受託開発という性質上、すべて当てはまるわけではなかったです。

ただ、ひとくちにドキュメントといっても、API設計が大事なときもあれば、共通言語というか、概念を表すユビキタス言語みたいなものがまとまっていると嬉しいときもありますし、コードの外に出て、ソフトウェアを使う人の業務のことが詳しく書いてあったほうが嬉しいケースもある、と改めて考えるきっかけになりました。

ペアプロも、ペアプロをがっつりやるのがよいときもあれば、ペアプロ風にIssueとそのIssueの解決方法をモブプロ的にやるのがよいときもありますね。

当時のチームでは後者が効いたかなと思います。

speakerdeck.com

とりあえず抑えておきたい Railsでの「テストの内容」の考え方

特筆すべきことはない、というかありすぎるので別の記事にしたいです!同じようなことを考えていたので、学びの再確認になりました。

speakerdeck.com

個人的な感想は残っていないのがすごく学びになった発表

メモには本当に発表内容のまとめしかしてないので、タイトルだけ記しておきます。 - 既存Railsアプリ攻略法 - CTOが見ること・やること・考えること - 外部サービス連携の設計 - メトリクス可視化から始める Rails ウェブサーバーのチューニング

2023å¹´

コードカバレッジ計測ツールを導入したらテストを書くのが楽しくなった話

https://youtu.be/54sOl5qQMK0?si=D1mHxbTvQifV7KG7

これは本当にタイムリーだなと思いました。 ちょうど勤務先で通常タスクの合間にテストの拡充をしていく業務をやっていて、既存のテストのスタイルが全然違うので、ある程度ルール化したほうがいいなと思っていました。

ルールの指標の一つとして、「どこまでテストを書くか」みたいなことは重要だと思います。

例えば自分の場合、リクエストスペックでインスタンス変数まで見る必要はないし、逆にリクエストスペックでカバーできているサービスクラスの詳細までテストする必要はないと考えています。

ですが、一方でサービスクラスのテストが書きたくなるときもありますし、そういうテストを見かけるときもあります。

この辺を言語化するのって難しいです。

こちらの発表で、「カバレッジという指標は4種類ある」ということを初めて知ったので、このカバレッジに基づいて考えるというのも1つの方針として良いなと思いました。

業務に落としたい時は、バグを起こしやすい部分だったり、バグがクリティカルな障害に繋がる部分だったり、そういった複合的な要素を鑑みる必要がありますね。

定数参照のトラップとそれを回避するために行う2つのこと

https://youtu.be/DprMyMethws?si=o89_tcQWCNmceH1h

本筋とは違うんですが、なぜapp配下のrequireが不要なのかという話はたしかにと思いました。

config.autoload_pathsに設定されたものは自動読み込みになるようです。

ちょうどこの辺は業務でnamespaceの仕切り直しを行った時に軽くハマったので、今後も意識したいところです。

以下は特に感想はなかったんですが、また機会があれば見返そうと思います

HTTPを手で書いて学ぶ ファイルアップロードの仕組み

APMをちゃんと使おうとしたら、いつのまにか独自gemを作っていた話

エンジニアリングワークルール

はじめに

実はワークルールというものを大切にしています。 大切にしているという割に久々に整備しようと思って改めて整備してみました。

そもそもワークルールって?

以前いた会社で、「ワークルール」というものがありました。働く上で生産性を上げるためのルールみたいなものです。 設計は単純ですが、すごく効きます。シンプルに週次で「達成できたかできなかったか」を振り返るだけです。

これの秀逸さは抽象に落とし込んで具体に転用するという設計が自然にできて、振り返りによって習慣化できることです。

失敗する→失敗した原因の本質をさぐる(抽象)→具体のエピソードで振り返る(転用)

という感じですね。

以前いた会社では、特に大事だなと思ったことを会社ブログの記事として書いていました。

エンジニアが身につけておきたいMyワークルール3選 | 株式会社divx(ディブエックス)

最新Myワークルール

最新はこんな感じです。

  • [ ] 事実に基づき判断する(推測よりもログ、datadog、Sentry)
  • [ ] 横着しない
  • [ ] 認知負荷を下げる
  • [ ] 意図を持つ
  • [ ] アウトプットの最適化(FIgma, システムガイド, シーケンス図, スプレッドシート)
  • [ ] 推測を減らす
  • [ ] 解決すべき課題の照準を絞る(無駄な確認作業、リターンの少ないチューニング)
  • [ ] 抽象的な仕事は解釈の余地のないゴールを設定する
  • [ ] 結論や前提を疑う
  • [ ] MTGは「全員が納得している」状態
  • [ ] 本を読んだらアクションプランを決める
  • [ ] 話題は細分化する
  • [ ] N + 1

解説

自明なものは除いて、いくつかピックアップしてみます。

認知負荷を下げる

たとえばソースコードだけがあるプルリクエストよりも、Issueの背景や設計の方針などがほどよくまとまった資料があるとわかりやすいですし、定例MTGなども共通の注目物などを用意しておくだけで認知負荷が下がるなということを常に意識しておきたいものです

意図を持つ

コード書いた理由、質問をSlackで送る際の背景などが、すべて自分の中で意図として言語化された状態で存在することが大事だなと思っています。 壁打ちなどは別ですが

結論や前提を疑う・話題は細分化する

先述した記事に書いています