これからのサーバサイドエンジニアの話をしよう
この記事はしおだいふく Advent Calendar 2020 20日目の記事です。
昨日ブログの方に掲載した記事の転載でもあります。Zennお試しです。
ここ最近のフロントエンドフレームワークの頑張りとかモバイルアプリの普及とかの理由により、Webのサーバサイド開発といえばAPIな風潮が強まってきました。
実際にはいわゆるフルスタックフレームワークみたいなやつもまだまだ現役ですし、モノリシックなWebアプリと向き合うケースもたくさんありますので、
基礎的なCLIの操作とか5年前くらいの教本に書いてあるようなWeb開発の知識とかもそれはそれで必要になります。
今日はあえてそのへんはいったん脇においておいて、来たる大API時代にサーバサイドエンジニアを名乗って仕事をしていくならば、
こんな事ができるといいんじゃないかなと思っていることを書き綴ってみようと思います。
セキュリティとユーザビリティのバランスを考慮した実装方式を提案できる
「100万円のものを守るために1億円のコストを書けるものは金の無駄」というような話は何度かTwitterでもしたのですが、 これが理解できていないエンジニアがいっぱいいるように思います[1]。
エンジニアが理解していてもチームや組織が理解していないため、妥当な選択をすることができないというケースもよく目にします。
このような状況下ではだいたいなんでもかんでも安全な方に倒れるので、結果としてこれまでに実績のある手法を杓子定規に適用してしまい、
結果としてユーザ体験とかフロントエンドの開発難易度とかが軽視される傾向にあります。
近年の例でいうと、「APIを叩くための認証認可に使われるアクセストークンをブラウザのLocal StorageやIndexed DBで扱うのは危険だから絶対にやってはいけない」
みたいな話をする人がいたような気もしますが、これは典型的なまがい物の安全思想に囚われた例だと思います。
この例で言えば、Indexed DBに保存してもCookieでやりとりしても(あるいは他の何かを使ったとしても)漏れるときは漏れます。
漏れないようにしようとか、漏れたら危ないからやめようとかではなく、(漏れることを前提として漏れたときにどんな被害が発生するか、
漏れたときにどう対処するかみたいな話を開発時から考えておくこと・考えられるだけの知見を備えておくことが重要です。
どの操作にどれくらいのリスクがあるのかはアプリケーションの要件~とやらかしたときのレピュテーションリスク~次第なので、ここでは詳細には触れないでおきますが、
一般的にはアカウントのログイン方式を変えるような操作とかお金の支払いに絡むようなところは高めのセキュリティが必要でしょう。
アクセストークンの安全性を向上させるには、有効期限を短くするとかそのトークンに与える権限を絞るとか、トークンが有効でも再認証を要求するとかいった方法が考えられます。
こういった引き出しを日頃から増やしておくと、いつか役に立つ日が来ます。きっと。
もちろん無意味にリスクを取れというわけではありませんのでそこは勘違いしないでほしいのですが、過剰な防御は損をするだけです。
セキュリティのための機能ひとつをとってみても、どれくらいの価値があるものを守っていて、どれくらいの価値を犠牲にしていて、
リスクが発現したときの対処はどのようにすべきなのかを把握した上で開発されるプロダクトは品質の高いものになると思います。
サーバサイドエンジニアとしてはそのへんをよく理解した上で、周囲にも理解させることができるような(だいたいは技術力に裏打ちされた)信頼感と
簡単なPoCがさっと用意できるようなスキルを獲得するといいのではないかと思います。
強整合性と結果整合性を要件に応じて使い分けることができる
Twitterのいいね数とかをよく見ている人ならご存知かと思いますが、この数字は強い整合性をもって管理されてはいません。
なので、自分が一番最初にいいねしたと思ったら他の人も最初にいいねしたように見えていた、なんてことがよくあります。
これは短期的なデータの整合性を諦めることによりパフォーマンスを向上させている例で、かつユーザ体験を大きく損ねるわけでもないよく考えられた設計と言えるでしょう。
従来のサーバサイド偏重のWebアプリケーションでは、リクエストを送ってからレスポンスを返すまでの間に必要なすべてのデータ処理を完了させるというのが当たり前でした。
時は移ろいAPI、すなわち非同期処理の時代になりましたので、このような考え方からは徐々に脱却していかなければなりません。
すなわち、どの処理は(ユーザ体験を犠牲にしてでも)整合性を担保しなければならない、どの処理は性能を重視して結果整合としても良い、
ただしどの時点までには処理を完了してなくてはならない、といったことを考えられるようになる必要があります。
そしてよくよく考えてみると、絶対にAPI呼び出しと同期的に整合性を取らなければならない処理はそんなにないことが往々にして判明します。
APIを呼び出す側としては、期待する結果がいかに高速に返却されるかが主な関心事であり、裏でどのような処理をしているかには興味がありません。
レスポンスを返すまでに整合性を取る必要があると考えられている理由の大部分は単に実装する側の都合だったりします。
フロントエンド界に首を突っ込んでみてわかったことですが、フロントエンドエンジニアの皆様はすごくマイクロな部分での性能改善にこだわっている[2]ことが多いです。
サーバサイドに携わってきた人間としては、そんな細かいところ気にするよりもっと違うところなんとかしたほうが効くぞという感想を持つことも少なくないのですが、
とにかくそういう頑張りに報いるためにはAPIも性能を大事にしなければなりません。
極端な例を上げるとするならば、デジタルコンテンツの課金システムのようなお金が絡む部分ですら同期的に整合性を取るのが必ずしも必須というわけではありません。
このAPIを利用する側としては、コンテンツが付与されていればとりあえず当座の関心事としてはOKなわけで、お金のやり取りは裏でうまくやっておいてくれという気持ちが結構あります。
パブリッククラウドの発展に伴い、サーバサイドの非同期処理の実装もずいぶん簡単になりました。
これもセキュリティの話と同様ですが、正確な結果を返すことに固執するのではなく、どの処理はどこまで遅延させても正しく完了させることができるかとか、
処理を完了できなかったときにどのようにリカバリできるか、みたいなところまであらかじめ織り込んでAPIを設計できると強いのではないかと思います。
余談: データの正確性自体がそもそもそんなに重要じゃないケースもあるよ
これは確か2年くらい前にクッソ優秀な大学の同級生の講演[3]に参加して得た気づきなのですが、そもそもデータが厳密に正確であることを期待されるシーンはそんなに多くないようです。
講演の中身は専門的すぎて正直ちゃんと理解できていたとは思えんのですが、大意を拾うと「機械学習の結果が本当に正確かどうかは人間にはわからんから、
正確さを求めて時間がかかる処理を頑張るよりもそこそこ精度の高い数字を高速に算出するほうが有効な場面も多いよ」みたいな内容だったと思います。
この考え方は日頃のWeb開発にもかなり応用できるなぁと思って勝手に感動していた記憶があります。
例えば、なにかの投稿時間を「n分前」みたいに微妙にごまかしてみたり、Twitterであればいいね数がめちゃくちゃ増えたときに「xx万」とか丸めてみたり、 といったケースが散見されます。
こうすることで前者であればソートの正確性が要求されなくなったり、後者であれば細かい数字の整合性を無視できたりといったような実装上のメリットが発生します。
もちろんやりすぎは禁物ですが、意外と応用範囲は広いと思います。
非機能要件に応じてマネージドサービスの選定ができる
最近のマネージドサービスは本当に種類が増えてきて、GCPのサービスに絞ってもバックエンドロジックを動かす環境だけでGCE、GAE、GKE、Cloud Run、Functionsなど様々な選択肢があります[4]。
これらはそれぞれに特徴があって、一概にどれがいいとか言えるものではありません。
一般的にはFunctionsのように実行単位が小さいものほどランニングコストとスケーラビリティの特性に優れていますが、
処理の実行環境としてはかなり強い制約があり、実行頻度の低い処理はコールドスタート等の問題と向き合う必要があります。
ここではロジックの実行環境を例に上げましたが、その他ネットワーク周りやデータベースにもさまざまな機能があるのは皆さんご存知のとおりです。
数ある選択肢の中から、要件を満たした上で最も有利なもの、構成がシンプルになるもの、拡張性に優れるものを適切に組み合わせるためのノウハウは磨いておくべきでしょう。
開発者体験を考慮した環境構築ができる
クラウド環境は手軽に構築できる一方で、他人に迷惑をかけずになんでもテストできる環境を用意するのが結構難しかったりします。
最近のフロントエンドアプリケーションはローカル環境でも動作するので、それをどうサポートするか、共用の開発環境と個人で開発しているバグってるかもしれないコードをどう共存させるか、
みたいな日頃の開発フローまで思いを馳せておかないと後々苦しむことになるので注意が必要です。
まとめ
ここに書いた話は、こうなったらいいなぁという僕のポジショントークなので見なかったことにしてください。
Discussion