2021/9 新人が知らない技術を身に着けるまで(Node.js非同期処理編)
初めまして、2021年4月、大阪事業所に新卒で入社した山口と申します。
大学時代は文系の学部で、プログラミングは全くの未経験で入社しています。
そんな私は配属されて間もなく、Node.jsで非同期処理に関する実装を行いました。
まだ非同期処理を完全に理解できたわけではありませんが、本稿では、完全未経験の新人の視点でいろいろ気づいたことを共有していこうと思います。
非同期処理とは
まず、簡単に「非同期処理とは何か」ということを説明いたします。
プログラムは基本的に、上から順に実行されます。裏を返せば、後ろのほうの処理は前の処理が終わらないと実行されません。これを「同期処理」といいます。
一方「非同期処理」は、誤解を恐れずに言うと、前の処理が終わらなくとも、後ろのほうの処理を行います。
非同期処理は料理でいうと、「オーブンでクッキーを焼いている間にボウルなどを洗う。」というイメージでしょうか。
同期処理だと、クッキーを焼いている間はなにもしていないので、洗い物をその前や後に行う必要があります。
どんな実装をしたか
「AWSのS3のあるバケットにファイルやフォルダーをアップロードしたときに、SQSとLambdaを介して別のバケットにコピーし、元のバケットにあるファイルを削除する。」という処理を実装しました。
ここからは、簡単に用語の説明をいたします。ご存じの方は読み飛ばしていただいて構いません。
-
AWS: Amazon Web Serviceの略。Amazonが運営しているクラウドサービスで、極端な話、webに関することなら大体AWSでできる。
-
S3: AWSが持つストレージサービス。バケット(データを保存するためのバケツのようなイメージ)にデータを保存しておくことができる。
-
SQS: AWSが持つメッセージキューイングサービス。データの送受信にSQSを介することで、受信側の状態にかかわらず送信側はメッセージを飛ばして、別の作業に移ることができる。
-
Lambda: AWSが持つプログラム実行環境。イベント駆動といって、特定の処理が来た時だけ、プログラムを実行してくれる。
非同期処理で苦労した点
本章では、私が実際に非同期処理を学ぶ上で苦労した点を3点ほど説明いたします。
1. SQSが非同期処理で動いているという実感が湧かない
非同期処理のたとえは調べればいろいろ出てきて、非常にわかりやすいのですが、「じゃあ実際のシステムでどう活躍しているのか」がピンと来ませんでした。
私のように経験が浅い人は、なにが軽い(早い)処理なのか、重い(遅い)処理なのかという感覚があまりないと思います。そこがピンとこない原因かなあと感じています。
正直、今もピンと来ていませんが、そこは実際のシステムに触れていくなかで身につく感覚だと思っています。ただ、ピンと来ていないながらも、先輩にサポートしていただくことで実装できました。自分の経験不足は、チームメンバーの経験で補いつつ、自分の経験値を積むのが大事だと感じます。
2. プログラミングの基礎能力が足りていなかった
非同期処理にはPromiseインスタンスと呼ばれる、javascriptにあらかじめ組み込まれているインスタンスを使用します。 非同期処理が成功した際にはFulfilled,失敗した際にはRejectedになります。
このPromiseというのが曲者で、私にとってはなかなか理解が難しかったです。Promiseは直訳すると、「約束」ですが、動作からはあまり「約束」という感じがしませんでした。
現在主流のasync/await文は、かならずこのPromiseインスタンスを返します。当時の私は、非同期処理にかかわらず、関数が何を返すのか、どんな型なのか、そのあたりをあまり意識せずになんとなく書いていました。
なので、非同期処理を書いているときも、何が返ってきているのかよくわかっていませんでした。そんな状態で書いていると、当然なにがしたいのかよくわからない処理ができてしまいます。
Promiseインスタンスという、私にとっては難しい概念だからこそ、基礎的なところをしっかり押さえる必要があると改めて感じました。
3. インプットとアウトプットのメリハリ
「資料をすべて読んで理解して、それからソースコードを書く」ということは難しく、必要な部分だけをかいつまんで学習して書いていく、ということになりがちです。
ただ、かいつまんでいるだけでは正しいソースコードを書くことは難しいでしょう。ましてやソースコードを書くのに慣れていない未経験の新人ならなおさらです。
学生時代のレポートでは、必要箇所だけかいつまんで書いても単位がもらえた。という経験がある方も多いと思います。しかし、社会人になると、それではなかなかうまくいかないということがわかりました。
私も今回の実装において、最初は非同期処理をかいつまんで理解して実装しようとしていました。その結果、インプットとアウトプットを並行してどっちつかずな状態になってしまい、理解も進まず、進捗もよくないという日がありました。
その解決策として、「インプットとアウトプットのメリハリをつける」ということがあげられます。私の場合は意識するだけでしたが、上司と相談して、「今日の午前中は資料を読んで、午後から実装しようと思います。」という風に業務時間内でインプットとアウトプットを明確に分けるとより良かったなと感じます。上司と取り組み方針を共有しておくことで、 心理的にもインプットに専念しやすくなります。
実装の段階でつまずいたとしても、インプットに専念していた時間の分、どこに戻ればいいかがわかりやすくなるというメリットもあると思います。もちろん、インプットの段階で詰まった箇所があれば、その時点で基礎に立ち返ることになります。
難しい概念に直面することは多くありますが、丁寧にインプットを行うこと、インプットとアウトプットのメリハリをつけることの大切さを知ることができました。
非同期処理を学ぶには
JavaScriptで非同期処理を学ぶにあたって、私はこちらのサイトを参考にして学習しました。
現在はasync/await文が主流なのですが、それまでの過程を踏まえないと使いこなせない部分があるので、時系列順にまとまっているこのサイトは大変参考になりました。
非同期処理についてはいろいろな資料がありますが、ここまで体系的にまとまっているものは少ないと思います。非同期処理はJavascriptのなかでも進化し続けている処理で、古いものだとasync/await文が載っていなかったりします。
結構ボリュームがあるので、下記のように三回に分けて理解するのが良いと感じました。
非同期処理をやってみて
非同期処理を学んだことで、いろいろ気づく部分がありました。それを紹介して本記事を締めさせていただきます。
1. かいつままず、基礎を着実に抑える。詰まったら基礎に立ち返る。
新しいこと、難しいことを学ぶ際にはどうしても下地が必要になります。それはプログラミングだけではなく、今回でいうSQSやLambda、S3といったアーキテクチャに関する内容も含みます。
基礎のインプットをおろそかにしてもよい実装はできません。インプットとアウトプットがどっちつかずにならないように、メリハリをつけて取り組む必要があります。 前述した参考サイトのような体系的にまとまった資料を、かいつままず、一歩一歩抑えてゆく。ということは遠回りのようで、近道なのかもしれません。
そして、インプットでもアウトプットでも、詰まった点があれば恥ずかしがらずに基礎に立ち返ることの重要性も学ぶことができました。
2. 難しいことを学ぶと自分の弱点が良く見えてくる。
難しいことを学ぶと、「なにがわかっていないのか」を明確にする必要が出てきます。その副産物として、「なぜわかっていないのか。」も明確になってきます。アーキテクチャがわかっていないのか、プログラミングの基礎がわかっていないのか、それとも非同期処理特有の書き方がわかっていないのか。
そこをつぶしていけばおのずと理解も深まります。
私も非同期処理にチャレンジする際は「難しそう…研修上がりの自分にできるかな…」と不安になる部分はありました。しかし、あえて難しいチャレンジをさせていただいたことで、非同期処理の理解だけでなく、自分のプログラミングに関する苦手な部分に気づき、対策することができたという点で、有意義な経験を積むことができたと思っています。
本稿を通して、同じように初めての技術を身に着けようとしている新人の参考になれば幸いです。