「現場で役立つシステム設計の原則」読書会レポート vol.3

株式会社リゾーム システム企画・開発部 第4グループの平松です。
今回は、読書会の第3回目のレポートになります。
前回のレポートは、こちらになります。

tech.rhizome-e.com

3回目レポート

今回は、第3章「業務ロジックをわかりやすく整理する」で参加者は4名でした。

それぞれの感想・意見交換

データクラスと機能クラス

  • Railsだとコントローラーとモデルの関係
  • コントローラーのアクションに処理をまとめるのは悪手
  • モデルにデータとロジックをまとめておけばコードの重複をなくせるし、テストもできる
    • モデルにデータとロジックを寄せているが、現状、値オブジェクトを使っていないため、半分正解の状態
  • モデルが肥大化したら、値オブジェクトを導入する良いタイミングでは?

ロジックとメソッド

パッケージ化

  • パッケージ化とは?
    • Rubyで言うとmoduleの名前空間で区切ることになるかも
    • コードが冗長になるため、やりすぎには気を付けたい

通化

  • 汎用クラスを使ったとしてもクラス数が多くなると探す手間もかかる
  • 同じような処理が多くできてしまい、使い分けができなくなる
    • RailsだとViewのヘルパーメソッドが汎用的なクラスと似てる

三層アーキテクチャドメインモデル

  • Railsだとデータソース層とドメインモデルが一体化したのがモデルになってる
    • そのおかげで、高速に開発できるが反面、複数のドメインモデルを使ってデータソースに保存する際、どこのモデルにロジックを書くべきか困る。
    • そして、どこかのモデルに書いた場合は、そのモデル同士が密結合になってしまう。
    • Railsの良いところと悪いところが同時に見えて面白い。

まとめ

本のサンプルコードはJavaRubyに置き換えることが難しい部分もありましたが、データクラスと機能クラス、メソッドの使い方など共通して言えることも多くありました。 データとロジック、ロジックとメソッドの関係からオブジェクト指向らしいクラス設計を知ることができたのではないかと思います。

次回は、第4章「ドメインモデルの考え方で設計する」になります。設計は開発の土台となる部分です。ここをしっかりと理解し、弊社のプロジェクトの改善に取り組んでいきたいと思います。

「現場で役立つシステム設計の原則」読書会レポート vol.2

株式会社リゾーム システム企画・開発部 第3グループの廣江(@buta_botti)です。

読書会の第2回目のレポートです。

第1回目のレポートは、こちらになります。 tech.rhizome-e.com

読書会の題材

前回に引き続き現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法を題材としています。

2回目レポート

今回は、第2章の「変更を楽で安全にするオブジェクト指向の実践技法」で、参加者は6名でした。

それぞれの感想 + 意見交換

  • if文がネストしてる箇所があるので、そこは短文にするとわかりやすくなりそう
  • 大きすぎるメソッドや不必要なネストがダメというのは、RubyだとRuboCopが指摘してくれるので意識できている
  • インターフェースってなんだ?(Rubyist)
    • Rubyだとインターフェースってないよな
    • Rubyだと継承や移譲を使ってインターフェース相当の表現をしてくのかな
      • メソッド定義がないとクラス定義でエラーになるような機能が標準でRubyにはない
      • 代わりにNotImplementedErrorをraiseするっていうのが筋がいいのかな
  • 状態遷移で列挙型が使えるというのは、なるほどなと思った
    • 列挙型使ってる?
      • C#で書かれてる自社製品ではほとんどみない
      • TypeScriptで書かれてる自社製品では使ってる
      • Rubyで列挙型というとActiveRecordenumのイメージが強い
    • 状態遷移はフラグ管理しているので、これを列挙型で管理するように直せばわかりやすくなりそう
  • リファクタリングは後回しにされがち、モチベーションの維持が難しい

個人的見解

区分オブジェクト

区分や種別で動作が変わるとき、それをif文やswitch文で書くと複雑になる。これはリファクタリングをする際にもよく聞く話で、ダックタイピングの手法を取ることで解決する。メリットとしてはそれぞれの処理が条件分岐で書かれなくなるため、コードが単純化すること。加えて、区分や種別ごとの処理がそれぞれのオブジェクトに定義されてあるため、処理の責任が明確に分かれているのもメリットだろう。

本書ではJavaのインターフェースを用いて説明されているため、静的型付けの言語としてこの手法を説明している。動的型付け言語にはダックタイピングをすることによるデメリットが存在するが、本書ではこの問題は無視されていると感じる。

