2024.10.10
将来は卵1パックの価格が2倍に? 多くの日本人が知らない世界の新潮流、「動物福祉」とは
Nuxt × Typescript × Graphql with Appolo で開発するつらみ(全1記事)
リンクをコピー
記事をブックマーク
樋口鉄朗氏:合同会社DMM.comオンラインイベント事業部の樋口鉄朗です。(※取材当時)今回は「Nuxt × TypeScript × GraphQLで開発した際のつらみ」についてのTipsを説明していきたいと思います。よろしくお願いします。
私は公立はこだて未来大学出身で、2019年に新卒でDMM.comに入社しました。趣味は自転車に乗ったり、旅行したり、ドライブに行ったりすることで、多趣味なエンジニアです。
以前は動画配信事業部に所属していて、売上グロース施策の関連開発などを担当していました。また、プラットフォーム事業部では、事業部内のシステムのリプレイスなどのプロジェクトを担当したり、運営事業部チーム向けのアプリケーションやbotを開発したりしていました。
現在所属しているオンラインイベント事業部では、オンラインイベント展示会「DMM showbooth」のCMS機能のフロント部分の開発を担当しています。担当している技術領域はJavaScript、React、Next、Nuxt、Vueなどで、さまざまなフレームワークを触っています。またPHPやGolang、Pythonなども少し触っていて、卒業研究ではSolidityで書いたスマートコントラクトを作っていました。ほかにも、「Mastodon」のサーバー管理をやっています。
それではここから本題に移っていきたいと思います。これはとある案件の話です。プロダクトについての詳細はお話できないのでTipsのみの説明です。ご了承ください。
今回のアジェンダです。Vue2とTypeScriptの組み合わせがつらい話と、GraphQLがつらい話の2点です。
「私、2019年新卒のてっちゃん! 既存システムの改修案件が一段落しそうなところで、突然案件が降ってきた! 『ねぇ。ちょっと楽しいことしない?』。NuxtにTypeScriptにGraphQLを使ったフルSPA(Single Page Application)! あまり触る機会のないモダン環境で開発できるよと誘われ、技術領域のモダンさに目を奪われていたら、背後から迫ってくる納期に気づかなかった!リリースは12月、アサインは6月。フロント開発人数は自分を含めて3人。初めてのVue。これから私、どうなっちゃうの〜??」という案件を担当したときの話です。
ざっくりとしたフロントの仕様は、WebViewがほとんどの、ネイティブアプリケーションライクな何かです。すべてキーボードで操作できる必要があります。動作確認対象のブラウザは1つだけですが、デバイスに入っているプリインブラウザです。アクティブフォーカスが見やすいようにアニメーションが必要です。既存のアプリケーションのデザインは、ほぼ移植するので、リプレイスに近いものになります。
技術仕様や置かれた環境ですが、事業部初GraphQLとTS(TypeScript)を導入しました。また、事業部2例目のNuxtを使ったSPAの開発です。GraphQLは、既存のAPIをリプレイスしていくためのBFF(Backends For Frontends)的な役割として導入することが決定しました。TypeScriptはJS(JavaScript)の“つらみ”を軽減できるのでは? と試験的に導入することになりました。
SPAの開発は以前の経験があったので、そこまでは苦労はしないだろうという環境での開発でした。
では本題に移りましょう。「Vue2×TypeScriptがつらい! 〜Vue3以前の型推論のない世界〜」にご案内します。嫌ですね、そんな世界。この案件を開発したときは、2.6がVueの最新だったので、Vue3のTypeScriptサポートが受けられなかったということを前置きしておきます。
まず、Vueについて解説をします。言わずと知れた、UI構築のためのJS(JavaScript)のフレームワークです。プログレッシブフレームワークという、部分採用可能な仕組みを取り入れているので、HTMLの一部だけをVueに置き換える書き方ができて、弊社のシステムの一部でもこれが動いています。
また、1つのファイルにHTMLのテンプレート構文を記述して、HTMLタグ、styleタグ、scriptタグで、各ロジックを分離して書けるので、1つのファイルで1コンポーネントを実現する単一ファイルコンポーネントと呼ばれる書き方が可能です。
具体的にはこんな感じですね。templateタグ、scriptタグ、styleタグと分けて書くところで、本来だったらファイルが全部別れているものを全部1個にまとめて書けるのがVueの特徴です。
続いて、TypeScriptの話をしておきます。動的型付けのスクリプト言語であるJavaScriptに対して、静的型付けを提供するスーパーセットです。とても良いものなんです。ただ、「VueのTypeScriptのサポートが完璧だったならば」という前置きが入るんですね。
ここがつらいよ、Vue。Vue2.6でTypeScriptのサポートがかなり進んだので、TypeScriptを入れようと気運が全体的に高まっていた時期でした。しかし、Vue2系のTypeScriptサポートは型推論がほぼ使えない状態でした。例えば、computedにhasNext()みたいなメソッドを生やした場合、このhasNext()の返り値は内部の型推論が効かないのでany型になります。
TypeScript tscがstrict modeの場合は、エラーになることがほとんどです。さらに言うと、booleanと型明示を絶対付けないといけないのはもちろん、1ヶ所でもこれが欠けていると、かなりの高確率でVS CodeのVueのlinterであるveturがプロジェクト内すべてを指して、シンタックスエラーですと吐いて、エディタが真っ赤に染まります。
また、「Vue Apollo」を使っていたんですが、ここの書き方が正しくてもVue ApolloのTypeScriptサポートが中途半端だったので、アサーションをしないとまともに型周りのサポートが入らないという残念な仕様でとても苦労しました。
どう書いてもany型になるので、どこかしらでアサーションをかける必要があります。TypeScriptを書いているのにアサーションを使うということに負けを感じて、「なんかなぁ」という感じでした。
また、Vueに「dollar」プラグインみたいなものを入れていると、これも型が付かないんですね。Vueのdeclareで型を明示してもなぜか吐かなくて、この下のほうに書いてあるconst dollarApolloみたいな感じで、「そのthis.$apolloはDollarApolloですよ」という型を入れないと、まともに型が付かないのがVue2.6のTypeScriptサポートのつらい世界でした。
今はVue3が正式に登場していて、Composition APIの登場で、ReactのFunctional Componentみたいなものが作れるようになりました。しかもVue2よりも厳格で、きちんと型推論の効くdefineComponentという型が登場したおかげで、TypeScriptをVueで書くのがかなり楽になりました。
実際にお試しで、運営さん向けツールとして作ったものがあるんですが、きちんと型推論が効いていました。今までだったらany型になっていた、downloadLinkEnable()もきちんとbooleanと型推論が出ているので、「あぁ、すごい!」と、感動を覚えましたね。
みなさんは苦労しなくていいと思います。とりあえずVue3を使いましょう。この問題に直面したときのVue2.6はとてもつらかったです。何も言いません、Vue3を使ってください。
では次の「GraphQLがつらい! 〜レガシーAPIベースで作り上げたクエリに支配された世界〜」の話に移ります。これはまた嫌な世界ですけどね。
API向けのクエリ言語のGraphQLですが、REST(Representational State Transfer)で使われるopenapi.jsonやhoge.json(任意のjson)みたいなファイルに代わってgraphql.schemaというスキーマファイルを定義することでクエリを構築していきます。
REST(Representational State Transfer)のAPIと異なって、1リソースごとではなく、そのリソースの必要な情報のみをクエリ定義できるのが特徴で、必要な情報のみをやることによってリクエストを最小限にしたり、DB負荷を抑えるたりできるのが特徴です。スキーマ設計が正しければ……です。
もともとはREST(Representational State Transfer) APIを使う予定だったんですが、バックエンドの技術力向上と将来性を見込んでGraphQLを使いたいとなりました。「あ、ふーん」と、この時点でちょっと私は暗雲が垂れ込めているなと感じていました。
GraphQLは、レガシーAPIからの置き換えを将来達成するためのBFF(Backends For Frontends)みたいな中継ツールとして使っていました。なので表側のリクエストはGraphQLでできますが、裏は今までどおりレガシーAPIでリレーしていました。このレガシーAPIは、機能ごとの関数がAPIとして生えているSOAP(Simple Object Access Protocol)的なものだったので、結果としてAPIの数だけクエリが生えるという状況が生まれてしまいました。
また、スキーマの命名規則について、フロントエンドとバックエンドのエンジニア間の合意がうまく取れていなかったのに加えて、バックエンドエンジニアとの調整不足により、「hogeItemListItem」「hogeListItem」「HogeItem」みたいな、多様性溢れる命名がたくさん誕生してしまって、フロントエンド側が「なんじゃこりゃー!」という状況になりました。
また、TypeScriptを利用したときに、「GraphQL Code Generator」でスキーマファイルから型定義を自動生成して、レスポンスに対して型を自動で当てていた結果、全部違う命名がそのままフロントエンドに返ってきて「命名違いすぎ! なんでや!」という状態になってしまいました。
QA期間を経て、1ヶ月間でリファクタリングを実施しました。スキーマファイルを一括で直す作業が行われたのですが、ローカルの開発サーバーを立ち上げるときにスキーマファイルを再取得するフロントエンドの処理をpackage.jsonのスクリプトに書いていたので、すべてのフロントエンドのPCで開発環境が壊れるという事態が起きました。「開発環境オワタ」という感じですね。
いろいろな“つらみ”が多いので、GraphQLを利用する場合は、必ずスキーマ駆動開発を使っておきましょうという教訓です。openapi.jsonやgraphql.schemaなどのスキーマ定義を、事前にフロントエンドとバックエンドの間で、要するに開発者と利用者の間で合意を取ってからAPIを作りましょうというのがこのSchema Driven Developmentです。
すでに完成後のインターフェイスがわかっているので、だいたいのライブラリを使えばモックサーバーもすぐに立てられます。フロントエンド側の開発がバックエンドのサーバーのデータの出来上がりを待たなくても、データがすでに完成した状態で開発を進められます。
また、開発における手戻りの発生リスクもとても小さいので、教訓は「スキーマ駆動開発はぜひ使っていきましょう」になります。そもそもGraphQLは本当に必要なのかも検討する必要があるかなと思います。GraphQLは仕組み上、かなりしっかりとした設計がないとあまりメリットがないかなと思っています。
特に今回のように工期やDB、APIの都合上、インターフェイスの自由度はほぼない状態で、機能がリソースに紐づいているのではなくて、リソースが機能に紐づいている、要するにSOAP(Simple Object Access Protocol)的なAPIの張り方をしている場合、GraphQLはBFF(Backends For Frontends)みたいな使い方がぜんぜん適していないんじゃないかと思います。
あとは新しい技術を使ってみたいだけで、GraphQLを使おうとしているのであれば絶対に良くないと思います。きちんと適材適所で使いましょう。
教訓です。モダンな技術もレガシーな技術も適材適所で使っていきましょう。プロダクションに入れるのは熟れてからです。自分用に使うのであればガンガン使っていきましょう。私の発表は終わりです。
関連タグ:
2024.10.29
5〜10万円の低単価案件の受注をやめたら労働生産性が劇的に向上 相見積もり案件には提案書を出さないことで見えた“意外な効果”
2024.10.24
パワポ資料の「手戻り」が多すぎる問題の解消法 資料作成のプロが語る、修正の無限ループから抜け出す4つのコツ
2024.10.28
スキル重視の採用を続けた結果、早期離職が増え社員が1人に… 下半期の退職者ゼロを達成した「関係の質」向上の取り組み
2024.10.22
気づかぬうちに評価を下げる「ダメな口癖」3選 デキる人はやっている、上司の指摘に対する上手な返し方
2024.10.24
リスクを取らない人が多い日本は、むしろ稼ぐチャンス? 日本のGDP4位転落の今、個人に必要なマインドとは
2024.10.23
「初任給40万円時代」が、比較的早いうちにやってくる? これから淘汰される会社・生き残る会社の分かれ目
2024.10.23
「どうしてもあなたから買いたい」と言われる営業になるには 『無敗営業』著者が教える、納得感を高める商談の進め方
2024.10.28
“力を抜くこと”がリーダーにとって重要な理由 「人間の達人」タモリさんから学んだ自然体の大切さ
2024.10.29
「テスラの何がすごいのか」がわからない学生たち 起業率2年連続日本一の大学で「Appleのフレームワーク」を教えるわけ
2024.10.30
職場にいる「困った部下」への対処法 上司・部下間で生まれる“常識のズレ”を解消するには