まえがき
なぜこの記事を書くのか
前職でエンジニアとして初めて雇っていただき、さらに挑戦したくなり、今年転職しました。
転職してから改めて思ったのですが、前職で教わったことは、今も、これからも、とても役に立つことが多いと思ったので、忘れないうちに残しておきたいと思いました。
ここに書いてあることは、日々の業務の中で判断に困ったとき、他のメンバーに相談する中で教わったこと・学んだことで、今も私が大事にしているものたちです。
前職はどんな環境だったのか
私は文系の大学を卒業して、数年程開発とは全く関係のない営業等をしていました。
空いた時間に個人開発をする間に、ソフトウェア開発を仕事にしたくなって、ソフトウェアエンジニアとして雇っていただくことになりました。
前職の開発チームは、全員で数人の小さなチームでしたが、皆さんが本当に優秀なエンジニアでした。
フロントエンドとバックエンドができるのは当然で、インフラやセキュリティもできたり、ハードからソフトまでできたり、アルゴリズムが超得意だったり、私以外のメンバーは学生時代からずっとバリバリ開発を行なってきた人たちでした。
全員がフルスタックで、要件定義からテストもこなし、お互いに助け合って進めていくようなチームでした。
そんな中に1人、HTTPリクエストが何かもわからない私が参画して、0から鍛えてもらいました。
本題: 前職で教えてもらったこと
1. 日々の業務編
1-1. 15分考えて分からないことは、他のメンバーに聞くこと
15分考えて分からないことは、他のメンバーに聞いた方が圧倒的に早いことが多いです。
特に小さなチームや、歴史が長いシステムの場合、ドキュメント化されていないことも多いので、いくらコードを読んでも分からないことはあります。
1-2. とにかくドキュメント化すること
新しい機能を作る時はもちろん、インフラの設定がわからなくて他のメンバーに聞いた時等、まだドキュメントされていないことは、どんどんドキュメント化します。
忘れてしまってまた教えてもらうとまた工数がかかりますし、他のメンバーが入ってくる度に同じ教える工数がかかることになります。
自分が分からなかったことは、他のメンバーも分からないことかもしれません。
1-3. 明日の自分は自分じゃないので、必ずどこかに書いておくこと
人間みんな忘れます!
自分が忘れてしまったことは、自分が思い出すのはもちろん、他のメンバーが改めて理解しようとすると、何倍も時間がかかります。
今日の自分が「絶対に忘れない」と思ったことも、明日とは言わずともいつか忘れてしまうので、必ずコード内にメモを残すか、チケットを切るか、ドキュメントにするかなど、とにかく残るようにします。
「明日の自分は自分じゃない」と思って、自分と、他のメンバーのために、どこかに残します。
(私は昨日やったことを大抵忘れます!笑)
1-4. 「レビューで見てもらおう」・「テストでバグを見つけてもらおう」と思わないこと
レビュー・テストする人よりも、コードを書く人の方がバグに気付ける可能性が圧倒的に高いです。
レビューする人やテストをする人がバグを見つけるコストは、コードを書いた人の何倍もかかります。
自分で書いたコードはレビューしてもらう前に自分で見直します。
面倒でも、コードを書いた人が動作確認をします。
動作確認が手間な時は、単体テストを書いたり、cURLのシェルスクリプトを書いたりして、工夫します。
2. コードの書き方編
2-1. コメントは極力控え、リファクタリングすること
大抵のコメントは、コードをリファクタリングすれば不要になることが多いです。
コメントを読むよりもコードを読む方が正確です。
変数名を工夫したり、関数を分けたり、クラス化したりと、リファクタリングをすれば、コメントを書かなくてもコードに意味を持たせることができます。
リファクタリングしても、コメントを残した方がわかりやすい時は、その上でコメントを残します。
関数に関するコメントは関数ごとのDocsに極力含めてIDEで補完できるようにします。
2-2. 長い関数はNG、必ずリファクタリングして関数を分けること
長い関数はデメリットをたくさん持っています。
- レビューする時や後からコードを読んだ時に、理解をするのに時間がかかる
- 長い関数は大量の変数名を持っていることが多く、読む時にすべて覚えている必要がある
- 複数の処理を持ち合わせていることが多く、すべて読むまでそれぞれの関係が理解ができない
- 単体テストを書くのも難しい
長い関数は、処理ごとに、複数の関数にリファクタリングします。そうすれば、
- コメントをつけなくても関数名をつけられるのでコード上に意味を持たせらる
- 変数も関数内に留めることができるので、読む側がたくさんの変数を覚えておく必要がない
- 関数ごとにテストを書ける
- 後で再利用できるかもしれない
- 関数ごとにDocsでコメントを残せ、IDEでも参照しやすくなります
再利用をするためというよりも、Readableにするため、関数は複数に分けます。
2-3. 命名は省略しないこと
省略してわかりにくくなるなら、長い名前の方が良いです。
2-4. 1ファイル1クラス・コンポーネント
1ファイルにいくつも処理を書かないようにします。
これにより、ディレクトリ構成を見るだけで、どんな処理が置かれているのかがわかるようになります。
2-5. 関数の戻り値をtuple型を返すのは避けること
tuple型で戻り値を返すと、使用する側で、戻り値の順番を気にする必要があります。
また可読性も下がります。
可能であれば、クラスやオブジェクトにして返します。
2-6. コードを読めば仕様がわかるようにコードを書くこと
仕様書やドキュメントを詳細に書くよりも、コードを丁寧に・後から読んでも理解しやすいように書いた方が、メンテナンスコストが圧倒的に安いです。
2-7. できるだけ、読みやすく、分かりやすく
書いた自分が分かりにくいと思うコードは、他の人にとってはもっと分かりにくいです。
自分でも明日読んだら理解できないかもしれないです。
ここまで書かれてきた長い関数はNG、命名の省略はNGなども、すべてここに理由があります。
3. データベース設計編
3-1. 自分が明日入社して、理解できないテーブル設計はしないこと
データベースのマイグレーションするのが面倒だからという理由で、用途に一致しない既存のテーブルやカラムを使ってはいけません。
後で見たときに、何が保存されているのか分からなくなるテーブル設計はしてはいけません。
何も知らない人が見ても、テーブル名とカラム名を読めば、何が保存されているのか、おおよそ理解できるような、テーブル設計・命名をします。
データベースは、自分がチームから外れた後も残るものなので、コード以上に丁寧に作成します。
3-2. user
テーブルは極力小さくすること
どんなアプリでも、user
テーブルはどんどん大きくなりがちです。
役割ごとにテーブルを分けます。
例えば、認証に関わるもの、権限に関わるもの、ユーザーが任意に設定できるものなど、それぞれ別のテーブルにします。
3-3. 不要なカラムの追加は避けること
カラムの追加は簡単ですが、後で削除・マイグレーションするのはとても大変です。
カラムを追加する前に、本当にそのカラムが必要か、まとめられないかを考えます。
例えば、is_canceled
やis_deleted
はstatus
カラムにまとめられるかも知れません。
3-4. Booleanのカラムは極力避けること
大抵の場合のBooleanのカラムは、まとめるか、より多くの意味を持つカラムにできます。
is_canceled
やis_deleted
のように用途ごとにBooleanのカラムを追加し続けると、テーブルが肥大しがちです。
status
カラムにまとめたり、canceled_date
やdeleted_date
のように、より意味のあるカラムにした方が良いかもしれません。
4. 工数見積もり編
4-1. 自分だったらX時間ではなく、「新しいメンバーが入ったらX時間」で見積もること
プロジェクトが進んで別の人が担当することになったりした時に、見積もりの確度がズレます。
大抵の場合、早くなることは問題がないのですが、遅くなることは問題があります。
急に他の人にお願いすることになっても、問題のない工数で見積もっておきます。
4-2. 工数を見積もるときは、必ずバッファーを持つこと
当たり前かもしれませんがとても大事です。
最後に
振り返ってみると、とても丁寧にレビューをしてもらえる環境でした。
設計書のレビューも、コードレビューも、大抵1回目のレビューでOKはもらえず、何度もレビューしていただいたこともありました。
メンバーも少なかったので、後からフォローし合えるように、理解しやすい・保守しやすいものを作ることがとても大切にされていたのだと思います。
これはチームが変わっても、チームが大きくなっても非常に重要なことだと思いました。