個人的には動的型付き言語で闇雲にダックタイピングを使っていくのは少し危険だと感じており、動的型付け言語でダックタイピングの手法を取るのであれば、レシーバにくるオブジェクトを限定させる工夫が必要であると考えている。本書ではJavaの列挙型を用いて、クラスの一覧を記述することでさらに簡単になると説明しているが、これ相当のことが動的型付け言語においては必須レベルだろう。

状態遷移を列挙型で管理する

興味深かったのはこの状態遷移を列挙型で管理するという話だ。今関わっているアプリケーションでは状態遷移をもっぱらフラグで管理している。最近ではActiveRecordenumを使ったりしているが、それはどちらかというとデータベースの列挙型のことであり、ここのでの列挙型というのはそういったものではない。

例えば、現在の状態だけを持っていても、その状態の遷移に関わるルールは複雑なコードになっている場合がある。ここでの「列挙型で管理」というのはこの「状態遷移のルール」を列挙型で管理するというものである。つまり、遷移元の状態から遷移可能な状態を列挙型で所持している。

Rubyでは明確な列挙型は存在しないが、その手法は真似できると思っていて、例えばHashを使って遷移元のキーと遷移可能先の値を持つことができる。レコードのカラムから現在の状態を取得し、ハッキュのキーから現在の状態で遷移可能な状態を取得し、イベントに従って状態を遷移させる。この時、発生し得るイベントの一覧は値にもつ遷移可能な状態から推測することができ、そのイベントが正当なものかどうかは、遷移先の状態が値に含まれているかどうかで判別できる。

状態遷移図の代わりにもなり、コードを読む際の負担も減ると思うので、是非とも取り入れていきたい手法だと感じた。

まとめ

読書会を通して得た知見を、自分たちのプロジェクトに具体的に当てはめて考えたり、Rubyでは存在しないインターフェースという概念を知るきっかけにもなり、言語の垣根を超えた有意義な意見交換ができました。また、問題点は認識しつつも、実際にそれの改善に着手するのにはやや及び腰である点が浮き彫りになり、今後の課題が出てきました。

読書会はベテランがさらに知識を深めるのはもちろんですが、経験の浅い人が本の内容に沿うことで、わからないことを質問しやすくしている*1なとも思うので、とても有意義な時間だと感じています。今後参加者が増えたり、今の本を読み終えても継続的に読書会を続けていけるといいなと思います。

*1:わからないことがわかるので質問が明確になる

「現場で役立つシステム設計の原則」読書会レポート vol.1

株式会社リゾーム システム企画・開発部 第4グループの尾古(@patorash)です。

先週から、社内の有志で新たに読書会を始めましたので、それをレポートしていきたいと思います。

読書会の題材

読書会の題材として選んだのは、現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法です。

こちらを選んだ理由ですが、読書会は今までも何度かやっていますが、その都度、具体的な技術の本、開発手法の本を交互に採用しています。その中で、今後の直近の開発で役立ち、且つ、技術者として長期的な視点で使える視座を与えてくれるのではないかということで、この本の採用を決めました。

読書会の進め方

開催頻度ですが、週に1回、1時間程度としています。読書会の進め方ですが、

  1. 当日までに事前に章を読んでおく
  2. 感想や疑問点をまとめる
  3. 読書会当日、感想をそれぞれ発表する
  4. 意見交換を行う
  5. まとめをYammerにアウトプットする

としました。YammerMicrosoftがOffice365で提供している社内SNSです。

これまでは交代しながら音読していくスタイルの読書会を行っていたのですが、読むこと・進めることに集中しがちで、本来やりたかった読書後の議論が疎かになっていると感じていたため、今回からやり方を変えることにしました。

1回目レポート

1章ずつ進めていくことにしましたので、初回は第1章の「小さくまとめてわかりやすくする」でした。参加者は6名の予定でしたが、業務の都合で不参加になった方もいて、4名で開催しました。

それぞれの感想

