社内勉強会で感動した話(DDD ユビキタス言語再考)
社内勉強会で先輩がお話していた内容に感動しました。
先輩のプレゼンに感動して泣きそう(´;ω;`)ブワッ
— まえとー (@maetoo11) 2016年5月12日
内容の解説ではなく、自分が思ったことを書くので他の人の役には立たないかもしれないです。
また、勉強会は社内クローズドなイベントでしたが、
先輩のスライドはSpeaker Deckというサービスで公開されており、
ブログに書いても良いという許可もご本人にいただいております。
先輩は下記のスライドをもとに発表していました。
どこに感動したのか
ユビキタス言語はチーム全員で合意し創るもの
ユーザーの言語 = ユビキタス言語 というわけではない
という部分に感動した。
感動というか「今ならわかる!」と思った。
なぜ感動したのか(なぜ今ならわかるのか)
多分、似たような話を半年ほど前にも社内勉強会でお話してもらったと思う。
でも、そのときの私は「ユビキタス言語??言葉そんなに大事なの????」という感じだった。
ここ3ヶ月、私は社内向けのシステムを開発している。
(そのシステムは経理担当者や営業担当者がExcelを用いて手動で行っていることをシステム化&一部自動化を目指している。)
ヒアリングを行い、システムの構造を考えていく中で、社内でAと呼んでいた書類が実は一般的にはBという書類とCという書類があってそれを組み合わせたものだということがわかる場面があった。(業務としてもB、Cの書類を発行すべきだった)
担当者から言われた書類の名前をそのまま使うのではなく、どうあるべきかということも担当者やその他関係するメンバーと考えながら認識をすりあわせて行くことができた。
同じ認識になった言葉をつかうと、資料つくりも楽で、認識の齟齬も減った気がする。
その実体験があったから「今ならわかる!」と思えたのだろう。
昔はわからなかったことでも、自分が体験すると理解しやすくなることもあるのかもしれない。
疑問(内容には関係ない可能性あり)
今回の発表内容には関係ないかもしれないが、下記のような疑問がある。
システム化するにあたり、社内オリジナルの名前で英語に直訳できないモデルの名前はどうすればいいのだろう?
(今は無理やり英訳した長い名前をつけている)
railsについて、先輩にもらったアドバイスまとめ(その1)
最近はRuby on Railsで社内システムを作っています。 その中で先輩からもらったアドバイスやレビューで受けた指摘をまとめます。
new()はいらない
hoge = Hoge.new()
は
hoge = Hoge.new
でよい。
(Rubyは短く楽に書けるときは楽をするのじゃ!)
is_available?のisはいらない
有効かを判定しtrue/falseを返却するようなメソッドの名前は
def is_available? # 何らかの処理 end
ではなく
def available? # 何らかの処理 end
でよい。
(present?やblank?というメソッドがありますよねー)
※私はこの「?」を疑問形の「?」だと思っていました…(Is this a pen?的な)
破壊的でないメソッドに「!」はいらない
def hoge! # 破壊的な処理 end
であり、破壊的でないメソッドに「!」はいらない。
(破壊的な処理を行う場合はprivateメソッドであっても「!」をつけるようにしています)
ある機能追加のために複数のテーブルにカラム追加を行う場合、migrateファイルは分ける
分けたのですが理由が思い出せず…。
※これはもしかしたら1つの機能追加で複数のテーブルに手が入ったことをわかりやすくするために、migrateファイルはわけないほうがよかったのかも?と思いました。
できるだけ短く、意味のある処理ごとにメソッドにする
def calc_hoge hoge = 0 hoge = hoge + (a * b) hoge = hoge + (c * d) end
は
def calc_hoge hoge = 0 hoge += calc_a_b hoge += calc_c_d end def calc_a_b a * b end def calc_c_d c * d end
のようにしたほうがコードが説明的になってわかりやすい。
2016/4/19(火)追記
ステータスコード404でリソースの存在を隠すこともできる
現在作成しているシステムはユーザーにロールを設定しており、ロールによっては閲覧できないリソースがある。
そのリソースを表示するようなページに権限のないユーザーがアクセスした場合、
403が返るとリソースが存在していることが権限のないユーザーにも分かってしまう。
存在自体を隠したいときは404を返す。
詳しくは下記の記事を参照
HTTPステータスコードを適切に選ぶためのフローチャート : 難しく考えるのをやめよう | インフラ・ミドルウェア | POSTD
railsで404のときに表示されるページは public/404.html
である。
任意のデザインにしたい場合は404.htmlを編集すればよい。
rspecのテストでカバレッジが計測できるgem、SimpleCovを導入する
テストを書くならカバレッジ計測と行単位で通った・通ってないの確認ができたらいいな、と思っていたら
@tmtms さんより「SimpleCov」を教えていただきました。
導入手順
Gemfileに「simplecov」を追加
group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' gem 'rspec-rails' # Test format nyan cat gem 'nyan-cat-formatter' # テストを自動実行 gem 'spring-commands-rspec' gem 'guard-rspec', require: false # カバレッジ取得 gem "simplecov" # モデルにテーブルのカラムをコメントで出力 gem 'annotate' end
gemをインストール
$ bundle install --path vendor/bundle --jobs=4 $ # .bundle/configに設定されている場合はbundleでOK
spec/spec_helper.rbにsimplecovのstartを記述
require 'simplecov' SimpleCov.start 'rails' RSpec.configure do |config| # rspec-expectations config goes here. You can use an alternate #・・・略・・・
これで準備は完了
使い方
rspecでテストを実行する。
$ bundle exec rspec spec/
するとプロジェクトフォルダ直下に「coverage」というフォルダが作成される。
coverageフォルダ配下の「index.html」をブラウザで開く。
するとファイルごとのカバレッジ一覧が表示される。
ファイル名をクリックすれば、行単位で通った・通っていないが確認できる。
導入にあたり参考にしたサイト
rspecでのテストがちょっと楽しくなるgem、nyan-cat-formatterを導入する
テストの待ち時間&結果確認がちょっと楽しくなるgemです。
GitHub - mattsears/nyan-cat-formatter: Nyan Cat inspired RSpec formatter!
導入手順
Gemfileに「nyan-cat-formatter」を追加
group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' gem 'rspec-rails' # Test format nyan cat gem 'nyan-cat-formatter' end
gemをインストール
$ bundle install --path vendor/bundle --jobs=4 $ # .bundle/configに設定されている場合はbundleでOK
使い方
オプションをつけてrspecを実行!!
$ bundle exec rspec --format NyanCatFormatter spec/
すると…
※テスト実行中はNyan Catが走ります
テストが落ちると…
とりあえずユーザー管理と認証を実装したいのでdeviseを使う
自力で実装する心の余裕が消えたのでdeviseを使うことにしました。
もうすでにあるものはガンガン使おう!そうしよう。
インストールや設定手順は下記リンクを参照しました。
- Rails 4.2 で ユーザー管理・認証 (devise) - Qiita
- Railsのログイン認証gemのDeviseのインストール方法 - Rails Webook
- [*Rails*] deviseの使い方 - Qiita
手順
Gemfileにdeviseを追加する。
gem 'devise'
bundle installを行う。
(ここではbundlerの設定をそのまま使用したいのでbundleコマンドを実行している)
$ bundle Fetching gem metadata from https://rubygems.org/........... Fetching version metadata from https://rubygems.org/... Fetching dependency metadata from https://rubygems.org/.. Resolving dependencies... Using rake 10.5.0 ・・・略・・・ Using rack-test 0.6.3 Installing orm_adapter 0.5.0 Installing warden 1.2.6 Installing bcrypt 3.1.11 with native extensions Using mail 2.6.3 ・・・略・・・ Using web-console 2.3.0 Installing responders 2.1.1 Installing devise 3.5.6 Bundle complete! 16 Gemfile dependencies, 72 gems now installed. Bundled gems are installed into ./vendor/bundle.
devise関連ファイルのをrailsコマンドで生成する。
$ bundle exec rails generate devise:install create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. If you are deploying on Heroku with Rails 3.2 only, you may want to set: config.assets.initialize_on_precompile = false On config/application.rb forcing your application to not access the DB or load models when precompiling your assets. 5. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================
環境を設定する。
config/environments/development.rb
に下記を追記する。
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
devise用のUserモデルを作成する。
$ bundle exec rails g devise User invoke active_record create db/migrate/20160321071935_devise_create_users.rb create app/models/user.rb invoke rspec create spec/models/user_spec.rb insert app/models/user.rb route devise_for :users
Userテーブルを追加するのでmigrateする。
$ bundle exec rake db:migrate:reset == 20160321071935 DeviseCreateUsers: migrating ================================ -- create_table(:users) -> 0.0166s -- add_index(:users, :email, {:unique=>true}) -> 0.0333s -- add_index(:users, :reset_password_token, {:unique=>true}) -> 0.0259s == 20160321071935 DeviseCreateUsers: migrated (0.0760s) =======================
deviseが出力するメッセージの表示場所を設定する。
(ここでは app/views/layouts/application.html.erb
に設定)
ついでにナビゲーションバーにログインしていない場合はログイン、ログイン済みの場合はログアウトというリンクを表示する。
<body> <header> <div class=""> <% if user_signed_in? %> <div> Logged in as <strong><%= current_user.email %></strong>. <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> </div> <% else %> <div> <%= link_to "ログイン", new_user_session_path %> </div> <% end %> </div> </header> <div> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> <%= yield %> </div> </body>
undefined method `devise_for'というエラーが出た。
→一度rails serverを再起動しないといけないらしい。
undefined method `devise_for' in rails - Stack Overflow
正しく動けば以下のようなログイン画面が表示されるはず。
その他
ログインしていないユーザーはログイン画面にリダイレクトするよう設定したかったので下記を参考に実装。
devise + omniauth-facebookでリクエストURLにリダイレクトする - yasuoza diary
初期ユーザーの追加をする。
Devise に初期ユーザを追加 - Ruby and Rails
Ruby on Rails 4 アプリケーションプログラミング
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2014/04/11
- メディア: 大型本
- この商品を含むブログ (5件) を見る
N+1問題を検出してくれるgem、bulletを導入する
Railsで作ったプロジェクトを開発環境で動かしていくと、ある一覧ページを表示する度にすごい量のSELECTが発行されているように見え、先輩に相談!
「N+1問題」というものを教えていただきました。
N+1問題 / Eager Loading とは - Rails Webook
解決策
以下のページを参考にしました。
ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い - Qiita
そもそもN+1問題はログを眺めていないと気づけないのでは…?と思ったところ、素敵なgemがあること先輩に教えていただきました!
それが「bullet」です。
GitHub - flyerhzm/bullet: help to kill N+1 queries and unused eager loading
導入手順
導入は下記ページを参考にしました。
» Railsライブラリ紹介: N+1問題を検出する「bullet」 TECHSCORE BLOG
Gemfileにbulletを追加
(開発環境でのみ使用する)
group :development do # Access an IRB console on exception pages or by using <%= console %> in views gem 'web-console', '~> 2.0' gem 'thin' gem 'rails_best_practices' gem 'bullet' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' end
bundleコマンドを実行し、gemをインストールする
$ bundle Fetching gem metadata from https://rubygems.org/........... Fetching version metadata from https://rubygems.org/... Fetching dependency metadata from https://rubygems.org/.. Resolving dependencies... Using rake 10.5.0 Using i18n 0.7.0 ・・・略・・・ Using sass-rails 5.0.4 Using web-console 2.3.0 Installing uniform_notifier 1.9.0 Installing bullet 5.0.0 Bundle complete! 15 Gemfile dependencies, 67 gems now installed. Bundled gems are installed into ./vendor/bundle.
開発環境のconfigにbullet用の設定を追加する
(config/environments/development.rbというファイルに下記の記述を追加する)
config.after_initialize do Bullet.enable = true Bullet.alert = true Bullet.bullet_logger = true Bullet.console = true Bullet.rails_logger = true end
railsサーバーを再起動する
(再起動しないとbulletが使えない)
再起動してN+1問題のクエリが発行されるページへアクセスすると、下記のようなポップアップが表示されるようになる
どこの処理で発生したかに加え対処方法をきちんと教えてくれるので、対処が簡単になりました(∩´∀`)∩ワーイ
素敵なgem、rails_best_practicesを導入する
先輩のアドバイスを受け、Railsのベストプラクティスに従っているかを確認できるgemを導入しました。
手順
Gemfileにrails_best_practicesを追加(今回は開発環境だけで使用する)
group :development do # Access an IRB console on exception pages or by using <%= console %> in views gem 'web-console', '~> 2.0' gem 'thin' gem 'rails_best_practices' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' end
bundleコマンドを実行し、gemをインストールする
$ cat .bundle/config --- BUNDLE_PATH: vendor/bundle BUNDLE_JOBS: 4 BUNDLE_DISABLE_SHARED_GEMS: '1' $ $ $ bundle Fetching gem metadata from https://rubygems.org/........... Fetching version metadata from https://rubygems.org/... Fetching dependency metadata from https://rubygems.org/.. Resolving dependencies... Using json 1.8.3 Using minitest 5.8.4 ・・・略・・・ Installing code_analyzer 0.4.5 Installing rails_best_practices 1.16.0 Bundle complete! 13 Gemfile dependencies, 64 gems now installed. Bundled gems are installed into ./vendor/bundle. Post-install message from rails_best_practices: ******************************************************************************** rails_best_practices is a code metric tool to check the quality of rails codes. I highly recommend you browse the Rails Best Practices website first. http://rails-bestpractices.com Please also try our online service http://railsbp.com Enjoy! Richard Huang (flyerhzm@gmail.com) ******************************************************************************** $
これでrails_best_practicesが使える状態になる。
早速実行してみる!
プロジェクトのディレクトリに入り、 rails_best_practices .
を実行する。
$ bundle exec rails_best_practices . Source Code: |==============================================================================================================================| /Users/maetoo11/workspace/rails-app-name/db/schema.rb:34 - always add db index (model_name => [column_name]) /Users/maetoo11/workspace/rails-app-name/app/views/hoge/index.html.erb:53 - law of demeter /Users/maetoo11/workspace/rails-app-name/app/helpers/humus_helper.rb:1 - remove empty helpers /Users/maetoo11/workspace/rails-app-name/app/views/humus/_form.html.erb:1 - replace instance variable with local variable /Users/maetoo11/workspace/rails-app-name/app/views/hoge/_form.html.erb:7 - replace instance variable with local variable Please go to http://rails-bestpractices.com to see more useful Rails Best Practices. Found 28 warnings.
各警告メッセージの意味(日本語)は下記の記事を参考にしました。
Rails Best Practices の警告をちゃんと考える - Qiita
Rails Best Practicesの本家ページ(?)です。
Rails Best Practices - Rails Best Practices
※どうやってプラクティスを検索していいかが不明…。
これでベストプラクティスをできるだけ守ったコードがかけるはず!!