こんにちは、hachi8833です。BPS社内勉強会でmorimorihogeさんが発表した「月刊Railsウォッチサマリー」の2018/11版を元にお送りします。
反応がよければ月刊として定着させたいと思いますので、皆さまからのフィードバックやご要望を@morimorihogeまたは@hachi8833までぜひお寄せください。
- スライド発表&コメント: morimorihoge
- 書き起こし&構成: hachi8833
週刊Railsウォッチ(20181105)
週刊Railsウォッチ(20181105)DBマイグレーション9つのコツとハマった話、Railsのモデルとディレクトリの設計ほか
この回は「公開つっつき会」でした。ご参加頂いた皆様ありがとうございました。
Railsの複数DB接続対応化
Rails 6で予告されている目玉機能のひとつに「複数データベース接続のサポート」があり、それに関連する改修が引き続き盛んに行われています。Rails 6そのもののリリースはしばらく先の話でしょう。
上で取り上げたPR #34196もそのひとつで、postgres://foo
のようなURL風の接続文字列をサポートするようになりました。
前回のウォッチサマリー↓でもご紹介したconnects_to
やconnected_to
も複数データベース対応のひとつで、特定のブロック内でだけデータベース接続先を変更できるメソッドです。もっともメソッド名などは今後まだ変わるかもしれませんが。
この時点で見た限りでは、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データベース対応も含まれるので、シングルデータベースであっても負荷分散機構として利用することも可能になります。
個人開発やスタートアップフェーズの開発といった「普通の」「素直な」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からはそれを標準で行えるようになることは押さえておきたいポイントだと思います。
昨今の流行りだと、複数システムを横断するデータアクセスは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 ファイルを編集すべきか問題
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
弊社のように多数の請負案件を抱えている場合、対策のための工数を捻出するかどうかよりも先に、潜在リスクを少しでも先行して把握するための手軽な手段として、こうしたセキュリティチェック系gemは有用だと思います。
継続的にメンテナンスされているプロジェクトであれば、少なくとも以下の定番セキュリティチェックgemをCIなどで週に1回は回して結果をSlackに投げることはしておく価値があるかもしれません。
- Rails向け
- brakeman: 静的解析で怪しいコードを指摘してくれる
- bundler-audit: bundleされているgemの更新をチェックしてくれる
- JavaScript向け
- yarn audit: yarnに含まれてるチェックツールぽい
セキュリティ周りは心配し始めるとキリがないのですが、重要なのは全てのセキュリティ警告に対して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を使ったコードが撒き散らされるリスクを抑えることができると思います。
jQueryは一時代を築きましたが、それが故にJavaScriptエンジニアというよりはjQueryエンジニアと呼んでも良いくらいにjQuery依存した人達も生み出したように思えます。
個人的には限られた範囲でちょろっと使う分には今でもそれほどアレルギーはないのですが、世の中の流れ的に最近は積極的に使うことが減ってきた感があります。
Ruby 2.6登場間近
- ウォッチ: Ruby 2.6.0-preview3リリース
Ruby 2.6のリリース時期が間近に迫ってきました。慣例に従えば今年もクリスマスにリリースされるでしょう。
Ruby 2.6については以下のjnchitoさんの記事にとても詳しく書かれていますのでそちらもご覧ください。
主な見どころ
この他にも多数の更新がありますが、普通にRubyのコードを書いていれば特に変えなければならないところはないと思います。
新機能を使うかどうかは別にして、ともかくチェックしておくとよいでしょう。
- Bundler 1系がRubyに組み込まれた
この変更で、gem install bundler
しなくてもデフォルトでBundlerを使えるようになります。
なお、今回Rubyに組み込まれるのはBundler 1系ですが、現在進められている2系はGemfileに完全前方互換性がないようですので、こちらも注意点となります。
今後世の中全体で使われるBundlerが完全に2系に移行完了するまでは、Bundlerのバージョンには注意を払っておくべきだと思います。プロジェクトで先行して2系が使われる可能性などもありますので。
--jit
でJITにオプションが有効に
JITをRailsで使うかどうかについてですが、JITの性質上Railsアプリケーションのような大きなアプリケーションではあまり劇的な効果はないかと思います。
場合によってはJITの処理が合間合間に挟まってくる関係で、NewRelicやrubyprofのようなプロファイラの処理結果が安定しなくなってしまうなども考えられるため、productionにいきなり入れるというよりは、大規模なデータを変換するようなバッチ処理などのJITが効きやすい処理について、チューニングが必要になったタイミングでの選択肢の一つとして考えるのが良さそうです。
yield_self
にthen
というエイリアスが追加
参考↓。
週刊Railsウォッチ(20181119)
週刊Railsウォッチ(20181119)レビューでチェックされる非効率な書き方、Local Storageは使うなほか
ブラウザのLocal Storage
同記事では特に新しい話は出ていないと感じましたが、これまでブラウザのLocal Storageを使ったことのない人や、JSフロントエンドの経験の少ない人は一度目を通しておくとよいかもしれません。
ブラウザのLocal Storageのポイントは、KVS(キーバリューストア)であること、文字列しか入れられないのでオブジェクトを入れるにはserialize/deserializeが必要であるという点です。
従来のcookieと比べれば容量が大きいのですが、それでも4MB程度しか保存できませんし、serializeのオーバーヘッドも含めれば、保存できるデータ量はこれを下回るでしょう。
Local Storageは、同じドメイン内で任意JavaScriptを実行されると全データにアクセスできてしまうので、secureな平文データの保存は危険です。なお、別ドメイン由来のJavaScriptコードからはLocal Storageにアクセスできません。
Local Storageはキャッシュ的に使われることがありますが、キャッシュにプライベートな情報が含まれることのないようにしておく必要があります。そうした情報をあえて保存するのであれば、サーバーから暗号・復号化用の鍵を提供して、暗号化した情報をキャッシュとしてLocal Storageに保存するなどの対応が考えられます(鍵はLocal Storageには保存しない)。ここは推測ですが、Gmailなどはそうした工夫を行っているのではないでしょうか。
localStorageはかなりプリミティブなインターフェースしかないので、リッチなアプリケーション開発ではストレージ層をwrapしたライブラリなどを組み合わせて使うことになるんでしょうか。
使ってみること自体はお手軽なので、触ったことがなければ試してみるのは良いと思います。
Google SheetsのQUERY関数
これは小ネタで、知ってる人は昔から使ってたようですが、意外に有用かもしれません。
Google SheetsではSQL風のクエリが書けます(あくまでSQL「ライク」ではありますが)。これは、アプリの仕様書などをGoogle Sheetsで管理している場合に有効な使いみちがありそうです。morimorihogeとしては、「あの」VLOOKUP()
を使わずに書けるのがとても嬉しい点です。
基本的にはVisualization APIのクエリが書けるようになっています。SQLは使い慣れているがExcel関数に不慣れな(あるいはVLOOKUP()
のようなExcel系関数がキライな)エンジニアにとって便利そうです。
参考: Query Language Reference (Version 0.7) | Charts | Google Developers
なお、このSQL風クエリはGoogle Sheetsでしか利用できないので、当然ながらExcelブックに書き出すとクエリを使った部分は動かなくなります。事前の納品物確認などで、Excelで完全に動作が再現できるものを求められる場合は残念ですが諦める必要がありそうです。
Excelフォーマットであればクエリが動かなくても良いのであれば、値として書き出しすることは恐らく可能なので開発チーム内部でのデータ作成はSheetsを使ってもいいかもしれませんね。
ExcelもGoogle Sheetsも程々に使いこなせるととても便利なので、ちょっとしたデータ処理手段の一つとして手札に入れておくと素早く質の高いアウトプットを出すのに役立つと思います。
普段プログラミング言語を触っていると神ExcelとかExcel方眼紙の話を聞いて敬遠しがちではあるのですが、ツールはツールと割りきって触るという寛容さも時には身を助けるかも?
「現代的な」JavaScript入門系リソース
最近大学の非常勤でJavaScript開発を教えているのですが、プログラミングの初心者向けに現代のJavaScriptを勉強してもらうための手頃な教材が以外にそんなにありません。
※既にある程度別のプログラミング言語を習得している人向けの書籍や解説はあるのですが「はじめてのプログラミング」かつ「ES5以降」向けとなると少ないです。
教えてるのはCS系学部ではなくメディア系の学生なので、ガチガチの上から下まで解説されたプログラミング本よりは、内容は浅くて良いのである程度実用的で長大過ぎず、かつ日本語の教材が望ましいのです。
js-primerの内容はwebpackやbabelなどにいきなり手を広げずに、pureなES5の内容となっておりとても手頃だなと感じます。
「はじめてのプログラミング」の自習向けとしてはやや難しいと感じるところはありますが、大学の授業などの誰か解説・レビューしてくれる人がいる前提で使うのであればとてもよく纏まっているので重宝しています。
他の現代的なJavaScript入門リソースとして、ProgateにもES6のinteractive courseもあります(途中から有料になります)。プログラミング経験のない方はこちらで学ぶとよいでしょう。
参考: JavaScript | プログラミングの入門なら基礎から学べるProgate[プロゲート]
その他にもいろいろあさってみた限りでは、mozillaのMDNの資料が現時点では総合的に最もよくまとまっているように思えました。サンプルコードも豊富で、日本語翻訳の質も高いので、最初にjs-primerで学んでから、わからない点をMDNで追うのがよいでしょう。
(2018/11/26)
(この回はお休みをいただきました)
社内発表は12月頭にやってたのですが、色々とこねくり回してたら2月になってしまいました
Railsウォッチを毎週やっている中では、時によっては半分以上がマニアックな話題に終始してしまうことがあり、普段のWeb開発業務に直接役立つ知識を追いかけている人にとってはノイズに思えてしまう部分も多いと思います(ノイズの中にも面白いネタが転がっているので意図的にやってるのですが)。
「面白さ」を追求する週刊Railsウォッチに対して「実用性」を追求した月刊サマリーとでもご理解下さい。
※なお、ピックアップしているトピックや内容の重要度については多分に僕個人の価値観が含まれるため、業務でのご利用の際は皆様一次ソースをご確認の上自己責任でご利用下さい。