月刊Railsウォッチサマリー: 2018/11(社内勉強会)

こんにちは、hachi8833です。BPS社内勉強会でmorimorihogeさんが発表した「月刊Railsウォッチサマリー」の2018/11版を元にお送りします。 反応がよければ月刊として定着させたいと思いますので、皆さまからのフィードバックやご要望を@morimorihogeまたは@hachi8833までぜひお寄せください🙇。 スライド発表&コメント: morimorihoge 書き起こし&構成: hachi8833 morimorihogeコメント(テンプレ): 社内発表は12月頭にやってたのですが、色々とこねくり回してたら2月になってしまいました💦 Railsウォッチを毎週やっている中では、時によっては半分以上がマニアックな話題に終始してしまうことがあり、普段のWeb開発業務に直接役立つ知識を追いかけている人にとってはノイズに思えてしまう部分も多いと思います(ノイズの中にも面白いネタが転がっているので意図的にやってるのですが)。 「面白さ」を追求する週刊Railsウォッチに対して「実用性」を追求した月刊サマリーとでもご理解下さい😉。 ※なお、ピックアップしているトピックや内容の重要度については多分に僕個人の価値観が含まれるため、業務でのご利用の際は皆様一次ソースをご確認の上自己責任でご利用下さい。 ⚓週刊Railsウォッチ(20181105) 週刊Railsウォッチ(20181105)DBマイグレーション9つのコツとハマった話、Railsのモデルとディレクトリの設計ほか この回は「公開つっつき会」でした。ご参加頂いた皆様ありがとうございました。 ⚓Railsの複数DB接続対応化 ウォッチ: ActiveRecordのconnected_toでハッシュやURLをサポート Rails 6で予告されている目玉機能のひとつに「複数データベース接続のサポート」があり、それに関連する改修が引き続き盛んに行われています。Rails 6そのもののリリースはしばらく先の話でしょう。 上で取り上げたPR #34196もそのひとつで、postgres://fooのようなURL風の接続文字列をサポートするようになりました。 前回のウォッチサマリー↓でもご紹介したconnects_toやconnected_toも複数データベース対応のひとつで、特定のブロック内でだけデータベース接続先を変更できるメソッドです。もっともメソッド名などは今後まだ変わるかもしれませんが。 月刊Railsウォッチサマリー: 2018/10(社内勉強会) この時点で見た限りでは、connection周りについてはおおよそ出来上がってきたように見受けられますが、migrationについてはまだ議論が続きそうな雰囲気です。 ⚓複数DB対応の意義 Rails 6で複数データベースに対してread/write/migrationを行えるようになると、外部システムとのデータベース連携で従来必要だったgemが不要になるということになります。なお、従来はswitch_pointやoctopusなどのgemが使われていました。Rails 6のやり方はswitch_pointに近い感じなので、switch_pointを使ったことのある人には理解しやすいのではないかと思います。 リポジトリ: eagletmt/switch_point リポジトリ: thiagopradi/octopus — Rails 6以降はメンテナンスモードを宣言 複数データベースには、いわゆるmaster/slaveデータベース対応も含まれるので、シングルデータベースであっても負荷分散機構として利用することも可能になります。 morimorihogeコメント) 個人開発やスタートアップフェーズの開発といった「普通の」「素直な」Railsアプリケーション開発ではあまり複数DBを扱うことはないかもしれませんが、サービスが拡大してきたり既存システムとの密結合を要求されるケースでは複数DBを扱うケースがままあります。 複数DB対応は全てのRailsアプリケーションに必要なものではないため、個人的にはRails coreに入れるべきなの?という気持ちはあります(switch_point等のgemとして、拡張として使えばいいのでは?というもの)。 ただ、Rails本体が複数DB対応を前提として設計されなおすことにより、ActiveRecord周りに手を入れるようなgemも自ずと複数DB対応を迫られることになるため、元々複数DB対応が要求されるようなより複雑なRailsアプリケーションでも安心して使えるgemが増える、というエコシステムの流れができるかもしれません。 どちらにしても、Rails 6.0への移行時、DB周りに手を入れるようなGemについては動作検証を含めた注意が必要になるでしょう。 ⚓マルチデータベースの事例 Railsでマルチデータベースを扱う経験のある人がここにどのぐらいいるかはわかりませんが、morimorihogeの場合たとえば以下のような事例を経験したことがあります。 機密情報を含むデータベースを通常のデータベースと分離する 既に稼働している別システムのデータベースにread onlyで参照アクセスする Railsシステムに限らずシステムを設計するうえでは、強く密結合する外部システムが存在する場合には複数データベース接続はひとつの手段として使えるということと、Rails 6からはそれを標準で行えるようになることは押さえておきたいポイントだと思います。 morimorihogeコメント: 昨今の流行りだと、複数システムを横断するデータアクセスはmicroservicesだのJSON APIだのgRPCだのGraphQLといった話が盛んです。 確かに、データベースを共有するシステム設計は互いのシステムを密結合にしてしまい、後々のお互いのシステム改修を難しくしてしまうことがあります。 以下、具体的な密結合の例です(わかっている人は読み飛ばしてOK)。 例えば、既存のlegacyAというシステムがあり、新しくmodernBというシステムを作る際にlegacyAのデータを参照したいとしましょう。 modernBからlegacyAのデータベース(RDBMS)を直接参照する設計にした場合、legacyAのコードを一切変更することなくmodernBの開発者は慣れたSQLインターフェースを使ってlegacyAのデータにアクセスすることができます。 これは一見単純かつ手っ取り早い解決策であり、良さそうな設計に見えます。 しかし、legacyAの開発がもう100%凍結されていて一切修正が行われることがないということであれば問題ないのですが、もしlegacyAのテーブル構造変更を伴う改修が発生した場合、legacyAの改修がmodernBの障害を引き起こす原因になる可能性があります。 とても具体的な話をすると、例えばSELECT * FROM users;というSQLはカラムが追加されることで結果の列数が変わるため、破壊的な変更になる可能性があります。 他にも「今までnoteというカラムはVARCHAR(20)だったけど、現場からもっと長い文字列を入れたいと言われたのでVARCHAR(100)にする」といった一見大したことのない改修でも、例えば連携先システムでPDF帳票を出力していた場合にはnoteを埋め込んでいた部分の文字がはみ出てしまったりする障害の原因になるかもしれません。 このように「legacyAにとっては大したことのない改修」が「modernBにとってはエラーや障害の原因になってしまうことがある」という状況をお互いに密結合していると呼ぶわけです。 せっかくなので、密結合の対義語である疎結合についても考えてみましょう。 まさに疎結合のアプローチこそが最初に上げたmicroservicesやJSON API、gRPCやGraphQLといった技術になります。 これらのアプローチでは、システムごとの責任範囲を機能面・データ面ともに明確に切り離し、お互いに越権したことをできないようにシステム設計上制限をかけることになります。 基本的にどの手法もそれぞれのAPIを通じて相互のシステムにアクセスしますが、逆にAPIで定義されていないことは一切できないというのが技術的な制限事項になります。これにより、そもそも想定されていないデータアクセスはできなくなりますし、もし新たな機能を追加・改修することになってもAPIの仕様変更を利用しているシステム側に連絡すれば良いことになります。 これであれば、legacyAのシステム改修を行う場合、modernBに提供しているAPIの仕様に変更がないのであれば特に連携せずに改修ができるという状態にできます。こうしたあるシステムが他のシステムに与える影響が限定的なアーキテクチャを疎結合と呼びます。 システム開発においてはコミュニケーションコストの割合が膨大になりますので、疎結合というのは将来的な継続的改修を考えると結果として良い選択肢になることが多いと言われます。 ただし、疎結合システムが全てのケースで密結合システムを上回っているかというとそれは前提条件(既存システムを)次第という点もあるため、どちらのシステムも一長一短あり、ケースバイケースで選択していく判断力がアーキテクトには求められるところです。 ⚓Railsアップグレードへの影響 複数DB接続対応化がRails 6へのアップグレードに与える影響についてです。 Rails 6では破壊的変更が多数行われますが、おそらくシングルデータベースのRailsアプリであればdatabase.ymlの更新ぐらいで済むのではないかと思われます。 こちらは今後の流れもあるので何とも言えませんが、既にswitch_pointやoctopusなどのマルチデータベース系gemを使っているプロジェクトは、Rails 6へのアップグレード自体がつらくなる可能性が考えられます(少なくともoctopusはRails 6に対応しないことが確定していますが、移行ガイドを出す予定だそうです)。マルチデータベースが必要な新しいプロジェクトでは、後からRails 6にアップグレードする際のアップグレードオーバーヘッドを検討しておく必要があるでしょう。 ⚓マイグレーション周りのTips ウォッチ: Railsのマイグレーション9つの秘訣 RailsガイドにもRailsのマイグレーションについての事細かなノウハウまでは掲載されていません。実戦的なマイグレーションのハマりポイントや回避手段などについて知っておきたい人は、上のウォッチエントリにかなり詳しくまとめられているので読んでおくとよいでしょう。 詳しくは記事に譲りますが、少なくとも以下について知らないまたは経験のない人は読んでおくことをおすすめします。 Migrationの中でActive Recordを使って初期データをセットする時の注意 Migrationファイルのタイムスタンプはどうやって決定されるか Migrationファイルを新しく作るべきか、既存のmigration ファイルを編集すべきか問題 morimorihogeコメント: DBのマイグレーションは個人や少人数の開発者で開発している分にはハマりどころが少ないのですが、チーム開発や環境が複雑になってくると気をつけないといけないことが増えてきます。 特に、既にmaster branchまで入ってしまったmigrationファイルを修正するのはリリース済みのプロジェクトでは色々とあちこちに不整合を起こしてしまう可能性が高いので、リリース済みのプロジェクトに途中参加する場合はプロジェクトの開発ルールやプロジェクトチームの中ではどのように運用しているのかなどを確認すると良いでしょう。 ⚓1. Migrationの中でActive Recordを使って初期データをセットする時の注意 ウォッチ: マイグレーション中のカラムデータをどう更新するか マイグレーションファイルの中で、Active Recordを使って既存のデータを参照・加工して、それを初期データとしてデータベースに設定したいなんてことはよくあります。 たとえば、ECサイトのusersテーブルにpremiumやstandardといった会員のランキングのカラムrankを追加するとします。そしてrankカラムのデフォルト値は、それまでの購買数や購入額を元にpremiumかstandardに決定されるとします。買物額が多い会員はpremium扱いになるというわけです。 こうしたマイグレーション処理で過去の購入額などを取り出すときにActive Recordのモデルを使ってしまうと、ずっと後になってからつまづきの原因になりうるという話を上の記事でしています。将来そのモデルが統廃合されてしまったら、そのマイグレーションファイルは当然動かなくなってしまうからです。 ⚓2. Migrationファイルのタイムスタンプの決定法 ウォッチ: マイグレーションのタイムスタンプ rails g migrateで生成するマイグレーションファイル名のタイムスタンプには、rails generateコマンドを実行した環境のローカル時間が使われます。 そして、rails db:migrateでマイグレーションを実行すると、マイグレーションはファイル名のタイムスタンプ順に愚直に実行されます。 チーム開発で複数の開発者が次々にマイグレーションをコミットすると、マージのタイミングによってはマイグレーションファイル同士の実行順序が原因で運悪くコンフリクトを起こす可能性があるという話を上の記事でしています。このあたりに鼻を利かせておくと身を助けることがあると思います。 ⚓3. Migrationファイルを新しく作るべきか既存のmigrationファイルを編集すべきか ウォッチ: マイグレーションよもやま話 開発中に自分の環境でカラムを追加したり削除したりすることはよくありますが、その際に既存のマイグレーションファイルを編集していいのかどうか、という話です。 これはよく議論になる話なのですが、会社やプロジェクトにもよってポリシが異なる点かとおもいます。 morimorihogeは「少なくとも既にマージされたマイグレーションファイルは編集すべきではない」という意見です。 「マージされていても編集してよい」というプロジェクトであっても、既存のマージ済みマイグレーションファイルを無断で変更すると確実にチームに迷惑がかかるので、やる前にチームに一声かけるべきでしょう。 # Aさんのローカルだけではうまく動くけど、他の人の環境ではうまく動かない、という問題の原因になることがあります ⚓セキュリティチェック系gem ウォッチ: Salus: セキュリティチェッカーをまとめて動かす 弊社のように多数の請負案件を抱えている場合、対策のための工数を捻出するかどうかよりも先に、潜在リスクを少しでも先行して把握するための手軽な手段として、こうしたセキュリティチェック系gemは有用だと思います。 継続的にメンテナンスされているプロジェクトであれば、少なくとも以下の定番セキュリティチェックgemをCIなどで週に1回は回して結果をSlackに投げることはしておく価値があるかもしれません。 Rails向け brakeman: 静的解析で怪しいコードを指摘してくれる bundler-audit: bundleされているgemの更新をチェックしてくれる JavaScript向け yarn audit: yarnに含まれてるチェックツールぽい morimorihogeコメント: セキュリティ周りは心配し始めるとキリがないのですが、重要なのは全てのセキュリティ警告に対して100%対応しなければいけないかという話ではなく、そもそもどれくらいのセキュリティリスクがあるのかを可視化し、把握できるようにしておくことだと思います。 インターネットに公開されていない社内向けシステムなどであれば外部犯による攻撃リスクは低いので、全てを技術的な改修に委ねるのではなく、NDAや内部統制によって対策するというのも一つの選択肢ではないでしょうか。 ⚓週刊Railsウォッチ(20181112) 週刊Railsウォッチ(20181112)Ruby 2.6.0-preview3リリース、非同期スレッドのテストはつらい、MySQL 8のGROUP BYほか この回はそれほど大きなネタはなかった感じです。 細かいところだと、rubocopのオプションで–safe-auto-correctというのがあり、これを使うとほどほどの範囲でオートコレクトを実行してくれるという話題がありました(Rubocopによる自動修正の注意点)。いきなりproductionのプロジェクトにかけて100%安全なのかは保証しかねるのでご利用は自己責任で。 他に、bootstrap.nativeという、BootstrapでjQueryを使わずに素のJavaScript(いわゆるVanilla JS)版のBootstrap向けライブラリを導入できるものもありました(bootstrap.native: Bootstrap 4でjQueryを使いたくない人に)。 Bootstrapは公式のJavaScript系コンポーネント(カルーセルやダイアログなど)ではjQueryが必須なのですが、jQueryをどうしても入れたくない人たちがこういうライブラリを作っているようです。最近のRailsアプリではWebpackerを使っていればjQueryを導入しないことも多いかと思うので、そういうプロジェクトではこうしたES5互換のライブラリを使ってみるのもよいかもしれません。今後そのライブラリが継続的にメンテナンスされるかどうかにもよりますが、jQueryを入れるとあちこちにjQueryを使ったコードが撒き散らされるリスクを抑えることができると思います。 morimorihogeコメント: jQueryは一時代を築きましたが、それが故にJavaScriptエンジニアというよりはjQueryエンジニアと呼んでも良いくらいにjQuery依存した人達も生み出したように思えます。 個人的には限られた範囲でちょろっと使う分には今でもそれほどアレルギーはないのですが、世の中の流れ的に最近は積極的に使うことが減ってきた感があります。 ⚓Ruby 2.6登場間近 ウォッチ: Ruby 2.6.0-preview3リリース Ruby 2.6のリリース時期が間近に迫ってきました。慣例に従えば今年もクリスマスにリリースされるでしょう。 Ruby 2.6については以下のjnchitoさんの記事にとても詳しく書かれていますのでそちらもご覧ください。 サンプルコードでわかる!Ruby 2.6の主な新機能と変更点 - Qiita ⚓主な見どころ この他にも多数の更新がありますが、普通にRubyのコードを書いていれば特に変えなければならないところはないと思います。 新機能を使うかどうかは別にして、ともかくチェックしておくとよいでしょう。 Bundler 1系がRubyに組み込まれた … Continue reading 月刊Railsウォッチサマリー: 2018/11(社内勉強会)