個人的メモ:Rails AntiPatterns(20)
AntiPattern: Wet Validations
- DBによってはvalidationで指定された制約をサポートしていない場合がある。その場合、DB上で発生する不整合データを検知出来ない可能性がある。
Solution: Eschew Constraints in the Database
★適切なgemを使うことで上記を回避出来ると記載があるが、ここで上げられているforeignerはrails4.2でrailsに機能が組み込まれた為廃止されている。
カラムの定義する際はデフォルト値を入れた方がいい。
CHAPTER 10 Building for Failureの手前まで読了
関連
個人的メモ:Rails AntiPatterns(19)
Solution: Never Use External Code in a Migration
- migrationをする際にDB上のデータを一緒に変更する事はよくある事だが、upメソッド内にrubyでその手順を直接書くべきではない
理由はパフォーマンスと、DBから見た外部依存性がrails側にできてしまう為で、このような場合はupメッソド内に生のSQLを書けないかを検討する。
もしrubyのコードにmigrationの内容を書く必要があるなら、モデル間の依存性をすべて移行用クラスの中に記載する。
- 例えばUserがhas_manyでJobを持っているのであれば、下記のように依存関係自体をモデルではなくmigrationスクリプトの中に内包する(以下コード抜粋)
class AddJobsCountToUser < ActiveRecord::Migration class Job < ActiveRecord::Base end class User < ActiveRecord::Base has_many :jobs end def self.up add_column :users, :jobs_count, :integer, :default => 0 User.reset_column_information Users.all.each do |user| user.jobs_count = user.jobs.size user.save end end def self.down remove_column :users, :jobs_count end end
★つまりmodelの最新版とmigration時点でのDBの状態は必ずしも一致しないので、マイグレーション時に想定されている依存性を記載した方がいいということ。
User.reset_column_informationはこれが呼ばれた時点のDBの内容を読み込み、それをActiveRecodeに反映させる。
Solution: Always Provide a down Method in Migrations
- 不可逆なmigrationを行う場合はActiveRecord::IrreversibleMigration例外をdownメソッドのなかで発生させることで、開発者に手動でのDB修正が必要な事を知らせるようにする。
AntiPattern: Wet Validationsの手前まで読了
関連
個人的メモ:Rails AntiPatterns(18)
Chapter 9 Databases
- railsはORMマッパーによって、DBの事を意識せずに済むように設計されているが、それでも気にしなければいけない点はある
AntiPattern: Messy Migrations
- railsはmigrationによってDBへ直接変更を加えなくてもよくなっているが、時間が立つとこのmigration機能自体が厄介な問題を引き起こす可能性がある。
Solution: Never Modify the up Method on a Committed Migration
- migrationはリモート環境で実行したら絶対に変更してはならない。
- すでに配布されているmigrationスクリプトを変更すると、他の開発者とのバッティングを起こすだけでなく、DB自体の破壊につながる。
- そのような自体にならないように、ローカルでよくmigrationを検証する必要がある。
- その為にはdb:migrationだけでなく、db:migration:redoも実施し、問題が無いかを確認したほうが良い。
- db:migration:redoはdownメソッドを実行した後にもう一度migrationを適用する
- ★ネットで調べると、rollbackの代わりに使ってるみたいだが、本当にmigrationを再適用してるのか不明。あとで試す。
- ★これの意図は一度downしてからもう一度upさせることで、双方のスクリプト正しく動くかをローカルdr確認できて安心という意図っぽい。
Solution: Never Use External Code in a Migrationの手前まで読了
関連
個人的メモ:Rails AntiPatterns(17)
Solution: Move Processing into Background Jobs
処理時間がwebでの応答に不適切なくらい掛かる場合はcronやキューイングといった。バックグラウンドJobの仕組みを検討した方がいい
cronの場合スクリプトを別に作ってそれを動かす。
例えば、テーブルのカウントをするのに毎回3分かかるような処理があるなら、事情が許すならcronで30分置きにカウントした結果を別のテーブルに格納する方がパフォーマンスの向上に繋がる。
cronは簡単だが、対象をcronスクリプト側で特定しなければならない。可能性であればキューイングを検討する方がいい
キューイングは画面からcsvをダウンロードする機能のような、バックグラウンドで纏まった処理をしなければならない物に向いている。
キューイングの機能としてはdelayed_jobとResqueが有名。
- Redisを使っているのでなければdelayed_jobを使った方がいい。
- ★Rails 4.2からはActive Jobがあるので、普通はそっちを使う。
- Redisを使っているのでなければdelayed_jobを使った方がいい。
キューイングやcronはは便利な機能だが、使い過ぎるとシステムが複雑になる。節度を持って使う事
- ★ 関係ないが「exercise restraint」で「抑止力を働かす」というのが面白い
Chapter9 Databasesの手間まで読了
関連
個人的メモ:Rails AntiPatterns(16)
忙し過ぎて時間が空いてしまった。
CHAPTER 8 Scaling and Deploying
AntiPattern: Painful Performance
- 単純なパフォーマンスの問題を防ぐ為の事例を紹介する。
Solution: Don’t Do in Ruby What You Can Do in SQL
@article.comments.count @article.comments.length @article.comments.size
- 一つ目の例は、DBのcount関数を実行する。
- 二つ目の例は、lengthがActiveRecordの関連で無い為、すべてのレコードをDBから取得する
- 三つ目の例はすでにレコードがロードされていればそれを使い、そうでない場合はDBのcountを使う。
ケースに応じて使い分ける事が重要。
SQLを上手く使えていないパターンとして以下の2パターンがある。
@account = Account.find(3) @users = @account.users.sort { |a,b| a.name.downcase <=> b.name.downcase }.first(5)
- 上記のコードよりも下のコードの方が、処理をよりDBに移譲できる為パフォーマンスを高められる
@users = @account.users.order('LCASE(name)').limit(5)
class User < ActiveRecord::Base has_many :comments has_many :articles, :through => :comments def collaborators articles.collect { |a| a.users }.flatten.uniq.reject {|u| u == self } end end
- 上記よりも、下記の方がより処理をDBに任せる事が出来る。
- このパターンはflattenを使うような処理になってしまっている場合に置き換えが出来る事が多い
- ★?の部分は、順番に配列の第2,第3要素が入る。
class User < ActiveRecord::Base has_many :comments has_many :articles, :through => :comments def collaborators User.select("DISTINCT users.*"). joins(:comments => [:user, {:article => :comments}]). where(["articles.id in ? AND users.id != ?", self.article_ids, self.id]) end end
Solution: Move Processing into Background jobsの前まで読了。
関連
個人的メモ:Rails AntiPatterns(15)
CHAPTER 8 Scaling and Deploying
AntiPattern: Sluggish SQL
Solution: Reassess Your Domain Model
- 高度に正規化されたテーブルはテーブル間の結合によってパフォーマンスの問題を起こしやすい。
- 単純に結合させるのではなく必要な要素をrails側で取得するようにするとパフォーマンスを改善する事が出来る。
- ★UserがPrefとCityと関連がある場合、下記のように取る事で負荷が減らせる場合がある。
search_pref = Pref.find_by_name('Kanagawa') search_city = City.find_by_name('Yokohama') User.where(pref: search_pref,city: search_city)
- 大きなサイズのテーブルになる事が分かっているなら、テーブル自体非正規化した方がパフォーマンスを向上出来る。
AntiPattern:Painful Performanceの前まで読了。
関連
個人的メモ:Rails AntiPatterns(14)
CHAPTER 8 Scaling and Deploying
AntiPattern: Sluggish SQL
- パフォーマンス最もネックになるのはDB。indexの貼り方と副問い合わせを使った方がいいシチュエーション、ドメインモデルを使った方がいいシチュエーションを考える。
Solution: Add Indexes
- 主キーは自動的にインデックスが貼られる
- 外部キーについても基本は自動的にインデックスが貼られる。
検索で複数のカラムを主キーとして扱うような場合は、複合indexを貼ることを検討する。
- ★内容的には1対多の多側テーブルが他にも多側になる外部キー存在する場合の話をしているが、途中から複合indexの話に読めた。
uniqu識別子が付いているカラムにはインデックスをつけると早くなる。
- STIを使ってる場合、typeカラムには継承先のクラス名が入る。このtypeにはインデックスを貼ったほうがいい。
その他のカラムも検索とかで使用しているならインデックスを貼ってみるとよい。
- ★後でも書いてあるが、インデックスを貼りまくるとupdateやinsertが極端に遅くなる。特にローが多いテーブルはインデックスの追加に慎重になった方がいいというのが個人的な考え。
状態を管理するカラム、フラグ的なカラムも場合によってはインデックスを貼った方がいい。
- created_atのような日付カラムもそれを使ってorder byをしていて且つwhere句に使ってるならインデックスを貼るといい
- インデックスを貼りすぎるとupdateやinsertが遅くなる
- どのカラムにindexをつけるかは、継続的に調査する必要がある。railsのプラグインであるLimerick Rakeなどを使うか、DB自体の機能で遅いクエリを取得する機能を使うと良い。
Solution: Reassess Your Domain Modelの手前まで読了
### 関連
個人的メモ:Rails AntiPatterns(13)
今日はあまり進まず。
CHAPTER 8 Scaling and Deploying
AntiPattern: Disappearing Assets
- Capistranoなどのデプロイツールを使ってアプリをリリースする際にユーザの添付ファイルなど、関係ないファイルもデプロイ対象になる
- Capisrranoの設定で回避出来る。
Solution: Make Use of the System Directory
- CapistranoのsharedディレクトリはRAILS_ROOT/public/systemを向いているのでそこにファイルを配置すればよい。
- ★意味が分かってない。そもそもCapistranoの2から3で大きな変更があったようなので今も通用する話なのか要調査。
AntiPattern: Sluggish SQLの手前まで読了
関連
個人的メモ:Rails AntiPatterns(12)
CHAPTER 8 Scaling and Deploying
- ソフト作った後保守にも非常に労力が掛かる。
- この章ではスケーリングについての問題を考える
AntiPattern: Scaling Roadblocks
- 不必要なスケーリングを考慮する必要はないが、簡単に出来る方法でスケーリングを確保する方法を考える
Solution: Build to Scale from the Start
- データの保管は設定ファイルで簡単にスケーリング出来るよい例
- 添付ファイル取り扱うPaperclipというプラグインは保存場所としてクラウドを設定出来る
- linuxのファイルシステムはその構造上32000までのファイルしか1つのディレクトリに入れられない(ext3の話。ext4や、xfsはこの上限に当たらない)
AntiPattern: Disappearing Assetsの手前まで読了
関連
個人的メモ:Rails AntiPatterns(11)
CHAPTER7 Testing
AntiPattern: Unprotected Jewels
- プラグインやgemはよくテストされている事が重要だが、実際にプラグインや、gemを作る際にテストを作るのは簡単ではない。
- gemやプラグインは不特定多数の物から呼ばれるため、テストを行う際にテスト用の別アプリケーションを立ててテストするのが簡単だが、保守性の面から考えるとよくない
- 作ったgemやプラグインがrailsとどれだけ疎結合になっているかで、3種類のテスト戦略がある。
Solution: Write Normal Unit Tests Without Rails
Solution: Load Only the Parts of Rails You Need
Solution: Break Out the Atom Bomb
C HAPTER 8 Scaling and Deployingの手前まで読了