2020年の振り返り
By kkoudev
2020年の仕事や技術について振り返ってみました。
前年に引き続きReact NativeによるiOS/Androidアプリの開発と、React Native本体への初PR
React Nativeは2020年になってからバージョンアップ頻度が遅くなったものの、
変わらずiOS/Androidアプリケーションの開発に非常に役立っているという印象です。
世の中的にはFlutterの採用事例が多く見られるようになり、そちらへ流れる方も多いのですが、
Reactそのものや言語的な書きやすさでいえばまだReact Nativeに分があるというのは個人的な印象です。
とはいえ、バージョンアップの遅さについては少々分が悪い感じがし始めてきました。
今年は初めてReact Native本体へPRを送ったのですが、これが最終的にマージされたのがPRを送ってから3ヶ月ほど経ったあとでした。
ちなみにこのPRです。
https://github.com/facebook/react-native/pull/29882
このPRは結構致命的な不具合の修正で、0.62系で一度修正されたものの、0.63系のブランチには修正が入っておらず、再び問題になっていました。
これにより何が発生するかといえば、Modalを閉じたときの処理をiOSで正常に処理出来ないという感じです。
Modalのライブラリでよく使われているreact-native-modalでは onModalHide というPropsもあり、それでうまく処理出来るかと思いきや、この onModalHide では正常にModalを破棄したタイミングを取得できず、 setTimeoutで500msほどタイミングをずらさないと上手く動きませんでした。(まだPRがマージされた正式バージョンがリリースされていないので、現在もこのワークアラウンドで対処してます)
そのため、iOSで正常にModalが破棄されたタイミングを取得するには現状 onDismiss が必須になります。
結構影響が大きい不具合だったのと、この修正は一度0.62系のときに修正されたにもかかわらず、
マージされるのに3ヶ月の時間を要するのは予想外でした。
React Nativeの開発体制大丈夫かな?と、不安になるくらいの遅さです。
(単に優先度が低いと思われていたのかもしれませんが)
とはいえ、この手の不具合は今までのバージョンでもいくつかあり、大抵はワークアラウンドで対処可能なものばかりなので、 React Nativeの利点を享受するためのデメリットとして根気よく付き合っていくしかないかなあという気はしています。
MariaDBの不具合によるサービス障害の発生
MariaDBの不具合によってテーブルの復帰ができなくなる(バックアップも損傷した状態になっている)という障害を起こしてしまいました。
詳しくは以下のリンク先で紹介しています。
結果的にMariaDBの不具合によるデータ破損であり、バックアップでも防げなかったとはいえ、ユーザーの皆様に多大な迷惑を与えてしまったと、責任を感じています。
MariaDBの該当issueは以下のURLから閲覧できます。
https://jira.mariadb.org/browse/MDEV-21088
具体的にこの不具合が発生するケースというのが、
「テーブルのプライマリキーに文字列(CHAR、VARCHAR)を使っており、かつutf8やutf8mb4の文字コードを利用している場合に、テーブルにカラム追加を行った後、DB再起動を行ったとき」です。
要するに、UUIDやULIDをプライマリキーにしているケースであれば基本的には該当する可能性が高い不具合で、かつデータが参照できなくなるという致命的な状況に陥ります。
この不具合の面倒なところが、カラム追加した時点でデータが壊れるものの不具合としてはその時点で即発現せず、その後DBを再起動したときに初めて発現するというものです。
その問題となったカラム追加以降もRDSのスナップショットを当然取得し続けてはいたのですが、先述のとおりカラム追加後のデータは既に壊れた状態であり、かつRDSのスナップショットはDB再起動が伴うものなので復旧不可、という非常に厳しい不具合でした。
この不具合は現在のMariaDBでは修正されているようなのですが、当時この不具合が修正されたMariaDBのバージョンがRDSにはリリースされておらず、
また修正バージョンでも一度壊れたデータは結局救えないパターンがあるため、精神衛生的にもさすがにこのような不具合を起こしてしまうMariaDBを引き続き使えないなと判断し、MySQLへ移行しました。
この不具合以外にも、10.3のときからForeign keyまわりでテーブルのデータを閲覧できなくなる不具合がMariaDBにはあり、(このissueの関連不具合としても出てくるのですが)
正直RDBとして大丈夫なのか?と思える不安さがつきまとっていたのが一番の理由です。
ちなみに救えないパターンがあるというのはソースコードの以下の箇所からも伺えます。
https://github.com/MariaDB/server/blob/mariadb-10.4.13/storage/innobase/btr/btr0cur.cc#L503
MariaDBはMySQLを元に作られているから同じでは?と思う方もいるかもしれませんが、
この不具合の原因となった処理はMariaDB独自の処理(上記ソースコードがそれにあたります)であり、その処理のせいで発生している不具合になります。
この不具合に対する事前対処方法
では最終的にこのような不具合にどう対処すればよいのかということですが、
RDSのスナップショットを盲信せず、mysqldump によるバックアップも併せて取ることで被害を最小限に留めることが出来たかもしれません。
DB再起動されるまでこの不具合は発生しないので、逆に言えば再起動する前に mysqldump を日々取り続ける必要があるということになります。
障害当時はDB負荷が上がってMariaDBへのログインすらも不可で mysqldump が出来なかったので、事前にこのような不具合があるということを知った上で、
RDSのスナップショットだけではなく、mysqldump によるバックアップの準備をしておかないと防げない障害だったと考えています。
またAWSにこのような不具合を回避可能なマネージドサービスがあるのかといえば、当時テクニカルサポートの方にもお聞きしたのですがバックアップ用途として回避可能なサービスは現状存在しません。
RDSのスナップショットをS3にApache Parquet形式で転送するサービスがそれに近いと当初は思ったのですが、これは対応バージョンが限られているのと、(当時使用していた MariaDB 10.4系 ではサポートしていませんでした)
壊れた状態(問題となったテーブルへカラム追加した以降)で取ったスナップショットはParquet形式へのエクスポートもエラーとなり出来ませんでしたので、結局有効な手段はAWSとしては提供していないということになります。
そのため、少なくともこの不具合に対しては原始的な mysqldump が一番信頼性が高いという結論です。
そんなこんなで、今までシステム開発してきた中でも最も大変な障害の1つでした。
もしMariaDBを利用されている方がいる場合は、この不具合のあるバージョンを利用していないかどうか気をつけて利用することをおすすめします。
Nuxt.jsによるWebアプリケーション開発支援
ミッコミというサービスの開発マネジメントとLPの作成(コーディング)をさせていただきました。
https://miccomi.com
Nuxtを使って開発しているサービスで、自分としては初Nuxtだったのですが、
メインで開発していたわけではなく、お手伝いとして入っていた感じです。
LPを久々にコーディングしたので、自分のLPコーディング用のプロジェクトもこれを機に以下のリポジトリへ一新しました。
kkoudev/static-site-starter-kit
Webアプリケーションを作成する際、近年はNuxtやNextなどのフレームワークを使う例が殆どですが、
LPのような簡易的な静的ページを作るには少々重いのと、IE対応を考えると無駄なものは入れずに1から環境を作る方が対処が簡単なので
今でもLPはそのように別プロジェクトとして作っています。
grpc-webを使ってのNext.jsによるWebアプリケーション開発
mocriのブラウザ版をNext.jsで作成しました。
APIには grpc-web を利用しています。
iOS/Android版もAPIはgRPCを採用しており、その流れで grpc-web を使っているのですが、
これについては結果的にgRPCを使っていてよかったと思う反面、本家のgrpc-webだとSSR対応ができない問題があったので、
途中で improbable-eng/grpc-web の方に変更するなど、
gRPCまわりは改めて言語やライブラリによって事情が複雑だなと感じました。
Storybookを使った開発による反省ポイント
今回Storybookを使ってコンポーネント作成を先に行い、
そのあとで画面作成を行っていったのですが、Storybookの初回起動がどんどん遅くなって後半の開発効率そのものに影響を与えるようになってしまいました。
Storybookはメンテできると便利な半面、少ない人数での開発に利用するにはあまり深入りしすぎるのは良くないのかもしれません。
特にコンポーネントは実際にNext.jsで作成した画面に組み込んでからでないと影響が読めないこともあるので、最初から画面作成と並行して進めるべきでした。
これはどちらかというと開発の仕方の問題だとは思うので、Storybookそのものの原因というわけではありません。
また、MDXを使ってStoryを書いていたのですが、MDXだと初回起動時のトランスパイル時に型チェックが効かないため、propsの内容が変わってもそのまま何事もなくStorybookが起動できてしまいます。しかし、実際にコンポーネントを閲覧するとエラーになってしまうので、結果的にいくつものStoryが動かなくなってしまうという状態に陥りました。
当初MDXを使った理由は addon-docs を使って見た目の良い画面を作ろうとしたのですが、実際にStorybookを見るのはエンジニアだけだったので、そのようなリッチな画面を見る前にソースコードを見ることが殆どで、まず使うことがありませんでした。
そのため、単なるコンポーネントの表示確認だけで良いのであれば、MDXよりはTypeScriptでCSF storiesを書いていくほうがメンテ効率を考えると比較的良いかもしれないという感想です。
2021年にやってみたいこと
フロントエンド (iOS/Android/Web)
2021年は事例の増えてきたGraphQLをそろそろやってみたいなと考えています。
今採用しているgRPCによるスキーマファーストのAPI開発もRESTに比べるとラクだなと感じていて、
OpenAPIは自分の用途では自動生成コードが微妙なものばかりで馴染まなかったのですが、gRPCはProtocol Bufferの書き方もわかりやすく、自動生成コードも基本的には拡張可能な形で出力されるため扱いやすいなと感じました。
ただ同時にgRPCのクロスプラットフォーム対応は言語によってサポート度合いが違うというところも実感しています。(C++とGoの対応が厚く、それ以外の言語だとそれよりは劣る感じです)
もっともこれはGraphQLを選んだところで同じような事情はあるかもしれませんが、クライアントの変更が多いアプリケーションだとGraphQLの方が上手くハマるという意見もちらほら見かけたので、単純に試してみたくなったという興味本位なところが強いです。
React Native関連
React Nativeではgrpc-gatewayをAPIとして使っているのですが、エンドポイントをRESTと同様に定義しているのが当初から煩わしく感じており、
クライアントコードの自動生成にも対応していないため、正直grpc-gatewayを使ってしまうとgRPCとしての利点をあまり享受できない(ほぼRESTと同じ)と感じています。
これについては昨年から正式対応された grpc-web に徐々に移行しようと考えています。
(React Nativeでもgrpc-webを利用可能なTransportが現在は提供されています)
バックエンド
バックエンドについてはフロントエンドと関連していますが、GraphQLサーバーの構築をしてみたいなと思っています。
現状APIではGoを使っているのと、gRPCでスキーマファーストの開発の良さを感じたため、同様にスキーマファーストで開発可能なgqlgenあたりがいいかなと思っていますが、これについては実際にいくつか試した上でどれを採用するかを決めたいと考えています。
インフラ
インフラではkOps(どうやら最近は O を大文字表記するようになったらしい)にてk8sのクラスタを構築しているのですが、
kOpsのクラスタアップグレードが段々辛いなと感じてきたので、そろそろ利用事例も増えてきたEKSに移行するべきかどうかを考慮しているところになります。
kOpsによるk8sクラスタのアップグレードは毎回masterノードのアップグレードが成功するかどうかを試しつつ、
失敗したら切り戻し、成功したらそのままworkerノードもアップグレードするという形を取っているのですが、
失敗した場合にその原因を特定するのがとにかく辛い感じです。
kOpsのissueを探ったり、etcdのサーバーログを確認したり、各コンテナのログを確認したり等々大変です。(当然、いきなり本番には適用せずに、ステージング環境から試しています)
原因がわかったところで対処できるかもその時々によるので、いずれアップグレードできなくなるのではと毎回戦々恐々としています。
このあたりはもし移行するとしてもどうやって移行させるかなど、まだ課題としている問題もいくつかあるので、
落ち着いた頃に対処したいなと考えています。
OSS活動
昨年はPRを送ることはあったのですが、自分の作りたいものは作れていなかったと感じていたので、
ndwやgvwのようにある程度簡単に作れるけど便利なもの、を思いついたらまた1つは作ってみたいなと思ってます。
まとめ
こうして振り返ると多くのことをやっていたわけではないですが、1つ1つは結構濃い内容だったかなと思いました。
2021年もこの調子で色々と技術的な挑戦をしていければと思います。