経験は何よりも饒舌

10年後に真価を発揮するかもしれないブログ 

はてなサマーインターン2020に参加した

はてなリモートインターンシップ2020 - 株式会社はてな に参加しました。

長文になると思います。
成果発表のスライドを貼っておくのでこれだけでも見てください。

speakerdeck.com

参加するに至るまで

はてなは近くて遠い会社でした。
エンジニアとしての職を探しさまよっていた時期も、京都、しかも通学経路に本社があることは知っていたのですが、技術力が相当高い会社であることも知っていたので、受かるわけがないと思いバイトも受けていませんでした。
今回のインターンシップも、これまでインフラの業務経験があるわけでもなく、趣味でDockerやk8sをゴリゴリ使っているわけでもなかったのですが、一縷の望みをかけてdocker run --rm -it hatena/apply-for-internship-2020:latestコマンドを叩いた結果、面接の機会をいただきました。
面接は、今までで一番自己肯定感が上がった面接でした。
アプリをストアに2本リリースしていたり、Qiitaで記事を70記事程度書いたり、atcoderのメモを 競ぷろぐ にまとめていたりと、結構アウトプットが溜まっていたので、そこを中心に話が進み、評価されたのだと思います。
また、自分のエンジニアとしての素質にも触れていただき、自信が湧いた感覚を今でも覚えています。
はてなのことをずっと知っていて志望動機が高かったのも伝わったと思います。
気持ちよく面接が終わった2時間後くらいに、サマーインターン内定の連絡が来て、まじかと思いました。
その勢いに乗っかって、バイトの面接も受けることにしました。
インターンの面接時に、バイトもしたいということを言っていたので、たぶんいけるだろうという自信と、先のインターンの5日間のパフォーマンスがめちゃくちゃ悪くて自信がなくなってしまうという事態も考慮して、絶対今受けた方がいい、と思ったのもあります。
バイトの面接では、夏休みが暇になることは確定していたため、インターンの前にバイトを始めることにちょっとした違和感も覚えつつ、8月からいけるという話をさせていただいたところ、8月から入社させていただく流れになりました。
うまく言語化できないですが、他のインターン生に対して、インターン開催の前にはてなに在籍しているという若干のずるさ的な感覚を若干感じていたのですが、自己紹介ページに actions-gh-pages の中の人や、アメリカから参加される方など、錚々たるメンバーが揃っていたので、ずるさ的な感覚が畏怖で消え去ると同時に、バイトはバイトで、インターンインターンで自分のやれることを精一杯やろう、という気持ちになりました。
先ほど記述した通り、これまでインフラの業務経験があるわけでもなく、趣味でDockerやk8sをゴリゴリ使っているわけでもなかったので、講義があるといえど、さすがに知識の補強をしないとまずいと思い、発表スライドの最後のページに記述した予習などをしておきました。
これはほんとにやってて良かったと思います。
他におすすめの本や動画があったら教えてください。

1日目

講義がありました。
普段は情報系の学部にいないため、技術の講義を受けるのは新鮮で、内容もわかりやすく、非常に勉強になりました。
ただ、事前に詰め込んでいた前提知識だけでは理解できない部分も少なからずあり、思考が停止していた時間もありました。
後にも書きますが、やっぱりネットワークやインフラの基礎知識が全然足りてなくて、今まではコマンド叩けてるだけだったことを痛感しました。
全体を通して言えるのですが、あとでしっかり復習したいと思いました。
話題のDockerQuizは、brew install aquasecurity/trivy/trivy の終了を待っていたら時間切れになりました。

講義が終わったあとの1時間くらい、ちょっとだけ実装する時間がありました。
しかしその時間は、Istio導入後の再起動時に、make up でサービスが立ち上がらない、という環境構築の問題を解決する時間となってしまいました。
k8sのエラーログとは初めましてで、どうしたらよいか分からず、Reset Kubernetes Cluster を押して make up叩いて祈る、みたいなことを繰り返しては落胆していました。
インターンの事前課題は、make upでサービスを立ち上げましょう、という課題で、その時は立ち上がっていたため、その時の状態に戻すしかないと思い、zoomでの歓迎会をしているときに、Docker Desktop for Mac の再インストールや git clone をしていました。(話はちゃんと聞いていた)
この環境構築でつまづくインターン生は他にもいたようで、成果発表の時にきちんと原因を突き詰めて発表していた方もいたので、それができるようになりたいです。

2日目

1つ目の課題である、基本的な記法の実装と、独自記法の実装をしました。
これから出てくるライブラリの説明やリンク等々は成果発表のスライドにまとめてあるので見ていただければと思います。
基本的な記法の実装は、goldmarkの力ですぐにできました。
とはいっても、レポジトリのファイル構成が今まで経験したことのない構成だったので、どこをいじればどう動くのかを掴むのが大変でした。
このときはまだマイクロサービスを構成している、という理解がまだできていませんでした。
独自記法の実装ですが、これもまた難しかったです。
ASTやParserに関しては申し訳程度の知識があるのですが、短い期間で自作Parserを作れる気もせず、とりあえずgoldmarkのソースコードを読んでみることにしました。
2時間程度ソースコードを読むために費やし、なんとなく仕様が掴め、既存のコードに自分なりの記法を足すことにしました。
そこで生まれたのが「xyz記法」です。
おなじみの マークダウンのチェックボックス記法 - [x]のnodeを拡張し、- [y]- [z] にも対応させてみよう、と思い実装しました。

