ソフトウェアエンジニアの基礎レベルと実務レベルのギャップについて
「いいね」ってめんどくさいよねという話
又は、本や、Webサービスで学んだ後、サービスを作るにあたって、独学プログラマーは何をすればいいのかという話です。
Twitterをどう作るか?
Webアプリケーションを学習し始めると、RDBMSを用いたDB設計に関して学ぶことになるかと思います。RDBMSの設計には「正規化」、という非常にわかりやすく学問的に体系化された手法があり、それに従うと比較的容易にDBを設計できるようになります。
多くのエンジニアインターンでは、課題としてよく既存のWebサービスのデータベース設計をしてみなさいと言われます。僕自身もめちゃくちゃ作って、めちゃくちゃいろんな人に課題として作ってもらってきました。
そして、正規化ができるようになり、正規化されたDBを使ったサービスが順調にスケールすると、パフォーマンスの壁にぶち当たるのです。
トランプがTweetした時に何がおこるのか?
トランプにはフォロワーが8200万人います。
正規化されたDBでは、トランプがTweetした瞬間に作成されるのは、Postテーブルの1レコードのみです。トランプのTweetがユーザーのtimelineに表示されるためには、followとfollowerの関係を示したmapping tableとPostテーブルをjoinした、クソでかいテーブルを作成する必要があります。これはもうスケール的に無理、、、しかも、Twitterの規模的にDBはシャーディングされまくっているはずなので、単純にjoinが不可能です。世のTwitterユーザーがタイムラインを表示するたびに、この膨大な処理を行っていたとしたら、遠い昔にTwitterはうごかなくなっていたでしょう。
非正規化戦略とNoSQL
そこで、パフォーマンスのために非正規化という選択肢をとります。
素朴に実装するなら、各ユーザーのTimeline用のレコードをユーザーIDを索引として作ってあげるのです。具体的にはトランプがTweetをした際に、follow followerのmapping tableをトランプのユーザーIDをキーにして全ユーザーを取得し、非同期で世界各地のトランプラヴァーズのTimelineテーブルを更新するのです。
この「データの方をクエリに最適化する。」という方針がNoSQLで取られている立場になります。
Single Data of Truthをどこに置くのか
やっとここから、表題の「いいね」の話に入るのですが、今や、どんなWebサービスにもついていると言って過言ではない、「いいね」機能。
ポチッと簡単に押せるし、見た目もボタンだけだし、すげえ簡単に見えるじゃないですか。あれ、よくよく考えると以下の二つの機能用件が共存するせいで、結構難しいんですよ。
1. いいね数の合計を表示しなくてはならない
2. 自分がいいねしたかどうかを判断できなくてはならない
まず、1に関して、
もしtweetを表示するたびに、集計を行っていたらどんなにコンピューティングリソースが潤沢でも足りないですよね。この時点でいくらTweetが編集不可といえども、Timelineテーブルに完全にPostの複製をするのはよくないということになります。
そして、2に関しては、Timelineテーブルのレコード内に保持すると同時にいいねテーブルを構築する必要がありますね。
以上から、Postの表示用のマスターデータは、いいねの集計データとともに保持する必要があって、Timelineレコードにはそのエイリアスが保存されることになり、Timelineの生成時にはN+1のクエリが必要になります。
このとき、N+1のクエリは、非常にシビアなパフォーマンスが求められるので、例えばTwitterではオンメモリの分散型キャッシュシステムを採用しているわけですね。
Twitterをつくれるか?
ここまで論をすすめると、「Twitterが作れる」にはかなり断絶されたいくつかのレベルが存在することがわかります。
機能を実現する。
生じた非機能要件を含めて機能を実現する。
事前に非機能要件を考え、その達成を見越して機能を実現する。
このどのレベルまでを考慮したシステムを設計できるかが、ソフトウェアエンジニアのレベルの差になると思います。
結局、何が言いたいのか?
プログラマーはググり力が問われます。特に入門期には、ググってググって答えに辿り着く方法を身に付けることが全てです。
このような習慣が身につくと、答えはネット上にあると勘違いしてしまいがちなのですが、実際にネット上にあるのは、単なる局所解です。その局所解が正解であるかどうかは、文脈に依存します。
入門レベルの時に扱うシステムの仕様は、かなり理想化された実験室環境であると考えた方が良く、その場合には局所解の文脈がかなりの精度で共有されます。それゆえ、ググれば理想化された丁寧な解説があるのです。
基礎レベルから、実務レベルへのジャンプは
解に対する興味が、それが解となる過程に対する興味へと移行した時に達成され得ると思います。
この移行の十分条件は、対象としているシステムに対する「主体性」と「責任」が伴うことかなと思います。(精神面以外は、企業の教育方針やタスクの振り方でも達成可能かと思います。)僕自身、独立してから必要だったので分野を問わず非常に学びました。
だから、
「自分で作る」
又は、
「好きなサービスにジョインする」
又は、
「好きな奴のために作る」
をすると、実力は鰻登ると思います。
以上、プロダクトオーナーシップ持ってるやつは強くなるよねという話でした!
エンジニア募集してます!
ところで、弊社では一緒に働いてくださるエンジニアを常に募集しています!募集職種はFrontEndになっていますが、BackEndもInfraも大募集しております!ご興味ある方は是非お話ししましょう!
この記事が気に入ったらサポートをしてみませんか?