APIの仕様をまとめて、全員の合意を取ってから開発を始める
コンピューター・システムの開発で問題が発生するとき、その原因はメンバー同士のコミュニケーション不足、あるいはコミュニケーションの失敗にあることが多い。例えば、クライアントとサーバーの通信に使うAPIについて、その名称や使い方など詳細な情報をメンバー全員にしっかり伝えることができていないと、コードとして実装するときに担当者がどのように実装すれば良いか分からなくなることが考えられる。
周囲のメンバーにちょっと確認して、すぐに問題が解消すれば良いが、解決しないときはほかのチームに確認することになる。システムのクライアント側のメンバーが十分に理解していないときに、サーバー側のメンバーに詳細について確認することにもなるかもしれない。最悪の場合は、サーバー側とクライアント側が仕様の確認のために自由に動けなくなり、歩調を合わせて開発を進めざるを得なくなる。
仕様の確認を繰り返すと、開発に使う時間をコミュニケーションのために浪費することになってしまう。こうなってしまうと開発のペースは落ちて、スケジュール通りには進まなくなる。かなり遅れてシステムが完成したとしても、バグがいくつも潜んでいることになりかねない。
このような事態を防ぐのに役立つ手法として土田氏が紹介するのが、「スキーマ駆動開発」という開発手法だ。この手法は簡単に言えば「API仕様(スキーマ)を先に決めてからクライアントとサーバーの開発を進める手法」(土田氏)ということになる。APIのインターフェースや仕様の詳細を先にキッチリと決めて、メンバー間でしっかりと合意を取ってからクライアント側とサーバー側のアプリケーションを実装していく手法だ。
では、APIのインターフェースや仕様の詳細をどのような形式で記述すれば良いのだろうか。そこで登場するのが業界標準のフォーマットである「OpenAPI」だ。土田氏はOpenAPIの利点について、「エコシステムが充実していて、オープンソースのライブラリやツールが多く存在する」と語る。
OpenAPIでは「YAML(YAML Ain't a Markup Language)」か「JSON(JavaScript Object Notation)」のどちらかの形式でAPI仕様を記述する。どちらも開発者なら触れる機会がある形式だ。OpenAPIを利用すると、最初にデータベースのテーブルを作成し、システムで使用するAPIのすべてについて名称や機能などを決め、決めたことをOpenAPIのファイルにまとめ、まとめたファイルをメンバー全員でレビューして、APIの定義(スキーマ)についてしっかりとした合意を得てから開発を始めることができる。
クライアント側とサーバー側が非同期で開発を進めることができる
土田氏はOpenAPIを利用したこのような開発スタイルの最大の利点として、「クライアント側とサーバー側が非同期で開発を進めることができる」点を挙げる。API仕様の確認のために打ち合わせを繰り返す必要がなくなるため、それぞれのペースで開発を進めることができるのだ。実際に土田氏は、さらなる利点として「サーバー側とクライアント側の開発者間のコミュニケーションコスト削減」を挙げている。
そして土田氏は3つ目の利点として、自動生成を挙げた。OpenAPI形式でAPIの定義文書ができれば、必要なライブラリなどを自動的に生成できるのだ。コードを人間が実装する工数を削減できるだけでなく、決まった形式の定義文書からコードを自動的に生成するため、間違いも減らせる。
OpenAPI形式の定義文書から自動的に生成できるものとしては、まずクライアント用のライブラリが挙げられる。これによってHTTPの通信を開発者が自身で実装する必要がなくなり、より抽象度の高いライブラリのAPIを呼び出して機能を実装できる。
次に、サーバー側APIのモックが挙げられる。クライアント側がサーバー側との通信を試すとき、実際にサーバー側のAPIと通信してみるのが最も確実な手段だが、サーバー側APIの実装が完了するのを待たなければならない。これではクライアント側とサーバー側が非同期で開発を進めるという利点がなくなってしまう。そこで、APIの名称と呼び出し方と戻り値を再現するモックを利用するのだ。
さらに最近では、OpenAPI形式の定義文書からサーバー側のコードを自動生成することができるようになってきている。これでサーバー側もAPIの定義と実装がずれることがなくなり、工数を削減できるのだ。
ただ、土田氏によるとOpenAPIファイルを利用するだけでは、解決しない問題があり、新たな問題を起こすこともある。よくある問題として土田氏は3点挙げた。1つ目はYAMLやJSONのファイルが開発者にとって読みやすいものではないということ。メンバー全員でOpenAPIファイルをレビューするときに、手間と時間がかかる。
2つ目はAPIの定義がデータベース設計に強く依存すること。途中でデータベース設計を変更すると、APIの定義も修正が必要になるが、修正が漏れてしまうことが長期的なプロジェクトではよくあると土田氏は指摘する。3つ目は、データベースを操作するCRUD(Create:データの作成、Read:読み出し、Update:更新、Delete:削除)のAPIの定義を書くのに大きな労力がかかるということだ。
コードとしてスキーマを記述し、DB設計も自動化
土田氏は以上3点の問題を解決する方法を探し、米Meta Platforms(Facebook)が開発したオープンソース・ソフトウェア「ent」を見つけ出した。entでは、API定義(スキーマ)をOpenAPIファイルではなく、Go言語のソースコードの形で記述する(Schema As Code)。YAMLやJSONに比べれば、開発者にとって読みやすい形式で記述できるわけだ。entにはさらにスキーマ・ファイルからデータベースのテーブルなどを自動的に作成する機能も持つ。データベースのテーブルを作成することなく、APIの設計に取りかかることができるのだ。
そしてentは各種自動生成機能も充実している。まず、Go言語で記述したスキーマ・ファイルから、OpenAPI形式のファイルを生成できる。OpenAPI向けのツールを使いたいときに役立つ機能だ。そして、Go言語に限った話になってしまうが、スキーマからクライアントがデータベースにアクセスする際に使用するORマッパーも生成する。
この結果、entを使用すると定義(スキーマ)と実装のずれが一切無い状態で開発を進めることができる。土田氏は「とにかくスキーマが最優先という形で開発を進めることができる」とメリットを強調する。
entを使用する場合、まずサーバー側の開発者がGo言語でスキーマを記述し、クライアント側など開発チーム全員にファイルをレビューしてもらい、合意が取れたらデータベース・テーブルを自動的に作成するという流れになる。データベースに変更があれば、それも反映させてくれる。さらに、OpenAPIファイルや、ORマッパー、CRUDコードも自動的に生成するので、スキーマで定義した内容と実装がずれるという事態が発生しにくい。
実際に開発でentを使用してきている土田氏は、使ってみて感じたメリットとして、手作業が減るので工数を大幅に削減できるという点を真っ先に挙げた。さらに、スキーマをコードで記述するため、読みやすくレビューもやりやすいともいう。そして、公式ドキュメントが分かりやすいという利点も挙げた。
一方で気になる点も挙げた。まず、開発の途中から導入するのは難しそうだということ。すでにデータベースの設計ができていて、稼働しているような場合は、データベースのテーブル設計からGo言語のスキーマに変換する作業が発生するからだ。
続いて、多機能なツールであり、あまりに頼りすぎると簡単にロックインしてしまいそうだという点を挙げた。土田氏は「ここで紹介したentの機能はごく一部。紹介できていない機能がたくさんある」と言い、entを導入するならentに依存しすぎることなく、部分的に採用するのが良いかもしれないと導入を考える開発者にアドバイスを送った。さらに、ORマッパーの自動生成機能について「Go言語のコードだけでなく、他の言語のコードも生成できるようになると良い」とした。
さらに土田氏は、「entの対抗馬となりそう」だというソフトウェア「Prisma」を紹介した。Prismaでは、「schema.prisma」という名称のファイルに独自フォーマットでスキーマを記述する形を採る。スキーマからのデータベース・テーブルの自動作成や、ORマッパー生成といった機能も持っている。ただし、ORマッパーはJavaScript/TypeScriptのコードで出力する。OpenAPIファイルを出力する機能はないが、その点については「schema.prismaファイル一つですべてを済ませてしまおうという思想があるからではないか」と土田氏は推測している。
土田氏はentやPrismaといったツールについて「この種のツールはまだ成長段階にあり、この先どうなるかは分からない。ロックインしないように上手く活用して開発を進められれば良いのでは」と語り、講演を締めくくった。