猫の魔法

主にruby系の技術メモを記載

個人的メモ:Rails AntiPatterns(9)

最近仕事が忙しく読む速度が落ちがち。

CHAPTER7 Testing

AntiPattern: Lost in Isolation

  • モックを使いすぎると改修の際にテストが漏れる事がある
  • 特にモジュール間の結合点は今回の事象が起こりやすい
    • ★あんまり理解出来てないが、前後の話を統合すると結合テスト以上の統合テストをする必要があると言っているように思える。

Solution: Watch Your Integration Points

  • テストフレームワークにCucumberを使ってユーザーストーリの視点からのテストを行う
  • ★Cucumberを後で調べる
  • なおこの試みは既存のコードに対してやると、むしろ状況を悪化させる可能性がある。

AntiPattern: Mock Suffocation

  • モックやスタブが多様されているプロジェクトは、その設計自体問題がある可能性がある。

Solution: Tell, Don’t Askの手前まで読了

関連

個人的メモ:Rails AntiPatterns(一覧) - 猫の魔法

個人的メモ:Rails AntiPatterns(8)

CHAPTER7 Testing

AntiPattern: Fixture Blues

Solution: Refactor into Contexts

  • fixstureを使った書き方は一見シンプルだが、テストを複数の人が書いたり何度も改修が入ると何をしてるか分からなくなる。
    • まずはfixtureで記載していた部分を必要な要素が見えるように記載する。
    • モデルのcreateには直接要素のハッシュを渡す
  • 上記の対応に加え、各テストで共通的に行う処理があるならcontextを使って意味のある単位に処理をまとめてsetup時にそれを実施するようにする
  • 一つのテストに複数のassertがある場合、上のassertが失敗すると下のassertは実施されない。
  • 上記を防ぐ為に複数のassertがあるテストはcontextで括った上で、共通の処理をsetupに記載するようにし、1assert毎別のテストに分ける。
  • テストの専門家は1テストで1assertを推奨している。
  • 上記の例はFactoryGirlを使うともっとシンプルになる
    • ★FactoryGirlを使うとなんでシンプルになるのかがいまいちピンと来ていない。

AntiPattern: Lost in Isolationの手前まで読了

関連

個人的メモ:Rails AntiPatterns(一覧) - 猫の魔法

その他

  • JSON.loadの件で追記があるかも。

個人的メモ:Rails AntiPatterns(7)

CHAPTER7 Testing

  • railsはテストを比較的簡単に行えるのでTDD(test-driven development)やBDD(behavior-driven development)に向いている
  • Shouldaというフレームワークを使ってテストフレームワークの機能を説明している。

AntiPattern: Fixture Blues

  • テストを行う際にFixtureが肥大化してしまう問題。
  • yamlファイルにテストケース毎にテストデータをどんどん追加していくと管理出来無くなる。

Solution: Make Use of Factories

  • テスト用のFactoryクラスを作り、そのクラス内でデータの登録を行う。
  • パターン毎に新たなFactoryクラスを作る必要があるが、Fixtureを管理するよりはまだいい。
  • FactoryGirlというgemを使うともっとシンプルにテストデータ作れる。 -例えばテストデータの一部のみを変更して登録するということができる。

Solution: Refactor into Contextsまで読了

関連

個人的メモ:Rails AntiPatterns(6) - 猫の魔法

個人的メモ:Rails AntiPatterns(5) - 猫の魔法

個人的メモ:Rails AntiPatterns (4) - 猫の魔法

個人的メモ:Rails AntiPatterns(3) - 猫の魔法

個人的メモ:Rails AntiPatterns (2) - 猫の魔法

個人的メモ:Rails AntiPatterns - 猫の魔法

個人的メモ:Rails AntiPatterns(6)

CHAPTER 5 Services

AntiPattern: Kraken Code Base

  • ある程度の期間をかけて巨大になってしまったアプリケーションのこと
  • modelの数が多くなるとそれに比例して保守性が下がる。

Solution: Divide into Confederated Applications

  • 一番いいのはお互い関係ない機能を別のシステムとして分離する方法。
  • 関連がある部分切り出す事も出来る。
  • アプリケーションを分離する所までは同じで、APIを作る事によってアプリケーション間の連携を行う。
  • APIで直接的にシステム間を繋ぐと、落ちないシステムが要求される。この場合、キューイングの仕組みを使うとベスト。

CHAPTER 6 Using Third-Party Code

  • gemを使う際の注意点を記載

AntiPattern: Recutting the Gem

  • アプリケーションを構築する際に2回以上繰り返すようなことがある状態

Solution: Look for a Gem First

  • 繰り返すようなコードがある場合、まずはgemがないかを探してみる。

