Railsらしく書こう

こんにちは、hachi8833です。
今回から趣向を変えて、弊社筆頭プログラマーのbabaさんによる社内講義録を元に記事を書きます。第一回は「Railsらしく書こう」です。

Railsらしく書こう

特にプログラミング経験の浅いうちは、コーディングに関するさまざまな慣習を知らないがために遠回りをしてしまうことがあります。この講義では、Rails (とRuby) の基本的なコーディングルールについて説明します。
なお、この講義はRails3時代のものを元にしていますのでご了承ください。

基本的なコーディングスタイル

class CommentsController<ApplicationController
   def index()
      @comment=Comment.find ( params[:id] )
      if(request.format==:xml) then
         render(:layout=>false)
      end
   end
end

上のコーディングスタイルには問題があります。どこがRails/Rubyの慣習に反しているでしょうか?

  • 全体: インデントがスペース3文字になってしまっている
  • 1行目: <の前後にスペースがない
  • 2行目: かっこは不要
  • 3行目: =の前後にスペースがない
  • 3行目: findメソッド後のかっこの前後にスペースがある
  • 4行目: ==の前後にスペースがない
  • 4行目: thenは不要
  • 4行目: かっこは不要
  • 5行目: =>の前後にスペースがない
  • 5行目: かっこは不要

細かい点には異論もあるかと思いますが、特にチームで開発する場合にはチーム内でコーディングスタイルを揃えるのが原則です。

以前はインデントをタブにするかスペースにするかという議論が多かったようですが、近年はHTML表示からのコピペで不具合の生じにくく、エディタによってインデント量の変わらない、スペースでのインデントが優勢です。私自身、以前はタブ派でしたがこの機会にスペースインデントに宗旨変えしました。

上記の問題を以下の慣習に合わせて修正したものを示します。

  • インデントはスペース2文字にする。タブは使わない。
  • 演算子の前後にはスペースを置く
  • メソッドとかっこの間にはスペースを置かない
  • 不要なかっこは使わない
  • ifを複数行で書くならthenは使わない
# 良い例
class CommentsController < ApplicationController
  def index
    @comment = Comment.find(params[:id])
    if request.format == :xml
      render :layout => false
    end
  end
end

その他にこんな慣習もあります。

  • 行末はスペースで終わらないこと。空行にスペースを置かないこと。
  • privateやprotectedの後には1段インデントを置く
  • ハッシュ記法は、なるべくRuby 1.9の { key: :value } スタイルにする (以前はロケット演算子 => を使用した { :key => :value } という記法)
  • andやorよりも&&と||を使用する
  • クラスメソッドの記法は「self.メソッド名」よりも「クラス名 << self」を使用する
  • 波括弧でブロックを表すときは { do_something } のように内側にもスペースを置く

出典: Railsのコーディングスタイル

スペルミスに気を付けよう

rollとroleの取り違えなど、スペルミスは意外と発生しやすいものです。不安であれは辞書で確認するようにしてください。

命名の慣習

クラス名・メソッド名・変数名は、英単語を複合させて命名するのが普通ですが、ここにも慣習があります。

大文字小文字

大文字小文字の表記法であるキャメルケースとスネークケースについて説明します。キャメルケースは「CamelCase」のように単語間のスペースがなく、単語が大文字で始まる表記法です。その中でも、先頭の単語も大文字で始まるものをアッパーキャメルケースと呼びます。スネークケースは「snake_case」のように単語を小文字にしてアンダースコアでつなぐ表記法です。

次にRubyとRailsの慣習を以下に示します。

  • クラス名: アッパーキャメルケースで表記します。例: MyClass
  • メソッド名: スネークケースで表記します。例: update_attribute
  • 変数名: スネークケースで表記します。例: @user_name

メソッド名の選定

メソッド名の命名に使う語彙にも慣習があります。

  • プロパティ的なメソッドには動詞を含めず、名詞のみで。
    • ○: def width
    • ○: def width=(val)
    • ×: def get_width
    • ×: def get_width=(val)

.get_widthとしなくても.widthだけで十分意味が通じるという考え方です。

以下はよく知られた慣習だと思います。

  • true/falseを返すメソッド名の末尾には?を付けます。例: valid?
  • メソッド名から推測されるよりも破壊的なメソッドの末尾には!を付けます。例: save!

前者は意味を限定して明確にし、後者は使用上の注意が必要であることを知らせます。

コントローラ名とモデル名

Railsでは、コントローラ名は英語の複数形で終わり、モデル名は英語の単数形で終わることが前提となっています。また、コントローラ名とモデル名が互いに関連する場合には原則として一貫した命名をする慣習があります。

