はじめに
こんにちは、ryokkkke(りょっけ)です。
この記事は、アプリサービスの新卒エンジニア1年目を(あらかた)終えた僕が、これから社会人エンジニアになる学生の同志に向けて伝えたい、開発における重要なことを書くものです。
これから社会人エンジニアを迎えようとしている方に、ゆるふわで入社した僕がこの1年目で感じたことをざっとお伝えします。
(自分の1年目の振り返りも兼ねてw)
(あと来年度チームにジョインする新卒のオンボーディングのためにも、こういう資料を残せたらなあと思っている)
「学生のうちは遊んだ方が良いよ」🤔
と言われること多いと思いますが、僕は**「学生のうちに一つでも多くの知識を入れるべき」**派です。
ていうかエンジニアリングに学生も社会人も無いのだけども。
その入社前に入れるべき知識の目安になると嬉しいです。
研修とかある人はあると思いますが、それはきっかけを与えてくれるものであって、自分の血肉となる技術力というのは教わって身につくものではないです。
エンジニアと言っても色々あると思いますが、僕の場合は、アプリ課金がマネタイズポイントとなるサービスで、プロダクトのサーバ・iOS・Webフロントの開発をするエンジニアです。
僕はメインでRailsのコードを書いていますが、もっと低レイヤーだったり型がしっかりしてる言語とかだと事情が違ったりするのかしら。
"ゆるふわ"とは♨️
ここで言う"ゆるふわ"とは、以下のような人です。
- 趣味でコードを書いてきた
- 体系的に情報科学・情報工学を勉強したわけじゃない。
- コードを書くのは好きだが、実際に運用しているサービスのコードを書いたことがあまりない。
- 数万件〜数百万件(もしくはそれ以上)のレコード数があるようなDBを触ったことがほとんどない。
- 実際にお金が動くサービスのコードを書いたことがあまりない。
つまり**入社前の僕です。**スキル的には今も大して変わらないかもしれん。
こういう人が記事書くと強い人に怒られそうだけど、伝えたいんだ、勘弁しておくんなまし。
- 大学1年生僕:「Webデザイナーやりたい!Railsってやつを使うとなんかいい感じにサイトが作れるらしい!」
- 大学2年生僕:「なんや、デザインよりプログラミングの方が楽しいやんけ!」
- 大学3年生僕:「IoT系のベンチャーで1年間エンジニアインターンしてめっちゃ楽しい!」
- 大学4年生僕:「起業した友達と一緒に動画サービスの開発してめっちゃ楽しい!」
- 「エンジニアのエキスパートじゃなくて、サービスを作れる人になりたい!」
- 就職1年目僕:「道のりが険しい(白目)」 <- イマココ
どこかに「これは自分と同じ感じだ!」という部分がありましたら、ぜひこの後も読み進めていってもらえると嬉しいです。
ちなみに僕は主にサーバサイドを書くことが多いので、基本的にこれからの開発の話もサーバサイドのコードを意識して書いています。
ではここから本題、行きます。
コードレビューの単位をなるべく小さくする🔍
なんと言っても新米エンジニアに必要なのはコードレビューです。
コードレビューで「これはクソコードですね」と言われて育つのが新米エンジニアです(血涙)。
これから入社するのであれば、基本的にコードレビューはGithubのプルリクエストを通して行われるでしょう。
ここで言いたいのはつまり、**「巨大なPRを作ってはいけない」**ということです。
「巨大」なPRの定義として確固たるものはないですが、Githubのchange filesのページでスクロール量がやたらと多いものは要注意です。
なぜなら、「コードレビューに要する労力」は、「変更したコードの行数」の増加に伴い指数関数的に増加していくからです。
10 lines of code = 10 issues.
— I Am Devloper (@iamdevloper) 2013年11月5日
500 lines of code = "looks fine."
Code reviews.
PRが巨大になると何が起きるか。
そう、自分では気付けなかった不具合が世に出る可能性も、PR内のコード量に伴い跳ね上がるのです。
「大きいプルリクエスト」とかでググるとたくさん良い記事が見つかるので、数個は読んでおきましょう🦁
検索キーワードが絵本の名前みたいだな。
蛇足🐍
コードレビューというのは非常に厄介なシロモノで、その厄介さを端的に表現しているのがこの文章だと思います。
レビューを依頼するということは、他の誰かに「責任を共有してください🙇」とお願いするということです。依頼された人は問題を理解し、あなたのコードを把握し、問題がなければ(そう願いたいものです)承認しなければなりません。
from 「巨大プルリク1件vs細かいプルリク100件」問題を考える(翻訳)
ともすると、コードレビューを受けるということは、自分のコードの責任をレビュワーの方にも負担させるような意識になりがちです。
「見てもらえるからいいや...」と。
が、ここだけはエンジニアの矜持として否定するべきだと思います。
つまり、誰にレビューしてもらおうと、そのコードを書いた責任は自分にあると思ってコードを書きたいと思っています。
$ git blame
というコマンドをご存知でしょうか。
(皮肉が効きすぎていて、僕はこのコマンド名をあまり好きになれないのですが)
これは指定したファイルのコードを誰が書いたのか表示するコマンドです。
コードの意図を聞きたいときや、最後の更新日などを確認するのにも有効なのでよく使います。
これを見れば分かる通り、誰にレビューしてもらおうと、誰に意見をもらおうと、最終的にコミットした人がそのコードのauthorとして名を残すことになるわけです。
自分の書いたコード、blameされるのは他でもない自分です。最後の砦は自分なのです。
見積もりを楽観視しない📅
今でもまだよく悩むのは見積もりです。
軽い感じで「これいつまでにできる?」と聞かれた時に、なんと答えるかというアレです。
まず前提として意識するべきなのは、
「自分の力量を把握し、正確な期間を出すこと」と、「期待に応える速さで開発すること」は別である
ということです。
「いつまでにできる?」と聞かれると、どうしても「最速の期間を言って信頼されたい」という見栄が、意識的もしくは無意識的に出てきます。
しかし、ここは自分がゆるふわであることを忘れてはいけません。
「今、4日くらいで終わると思った?それ2週間はかかるよ。君は修正が必要なファイルを見つけるのに1時間かけるし、最初に考えていた設計は3日目にダメだと気づいて修正が必要になる。コードレビューでは想像の10倍くらいのコメントをもらって、その修正に3日はかけることになる」
😕.........
1年くらい前の自分に会ったらこんな感じに言うと思います。
これはひどい、と思うと思いますが、僕のリアルはこんな感じでした。
まとにかく何が言いたいかと言うと、開発の見積もりに慣れるまでは、最善の時間ではなく、最悪の時間を言いましょうということです。
さらに言えば、自分が「これくらいかかるだろう」と思った時間の1.5倍から2倍くらいの時間を言っておくと良いです。
ここに関しては自分を信用しちゃいけません。だって色々慣れてないんだもの。
自分の力量だけでなく、知らなかった(もしくは想定以上に時間がかかる)開発フローが社内にあるかもしれないですし、レビューをお願いした方にすぐ見て頂けるとも限りません。
途中で緊急の不具合の対応を頼まれるかもしれないし、はたまた風邪を引くかも...
予想外しか起こらないと意識して、バッファを持つことが重要です。
開発というのは嬉しいことに(悲しいことに?)ごまかしが効きません。
エラーが出ていたら、意図しない挙動があったら、絶対に完了できないのです。
見積もりを早く言ったところで自分の開発速度は上がりません。
見積もりオーバーを数回繰り返すと、「そう言ってるけどまた延期するんでしょ?」と思われて、オオカミ少年もいいところです。
うへぇ、耳が痛い😢
クエリのパフォーマンスチューニングを知っておく🔧
これも学生のうちはなかなか経験しづらいことでした...
僕が学生の時に経験(実際にコンソールで操作)したのは、DBのレコード数なんて最も多いものでも1万件とかでした。
そのレベルだと、どんなに酷いクエリ(SQL)を書いていても、大した問題にはなりません。
その時のプロダクトはユーザー数も数えられるくらいしかいなかったし。
しかーし、運用されているサービスでDAUが5桁とか6桁とかになると話は違ってきます。
リアルタイム性が求められる機能であれば、1クエリに1秒かかっていたらそれはもはや障害です。
意識として必要なのは、自分のPRに含まれるSQLが目的に対して最適なクエリになっているかどうかを調べる必要があるということです。
そして、調べる方法はEXPLAINです。
「SQL EXPLAIN」とかでググるとこれまた解説はいっぱいあるので、ぜひ読んでおきましょう。
SQLを発行する開発を行うのであれば、必ず使います。
その割に、初めて使うと表示の意味が全くわかりません😂
現場で急にレビュワーの方から「EXPLAINした?」と言われて焦ることのないように、最低限の見方を知っておきましょう。
ロック🔒
これまたレコード数の少ないDBやユーザーの少ないプロダクトだと全然気にしない、DBのロックのことです。
このDBのロックも、学生の頃全然体験できないのに知っておかないと現場でめっちゃ困るシリーズの一つになります。
ユーザーが多いサービスでは同時更新とかが本当に起こるので、何も考えないで書いていると意図しないレコードが出来上がります。
ていうかここは僕が現在進行形でヤバい、理解が浅い...
テストを書こう🏝
もうこのフレーズ、見るの何度目?って感じだよね。
でも本当にそうなんだ。信じてくれ。テストを書こう。
テストは、このプログラミングという過酷な荒野でただ一つ僕らを守ってくれるオアシスなんだ...
オアシスの建設にも労力を伴うが.........
でもそれ以上の恩恵を授かれるはず。
少なくとも、入社する先で使用しているテストフレームワークの書き方は覚えておこう。
僕は学生のころRailsでRspecを書いていたから、入社後にRspecだと知った時は本当に安堵した。
FactoryGirl(...おっと、今はFactoryBotか)(軽率な経験アピール)も使っていたし、letの素晴らしさも知っておくことができた。
そういやこの前、テストを書いていてバグを発見したよ。
TDDしなきゃ...
デプロイ環境を自分で作ってみる
これは完全にサーバサイドの話になってしまいますが、めちゃくちゃ重要です。
幸い僕は、友人と一緒に動画サービスを作っていた時にRailsのデプロイ環境をAWSで1から1人で作っていました。
VPC上にサブネット切って、EC2立てて、RDS立てて、ロードバランサー立てて、AMI作って、CloudFormationでインフラをコード化して、AnsibleでRailsのデプロイ自動化して、コマンド叩いて自動デプロイ、みたいな。
特別なことはしていないですが、この標準的な仕組みを全部自分で作っていた経験は非常に貴重だと今感じています。
すでに運用しているサービスにおいては、この辺りってもう強い方が整備済みなんですよね。デプロイコマンドを叩くだけ。
なので業務でこれを1から作ることってまずないと思います。
その割に、障害対応とかになるとインフラの知識も必要になる。
これ自分でやってなかったら絶対わかんなかったな...みたいな話も結構多いです。
何より得体の知れないものを使うというのは気持ち悪いんですよね。
できる限り知っておきたい。
業務が始まってからはゆっくり腰を落ち着けてAWS上に環境を作る時間がとれないこともあると思うので、ぜひ学生のうちにやってみてください。
本番にデプロイしたらやること
頑張ってコードを書いて、やっと本番にデプロイできた!
俺の仕事はここまでだ、さあ次の機能に...
となるのは気が早く、残念ながらこの時点ではまだ開発の仕事は終わっていません。
不具合とは...
不具合は大きく以下の二つに別れると思っています。
1. プログラムがエラーを吐く
エラーへの対策は明確で、機能をリリースしたら、しばらくはログを確認するということです。
ログの確認が何より大事です。
ていうか、基本的に常にログは見ておいた方が良い。
改めてログを見てみたら、なんか怪しいエラーとかWarningが出てたりするから...
エラーの通知機能とかがあるのであれば、通知を見過ごさないように。
2. プログラムのエラーは出ないが、意図した挙動でない
どっちかと言うとよりツラいのはこっちですね。
a + b
を表示するところで間違ってa - b
を表示していたら、プログラム上エラーではないけど、ユーザーから見ればバグなわけです。
可能であれば自分でも機能を触りましょう。
あとは、ユーザーの反応を見るのも大切です。お問い合わせとかTwitterとか。
開発の終わりは
これらの2種類の不具合は、もちろんテストでカバーしようとします。
それでもエッジケースでテストを抜けてくる連中がいるんですよね...
日・月・年の変わり目とか、数字が大きいときとか、データが0件のときとか...
意識として、開発は「リリースまで」じゃなくて、「意図した通りに挙動するまで」だと思った方が良いですね。
はい、肝に命じます。
「本番環境のコンソール」の恐ろしさを適切に理解する
学生の頃、大学の授業のノートを、自分で作ったWiki(Webアプリ)で取っていました。
であるとき機能を追加しようとして、DBのresetを叩いたんですよね。
開発用のDBだと思ってましたが、実際に稼働しているDBでした。
大学のノートが半年分くらい消え去ったわけです。
OH MY GOD WHY JAPANESE PEOPLE RESET A PRODUCTION DATABASE!!!!
...🤔
これ自分の大学のノートだからまだ厚切りジェイソンで良いんですが、商用で起こしたら...マジでツラい。マジで。
ちょっと前に自分は今のチームの本番環境で少しだけやらかしました。
直接影響はなかったものの、それだけでも心底冷や汗かきました。
本当に今後やらかしたくなかったので、チームでの対策実施のあと、自分と同じやらかしを防げるコンソールのコマンドを追加しました。
最初は本番だ...とか思うんですが、だんだん触ってるうちに本番であることにも慣れてきて、油断が出るんですよね。
油断してきた頃がヤバいです。
便利さと危険はだいたいトレードオフなので、本番コンソールを触る際に、絶対に緊張感を忘れないでください。
仕組みで解決⚙
と、言いつつ、基本的にはそういう精神論はやめにして、仕組みで解決できることが最も良いと思っています。
ヒューマンエラーを運用でカバーするのはきつすぎます。
誰かがヒューマンエラーを起こしたとすると、悪いのはそれが起きうる環境だと僕は思います。
誰でも起こしうる失敗ということです。
そもそもコンソールから本番環境にRead以外の処理をする方がおかしいのだから、Readonlyなコンソールにする、とか。
書き込みをすることもあるけど、用途は限られているからその用途だけのためのコマンドを用意する、とか。
もしなければ、自分で作りましょう。
自分のコードやコマンドが不具合を起こしたら
それでもやってしまうことはある...😭
もうあのお腹の底がヒヤーッとなる感覚は味わいたくないですが、そうなったときに落ち着いて対応できるように、必須の行動を確認しておきましょう。
基本的には大規模な障害の場合には、チームで障害対応フローが決まっていると思うのでそれに従います。
1. 適切な方への迅速な連絡、相談
不具合の種類によって対応も異なるとは思うのですが、これは100%必要です。
チームの必要なエンジニアメンバーにはもちろんのこと、ユーザーに影響があるのであればユーザーへの連絡業務をしてくださるメンバーにも報告が必要です。
特に慣れていないうちは、独断での対処が二次災害を生む可能性もあります。
対応策については、すぐに適切な先輩エンジニアに相談しましょう。
自分の評価が、とか言っている場合ではありません。
最優先で阻止するべきことはユーザーに悪影響が及ぶことですし、評価的な意味で言うと、「何かあったときに隠す奴」と思われる方が最悪です。
これは先輩にオススメされた「エッセンシャル思考」という本に書いてあったことですが、人間関係においては、
長期的に見れば、好印象よりも敬意の方が大切である。
至言ですね。
脱線しましたが、メンバーに伝える内容は以下の通りです。
- 何が起きているのか
- ユーザーにどういう影響があるのか
- いつ直るのか
- 今後の行動方針
2. 修正
行動方針が決まったら兎にも角にも不具合を修正しましょう。
焦らずにね。コードの修正が必要なのであれば、どんなに少ない行数でもコードレビューを頼みましょう。
3. 補填作業
もしも必要なのであれば、ユーザーへの補填作業もあるでしょう。
ここはエンジニアだけでなくビジネスメンバーとも相談しながら決めることです。
4. 障害のまとめ
チームの中でルールになっている場合もあると思いますが、今回起きた障害についてまとめましょう。
- 起きた事象
- なぜ起きたのか
- どう修正したのか
- ユーザーにはどういう対応をしたのか
- 今後起こさないために取った対策
エンジニアメンバーに共有すると共に、今後同じことが起きないような仕組みづくりも行います。
大規模障害時に自分ができること
この1年目で、1回だけ徹夜の障害対応をしたことがあります。
しかし、そういったサービスにとって本当にクリティカルな障害に対して、自分があまり貢献できないこともあります。
実際、そのとき根本の原因究明や修正には僕は貢献できませんでした。
そのとき自分が何をしていたかと言うと、以下のことです。
これはもう体験の記録になってしまうのですが、参考程度に書いておきます。
1. エンジニアメンバー以外への状況報告
エンジニア以外のメンバーには、基本的になぜ障害が起きているのかということはとてもわかりづらいです。
つまり、今の状態が回復に向かっているのか否かわからないということです。
そこで、自分はリードエンジニアの方の作業のお供をしながら、他メンバーに技術サイドから現状をお伝えするコミュニケーション役になっていました。
2. 補填のためのコードを書く
原因はなんであれ、機会損失を与えてしまったユーザーの方々に補填する必要がある場合があります。
僕はそのうちの一つの補填方法を他メンバーと相談しながら考え、実際に適用するコードを書いていました。
これは原因究明や修正とは全く別レイヤーの話なので、自分でも動くことができました。
😔
正直悔しいですね。
まだまだ理解が浅い部分が多く、実用に耐えうる技術レベルに達していない部分があるということです。
今後、障害が起きないプロダクトを作り、起きてしまったときに修復できるエンジニアになりたいと思った日でした。
本を読もう
最後に至極当然のことを持ってきてしまいました。
でもこれ本当に重要です。「これ重要です」ってこの記事で何回言ったんだろう。
知識が無いということは、サーバにコマンドがインストールされていないのと同じです。
チームで「ここはHogeという概念を使おう」となったときに、いざ自分の脳内でHogeを使おうとしてHoge: command not found
では文字通り話になりません。
本を読むということは、同じ本を読んだ人と同じ知識をインストールできるということです。
自分のサーバには、便利なコマンドをたくさんインストールしておきたい!
本を読もう。
さて、部屋に積んである未読の本の山をどう解体していくか...
timesチャンネルを作ろう
Slackのtimesチャンネルをご存知でしょうか
Slackで簡単に「日報」ならぬ「分報」をチームで実現する3ステップ〜Problemが10分で解決するチャットを作ろう
僕は中学生のころからTwitterの民だったので、このtimesチャンネルに深く共感しました。
研修中に同期から教えてもらい、チームにジョインしてから勝手に自分のtimesチャンネルを作り、一人でつぶやき始めました。
今では多くのチームメンバーのtimesチャンネルがあり、とても良い流れが出来ていると思っています。
- Slackに居場所が出来る
- 助けてもらえる(かも)
- 自分がチームメンバーを助けられる(かも)
- どうでも良いことを呟ける
- 人となりが知れる
今の僕の課題は、人のtimesにもっと反応する、ということです。
timesの思想的に、発言に反応するか否かは完全に読者側に委ねられており、そこにチームとしての強制力を働かせるとtimesの仕組みは崩壊します。
しかし、僕のtimesにこまめに反応し助けてくれる先輩や同期に、少なくとももっと恩返しをしなければと日々感じています。
僕個人の課題ですね。
もう一つ重要な点
もう一つtimesチャンネルには重要なポイントがあって、それは自分の行動の記録にできるということです。
何かバグにハマったとしましょう。
timesに「なんで動かないんだ、絶対に俺は悪くない」と呟くとします。
解決してからこうつぶやきます「俺のコードのエラーだった...」
(「自分は悪くない」と思った時は、たいてい自分のコードが原因だ)
この何気無い2つのつぶやきによって、自分がどれだけその問題にハマっていたかが後からわかるのです。
その時々で自分が何を思って何に時間をかけていたのかを振り返ることはとても重要で、timesはそれにとても役立ちます。
積極的に呟いていくことで、振り返りに使える強力な記録になるのです。
まとめ
まだ追加したい項目があったりするので、この記事には随時足していきます💡
正直言って、ここに書かれていることには全く新鮮味が無かったと思います。
先人たちが口すっぱく言っていること。
文字にするとなんて当然のことなんだろうと自分に呆れますが、でもこれ全部をちゃんと実行するのはとても難しいです。
入社する前にこれらのことを知っておいたら、僕はもう少しミスをしないでこの1年を過ごせたかも。
それでも、ミスをしながら大量に学びつつ、楽しく仕事をさせてくれるチームのエンジニア、デザイナー、ビジネスメンバーに感謝です。
エンジニアは楽しい!
道は険しいけど!😇
脱ゆるふわしていきます🚀