ホーム DoRuby Rubyを書くときに気をつけたいこと
Rubyを書くときに気をつけたいこと
 

Rubyを書くときに気をつけたいこと

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Ruby初心者の私がコードを書くときに気をつけていることをまとめてみました。

はじめに

 こんにちは。今年新卒で入社したエンジニアです。
Rubyを学習し始めてからインターンの数日を除くと1ヶ月半ほどになりますが、先日初めてコードレビューを行った際に先輩方から「Rubyらしいコードで書こう」との指摘をいただいたのを機に色々調査しながらコードの修正を行いました。基本的なことですが備忘録という意味も兼ねてまとめたいと思います。
 

目次

 1. 適切なメソッドを使う
 2. 目的と同じ実装をしてくれるライブラリを使う
 3. 読み手に分かりやすいように書く

1. 適切なメソッドを使う

 この記事のきっかけとなったコード修正で一番多かったのがこれでした。
Rubyには初めから便利なメソッドが多数用意されており、それを利用することでRubyらしくちょっとだけクールなコードを書く事ができます。
今回この記事を書くきっかけになった実装が文字列処理を含むものだったので、文字列自体の処理を簡素化して実際にコードレビュー前と後の差に似せて出してみようと思います。
stringという小文字とコンマで表された文字列をコンマで区切って全て大文字にして配列に格納するコードを例にします。

# 修正前
str = []
string.split(",").each do |s|
  str << s.upcase
end

ここで使ったeachは単に各要素を参照して処理を行うだけで戻り値に変化はありません。
このコードをmapを使って修正すると以下のようになります。

# 修正後
str = st.split(",").map {|s| s.upcase}

mapは各要素を参照して処理をしたあと、結果を新しい配列にしてくれます。
Rubyには同じような処理をするメソッドでも明確な違いを持ったメソッドが多数あります。

今回例に挙げた配列の要素の数だけ各要素を参照してブロックを実行するメソッドについて基本的なものをまとめておきます。

  • each 要素を順番に参照してブロック内の処理を行う
  • reverse 要素を逆順に参照してブロック内の処理を行う
  • map 要素を順番に参照してブロック内の処理を行い、各要素の処理された結果を新しい配列として作成
  • select 要素を順番に参照してブロック内に書かれた条件を満たすものだけ返す(ブロックが真を返す要素だけで配列を作成)
  • reject selectとは真逆で要素を順番に参照してブロック内に書かれた条件を満たさないだけ返す(ブロックが偽を返す要素だけで配列を作成)

自分が実装したい処理、目的と合うメソッドを使う事で処理をシンプルにまとめることができるので、もっと適切なメソッドがないか、使いやすいメソッドがないか考えながらコードを書くと自然とRubyらしいコードが書けるようになると思います。

2. 目的と同じ実装をしてくれるライブラリを使う

Rubyを使っているとよくgemという言葉を耳にします。
gemとはRuby用のライブラリやアプリケーションを指す言葉で、誰でも簡単に公開することができます。
それゆえ大量のgemが存在し、目的のものが見つかりやすいうえgemの中でも同じような実装をするものも多数あるので目的に合わせて好みのものを選んで使うこともできます。
よく使われるものでbundlerやrails、知名度が高いものの中でもnokogiriやkaminari、kakurenboなど親近感の湧く和名のgemもよく見かけますね。
gemはコマンド1つでインストール出来るうえ簡単に実装することも出来るので1から全てを実装せずに済みます。
実装に直接関わるものだけでなく、デバッグ時に役立つブレークポイントをつけてくれるgemや好きな時刻に変更したり、とある時刻で止めたりしてくれるgemなど多数存在します。
これらを活用すると実装のコードをシンプルにしたり時間効率を上げることももちろん可能になります。
何か新しく実装を加える時は似たような実装ないか探してみたら夢を叶えてくれるgemに出会えるかもしれません。

3. 読み手が分かりやすいように書く

 これはどの言語にも言えることですが、他の言語に比べてRubyはやる気さえあればどこまでもコンパクトに書けてしまう言語だと思っています。