たとえば、ユーザープロファイルを扱うコントローラとモデルを作成する場合、コントローラ名はUserProfiles、モデル名はUserProfileとします。

#コントローラ
class UserProfiles < ApplicationController
end
#モデル
class UserProfile < ActiveRecord::Base
end

コントローラ名とモデル名はどちらもクラス名なのでキャメルケースで表記しますが、それぞれが保存されるファイルの名前はスネークケースで記述しますので注意してください。

  • コントローラ名: user_profiles_controller.rb
  • モデル名: user_profile.rb

なお、モデルと関連付けられるデータベースのテーブル名は「複数形かつスネークケース」となります。

rails generateコマンドでファイルを生成すればファイル名設定は自動的に行なってくれます。

rails generate controller UserProfiles
rails generate model UserProfile

コントローラ名やモデル名を決める時も、スペルが不安な場合はirbなどで確認しましょう。

rb -r active_support/all
irb(main):001:0> 'user_profiles'.classify
=> "UserProfile"

なお、personの複数形はActiveSupportではpersonsではなく「people」だったりなんかします。これは罠になりえますね。

rb -r active_support/all
irb(main):001:0>'my_people'.classify
=> "MyPerson"

このあたりを操作できる便利メソッドもご紹介します。

  • singularize: 単数形にする
  • pluralize: 複数形にする
  • camelize: キャメルケースにする
  • underscore: アンダースコア形式(スネークケース)にする
  • tableize: テーブル名にする(pluralize + underscore)
  • classify: モデル名にする(singularize + camerize)
  • constantize: その名前の定数にする

Railsらしい書き方

一目瞭然のメソッド名にしよう

メソッド名の命名にはうんと気を遣いましょう。メソッド名を見るだけで目的と用途が一目瞭然になるのが理想です。これができるようになると、他のメンバーも未来の自分も助かります。

コメントは最小限に

コードに付けるコメントは最小限にしましょう。余分なコメントがなくても楽に読めるコードを書く(よく言われることですが「ソースコードに語らせる」)ように心がけます。逆に言えば、コードのまずさを補おうとしてコメントを増やすのは最悪です。

コメントは、方法を説明するためではなく理由・目的を説明するようにします。方法はコードが語っているのでコメントで説明する必要はないはずです。

メソッドはコンパクトに

メソッドはなるべくコンパクトになるように心がけましょう。メソッドが大きくなるようならリファクタリングします。

enumerableを使おう

Rubyの強力な機能であるenumerableを積極的に使いましょう。Rubyでは、forやwhileなどはenumerableで書く方が簡潔になります。

  • each
  • all?, any?, select, collect, detect, reject, map, inject

レールに乗せよう

Ruby on Railsという名前からもわかるように、フレームワークを使用する場合には独自の実装よりも既存のレールに乗っているものを極力活用するようにしましょう。そのためには:

  • 欲しい機能があれば、それを書く前にまず探してみよう
    • まずRailsの基本機能を探す(忘れがち!)
    • 次に有名なプラグインを探す

コントローラやビューを簡潔に

コントローラやビューが散らからないように、コード量を増やさないように心がけましょう。よく使うコードはlibやhelperにまとめておくとよいでしょう。

古い情報には気を付けよう

ネットなどで見かける古い情報の扱いには注意が必要です。

  • 1年前の情報は鵜呑みにすべきではありません。
  • バージョンが0.1上がれば、もうそれは別のライブラリであるぐらいに考えておく方がよいでしょう。
  • マイナーな情報にはしばしば嘘や誤りが混入しますので吟味が必要です。環境が違えば解決法も異なります。
  • 極論すれば、ドキュメントも時には疑ってかかるぐらいの心構えが必要です。一番信用できるのはコードそのものです。コードを読みましょう。

ライブラリの相性とバージョン

ライブラリには、ライブラリ同士の相性や、バージョン依存の問題が生じることがしばしばあります。ライブラリ導入の際にはREADMEをよく読み、テストを書いて実行するようにしてください。
最近だとRMagickとImageMagickのバージョンの問題が有名です。

勉強会のお知らせ

さてここで宣伝です。今月12月25日19:15より、弊社オフィスにてbabaさん主催の勉強会「良い設計、悪い設計について議論する会」を無料にて開催いたします。どなたでもご参加いただけます。
詳細についてはatnd.orgのエントリを参照してください。

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833 コボラー、ITコンサル、ローカライズ業界を経てなぜかWeb開発者志願。 これまでにRuby on Rails チュートリアルの大半、Railsガイドのほぼすべてを翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