まず、それぞれの読書の感想をまとめます。

  • 変数を使い回していたことがあったので、気をつけていきたい。
  • 新しく型(クラス)を作って値の制限をしているところがRailsのモデルでバリデーションしているところと似ていると思った。
  • 重複したコードをなくすのはいいけれど、たまたま同じようなコードがあるのを無理やり共通化するのはよくないとプリンシプル オブ プログラミング 3年目までに身につけたい 一生役立つ101の原理原則に書いてあったのを思い出した。*1
  • 読みやすいコードの話などをまだあまり知らなかったのでよかった。定期的に読み返したい。
  • 変更が大変なプログラムのアンチパターンについて書いてあって、担当プロジェクトでもよく見かけるケースがあった。
  • Railsだとクラスを増やしにくい印象がある。わかっていてもこのように進めにくいのでは?Railsは大きなプロジェクトを作るのに適していないなと感じた。
  • 弊社ではメソッドへの切り出し、クラスへの切り出しは既によくやっている手法である。切り出すと、テスト可能になる。
  • バリューオブジェクトの定義がドメイン駆動設計の根幹になりそう。
  • Rubyでも3.0以降はRBSで型の恩恵が受けられるので、バリューオブジェクトを充実させるのはよさそう。

意見交換

感想を聞いた後、本を見返しながら、意見交換を行いました。

  • Railsでもcomposed_ofを使って値オブジェクトとカラムのマッピングできるとパーフェクトRuby on Railsに書いてあった。*2
  • 無理やり共通化しているコードを担当プロジェクトで見たことがあった。変数の初期化がブロックの外で行われていたため、わかりにくかった。
  • before_actionで変数の初期化をする件について
    • シンプルなsetくらいであれば許容できる。
    • アクション毎にメソッドを呼んで変数の初期化をちゃんと行っていることを確認したい。そうでないと、いちいちbefore_actionで初期化されているかどうかを確認しなければならなくて面倒。
    • before_actionでやるのは認証・認可などだけにしてほしい。
    • 他のbefore_actionが、更に他のbefore_actionでの変数初期化に依存しているケースがあった。
  • 値オブジェクトはRailsならばどこに置くべきか?
    • app/domains/がいいのではないか?
      • app/以下は自動的に読み込まれるため。
  • プログラミング初心者は逆に値オブジェクトを煩わしく感じそう。
  • 業務アプリケーションでよく使う値オブジェクトの表を見ながら…
    • こういうのはよく使うから、プロジェクト毎に作らずに共通化できたらよさそう。
    • よく姓名を扱うのだが、PersonNameクラスを作りたいと思った。
    • 会社用のライブラリ置場を作りたい。そこに値オブジェクトを定義したgemを登録していくと工数削減できそう。
      • GitHub Packagesが使えそうか検討してみよう。*3

まとめ

値オブジェクトから変数の初期化をどこで行うべきか等、幅広く意見交換することができて有意義な会になったと感じました。その反面、経験の浅いメンバーからの意見や疑問点をなかなか引き出せなかったなというところが反省点です。

次回からは、感想を事前に書いてもらって、意見交換の時間を十分に取るようにする等、改善していきたいと思います。

*1:以前に読書会を行った題材です

*2:11章 複雑なドメインを表現するより。 https://gihyo.jp/book/2020/978-4-297-11462-6

*3:https://github.com/features/packages

CoffeeScriptからJavaScript(ES2015以降)への移行

はじめに

株式会社リゾーム 企画・開発部第4グループの平松です。
現在、自社サービスの一つである交渉管理ware*1の改修を行っています。

現時点の交渉管理wareのRailsのバージョンは5.2.6です。最新版にバージョンアップしていこうと思っているのですが、その改修の一環として今回はCoffeeScriptからES2015以降のJavaScriptへの移行を行いました。

弊社のプロジェクトでは逐次CoffeeScriptからJavaScriptへの移行が進んでおり、当サービスにおいてもJavaScriptの方が他のライブラリやフレームワークを使う際など開発や保守が行いやすいと判断し、移行することにしました。

今回の移行ですがWebpacker等を使った移行ではなくSprocketsを使っているため、Sprockets用の作業内容が含まれています。ご注意ください。

移行の準備

JavaScriptに移行していきますがファイル一つ一つ手作業で直していくのは時間が掛かります。 そのため、decaffeinateというツールを使ってJavaScriptに変換していきます。

decaffeinateのGitHubのページに変換ガイドがあるのでそれに沿って進めていきます。
まずは、ツールのインストールから始めます。

npm install -g bulk-decaffeinate decaffeinate eslint

インストールできたら次は変換していくのですがその前に、変換できるかどうか確認します。 問題なければコマンドを打って変換していきます。

bulk-decaffeinate check