ですがコンパクトに書く事だけに意識を向けてコードを書いてしまっては読み手にとっては難解なコードになりかねません。
※後述するFizzBuzzの最短コードは文字数を減らすのが目的で書かれているので説明がないとどういう処理なのか分からない人がほとんどだと思います。
私が分かりやすいコードにするために心がけていることは以下の2点です。

  • 変数やメソッド、クラスの命名
     多少長くなってもいいのでその変数が何で使われているのか、何を意味しているのかを見てわかるように命名する
  • 改行やスペースを活用する
     稀に巡り会うずらずらとスペースも改行もなしで何行にも渡るコードは、見にくくて時折書いた本人でも嫌になることもあるので、見やすいように書く

1点目はごく当たり前のことですが、私は実装を進めていると2点目を忘れがちで必死にコードをガリガリと書いてしまいます。
配列や括弧の中であれば普通に改行しても問題ないですが、改行したら文末と解釈されてしまって正常にプログラムが動作しないからどうしようもない!という場合があります。その時はバックスラッシュ(option+¥)を文末に入れることで「ここは改行されているけど文末ではない」と教えることが出来ます。
今挙げた2つのルールはプロジェクトによって明確にこうだと決まっていることが大半なので合わせて書くことも大切ですが、もし特に決まっていない場合のことも考えて自分ルールを作っておくとコードを書くときに迷わずに済むかもしれません。

最後に

 これらは基本中の基本で、この他にももっと留意すべき点や使うと便利なものはまだまだあると思いますが基本が一番大切だと思うので書かせていただきました。
私がインターン時に初めてRubyを学習した際に先輩からRubyは「クールに書く」「車輪の再開発は良くない」と言われたのを覚えています。
正直その当時はあまりピンと来ていなかったのですが、これらは今回の1、2に通ずるもので実際に書いて修正しながらコードを書いていくうちに言葉の意味が理解できてきました。
先輩方のようなシンプルでかつ読みやすい優しいコードが書けるようにこれからも学習していきたいと思います。
 

おまけ: FizzBuzz

 おまけ程度に書くつもりが結構なボリュームになってしまいましたが、私がRubyを初めて学習したときに見つけたFizzBuzz最短実装を目指す人たちのコードや記事が面白かったので紹介したいと思います。
※FizzBuzzとは1から100まで順番に数え、3の倍数の時はFizz、5の倍数の時はBuzz、15の倍数の時はFizzBuzzと言うゲームのことです。
ちなみにこのFizzBuzzをRubyで何も考えずに実装すると以下のようになります。

(1..100).each do |number|
  if number % 15 == 0
    puts "FizzBuzz"
  elsif number % 3 == 0
    puts "Fizz"
  elsif number % 5 == 0
    puts "Buzz"
  else
    puts number
  end
end

条件文をどうにかしたい。15の倍数はどうにか省略できないものかと試行錯誤して書いてみたコードが以下です。

(1..100).each do |n|
  str = "#{['Fizz'][n%3]}#{['Buzz'][n%5]}"
  str = n.to_s  if str == ""
  puts str
end

配列アドレスに剰余を入れる事によって割り切れるときつまり剰余が0のときに配列の0番目が呼び出されるので3の倍数ならFizz、5の倍数ならBuzz、15の倍数ならFizzとBuzzが両方呼び出されてもしどちらも呼び出されなかったら数値自身を入れて出力するといった実装です。無茶苦茶なコードですが私にはこれが限界でした。
ちなみにRubyを用いた最短コードが51byteで書かれたこのコードのようです。

1.upto(100){|n|puts'FizzBuzz
'[i=n**4%-15,i+13]||n}

面白かったのでこのコードを書かれた方が解説しているページのリンクを載せておきます。
perlだともっと短いコード(最短30byte)で書けたり、FizzBuzzを実装してくれるgemやRubyでもっと変わった方法で実装されている方も多数いました。興味があったら是非調べてみてください。

記事を共有

最近人気な記事