GunosyでのRails開発フロー

この当時の内容と大きく変わっていませんが、最新のRails開発について公式テックブログに書きました。そちらも合わせてご参照ください。


この記事はGunosy Advent Calendar 2014の22日目の記事です。

こんにちは、Gunosyのtoshimaruです。Gunosyでは主にRuby on Railsアプリを担当しています。

はじめに

Gunosyでは昨年度よりAPIの実装をRails実装からGo実装へと変えたことでAPIのパフォーマンスの大幅な改善が行われました。そんなわけで「GunosyってRails捨ててGoを使ってるんじゃないの?」とお思いの方もいらっしゃるかもしれませんがそんなことはありません。大規模アクセスのない管理画面などではRuby on RailsはまだまだGunosyで現役バリバリです1。高速にWEBアプリを作る必要のあるシーンにおいてはGoはRailsにはまだ敵いません。あのGoカンパニーとして名高いHashiCorpでさえもRailsは手放せないようですしね。

本エントリでは僕がGunosyでかかわっているRailsプロジェクトにおいてどのように開発を進めていっているのかを紹介したいと思います2

ブランチの運用

基本はGit flowに則って開発を進めています。ただGit flowにおけるリリースブランチの運用はフローの簡易化のため、またスモールチーム(2〜3人)での開発ということもあり省いています。これによりdevelop→master間のフローがラクになりスピーディな開発が可能になります。

【↑図】developからfeatureブランチが切られ、developにマージ・確認した後にmasterへ

デプロイ

デプロイフローは下記のようになっています。

  1. ローカルで開発
  2. コードをGithubにプッシュ
  3. CircleCIでテスト & テスト結果を通知
  4. CircleCIからAmazon OpsWorksにデプロイ命令(Chefのデプロイレシピを実行させる)
  5. OpsWorksからデプロイ完了通知

※Amazon OpsWorksについては昨日のChefAdventCalendarにまとめさせていただきましたのでよかったらどうぞ。

Amazon OpsWorksでRailsアプリを簡単Chefプロビジョニング

上記のブランチ運用と照らし合わせるとこうなります。

developブランチ変更時 CircleCIテスト後に、(テストパスすれば)OpsWorksのステージング環境にdevelop ブランチをデプロイ
masterブランチ変更時 CircleCIテスト後に、OpsWorksのプロダクション環境にmasterブランチをデプロイ

アプリケーションレポジトリの責任範囲がCircleCIでテストを実行してOpsWorksにデプロイリクエストを投げるまでで、その後のデプロイは別レポジトリとして管理されているChefのレシピの責任範囲として役割が分けられています。デプロイ環境が一通り揃ってしまえば、アプリケーション開発者はほとんどデプロイに関するアレコレを考える必要がなく本来の開発に集中できます。

Railsのバージョン

入社以来、Gunosyでは2つのRailsプロジェクトにかかわってきましたが(どちらも入社後にゼロから開始したプロジェクトです)両プロジェクトともにバージョン4.1.8です。まだ現時点で最新のバージョン4.2.0には上げてませんが今後も最新のRailsに追従していく所存です。

テスト

Railsのテストに関してはRSpec, FactoryGirl, Capybaraあたりを使っています。

RSpec モデル、コントローラー周りのテスト
Capybara ビューを含むEnd-to-Endテスト3

カバレッジ率に関しては90%前後を保っています。カバレッジはsimplecovを使用し、結果作成されるカバレッジ率はCircleCIのartifactsの機能を使いカバレッジ率と共に公開しています。

【↑図】artifactsで公開されたカバレッジ率

ただ「テストカバレッジを上げること」が目的化してしまっては本末転倒なので(いわゆる「テスト書きすぎ問題」)、「どこまでテストを書くか」は今後も考えていきたいテーマではあります。

複数DB

Railsの悩みとして1つ大きいのは複数DBの扱いではないでしょうか? Gunosyでももちろん複数DBを使い分ける必要があり、そのときはCookpadさん, DeNAさんで実績のあるswith_point gemを使用しています。

この2社のDB事情に関しては下記ブログ・資料に詳しいです。

上記に紹介されているように下記のように簡単に複数DBをswitchでき素敵です。

# Configuration
SwitchPoint.configure do |config|
  config.define_switch_point :blog,
    readonly: :"#{Rails.env}_blog_slave",
    writable: :"#{Rails.env}_blog_master"
end

# Model
class Article < ActiveRecord::Base
  use_switch_point :blog
end

Railsの機能として複数データベースがサポートされる話もあるようなのでそこも期待ですね。参考: #12 Rails mozaic.fm

権限管理

管理画面の権限管理に関してはauthorityを使用しています。権限は大まかにそれぞれの機能においてそれを参照できる権限(READ)・更新できる権限(CREATE/UPDATE/DELETE)というような権限分けを行っています。例えば<ユーザーを閲覧可能>という権限、<ユーザーを更新可能>な権限、これらを組み合わせて管理ユーザーの権限を定義します。

なお、初期の権限設定はseeds.rbで権限をまくようにしています。

バッチ

cronの管理に関してはwheneverを使用しています。こちらはOpsWorkのデプロイ実行時にChefのwheneverレシビが定義してあり、そこでcronがデプロイ時に更新されるようになっています。

非同期ジョブ

重い処理に関してはSidekiqを使いRails側ではSidekiqにキューイングするまでにして、その後の処理はSidekiqで行うようにしてます。例えばGunosyの場合何が重い処理にあたるかというと「全ユーザーにプッシュ通知を送るぞ!」みたいなケース。そのような時間のかかる処理に関してはSidekiqで処理を行っています4

その他・今後の課題

  • 僕が携わったプロジェクトはどちらもRails4系だが、歴史が積み重なったRails3系プロジェクトもあるので今後どうアップデートしていくか。
  • Hubotは遊びで飼ってるけどChatOpsといえるほど真面目に運用していない。もっとうまく使えば幸せになれるかも?

最後に

Ruby/Rails業務経験歴半年足らずのヒヨッコではありますが、僕がかかわった範囲内でのGunosyでのRailsの開発の方法を紹介してみました。もし「うちはこんなRailsの開発してるよ!」とか「これ使うともっと便利になるよ!」とか教えていただけたら嬉しいです。

ではでは。

  1. ちなみにDjangoも使われています。 

  2. とはいえ会社全てのRailsプロダクトが今回紹介するようなやり方で統一されているわけではありません。あくまでも自分がかかわっている範囲での開発の進め方です。 

  3. デフォルトのrack_testドライバーを使っていますが、poltergaistが良さ気なので今後使っていきたいと思っています。 

  4. 正確には別途配信ワーカーがいるのですがここでは割愛