JavaScriptに一括変換

下記のコマンドでCoffeeScriptからJavaScriptに一括変換します。
-d オプションでディレクトリの指定をしています。
-f オプションでファイルの指定が可能です。

bulk-decaffeinate convert -d app/assets/javascripts

これでJavaScriptに変換できました。 しかし、単純に変換をかけただけではエラーが発生し、動きませんでした。 まずは正しく動くように修正し、その後、リファクタリングをしていきます。
参考: decaffeinate/conversion-guide.md at master · decaffeinate/decaffeinate · GitHub

動作するように修正

thisの前にsuperを配置

クラスが親クラスを継承している場合、thisを呼ぶ前にsuperを呼ぶ必要があります。 superを呼び出すことで親クラスのコンストラクターを呼ぶことができます。
先にthisを呼んだ場合、ReferenceErrorになります。

// before
class foo extends bar {
  constructor(hoge) {
    this.hoge = hogehoge;
    super(hoge); // エラーになります
  }
}
// after
class foo extends bar {
  constructor(hoge) {
    super(hoge); // superを先に呼ぶ
    this.hoge = hogehoge;
  }
}

参考: super - JavaScript | MDN

ES6(ES2015)に対応

元々のCoffeeScriptの方でES6の構文で書かれている箇所もあるため、それに対応していきます。 交渉管理wareではアセットファイルの管理にSprocketsを使用しています。
GitHubのページにES6サポートの項目があるのでそれに沿って進めます。

babel-transpilerをインストールする

Gemfileに追記してbundle installをします。

gem 'babel-transpiler'
manifest.jsのコンパイル対象に「.es6」を追加する

ES6に対応したファイルがコンパイル対象になるようにmanifest.jsに追記します。

//= link_directory ../javascripts .es6
拡張子を「es6」に変更する

拡張子を変更してES6ファイルとして扱われるようにします。

hogehoge.js => hogehoge.es6

ここまで行ったところ、正常に動作することが確認できました。

参考:
GitHub - rails/sprockets: Rack-based asset packaging system
Sprockets 4 なら ES6書けるよ - Qiita

リファクタリング

正常に動作するところまでできたので次はリファクタリングをしていきます。

varをlet,constに置き換える

varは再宣言でき、またスコープ外から参照できるため扱いづらいです。
そのため、letもしくはconstをできるだけ使うようにします。

let hoge = hogehoge;
// もしくは
const hoge = hogehoge;

constructorの引数をデフォルト引数にする

decaffeinateで変換した結果、元々デフォルト引数だったものがif文でデフォルト値を定義するように変換されていたため、元に戻しました。

// before
class Foo {
  constructor(hoge) {
    if (hoge == null) { hoge = 'hoge'; }
  }
}
// after
class Foo {
  constructor(hoge = 'hoge') {

  }
}

アロー関数を使用する

function()と書かれている箇所を() =>のように修正します。 アロー関数自体はthisを保持しないため、アロー関数によってthisの参照先が変わることはありません。
そのため、selfにthisを代入する必要がなくなります。
※ 元々の処理がthisの値が変わること前提の場合、アロー関数にしてしまうと動作が変わってしまうので注意が必要です。

// before
var self = this;
this.hogehoge = function() {
  self.foo = "baz";
};
// after
this.hogehoge = () => {
  this.foo = "baz";
};

var self = this;を削除する

前述のアロー関数を使用することでselfを使う必要がなくなるので下記のコードを削除し、selfをthisに置換します。

var self = this; // この行を削除

配列をforからforEachで処理する

decaffeinateで変換した結果、forで配列を処理をしていた箇所があったため、forEachで簡潔にします。

// before
for (let index = 0; index < hoges; index++) {
  hoge = hoges[index];
  // 何らかの処理
}
// after
hoges.forEach(hoge => {
  // 何らかの処理
});
// または
hoges.forEach(hoge => "何らかの処理");

まとめ

今回はdecaffeinateを使用してCoffeeScriptJavaScriptに一括変換しました。decaffeinateは便利ですが、既存の処理が変わっていたり、そもそも正しく動かなくなってしまうこともあるため、JSファイルの数によっては手動で直したほうが手間がかからないかもしれません。

移行作業の中で難しかったところはアロー関数に変更していった部分です。thisの値によってアロー関数を使わない方がいいところもあったため、都度確認が必要でした。
また、作業自体は動作確認をしながら進めていき、漏れがないように注意してましたがテストを流した際に何個か落ちてしまいました。 各機能の処理内容の理解とともにテストの重要性が感じられた作業となりました。

