スキーマ駆動開発ってなに?便利なの?って方へ。
みなさんはどんな開発手法でやっていますか?
巷では、TDD(テスト駆動開発)やMDD(モデル駆動開発)など、
いろんな開発手法が有り、それぞれメリデリはあります。
その中で、現在自分が関わっているPJでは、
モノリシックなRailsの構成から、フロント側を
Reactにリプレイスする際に用いる開発方法として
「スキーマ駆動開発」という手法を採用しています🎉
フロントとサーバーが分かれているSPAやネイティブアプリに関して、
apiの開発をしていく上で、スキーマ駆動開発の導入は個人的に
結構相性はいいと思っています。
実際に自分が機能を設計、実装していく上でどんな点が気に入ったか、
導入前と後でどう変わったか?という点について書こうと思います。
もし開発手法の選択を決めかねているという方がいましたら、
参考になったら嬉しいです😇
スキーマってそもそも何?
いろんな文献を見ると、データベースの構造や集合体など、
表現は様々ですが、IT業界的な解釈でいうと要するに
「ひとまとまりのデータ定義」といったイメージで概ね
ズレはないんじゃないかなと思います。
といっても、どういうこっちゃ?🙄という人のために、
ちょっと、レストランで例えてみましょう。
レストランでは、常にいろんなお客さんが
ご飯を食べに来ます。
そして、お店に来たお客さんが注文で
「卵焼き」を頼んだとしましょう。
さて、ここで言う卵焼きとは、どんな卵焼きでしょうか?
- あまあまなスイーツ卵焼き?
- だしの効いた料亭風?
- ちゃんと何層も巻いてる玉子焼き?
- 卵焼きという名の、寄せ卵?
このように、卵焼きにも色んなバリエーションがありますね。
また、それに応じて使う調味料や分量も変わります。
では、この店では仮にあまーい卵焼きを提供していて
以下のようなレシピで10分で作るように書かれていたとします。
++++++++++++++++++++++
- 卵 4つ
- 砂糖 大さじ3倍
- 出汁 100cc
- 油 大さじ1
++++++++++++++++++++++
見た目はこんな感じです。
これがこの店の卵焼きの定義であり、
基本的にこの材料や分量で作られた卵焼きが
毎回お客さんの前に提供されます。
ここで感の良い方ならお気づきかと思いますが、
先程書いた「レシピ」がスキーマという感覚に近いです。
これは、開発におけるところでも同じで、
http://restaulant.com/tamagoyaki
というリクエストを送ったら、
{
material: {
egg: 4,
suger: 3
water: 100,
cookingOil: 1,
},
visual: fliedEgg.png,
time: 10,
}
という結果が返ってくる。
【レスポンスの返却内容の定義】
のことをスキーマと覚えとけば
問題ないと思います。
スキーマ駆動開発をするメリットは??
先程のレストランの例でいうと、スキーマ駆動開発とは
まずはホールとキッチンで同じ玉子焼きの見た目とレシピ等を定義して、それからメニュー表や作り方を決めよう
というイメージです。
これにより先程のレストランでは以下の各スタッフの悩みが解決されます。
ホールのスタッフの悩み
- 毎回メニュー表と同じ卵焼きを出してほしい!
- お客さんはそれを期待してるのにしょっぱい卵焼き来たら怒られる😥
キッチンのスタッフの悩み
- 毎回お客さんに合わせて好みの卵焼きなんて作ってられないぜ😤
- どこまで材料とか、時間とかかけていいか分からないよ😰
そして何よりも大きいのが、
ホールとキッチンスタッフが常に頭の中で同じ料理を認識している状態で
同時並行で作業ができることや、レシピを変更した際に常に認識が揃うということです。
これを開発現場に置き換えると、
-
フロントエンジニアとサーバーエンジニアが常に共有できるレシピ(定義書)を先に作る
- フロントエンジニアはレシピに書かれたデータが来る前提で画面を作り出す
- サーバーエンジニアは、定義書に書かれたリクエストと、返却するデータの形だけ考えてapiを作ればいい(どうやって使われるまでは考慮しなくていい)
-
スキーマに変更があった場合は、スキーマの定義ファイルを更新する
- 常に定義ファイル == 本番で使われるスキーマになるように運用する
- 両サイドのエンジニアが常に最新かつ、現行のスキーマを共有しあえる(ズレがなくなる)
- 常に定義ファイル == 本番で使われるスキーマになるように運用する
というメリットがあります。
それは大規模プロジェクトの話じゃないの??
・・・ん? 待てよ?
それはつまり、フロントとサーバー、それぞれのエンジニアがいる現場なら
いいかもしれないけど、うちはサーバーとフロント一気通貫で一人が担当するから
そんなにメリットなくない?🤔
それに、毎回定義ファイルを更新するの面倒じゃない?
それができてたら苦労しないよ!😡
と思った方もいるのではないでしょうか?
自分も最初はそう思いました。
なんで一人で実装するのにスキーマ決めるとこから作らないといけないんだと。
それがなければ、すぐに画面作って、そのまま必要なapiを作ればいい。
1つ手間が増えるじゃないかと。
ただ、これはチーム開発をしているPJであれば、有用に働きます。
自分がそれを感じたのは、【PRのレビュー】の時です。
例えばですが、
- 自分がレビュイーの場合
- スキーマ自体のレビュー時に、設計や実装イメージの相談、共有が可能
- 認識乖離や設計の手戻りの可能性が減る
- スキーマが決まると、画面側とapi側を同時並行でレビューに出せる
- 画面が固まらないとapi側が作れない、というタイムロスを減らせる
- 画面のレビュー時には画面の部分だけスコープにする、apiも然り
- PRのレビューのスコープ(粒度)を細かくできる
- PRの確認速度が上がる
- PRのレビューのスコープ(粒度)を細かくできる
- スキーマ自体のレビュー時に、設計や実装イメージの相談、共有が可能
- 自分がレビュアーの場合
- 画面やapiで使う情報の過不足が、定義書ですぐ確認できる
- 定義書でやり取りする型も定義できるため、変数名の妥当性とかも判断可能(api側が動的型付け言語とかだと特に助かる)
- 上の通り、スコープが小さくなるため、見やすい
とまぁ、こんな感じです。
レビューを出す粒度としては、
e.g.
ユーザー一覧画面の場合(数字はレビューに出す順番)
- 1.一覧取得のスキーマ(リクエストとレスポンスの形式)定義 👈 ここで仕様の認識合わせができる
- 2.(サーバー)一覧取得で必要なDBの定義ファイル作成
- 3(サーバー)一覧取得のapi作成
- 2.(フロント)一覧画面の作成
以前の自分は、一気に機能を作って粒度の大きいPR
(画面+サーバーサイドまとめて30~50ファイルとか)を
普通にぽんと依頼をしていたので、負担のかかるレビューを
お願いしてたなぁと、反省しています😅
これを導入してから、大掛かりな機能や、テストファイルが膨大でない限りは
FileChangedが~20くらいまでに収められるようになって、レビュー速度も
早くなった感じがします。
と入っても、まだ慣れていなくて、気を抜くと差分が大きくなっているので、
PRの粒度はこれからも課題です🙄
あと、定義ファイルの作成、更新に関しては、
Swagger(OpenApi)やGraphQLと呼ばれるツールが有ります。
これらは、定義ファイルの記載をもとに、リクエスト/レスポンス定義や
apiでやり取りするスキーマの定義や、リクエストを呼び出すためののコードを、
利用言語に合わせて自動生成してくれます。
つまり
【定義書の内容が常にプロダクションのコードと一致する】
ということです。
定義書の内容と実装が乖離する、ということが起こらない仕組みになっています。
更に便利なのが、OpenApi等で事前の設定をしておけば、
モックサーバーをすぐに立ち上げることが可能なんです。
これによって、以下の悩みが解決できます。
(自分は個人開発等をしてて感じていた悩みです。)
いままで
- 一覧画面で、ユーザーのテーブルがレイアウト崩れないか確認したい
- Reactに直打ちして確認
- サーバーを作りきって、サーバーのDBにモックデータを突っ込んでから確認
これから
- 一覧画面で、ユーザーのテーブルがレイアウト崩れないか確認したい
- OpenApiの定義書をもとに、モックサーバーを起動
- 定義書に記載した型やバリデーションに沿ったダミーデータを返却してくれる!
- サーバーが完成していなくても動的なデータ取得して表示が確認可能!
- 定義書に記載した型やバリデーションに沿ったダミーデータを返却してくれる!
- OpenApiの定義書をもとに、モックサーバーを起動
このような改善を図れるという点においても、、
スキーマ駆動開発を取り入れるのは
結構有りなんじゃないかなと思っています🤔
もしも、気になったぜとか、もっと具体的な導入まで知りたくなった
という気持ちになって頂けたのなら嬉しいです。
ぜひ次回の記事も見てもらえると幸いです。
追記
メインではFlutterに関する記事とか書いていきたいなと思っています。
もしFlutterについて気になるという方がいたら、
自分も入っている「Flutter大学」というコミュニティがあるので、
よかったら参加してみるのも良いと思います💪
それではみなさん、良き開発ライフを〜👋
Discussion