リーダブルコードを心がける

レールの上のルビーが好きな前田です。
梅雨で雨が続いています。
主な移動手段が自転車な私としては辛い時期になりました。

現在、リーダブルコード(オライリー・ジャパン)を再読しています。
進行中のプロジェクトで、メソッド名や変数名に悩むことが多かったので、その参考になればと再読している次第です。

命名の大切さ

忙しいから、めんどくさいから、とついつい命名に対して疎かになっていませんでしょうか。
プロジェクトスタート時におかしな名前を命名してしまうと、プロジェクトの途中で担当者が代わったりした時など、全く意味が分からなかったり、非常に扱いにくいデータとなってしまったりなど、弊害は計り知れません。
一番最初に名前やアーキテクチャをしっかり設計しておく、ということがメンテナンスしやすいWebシステムを作る上で非常に重要だということです。

Webシステムを作っていく上で決めていかなければならない重要な名前はたくさんあります。
データベース名、テーブル名、テーブルカラム名、メソッド名、変数名、などなど。
プログラミング言語はアルファベットで書いていくので、当然日本語から英語に変換しなければなりません。
どうしても該当が無い場合は日本語のアルファベットにするしかないですが。
本当にビシっと決まる名前を命名することは非常に難しいと思います。

弊社ではこの名前決めに非常に時間を割いて議論しているように思います。
一番重点を置いているのは、名前を見ただけでその役割を理解することができるような名前になっているか。

命名規則

リーダブルコードの中では命名の際に、下記のルールを守れと書いてあります。

①明確な単語を選ぶ
②汎用的な名前を避ける(あるいは、使う状況を選ぶ)
③抽象的な名前よりも具体的な名前を使う
④接尾辞や接頭辞を使って情報を追加する
⑤名前の長さを決める
⑥名前のフォーマットで情報を伝える

①〜④までは名前を具体的にする、ということ。

⑥については、RailsRubyの規約がありますので、名前のフォーマットもそれらに従うのが良いと考えられます。

⑤については難しいところだなと思いました。
リーダブルコード文中では「長い名前を命名するのは問題じゃない」と言っています。
スコープが小さい時は短くても良い、ただしスコープが大きい時は、長さを優先させたほうが良い、という内容でしたが、弊社ではrubocopでコードをチェックしており、あまりメソッド名や変数名が長いと1ラインあたり80桁の制限に引っかかりやすくなり、無駄な改行などで余計にコードが見づらくなってしまう、という本末転倒なことになることが想像できるので、やはり短く具体的にする、というハードな命名センスが必要になってきます。

重要なのはやはり名前に情報を詰め込む、ということ。

コード修正

以上を踏まえてカタカナを扱うカタカナクラスのコードを修正してみました。
各メソッドの役割は以下の通りです。

  1. include_kana_list?
    与えられた文字(ローマ字)が、KANA_LISTの各行の先頭文字をローマ字にしたキー値一覧['a', 'ka', 'sa', 'ta', 'na', 'ha', 'ma', 'ya', 'ra', 'wa']に含まれているかどうかを返す。
    例: 'na'true
    例: 'ナ'false '20'false

  2. kana_list_line
    与えられた文字(ローマ字)からKANA_LISTの各行を取得する。
    例: 'a'['ア', 'イ', 'ウ', 'エ', 'オ']
    例: 'sa'['サ', 'シ', 'ス', 'セ', 'ソ']

  3. alphabetical_head_string
    与えられたカタカナ文字列の先頭文字が、50音のどの行(あ行、か行など)に所属しているか判断し、あ行なら'a'、か行なら'ka'といったローマ字で返す。
    例: 'ニシノミヤシ''na'
    例: 'ゲロシ''ka'