今後も改修を続けていくので内容がまとまったら記事を出していこうと思っています。

*1: デベロッパーとショップとの交渉内容をシンプルに効率的に一元管理できるクラウドサービス(ホームページ商品説明引用)

Railsのバージョンを6.1に上げました

株式会社リゾーム 企画・開発部第3グループの廣江(@buta_botti)です。
今年から弊社のテックブログがスタートします。どうぞよろしくお願いします。

弊社サービスについて

弊社ではショッピングセンター向けの製品の自社開発を行っています。その中の一つにRuby on Railsで開発しているBOND GATE*1というサービスがあります。僕はこの製品の開発を担当しています。

BOND GATEのFirst commit を見てみると2011年の1月末となっており、ちょうど11年になります。

% git log --reverse
commit 927e662f96154982d887d7b1f48c483935a0404d
Author: ************
Date:   Mon Jan 31 20:09:17 2011 +0900
    First commit BOND GATE

2011年ということは、Rubyは1.9系、Railsは3系くらいでしょうか。*2
現在ではRubyは3.1、Railsは7系が最新となっていますが、BOND GATEはまだまだ追いつけていないというのが現状です。

そんなBOND GATEですが、ここ数年はライブラリのバージョンアップに力を入れて取り組んでおり、先日でなんとかRuby2.7、Rails6.1までバージョンアップするプルリクエストがマージできるところまで来ました。 今日はRails6.1に上げる際にやったことをいくつかピックアップしてみます。

Rails6.1に上げる前に

バージョンアップ作業と言っても、いきなりbundle update railsなんてするわけにもいかないので、まずは変更点の調査とコードの事前修正をします。
リリースノートを見ると変更点はいくつかありましたが、影響がありそうな変更点は主に以下の4つでした。

  • ActionDispatch::Http::ParameterFilterの削除
  • ActiveRecord::Base#update_attributesおよびActiveRecord::Base#update_attributes!の削除
  • where.notがNORではなくNANDを述部で生成するようになる
  • ActiveRecord::Relationメソッドでの安全でない生SQLの利用を削除

これらの修正を行います。

古いコードの置き換え

  • ActionDispatch::Http::ParameterFilterの削除
  • ActiveRecord::Base#update_attributesおよびActiveRecord::Base#update_attributes!の削除

年季の入ったコードなので古いクラスやメソッドを利用した部分が多く、そういった箇所が影響を受けていますね。
これらは新しいものに置き換えてやれば良さそうです。エディタの置換機能を使ってサクッと置き換えてしまいます。

ActionDispatch::Http::ParameterFilter -> ActiveSupport::ParameterFilter
update_attributes -> update

where.notの挙動変更

  • where.notがNORではなくNANDを述部で生成するようになる

こちらはRails6.1からの挙動の変更になります。where.notの引数に複数のキーワードを渡している場合に影響を受けます。
例えばUser.where.not(country: 'Japan', age: '20')とした場合、Rails < 6.1では「日本人ではない"もしくは"20歳ではない」ユーザーを抽出できますが、 これがRails >= 6.1では「日本人ではない"かつ"20歳ではない」ユーザーを抽出します。

元々where.notをNORの挙動を期待して使うことはなく、意図しない挙動を招く原因となるとして今回挙動が修正されることとなったようです。
書いてて混乱してきそうな話ですが、要はAかBではないのような抽出では

Model.where.not(column_a: ...).where.not(column_b: ...)

のように分けて書き、AでもなくBでもないのような抽出では

Model.where.not(column_a: ..., column_b: ...)

のように書きなさいよという話です。

Rails < 6.1 ではこれら2つが同じ挙動をしていたのですが、6.1からは挙動が分かれるため分けて書くように修正します。

安全でない生SQL

これが今回のバージョンアップで一番よくわからないところでした。
ActiveRecord::Relationメソッドでの安全でない生SQL」が何を指すのかがよくわかりません。
とりあえずRails6.1でrails newして、6.0では動いて6.1ではエラーの出る生SQLを探してみると、以下のようなコードでエラーが出ました。

Model.group(:parent_id).pluck(:parent_id, 'SUM(CASE WHEN column_1 = "something" THEN column_2 ELSE 0 END)')
# ActiveRecord::UnknownAttributeReference: Query method called with non-attribute argument(s): "SUM(CASE WHEN column_1 = \"something\" THEN column_2 ELSE 0 END)" 