AntiPattern: Amateur Gemologist

  • 十分に成熟していないgemを使ってしまっている状態

Solultion: Follow TAM

  • TAM(test, activity, and maturity)の原則に従い、使うgemを評価する。
    • 自動テストがついている事(test)
    • コミュニティが積極的に活動している事(ソースコード、チケット等の更新が最近されている事)(activity)
    • 作成されてから時間が経過していて、よく管理され、多くのユーザがいる事(maturity)

AntiPattern: Vendor Junk Drawer

  • gemを利用することは一般的にいいことだが、使うgemの管理に注意を払わず、闇雲にgemを使ってしまっている状態。

Solution: Prune Irrelevant or Unused Gems

  • 使用していないgemを削除する。
    • ただこれは簡単なことではないため、そもそもgemの追加をするときに慎重になるのが正しい。

AntiPattern: Miscreant Modification

  • 使っているgemに不具合がある状態。

Solution: Consider Vendored Code Sacrosanct

  • モンキーパッチを当てる。lib以下に作る。
    • 直接vendor/以下のコードをいじらないように。
  • モンキーパッチとは下記のような物
    vendor/gems/hoge/hoge.rb
module Hoge
 class Piyo
  
  def print
     p 'piyo'
  end
end
lib/hoge_extensions.rb
module Hoge
 class Piyo
  
  def print
     p 'gao'
  end
end
  • 修正が恒久的な解決策なら、forkして開発にプルリクエストするといい。

CHAPTER7 Testingの前まで読了。

関連

個人的メモ:Rails AntiPatterns(一覧) - 猫の魔法

個人的メモ:Rails AntiPatterns(5)

CHAPTER 5 Services

  • ここで言うサービスとはサービスクラスのそれというよりAPIやウェブサイトと言った外部が提供or外部に提供する物の総称の事。

AntiPattern: Fire and Forget

  • 外部のAPIを呼ぶ際に、「例外返却される可能性があるメソッド」の例外を取得しないことによって発生する問題。
  • 本来であれば無視したい例外を無視出来なくる。

Solution: Know what Exceptions to Look Out For

  • とりあえず全部rescueして、何もしないというのが一番簡単
    • だがその場合、本当の例外も全部消えてしまう。
  • どのような例外が発生するか調べて、rescueする必要がある例外を配列の定数に持つ
    • 必要な例外のみを無視出来る。万が一見落としがあったとしても配列にその例外を追加するだけで足りる。
  • 例外が調べられないような場合は分かっている最低限の例外だけをrescueする。
    • このような場合は、未知の例外が発生を追えるように、ロギングする事が大切。

AntiPattern: Sluggish Service

  • 応答が遅い外部サービスによりアプリケーション全体が上手く動かなくなる問題

Solution: Set You Timeouts

  • Net::HTTPライブラリを使っている場合、デフォルトタイムアウトが60秒なので、これを短くすることで、アプリケーション全体の問題から局所的な問題へと置き換えることが出来る。
    • ようは待ち続けてコネクションプールが枯渇するというような致命的な問題をさけられるよという話だと思った。

Solution: Move the Task to the Background

  • 処理を非同期にしてしまう。
  • バックグランド処理をする仕組みとしてdelayed_jobを使うのがよい

AntiPattern: Pitiful Page Parsing

  • APIみたいのが提供されておらず、サイトのHTMLを解析するような処理が必要な場合、正規表現でそれを実装すると容易に壊れてしまう問題

Solution: Use a Gem

  • Nokogiriというgemを使って解析するとよい
    • XPath,CSS3セレクタを介してHTMLとXMLを検索するパーサー
    • rails使うと標準でインストールされるが、このような仕組みだとは知らなかった。もう少し詳しく調査したい

AntiPattern: Successful Failure

  • API等で外部に応答するシステムの場合、エラーの際にその応答にエラーコードを返すようなシステム(エラーが発生したかどうかは応答をパースする必要がある)

Solution: Obey the HTTP Codes

  • エラーの場合は適切なHTTPレスポンスコードを返すようにする。
    • RESTfulなAPIだとこれはその通りという感じ。
  • 画面であってもエラーの際に正しいレスポンスコードを返すのは重要。例えば認証エラー等は401を返すべき。

AntiPattern:Kraken Code Baseの手前まで読了

関連

個人的メモ:Rails AntiPatterns(一覧) - 猫の魔法

個人的メモ:Rails AntiPatterns(4)

Rails AntiPttrnsに関する個人的メモ。今日読んだとこまで。

CHAPTER 4 Controllers