1
# カタカナクラス
class Katakana
  KANA_LIST = { a: %w(ア イ ウ エ オ),
                ka: %w(カ キ ク ケ コ ガ ギ グ ゲ ゴ),
                sa: %w(サ シ ス セ ソ ザ ジ ズ ゼ ゾ),
                ta: %w(タ チ ツ テ ト ダ ヂ ヅ デ ド),
                na: %w(ナ ニ ヌ ネ ノ),
                ha: %w(ハ ヒ フ ヘ ホ バ ビ ブ ベ ボ パ ピ プ ペ ポ),
                ma: %w(マ ミ ム メ モ),
                ya: %w(ヤ ユ ヨ),
                ra: %w(ラ リ ル レ ロ),
                wa: %w(ワ ヰ ヱ ヲ ン) }

  def initialize(str)
    @katakana = str
  end

  def self.include_kana_list?(param)
    KANA_LIST.key?(param.to_sym)
  end

  def self.kana_list_line(param)
    KANA_LIST[param.to_sym]
  end

  def alphabetical_head_string
    KANA_LIST.each do |key, val|
      return key.to_s if val.include?(@katakana[0])
    end
    nil
  end
end

順に見ていきます。

3行目 KANA_LIST
実際にこのKANA_LISTにアクセスすることはありませんが、アクセスすると、
Katakana.KANA_LISTとなり、kanaが続いています。
Katakanaクラスのリストは当然カタカナとなりますので、KANA_を削除します。

18行目 include_kana_list?
3行目のKANA_LISTに含まれているか、を判断するものとして、kana_listとしましたが、3行目をLISTだけにしたので、こちらもkanaを削除します。
各行のキー値一覧line_keysとしますと、include_list_line_keys?となります。
実際にメソッドを使う時はKatakana.include_list_line_keys?(chara)となりますが、keysというのは外から見た時には何のkeyかが分かりにくいかなと思いました。
そこで最終的にはinclude_line_head_charas?(chara)としました。

22行目 kana_list_line
こちらもkana_listを削除します。
lineだけだと分かりづらいので、ありふれていますがget_を付けて、get_lineとしました。

26行目 alphabetical_head_string
alphabeticalとはアルファベット順のという意味です。
日本語の50音、を英語に変換しているのですが、少し無理がありそうですね。
50音の各行の先頭文字というのを表したかったのですが少し説明不足と誤解を与えてしまうことになるかもしれません。
alphabeticalを大胆に削除して、get_line_head_charaとし、行の先頭文字を取得するという意味を持たせることにしました。

その他
引数やメソッド名の中の文字列str一文字charaとしました。
charaといいながらもkaなどを返していたりするのですが、このクラスはKatakanaクラスということで、あくまでも日本語の意味での一文字という意味でkaなども一文字とみなすことにしました。

整形後

1
# カタカナクラス
class Katakana
  LIST = { a: %w(ア イ ウ エ オ),
           ka: %w(カ キ ク ケ コ ガ ギ グ ゲ ゴ),
           sa: %w(サ シ ス セ ソ ザ ジ ズ ゼ ゾ),
           ta: %w(タ チ ツ テ ト ダ ヂ ヅ デ ド),
           na: %w(ナ ニ ヌ ネ ノ),
           ha: %w(ハ ヒ フ ヘ ホ バ ビ ブ ベ ボ パ ピ プ ペ ポ),
           ma: %w(マ ミ ム メ モ),
           ya: %w(ヤ ユ ヨ),
           ra: %w(ラ リ ル レ ロ),
           wa: %w(ワ ヰ ヱ ヲ ン) }

  def self.include_line_head_charas?(chara)
    LIST.key?(chara.to_sym)
  end

  def self.get_line(chara)
    LIST[chara.to_sym]
  end

  def self.get_line_head_chara(str)
    LIST.each do |key, val|
      return key.to_s if val.include?(str[0])
    end
    ''
  end
end

まとめ

読みやすいコードを書くということは奥が深いですし、終わりが無い作業のようにも思います。
弊社ではプルリクエストでプロジェクトに携わる関係メンバーにコードレビューをしてもらいますが、何故その名前にしたのか、無駄は無いかなど、激しくツッコミを受けますので気を付ける癖が自然と身に付いてきたように思います。
大事なことは、日々考えながら少しでも良いコードを書けるように努力することだと思いますので、これからも頑張ります!

リーダブルコードを意識した保守性の高いシステム開発やモバイルアプリケーション開発をご検討の企業様は、是非MMMにご相談下さいませ!

このエントリーをはてなブックマークに追加