どうやらActiveRecord::UnknownAttributeReferenceがキーワードのようです。
コードを追っていくと、どうやら設定でActiveRecord::Base.allow_unsafe_raw_sqlの値を:deprecated以外の値にすることで例外が起きるようになっていることがわかります。

github.com

とりあえず設定をActiveRecord::Base.allow_unsafe_raw_sql = nilで適当に設定し、Rails6.0で例外を起こすようにしておきます。
あとはテストを実行して例外で落ちる場所を地道に直していくだけです。

修正方法ですが、このキーワードでググるArel.sqlを付けるという解決方法が出てきますが、小手先の解決方法なのであまり好ましくありません。
どういうコードを書いているかにもよるとは思いますが、できるだけきちんとサニタイズしてあげたいですね。
ちなみにBOND GATEでは全ての箇所においてsanitize_sql_arrayを用いることでサニタイズが可能でした。

Model.group(:parent_id).pluck(ActiveRecord::Base.sanitize_sql_array(['parent_id', 'SUM(CASE WHEN column_1 = "something" THEN column_2 ELSE 0 END)'])

どうしてもサニタイズメソッドで対応ができない場合はArel.sqlをつけてあげましょう。

Model.order(Arel.sql('COALESCE(foobar, 0)'))

サニタイズのメソッドは多く用意されているので、きっと利用できるものがあると思います。

安全でない生SQL調査の番外編

テストを実行して例外で落ちる場所を地道に直していくだけ

と簡単そうに書いていますが、これが実は少し大変でした。
弊社サービスのBOND GATEAではActiveJobでdelayed_jobを使っており、該当のコードをdelayed_jobで実行している箇所があります。そこを経由するテストが落ちるには落ちるんですが、 例外が起きた形跡がありません。失敗したというテスト結果だけがログに出ており、テストコード自体は最後まで走っているように見えます。 どうやらdelayed_jobで実行された部分で起きた例外ではRSpecは落ちないようで、delayed_jobで実行されたものが例外で正しい結果を返さないためにテスト結果がたまたま異なって失敗したようです。これではdelayed_jobで例外が起きたけど、たまたま結果は同じだった場合に気づけません。何とかしないと...。

そこでTracePointを使って例外にフックして現在地を書き出すようにしてみました。

RSpec.configure do |config|
  config.around do |e|
    trace = TracePoint.trace(:raise) do |tp|
      File.open('tmp/errors.txt', 'a') { |f| f.puts [tp.inspect, tp.raised_exception, nil] }
    end

    trace.enable
    e.run
    trace.disable
  end
end

テストを回して出てきた箇所を調査し、これで無事全ての修正を終えることができました。

6.1にバージョンアップ!

事前に修正を終えると、やっとバージョンを上げる作業に入れます。Gemfileのrailsのバージョンを指定して...

% bundle update rails
% rails app:update

あとは設定をいい感じに直して終わりです。
とは言ってもこの「設定をいい感じにする」のが実は一番大変な作業ではあるんですが、大体古い設定を使い続けるという選択をするので、バージョンアップ後に少しずつコードを修正しながら設定を切り替えていくという流れになっていくはずです。バージョンを上げるとバージョンアップ作業が終わるのではなく、バージョンを上げてからがバージョンアップ作業の始まりというわけです。

まとめ

今更なんですが、Rails6.1に上げる際の作業をざっくりと綴ってみました。
ここではあまり触れていませんが、バージョンアップする際に一番大事なことはテストが充実しているということです。バージョンアップして影響がないかどうかは最終的にテストを回して担保することになるので、テストが無い内にバージョンアップ作業をするのは無謀とも言えます。バージョンアップに限らずテストを書くということはとても重要なので、日頃からしっかりと書いていきたいですね。

バージョンアップ作業はこれからも続いていき、Rubyは3.1、Rails7.0.1に早く追いつきたいと思っています。
そんな弊社ではRuby on Railsで一緒に開発をしてくれる仲間を募集しています。興味がありましたら以下からご連絡お待ちしています。

www.rhizome-e.com

*1:BOND GATEは直観的で使いやすい、店長支援のためのSC・専門店向けコミュニケーションウェアです。(ホームページ商品説明引用)

*2:その頃僕は入社してないので正直よくわかりません