Classiエンジニア新人研修での学び方の学び

Classi Advent Calendar 2019の16日目の記事をご覧いただき，ありがとうございます！
2019年新卒エンジニア@willsmileです．自称コーヒー好きですが，コーヒーのことを語ると，教育と学習の方に“脱線”してしまい，「結局，教育のほうが趣味なんじゃないの」と最近自覚した者です．

# まえがき
本文では，Classiエンジニア新人研修を通じて，自分自身が「気づいた開発について新たな観点（の一例）」を語り，将来の自分，あるいは他の人にも参考できるように，「どうやって気づいたのか」を一段上の観点から言語化することを試みます．

# 本題
## 研修の概要
Classiエンジニア新人研修のカリキュラム担当者が業界で有名なRubyist[@igaiga](http://twitter.com/igaiga555)です．Classi入社前に@igaigaさんが著者である「[ゼロからわかるRuby超入門](https://www.amazon.co.jp/dp/B07KQXFF6D/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)」という本を持っています．それを読んでいて，Ruby言語の概念の厳密さと理解しやすさのバランスをよく取れている本という印象を残っています．@igaigaさんとの初対面の自己紹介で，「あの本の著者だ！すごい！」というびっくりから，研修の一日目が始まりました．

研修の題材と進み方について，[4日目の記事](https://qiita.com/yukoono/items/f403718318abc9ba0c81)で@yukoonoさんが紹介したように，万葉さんの[公開カリキュラム](https://github.com/everyleaf/el-training/blob/master/docs/el-training.md)にベースにして，各課題ステップにおいて，実装案の議論・検討，コーディング，コードレビューと修正といった「疑似体験」のサイクルが回します．このプロセスを通じて，わかったこと・気づいたことをメンターと話し合いながら，一緒に整理することで，これからの業務とつながるように，自分自身の理解を構築（再構築）していきます．これからは，実装案の議論・検討について，一個の例を通じて，自分自身の気づきを紹介します．

## 気づきの経緯
カリキュラムで定義されたタスク管理[システムの要件](https://github.com/everyleaf/el-training/blob/master/docs/el-training.md#システムの要件)の一つとして，「タスクに優先順位をつけたい」があります（以下の図がシステムの目標状態のイメージ）．

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256687/005c42e5-b893-38b5-369a-5f575fa63bda.png)
図1．タスクとその優先順位（イメージ）

カリキュラムの[ステップ6](https://github.com/everyleaf/el-training/blob/master/docs/el-training.md#ステップ6-タスクモデルを作成しよう)において，この要件を満たすために，モデル作成の段階では，タスクの優先順位をValueがStringのEnumで定義という実装案を考えていました．そう設計した理由として，現在の優先順位の仕様（例：低，中，高）を将来的に変更（例：低，やや低，中，やや高，高）があった時にも，対応しやすくなるからです．

```ruby
class Task < ApplicationRecord
  ...
  enum priority: {low: "low", normal: "normal", high: "high"}
  ...
end
```

この実装案を採用して，[ステップ17](https://github.com/everyleaf/el-training/blob/master/docs/el-training.md#ステップ17-優先順位を設定しよう類似した実装経験のある人は省略可)までに進んだ時に，「優先順位を使って，タスクをソートできるようになる」といった仕様に対して，優先順位の順番を表す情報がシステムにはなかったため，ソートの実装ができなくなりました．それを解決するために，以下のようなコードを書いてみました．それは「そう！」，自分が書いたコードなのに，いま改めて読んでも驚きほどの複雑なもので，コードのリーダビリティーがかなり低くなりました．

```ruby
class Task < ApplicationRecord
  ...
  enum priority: {low: "low", normal: "normal", high: "high"}
  PRIORITY_ORDERS = ['high', 'normal', 'low']

  scope :priority, -> (order_of_priority) {
    if %w[asc desc].include?(order_of_priority)	
      if order_of_priority == "desc"	
        priority_orders = PRIORITY_ORDERS	
      elsif order_of_priority == "asc"	
        priority_orders = PRIORITY_ORDERS.reverse	
      end	
      order_by = ['CASE']	
      priority_orders.each_with_index do |priority, index|	
        order_by << "WHEN priority='#{priority}' THEN #{index}"	
      end	
      order_by <<'END'	
      order(order_by.join(' '))	
    else	
      raise ActiveRecord::StatementInvalid	
    end
  }
end
```

この状況を整理して，最終的に，優先順位を”マスター化”する（タスクのAssociationで定義）という実装案にしたが，「なぜこうなったのか？」，「そもそも，このような仕様って，どう選択すれば良いのか」といった疑問を持ち，先輩たちの意見を聞きました．

## 学び方の学び
更に，この経験をメンターと一緒に振り返って，以下のようなかたちで，それぞれの実装案について，様々な意見をまとめていました．

表1．実装案のメリットとデメリットの比較
![Untitled 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256687/807849e1-27b6-bdeb-187f-9ce7a84316f2.png)
注：上の表には，コストという概念を使っているが，この例の場合．プロの人にとって，実装のコストの差があまりなく，適切ではないかもしれないが，ここの意図は「コストというよく見かける判断軸を登場させる」ことである．

それを通じて，「正解って，実はないですね！」ということが初めて気づきました．つまり，それぞれの実装案はメリットとデメリットがあって，どれにするかが具体的な状況に合わせて選択することが重要です．例えば，自分が「最適だ」と思っていた実装案③でも，「何でもかんでもマスターデータにすると，管理するのは大変になっちゃうよ」というデメリットがありますし，最初に却下した実装案①でも，「後からソートしやすいね」というメリットがあります．問題の本質は，コスト，機能の拡張性といったことについてどう考えているのです．もちろん，それについて，ディベロッパーだけではなく，デザイナー，プロダクトマネージャーなどの異なる役割の方を含めて，一緒に議論して考えることは大切だと考えます．
このように，自身の「うまく考えていなかったことで，やっちゃった」経験から，様々な人の知恵を借りて，経験者の補助で振り返ることを通じて，プロのように考える「判断軸」（もちろん，これは氷山の一角にすぎない）を見つけていました．

# あとがき
その2ヶ月間の研修を通じて，@igaiga先生，メンターの@nagatashinyaさん，またたくさんのエンジニアの先輩たちのおかけで，今でも「生きている経験」をたくさん得ました．以下の研修卒業の時に，自分のTwitterのメッセージで，本日の話を締めます．
<img width="589" alt="Twitter_message.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256687/f73d9f57-f210-eb4b-673b-783fa06ab77c.png">
明日の投稿は，メンターの@nagatashinyaさんです．お楽しみに！