Solution: Refactor Non-RESTful Actions into Separate Controller

  • この章ではRESTfullなContollerが責務を負いすぎている例として、認証管理を上げている。
  • 認証機構はUsersコントローラのようなものに直接実装するのではなく、それ用のクラスを作りログインが必要なときに呼び出せるようにroutes.rbを記載する。
  • Railsで作成されるnewとeditアクションは純粋なRESTfulには必要ない。画面の場合のみ、人間のUI上必要になっている。

AntiPattern: A Lost Child Controller

  • 1対多のモデルをview側で多側の情報と同時に1側の情報を取得する際に、1側のIDを指定する必要があるような状態。
    • computer:display 1:多のような形だと/computer/:computer_id?display=:idのような形でアクセスするような物

      Solution: Make Use of Nested Resources

  • routes.rb側でresourceをネストするようにする。
    • /computer/:computer_id/display/:idのような形でアクセス出来るようにする。

AntiPattern: Rat’s Nest Resources

  • 同一のモデルがネストされてアクセスされる場合と、単一でアクセスされる場合の話。
    • 同じViewテンプレートを使っているが、表示条件が異なる為にView内に条件分岐が生まれてしまっている状態。

Solution: Use Separate Controllers for Each Nesting

  • Controller側をネストするものとそうでない物で分離し、Viewテンプレートも別物を使う。
    • 例えば、controllers/display_controller.rbはcontrollers/display_controller.rbとcontrollers/computer/display_controller.rbに分離する。
  • この方式にするとサブディレクトリに入るものとそうでない物が混在する可能性があるので、サブディレクトリを切るなら必要なものはみなそこに入れるようにした方がいい。
  • また、この方式はDRYの原則を弱めることに繋がる可能性があるが、上手く使えば保守しやすいコードになる。

AntiPattern: Evil Twin Controllers

  • 機能が大きくなってきて、HTMLとXMLを画面とAPIによって返し分ける必要があるようなアプリケーションの場合に、一つのメソッドの中で同時に処理を行ってしまっているようなパターン

Solution: Use Rails 3 Responders

  • Rails 3から導入されたrespond_to メソッドとrespond__withメソッドを使う事で解決出来る。
    • ★このrespon_toから呼び出している実体が恐らく掲載されているコードの他にある気がするのだが、respond_to自体を調べないとなんとも。。。

CHAPTER 5 Servicesの手前まで読了

関連

個人的メモ:Rails AntiPatterns(一覧) - 猫の魔法

個人的メモ:Rails AntiPatterns(3)

Rails AntiPttrnsに関する個人的メモ。今日読んだとこまで。

CHAPTER 4 Controllers

AntiPattern: Bloated Sessions

  • Railsは仕組み上ステートレスな動きを得意としている。
    • ステートフルな動きをなんらかの理由でしなければいけない場合、その内容をクッキーとしてクライアント側に保存することになる。
    • このクッキーになんでもかんでもツッコミ過ぎるのはよくない。

Solution: Store References Instead of Instances

  • DBではなくセッションにオブジェクトそのものを格納しないでIDを引き回すようにする。
  • セッションが短い場合はviewのHiddenに値を持たせるのもあり(本当か?)

AntiPattern: Monolithic Controllers

  • RESTfulの原則に従わない動作をしようとしているコントローラ。

Solution: Embrace REST

この場合はRESTfulになるように直す。直す前にインテグレーションテストを書いておくことを忘れずに。

AntiPattern: Controller of Many Faces

  • アプリケーションが大きくなって非RESTfulな動作がコントローラ内に混じってしまっている状態。

Solution: Refactor Non-RESTful Actons into Separte Controlerの手前まで読了

関連

個人的メモ:Rails AntiPatterns - 猫の魔法

個人的メモ:Rails AntiPatterns (2) - 猫の魔法

個人的メモ:Rails AntiPatterns (2)

Rails AntiPttrnsに関する個人的メモ。今日読んだとこまで。

CHAPTER 4 Controllers

AntiPattern: Fat Controller

  • コールバックは条件付きにすることも出来る。
  • モデル側に処理を寄せる場合はトランザクション処理をコントローラ側に持たせる必要はない。
  • _idメソッドよりもアソシエーションプロキシを使う
    • ★association proxyがよく分からなかったので調査。

Solution: Move to a Presenter

  • コールバックに持っていけばいいという話でもない。バランスが重要
  • 特に2つのモデルに対する更新処理等で、複数のモデル間にトランザクションを貼らなければならない場合、 コントローラでもモデルでもない第3の仕組みを用いてそちらに寄せるのがいい
    よくない例