// NewTaskCheckBox returns a new TaskCheckBox node.
func NewTaskCheckBox(checked bool, ranged bool, colored bool) *TaskCheckBox {
	return &TaskCheckBox{
		IsChecked: checked,
		IsRanged: ranged,  // 追加
		IsColored: colored, // 追加
	}
}

実装に取りかかってからは詰まった部分はあったものの、正規表現をゴリゴリ書いたり、ASTの構成を変える必要はなかったため、ソースコードを読み解くほど難易度は高くありませんでした。
しかしその分、拡張することが目的となってしまい、独自性や実用性は薄れてしまったのがトレードオフでした。
なにはともあれ、goldmarkのextensionのコードを流用したり、testutilを利用してテストをサックリ書いたりと、既存のコードをうまく生かして2日目を食らいつけたのはよかったです。

3日目

2つ目の課題である、タイトルの自動取得機能の実装をしました。
URLからタイトルを取得する機能は、goqueryを使ってサクッと実装できたのですが、その独立した機能を他のマイクロサービスとgRPCによって統合するのがとても難しかったです。
他のrendererやblogなどのサービスがどのように実装されているのかを参考にしつつ、理解半分、コピペ半分で実装を進めました。
この実装は、podを増やしたことによってmake upが再びコケるなど、結構時間がかかってしまい、翌日に縺れ込むことになりました。
ちなみに最近は質の良い睡眠を心がけているため、寝る前にパソコンを開けることはしていません。
しかしインターン期間中は周囲がレベチであるが故の不安やら新技術に対する興奮やらで3/5日睡眠導入に失敗しました。

4日目

statusCheckDeadlineSecondsを伸ばしてなんとかmake upを成功させたのですが、gRPCによる通信がなぜかうまくいかなかったので、メンターさんと一緒に画面共有でトラブルシューティングすることになりました。
いろいろデバッグをしても原因究明には至らず、諦めかけていたのですが、ふとした瞬間に試してみると上手くいく、という、よくありがちな気持ちの悪いトラブルシューティングとなりました。
原因は究明できていないですが、podの再起動に時間がかかっていた、というのが一番有力です。
しかし、デバッグの仕方や、バグ発見の勘所などを、その時間を通して得られたので、貴重な経験になりました。

2つ目の課題である、タイトルの自動取得機能の実装と統合が終わったので、発展課題を進めることにしました。
これは自身の弱さが一番露呈したところなのですが、並行処理や、リバースプロキシ、キャッシュの実装に対する知見、経験がなかったため、robots.txt を解析してクロール禁止サイトに対するスクレイピングをしないようにする、という機能を実装することにしました。

robots.txt の解析に便利なpythonモジュールがあったため、せっかくのマイクロサービスだし別言語での実装ができたらかっこ良さそうというノリで実装をはじめました。
Dockerfileやcompile、gRPCの定義を、コピペではなく自力で考えて実装することで、システム全体に対する理解度が上がりました。

mkdir -p python/inspect
docker run -v "$(pwd):/pb" -w /pb --rm hatena-intern-2020-protoc-python \
    python3 -m grpc_tools.protoc -I./ --python_out=./python/inspect --grpc_python_out=./python/inspect inspect.proto
mkdir -p ../services/inspect/pb
cp -r ./python/inspect ../services/fetcher-go/pb
cp -r ./python/inspect ../services/renderer-go/pb
cp -r ./python/inspect ../services/inspect/pb

protoファイルからpythonのコードを生成することはできたのですが、ファイルが2種類生成され、「あれ?Goと全然違うじゃん」となり困惑していたら時間切れになってしまいました。
今振り返ってみると、gRPCをpythonで実装するコストの大きさや、講義でも紹介されていた、サービスを分割する基準の失敗パターンである、「サービス内の概念ごとに無条件で分けまくる」、「一つの機能を出すのに多数のサービスをデプロイ」に当てはまりかねない設計だったため、Goでパースした方がよかったのかなぁ、とも思います。

5日目

成果発表がありました。
独自記法や実装方針が十人十色で、とても聞いていて楽しかったです。(発表がトップバッターでよかった)
ASTの構造まで踏み込むことや、並行処理、リバースプロキシ、キャッシュの実装やCI/CDの構築に対する知見、経験の差が出たかなぁと思います。
2人のインターン生に対してメンターが1人つき、Discordの部屋でそれぞれ作業する、インターン生は作業のログをScrapboxに残し、それがDiscordの別チャンネルに流れてくる、という形式でした。
他のインターン生のログや発表内容が高度すぎて理解できない部分があり、経験年数の違いがあるといえど、3日間の実装でここまで差が出るのは悔しいという感情と、そこまで引けを取っていないという自信とでちょうどいい感情になりました。
5日間の成果であるスライドやこのブログを10年後に見ても、頑張ったな〜となると思います。(同時に社会学部にいたことを忘れている)

感想と今後の展望

5日間で進化した点を簡潔にまとめると、

  • 事前に補強した知識を生かすこと
  • ソースコードを読みに行ってアイデアを絞り、自分で手を加えること
  • k8sやgRPCといった技術を、開発を通してキャッチアップすること
  • システムや実装の設計を俯瞰で捉えること

があげられると思います。


今後は、はてなで戦力になることを最優先の目的としつつ、学生生活もまだ長い(院に行く可能性は100%ないけど)ため、自分の実力を試していけたらいいなと思っています。

5日間を共にしたインターン生やメンターの方々、ありがとうございました。
これからもよろしくお願いします!