フリーランス歴20年の強強エンジニアからのガチコードレビュー集

# はじめに
こんにちは、[まつけん](https://twitter.com/matsuken_web314)です。
早いもので、Webエンジニアになって、**10ヶ月**経とうとしています。
先月末、僕の職場に参画していたフリーランス歴20年の強強エンジニアCさんが卒業されました。（以降**Cさん**と称します）

Cさんには、いつも迅速かつ丁寧なレビューをしていただいてました。
たまに補助で僕のプルリクにコミットを積んでもらうことなどもあり、お世話になった記憶が大半です。

今回はそんなCさんから受けたコードレビューから、今後どう改善していくのかアウトプットして学びを深めたいため、こちらの記事を書きました。

ペアプロしている時の参考になったこともおまけで書いてます。



:::note info
**この記事が参考になりそうな読者**
- Rubyの「アンチパターン」から良いコードを学びたい人
- エンジニア1年目がどんなコードレビューを受けているのか知りたい人
:::


※こちらの記事に出てくるコードに関しては全て`Ruby`です。実務で学んだことなので、出てくるコードは全てフィクションです。(実際のサービスのコードではないです)



# レビュー1: migrationファイルを追加する時「db:rollback」も考慮してね
>〜〜〜〜migrationファイルを作成して、DBをいじるタスクの時〜〜〜〜

Cさん　「migrationファイルを追加するときは必ず`rails db rollback`コマンドで更新前の状態に戻れるのか？　の確認をお願いします。
万一何らかのトラブルがあったときに、元に戻せない・・といった状況はなるべく避けたいです。
`up`の書き方をするならば、`down`も必要そうです」

僕　「その視点はなかったあああ。。。migration実行できて、満足してました。。」

### [Before] アンチパターン
▼ 僕がレビューしてもらったmigrationファイルは以下のように`up`の記述しかなく、マイグレーションの実行はできるけど、`db:rollback`で<font color="red">マイグレーション実行前の状態に戻せない</font>ようになってました。

```ruby
class <クラス名> < ActiveRecord::Migration[7.0]
  def up
    <マイグレーション実行時の処理>
  end
end
```



### [After]　どう改善したか？
▼ `down`メソッドを追加することで、`up`メソッドで行った変更を元に戻す処理を定義しました。
これによって、`db:rollback`でマイグレーション実行前の状態に戻せるようになりました。
```ruby
class <クラス名> < ActiveRecord::Migration[7.0]
  def up
    <マイグレーション実行時の処理>
  end

  def down
    <ロールバック実行時の処理>
  end
end
```
最近で1番勉強になりました。そしてこの記事で、1番伝えたかったので最初に書きました。


:::note 
学んだこと
- migrationファイルを追加したとき必ず`rails db:rollback`でマイグレーション実行前の状態に戻せるかを確認する
:::



### 参考記事
- 以下の記事がロールバックの処理について詳しく書かれてます

https://prograshi.com/framework/rails/rollback_schema-migrations/




# レビュー2: Viewファイルはシンプルに！ロジックは書かない方がいいよ
>〜〜〜〜ビューファイルにゴリゴリロジックを書き連ねてしまった時〜〜〜〜

Cさん　「Viewファイルの中の〇〇の条件分岐はヘルパーの中で１つのメソッドにまとめてほしいです。
ヘルパーフォルダの中にViewで使いたいメソッドがまとまっています。
Viewファイルの中で 長いif文を書くよりも、ruby側でまとまっているほうがプログラムが書きやすいためです」

自分　「何となくイケてないのはわかってたけど、詳細なイメージが沸いてなかったので、ありがたいです！」

### [Before] アンチパターン
▼ ビューにロジックをづらづらと書いてました。（実際のコードは11行くらいありました:sweat_smile:）

``` slim:Viewファイル
- if product.price > 10000
  p 高価な商品です
- elsif product.price > 5000
  p そこそこ高価な商品です
- else
  p 手ごろな価格の商品です
```


### [After]　どう改善したか？
▼ ロジックをヘルパーファイルに切り出し、Viewファイルを1行にすることができました

```slim:Viewファイル
p = price_category(product)
```

``` ruby:Product_Helper
module ProductHelper
  def price_category(product)
    if product.price > 10000
      "高価な商品です"
    elsif product.price > 5000
      "そこそこ高価な商品です"
    else
      "手ごろな価格の商品です"
    end
  end
end
```

:::note 
学んだこと
- Viewファイルにはロジックをできるだけ書かない。できるだけヘルパーやモデルに切り出す
:::


# レビュー3: `.include?`ではなく`==`を使ったほうがいいかも
>〜〜〜if文で`include?`を使って、条件分岐してた時〜〜〜

Cさん　「これでも動くのですが、1つ提案です。
`.include?` は、配列の中に対象の文字列が含まれているか？　を返すときに使われるのが一般的です。
この場合、変数 A は配列ではなく文字列なので、単に `==` で比較したほうが適切かもしれません。」

僕「変数の中に文字列が含まれているかを調べるとき`include？`メソッド、脳死で使ってたかもです。。。」

### [Before] 
レビューで指摘されたコードは、正しく動く状態でした。ですが、変数Aが文字列（String型）だったので、「配列の中に指定した要素が含まれるか」を検証するための`include?`は正しい使い方ではありませんでした。

```ruby
if A.include?('specific_string')
```

### [After]　どう改善したか？
変更後のコードでは、`.include?`ではなく`==`を使うことで、文字列の比較をして、`true` or `false`を返します。

この変更で、コードの意図をより明確にし、可読性を上げることができたかな〜と思います。


```ruby
if A == 'specific_string'
```

:::note 
学んだこと
- `include？`メソッドは配列中に指定した要素が含まれているかを検証するために使う
:::

### 参考

https://docs.ruby-lang.org/ja/latest/method/Array/i/include=3f.html

# レビュー4: `.min`使ったら、5行を1行にできますよ
>〜〜〜ある数値を超えると条件が切り替わる分岐を作ってた時〜〜〜

Cさん「この条件分岐、`.min`使ったら1行にできると思います」
僕「1行？　それはやるべきですね。やり方ググります。」

### [Before]
`(ruby_start..ruby_end).count`が「10を超えるか超えないか」で条件分岐をしていました。
リファクタリングできそうでできないなあと思ってましたが、、、、
```ruby
if (ruby_start..ruby_end).count > 10
   abc = 10
elsif (ruby_start..ruby_end).count <= 10
   abc = (ruby_start..ruby_end).count
end
```

### [After] 　どう改善したか？
リファクタリングで1行になりました。
「配列の中の最小の要素を返す」`.min`メソッドを使うことで、1行にできました。

```ruby
abc = [(ruby_start..ruby_end).count, 10].min
```
`min`メソッドを使うのは思いつきませんでした。。。`if`~`end`の【Before】のコードを見るだけで`min`メソッドを使って1行にできるかもと思いつくのは本当に流石だなあと。。。

:::note 
学んだこと
- `if`~`end`の条件分岐をリファクタリングするときは、どう`if`~`end`を短くできるかだけに囚われすぎないこと
   - Rubyの他のメソッドを使えば`if`~`end`をまるっと省略できる選択肢もあるということ
:::

### 参考
https://docs.ruby-lang.org/ja/latest/method/Array/i/min.html

# ペアプロ中1: 「git addする時、いつもどうやってますか？」
>〜〜〜Cさんとペアプロ中〜〜〜

Cさん　『git addする時、いつもどうやってますか？　
　`git add .`よりも　`git add <変更したファイル名>`とする方が、不要な差分とかが入ってこないので、良いですよ〜』

僕　「ホントだわ。`git add .`は全てのファイルをインデックスにあげちゃうもんな。。。」

### [Before]
Cさんからこの指摘を受ける前は、以下の流れでプッシュしてレビューを受けることが多かったです。
```
git add .
git commit -m 'コミットメッセージの内容'
git push origin HEAD
```



`git add .`で全てのファイルをインデックスに上げると、たまに意図せず変更した<font color ="red">不要な差分</font>が入ってしまうことがあり、Cさんから「不要な差分が入っちゃってます」と指摘されることが割とありました。



### [After] 　どう改善したか？
Cさんの指摘を受け、自分がインデックスにファイルをあげる前（`add`する前に）`git　status`で変更ファイルを確認して、プッシュし、レビューを受けるようにしています
```
git status 
git add <変更したファイル名>
git commit -m 'コミットメッセージの内容'
git push origin HEAD
```


# レビューを受け、重要と思ったこと
自分が完璧だと思ってレビューを受けても、リファクタリングが足りてなかったり、想定する場面が考慮漏れしていたり等々、まだまだ実力不足だなと感じることがありました。

そして、1番大事と感じたのがプルリクを出す前の「セルフレビュー」です。
Cさんみたく門番のようなレビュワーの方がいると、セルフレビューがおろそかになることもあり、レビュワーの方の負担軽減をするため、今後は下記のように「セルフレビュー」により力を入れたいなと思ってます。

- ローカルで動作確認2周
- 「Files changed」で不要な差分が入ってないか確認
- リファクタリングできそうなところは事前にプルリクに書く

<br>

「セルフレビュー大事だよな〜」と思ってた中で、流れてきた最近のこのツイートがめっちゃ刺さり、また見返したいので記事に載せます。経験年数が浅い人は、100回はこのツイートを振り返るべき。

https://twitter.com/engineer_ryoma/status/1671095869683425280?s=20


# 終わりに

Cさんからは本当に学ぶことが多くて、正直この記事に書ききれませんでした。
コードレビューを受けた以外の面でも学ぶことが多かったです。
▼例えば、、、
- 新機能開発の時、チーム全体での進捗共有を円滑にするためのシートを作る
- レビュワーがレビューしやすいように、プルリクの説明欄を動作確認の方法まで丁寧に書く　
  - プルリクの変更箇所を画像付きで書く

他にも色々。。。。



そして、「仕事は楽しむもの」と言ってたのが印象的です。
僕自身、たまに成長することに囚われすぎて、少しナーバスになることがあるので、仕事を楽しむことを忘れないようにしたいなと書きながら思いました。

エンジニアとしての駆け出し期に、模範となる働き方を背中で見せてくれたCさんと働けたのは僕の**財産**です。