社内のギルド活動でワイワイしながら管理画面改修を進めている話
こんにちは、株式会社POLでエンジニアをしているmotikomaです。
こちらはPOLアドベントカレンダー2021の14日目の記事です。前日の記事は「Recoilの非同期Selectorを考える」です。
POLのギルド制度
POLの開発組織ではギルドという制度があり、毎週木曜の午後を活動時間に充てることができます。ギルド自体はフロントエンド, バックエンド, インフラなどがあります。どういった活動をするかについては特に指示されるわけではなく、メンバーの自主性に任されています。
例えば「リリース時の Aurora バックアップ手順の自動化」「社内Slack botのbolt化」などが進んでいますね。私もギルド活動の時間に他メンバーと一緒に管理画面改修プロジェクトに取り組んでいます。
管理画面改修プロジェクト発足
POLのプロダクトとしてLabBaseがありますが、カスタマーサクセスやSalesが使用するための管理画面も存在します。ただ、これまでの継続的な開発や運用を通して、現状は下記のような課題が生まれていました。
動作が重く、エラーが頻発するため業務効率が悪い
現在は使用されていない不要な機能が放置されている
そこで有志で管理画面を改修することにしました。ステークホルダーにヒアリングしてユーザーストーリーを整理しつつ、インセプションデッキに情報を整理しながら開発を進めています。なお、管理画面の技術スタックとしてはこんな感じです。
インフラ: AWS
バックエンド: Kotlin, SpringBoot
フロントエンド: TypeScript, Next.js
モブワークでスキーマ駆動開発
昨年度のPOLアドベントカレンダーで「OpenAPI Generatorでフロントエンドもバックエンドもコード自動生成する」という記事を高橋さんが書いてくれましたが、管理画面の開発の進め方もOpenAPIを用いたスキーマ駆動開発を採用することにしました。
毎週木曜にメンバーが集まって画面を見ながらAPIのスキーマを定義し、それを元にバックエンドとフロントエンドの開発を進めています。また、現在はOpenAPI Generatorでバックエンドのみ型定義ファイルを自動で生成しています。
こんな感じでController の Service Interface と Request/Response のモデルが作成されるので、あとはロジックを実装するだけです。
interface AccountsApiService {
fun accountsAccountIdDelete(accountId: kotlin.Long): Unit
fun accountsAccountIdGet(accountId: kotlin.Long): ApiAccountDetailResponse
fun accountsAccountIdPut(accountId: kotlin.Long, apiAccountsRequest: ApiAccountsRequest): Unit
fun accountsGet(): ApiAccountsResponse
fun accountsPost(apiAccountsRequest: ApiAccountsRequest): Unit
}
やってみた感想
LabBaseの開発においてはConfluenceにAPI定義を記載していましたがフォーマットもバラバラだったり, 人によって書いたり書かなかったりと運用が属人化していました。
今回はフォーマットと運用フロー(最初にスキーマを定義して、それを元にして生成された型定義を用いる)が決まっているため、属人化を防ぐことができそうです。作業をJIRAチケットで管理しているのですがユーザーストーリーごとに作業タスクとして「スキーマ定義」を登録しています。開発者の認識違いに伴う不要な手戻りが減るのは嬉しいですね。
管理画面の改修ではフロントエンド担当3人, バックエンド担当2人で同一チームとして開発しているため、スキーマに修正が必要になった場合でも同じチームなのでコミュニケーションしやすそうです。引き続き、ワイワイしながら楽しく開発を進めていきたいと思います!
今後について
現在はバックエンドの型定義ファイルのみスキーマから自動で生成していますが、フロントエンドでも試してみたいと考えています。個人的にはopenapi2aspidaが気になっています。スキーマ定義をもとに自動的にHTTPClientの型定義が生成されます。
import axiosClient from '@aspida/axios'
import api from "./api/$api"
import type { Pet } from './api/@types'
;(async () => {
const client = api(axiosClient())
const petId = 100
const body: Pet = {
id: petId,
name: 'hoge',
photoUrls: [],
status: 'available'
}
await client.pet.$post({ body })
const pet = await client.pet._petId(petId).$get()
console.log(pet)
})()
また、Prismを用いたモックサーバーも便利そうです。スキーマを元にしたexampleを返してくれるので、APIの開発と並行してフロントエンド実装が捗りますね。
最後に
明日のアドベントカレンダー担当は@ryu19-1です!よろしくお願いします!