Share
Embed
Transcript
69 slides
-
自己紹介 module.exports = { name: “Yuta Ide”, belong: “日本経済新聞社”, role:
[“Client”, “Edge”, “BFF”], lang: [“TypeScript”, “Rust”].push(“Scala”), “schema now I’m using”: [“JSON Schema”, “zod”, “joi”, “GraphQL”, “pbuf”] } 2 -
日本経済新聞社の負債返済活動 • 3ヶ月開発を止めて非機能要件開発 ◦ Node.jsアップデート作業 ◦ アラート改善活動 ◦ スキーマ改善活動 ◦
パフォーマンスメトリクス計測の仕組み ◦ 過去ページのアーカイブ化(SSG) ◦ E2E整備 https://speakerdeck.com/sadnessojisan/jian-shi-senaakansi-w u-da-zhi-dakeniookamitutena https://www.youtube.com/watch?v=L--AVk29m6w 6 -
スキーマ改善活動 • バックエンドチームを兼務してSpecやMiddlewareを書いていた • 手書きyaml の Spec から Validator を生成して、それを
Django (Python) に組み込む仕組みを作った • そして現実を知るのである、「Specが信用できないのはAPIチームのサボ タージュや技術不足ではなく、そもそも・・・」 スキーマ駆動開発導入の難しさを知る 8 -
反対にスキーマがあると何が嬉しいのか • サーバーサイドの開発を待たずにどういうレスポンスが返るか分かる • サーバーの戻り値の型を得られる • APIクライアントも得られる(作れる) 12 API開発 フロント開発
API改修 フロント対応 schema schema BE FE -
JSON Schema • スキーマ: JSON Schema • 型: typebox, json-schema-to-ts
• バリデーション: ajv 16 -
Swagger • スキーマ: Open API Spec • 型: swagger-typescript-api •
バリデーション: swagger-model-validator, ajv(OAS is based on json schema) 17 -
GraphQL • スキーマ: GraphQL schema • 型: graphql-code-gen • バリデーション:
??? (graphql-codegen-typescript-validation-schema と いうのが最近あるらしいが筆者は触っていない) 19 -
gRPC • スキーマ: Protocol Buffers • 型: ts-protoc-gen, ts-proto •
バリデーション: ??? 20 -
バリデーション系の話をあまり聴かない • ajv はともかく、schema に対するバリデーションの話を聞かない ◦ ajv は逆で、バリデーションライブラリがあって、要求しているIDLがJSON Schemaという関 係
• unknown な箇所に validation して型をつけた後のレスポンス作成におい て、プログラミング言語が型安全を保証しているのであればvalidation は不 要では? 26 -
日本経済新聞社のアーキテクチャ CDN Origin API GW 13年間も積み重なった レガシー&入稿基幹サー ビス群 Frontend Teamの持ち物
信用できない データ 32 Swaggerとかが生まれる前から稼働してい るサービスなのだから仕方がない! -
日本経済新聞社のアーキテクチャ CDN Origin API GW 13年間も積み重なった レガシー&入稿基幹サー ビス群 Frontend Teamの持ち物
信用できない データ 33 Gateway の責務は Gateway なので素通しする 信用できない データ -
日本経済新聞社のアーキテクチャ CDN Origin API GW 13年間も積み重なった レガシー&入稿基幹サー ビス群 Frontend Teamの持ち物
信用できない データ 34 信用できない データ どちらかでバリデーションをしたい -
日本経済新聞社のアーキテクチャ Origin API GW 信用できない データ 本当はここでバリデーションをして、信 用できるデータにしたい 36 一部APIにおいて、バリデーションに使うための
OAS準拠の仕様書が存在せず、サーバー側でバリデータを作れない。 (スプレッドシートにある) -
選ばれたのは JSON Schema でした • 2023年現在、一番良いのは zod だと思う • が、これまでの歴史上
joi -> yup -> zod とスキーマライブラリが乗り換えら れている • zod の次が出た時、zod ベースのソースはどうなるのか?スキーマはサー バーの根幹であり、そこが流行に振り回されていいのか??? • 長生きするIDLを採用したい -> JSON Schema 言語や流行に左右されないIDLを使おう 43 -
ajv とは • Another JSON Validator • JSON Schema で定義された
validator を作れる https://ajv.js.org/ 45 -
fastify との相性が良い • frontendチームの技術スタックは Fastify での自作SSR • Fastify は Ajv
が標準で組み込まれ ており、req/res を検証・シリアラ イズできる • APIを持つ場合のSpec生成に Swagger を使う後JSON Schema か らSwaggerを吐き出すプラグインが ある https://blog.ojisan.io/swagger-validator-ts/ 46 https://blog.ojisan.io/swagger-validator-ts/ -
クライアントサイドにどうやって Schema を作るか • 手書きされた API Spec から JSON Schema
を作る ◦ 手書きされたSpecが実値と乖離しすぎていて却下 • サーバーの実値から JSON Schema を生成する ◦ 動的なキー(やめろ!)やOptionalがあるので実値からだとスキーマの完成形が分からない • TypeScriptの型から JSON Schema を生成する ◦ クライアント側はすでに await res.json() as any as Type としていて稼働実績ある型を使っ ている。それが正しいのかはさておき・・・ 49 -
TypeScriptの型から JSON Schema を生成する • quicktypeやtypescript-json-schema • すでにクライアントサイドにある型から JSON Schemaを自動生成する。運用し
ている型なのである程度正しい実績もあ る。 • 実は Optional, Nullable, Undefined の 扱いが怪しい・・・ https://blog.ojisan.io/typescript-json-schema-ajv/ 50 https://blog.ojisan.io/add-nullable-to-json-schema/ -
JSON Schema に対応した型を作る • 今回はTSからJSON Schema を生成し たので考えなくてもいいが、そうで無 い場合どうすればいいか •
TS first な JSON Schema を生成でき る IDL を使う ◦ typebox ◦ zod • json-schema-to-ts の型 Util https://blog.ojisan.io/ajv-to-type/ 56 -
バリデーションに失敗すること前提で作る • そもそも “single source of truth” が存在していないところにスキーマを導 入するので、バリデーションがスキーマ通りに成功する訳が無い •
残念ながら、バリデーションに失敗した時にそこで例外を投げられない • 例:記事表示ページで、おすすめ記事一覧リストのデータがバリデーション 違反でした。例外を投げて記事全体を表示されなくなることが許されるの か? 58 -
スキーマ違反を素通しさせて意味があるのか? • 「結局スキーマ違反な値にウソの型を与えてクライアントに返せば、クライア ント側でランタイムエラー起きますよね」「わかっとるわ!!!!」 • Validation Error を集計することが大切 • クライアントが期待するデータに対する
Validation Error を集めることで、 APIチームやさらにその裏側に「こういうデータを返してください」と言える API側の手書きスキーマを改善する サイクルを作るための第一手 60 -
日本経済新聞社のアーキテクチャ CDN Origin API GW 13年間も積み重なった レガシー&入稿基幹サー ビス群 Frontend Teamの持ち物
信用できない データ 62 信用できない データ どこかでバリデーションをしたい どこか一層に信頼できないデータ層が生まれると、その前段に信頼できないデータは伝 播していく。つまりスキーマ通りの値を返す仕組みを作るのであれば、入稿や DBのス キーマから正しいスキーマを伝播していく必要がある -
日本経済新聞社のアーキテクチャ CDN Origin API GW 13年間も積み重なった レガシー&入稿基幹サー ビス群 Frontend Teamの持ち物
信用できない データ 63 信用できない データ どこかでバリデーションをしたい 信用できないデータソースがある状況で信用できるデータを返すようにしたいのであれ ば、結局はどこかの層でバリデーションは必要で、誰かが APIがエラーを返す覚悟で例 外を投げなければいけない -
リプレイスする時に守る1つの鉄則 • スキーマやドキュメントに違反した 値を返してはいけない ◦ 外部に公開するAPIは必ずSpecを公開す る ◦ Spec違反の値を返さないように検証する •
防御的(!?)・予防的・攻撃的・契約 プログラミングの考え方を自チーム や自社に当てはめて戦略を考えよう ◦ 0ベースで開発する場合、違反するもの は落として欲しい 64 https://speakerdeck.com/twada/php-conference-2016 -
DBや入稿側から正しいスキーマを伝播させる • DBに面する入稿システムやマイクロサービスが、DBのスキーマを元に型安 全なAPIを作ると信頼を伝播させられる ◦ ORM ◦ Compile-time SQL Check
DBからクライアントまでを 型安全に繋ぐ技術を採用する 65 -
例: ORM • Entity とクエリのマッピング • DBからの値が Entity として型がつくようになる •
例) Prisma, TypeORM, Active Record, Django ORM… 66 -
例: sqlx • Compile-time checked queries • ORMではないが、コンパイル時にス キーマを検証し、DTOへのマッピン グまでもマクロで可能
• コンパイル時にDBに対してクエリが 走り、クエリの実行結果とRustの世 界で型検査できる https://github.com/launchbadge/sqlx 67 -
型安全な言語を利用する • 多くの言語は、GraphQLもgRPCも型やスキーマをごまかして使えてしまう ので、クライアントからするとクエリやメッセージ通りの値を受け取れる保 証がない • 自分がサーバーを実装するなら Rust で書きたい!!!!!!!!! •
Rustの一番好きな点は、「型を誤魔化すコストが高く、誤魔化すモチベー ションがなくなる」ところ。any や ts-ignore 的な抜け道が塞がれている。 Rustで書かれたサーバーはそれだけでフロントエンドエンジニア視点で信用 できて、過剰な防御をやめる動機になる!!! 68 -
っていうのは全部妄想です • まとめ①: スキーマレスで動いてしまってるものにスキーマを入れるのは難しいです。フル リプレイスは救いですが、現実的にフルリプレイスなんてものは簡単にできるわけがないの で、できるところからやっていきましょう。妥協するには JSON Schema が良いです •
まとめ②: しかし妥協するからにはコンピューターフレンドリーで自動化された運用フロー に期待できず、人間が運用フローを作らないといけないです • そんな運用フローを一緒に整備してくれる方を募集しています 「散々レガシーなこと話しておいて人が来ると思ってるの?」と思うかもしれませんが、どこの会 社にもレガシーはあるはずだし悪いことだとは思っていないです。むしろそういった過去の遺産 を、技術力や組織の力でどう未来に繋げていくかという仕事はクリエイティブで面白いと思います し、自分も楽しいです。面白そうと思った方はぜひカジュアル面談しましょう。もちろんモダン環 境(Nix, Rust, Scala)でひたすら楽しい開発ができる仕事もあります。是非カジュアル面談をしま しょう。 69