class HouseControleer < ApplicationController
  def create
    @house= House.new(params[:house])
    @address = Address.new(params[:address]
    @house.address = @adress

   ActiveRecord::Base.transaction do
     @address.save!
     @house.save!
  end

  redirect_to(@address)
end
  • 記事の中ではMVPとMVCを合体させて、VC間にPを持ってくる手法が紹介されている。

    • 具体的にはPとしてActive Presenterモジュールを使っている。
    • 上の例だとhouseとaddressをpresentsに持たせたActivePresenter::Baseを継承したクラスを作成する。
      • そのクラスをnewしてsaveするようにコントローラ上は実装すれば、余計なトランザクションがいらなくなる。
        • ★今は理解しているが、この書き方だと忘れそうなので、もう少し具体例を考える。
  • AntiPattern: Bloated Sessionsの前まで読了

関連

個人的メモ:Rails AntiPatterns - 猫の魔法

個人的メモ:Rails AntiPatterns

Rails AntiPttrnsに関する個人的メモ。今日読んだとこまで。

CHAPTER 4 Controllers

AntiPattern: Homemade Keys

  • 認証用のロジックは独自の物を作らない。セキュリティホールになる。gemを使ったほうがいい。
  • 認証機構用のgemとしてClearanceとAuthlogicが紹介されている
    • ★後で詳細を調べる。

AntiPattern: Fat Controller

  • トランザクションの管理等は普通モデルに寄せる
  • 具体的にFat Controllerになってしまっている物をいかにしてModelに寄せるかの実例
    • 更新日/登録日は独自に持たない。updated_atかcreated_atを使う事。
    • デフォルト値はロジックでなくテーブル側に持たせる
    • モデルのコールバックに処理を寄せられないか考える
      • ★後でもう一度読む。
  • Simplified Calbacksの手前まで読了。

関連

個人的メモ:Rails AntiPatterns(一覧) - 猫の魔法

JSON.parseのquirks_modeと2.4.0での変更

どんだけJSONネタで引っ張るのかという話もあるが、色々と調べて見て分かった事があったのでブログに記録しておく。

JSON.parseでは:quirks_modeというオプションがある。

通常JSONを解析する場合、そのトップレベルはオブジェクト若しくは配列になっている必要があるはずだが、 このオプションが真のときは単一のパラメータを解釈してくれる。

irb(main):001:0>require 'json'
=> true

irb(main):002:0>JSON.parse("12",{:quirks_mode=>true})
=> 12

irb(main):003:0>JSON.parse("12",{:quirks_mode=>false})
JSON::ParserError: 784: unexpected token at '12'
    from /Users/nekomaho/.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:156:in `parse'
  from /Users/nekomaho/.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:156:in `parse'
  from (irb):9
  from /Users/nekomaho/.rbenv/versions/2.3.1/bin/irb:11:in `<main>'



irb(main):004:0> JSON.load(nil,nil,{:quirks_mode=>true})
=> nil

irb(main):005:0> JSON.load(nil,nil,{:quirks_mode=>false})
TypeError: no implicit conversion of nil into String
    from /Users/nekomaho/.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:156:in `initialize'
  from /Users/nekomaho/.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:156:in `new'
  from /Users/nekomaho/.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:156:in `parse'
    from /Users/nekomaho/.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:335:in `load'
  from (irb):4
  from /Users/nekomaho/.rbenv/versions/2.3.1/bin/irb:11:in `<main>'

このオプション、ruby 2.4.0から廃止され:allow_blankというオプションになっている。

正確には、nil以外の単一のパラメータを解釈するのがデフォルトの挙動となり、 :allow_blankで"nil"を受けるかどうかのみ変更出来るようになったというのが正しい。

irb(main):001:0>require 'json'
=> true

irb(main):002:0> JSON.load(nil,nil,{:allow_blank=>true})
=> nil

irb(main):003:0> JSON.load(nil,nil,{:allow_blank=>false})
TypeError: no implicit conversion of nil into String
    from /Users/nekomaho/.rbenv/versions/2.4.0/lib/ruby/2.4.0/json/common.rb:156:in `initialize'
  from /Users/nekomaho/.rbenv/versions/2.4.0/lib/ruby/2.4.0/json/common.rb:156:in `new'
  from /Users/nekomaho/.rbenv/versions/2.4.0/lib/ruby/2.4.0/json/common.rb:156:in `parse'
    from /Users/nekomaho/.rbenv/versions/2.4.0/lib/ruby/2.4.0/json/common.rb:335:in `load'
  from (irb):15
  from /Users/nekomaho/.rbenv/versions/2.4.0/bin/irb:11:in `<main>'

ただ、 Parsing JSON with `quirks_mode: false` parses as if it is `true` and does not warn me. · Issue #309 · flori/json · GitHub

という指摘も出ていて、本当にこの変更がそのまま2.4系に適用されるのかは怪しい。

関連

nekomaho.hatenablog.jp nekomaho.hatenablog.jp