マネーフォワード関西開発拠点 - チームの日々の開発を紹介
この記事はMoney Forward Kansai Advent Calendar 2024の4日目の記事です!
こんにちは、株式会社マネーフォワードの大阪拠点でバックエンドエンジニアをしています。
Kazuki Tanidaです。
今回は私の所属するチームのエンジニアの日常についてざっくりと雰囲気を感じていただければと思います!
私たちのチーム
関西開発拠点は京都と大阪があり、多くのメンバーがビジネス向けプロダクトの開発に関わっています。
エンジニア、QA、デザイナー、エンジニアリングマネージャー、プロダクトマネージャー等々日々関わりながら開発しています。日本側のチーム、ベトナム側のチームがあります。(今回は日本側のチームについてメインで紹介していきますね)
実は、私はマネーフォワード クラウド連結会計の立ち上げ当初から携わっており、当時はフロントエンド、バックエンド垣根なくコードを書いていました。しかし現在はエンジニアの人数も増えてきたので、フロントエンド、バックエンドそれぞれでメインでどちらを担当するか基本的には役割を分けています。
そして現在ではチームを2つのユニット分けて メイン機能開発チーム
と 機能開発&改善チーム
で分けて開発するようにしています。社内システムの開発も関わってくれているインターン生もいます!
日々の開発プロセス
アジャイル開発・スクラム開発
私の所属するチームが日々どのようなプロセスで開発に取り組んでいるかをご紹介します。
私たちの拠点ではスクラムを活用しています。アジリティを高め価値提供のスピードを上げるための手段として活用しています。
スプリント期間というものがあり、簡単に説明するとタイムボックスを設定してその中で開発、リリースをしていくものです。チームができた当初は1週間でしたが今は2週間毎にしてしっくりきていると思います。
個人的には初めてのスクラム開発だったのでこれらのイベントは全てが新鮮で日々刺激を受けています。全ては紹介できませんがその2週間で行うメインとなるイベントを一つ一つ紹介していきます!
スプリントプランニング
スプリント開始時に行う計画で、スプリント中に達成すべき目標(スプリントゴール)とそのために必要な作業(バックログアイテムを)決定します。
プロダクトオーナーや開発メンバーもみんな参加して決めます。
ユーザーへの価値を意識して開発しており、スプリントゴールの設定では
「〇〇の機能を作りきる!」などではなくなるべく「ユーザが〇〇を利用して〇〇業務の素早くできる」
といったことを意識しています。
ゴールが決まればどのバックログアイテムを選ぶかを選択して、エンジニアで集まって詳細のプランニングについては後ほど紹介します!
デイリースクラム
スプリント期間中に毎日行う短いミーティング(だいたい15分以内)で、チームメンバー間で進捗状況や課題を共有します。
基本的にチーム全員が集まって朝会でデイリースクラムをしています。
主な内容は以下:
- 昨日までに達成したこと
- 今日やる予定のこと
- 現在直面している課題や障害(あれば)
ヘルプが必要な時や、何か別の対応をしなければいけない時もこの朝会で共有してから業務に入ります。
全員で認識をそろえてから進めます。
リファインメント
プロダクトバックログを継続的に見直し、アイテムを詳細化・優先順位付けするプロセスです。スプリント中に適宜行われます。
プロダクトオーナー、開発チーム、デザイナー等が参加します。
主な内容は以下:
- バックログアイテムの詳細化(分解、サイズ見積もり)
- 優先順位の確認や変更
- 今後のスプリントで扱う可能性のあるアイテムの準備
例えば、次回以降のスプリント期間で作る機能やデザインについて、エンジニアもフロント、バックに関わらずディスカッションします。
このデザインだと既存のコードを改修して新しいコンポーネントを作る必要があるから工数がかかりそうだとか、データの持ち方によっては計算量が多くなるのでデータの持ち方を決めてデータベース設計をしっかりしなければならないなど工数のざっくりとした見積もりと認識をそろえる機会にもなります。
ユーザーへの価値提供を考えディスカッションした結果、文言やデザインを変えて次回のリファインメントで再度確認することもあります。
スプリントレビュー
スプリント終了時に行うミーティングで、スプリントで作成した成果物をステークホルダーに共有し、フィードバックを得ます。
成果物を披露するお祭りのようなイベントです!私のチームでは会計ソフトを開発しているのでここで言うステークホルダーは社内のドメイン知識を持った人たち、社内の経理の方達などのに見ていただくことが多いです。
この時点ではユーザー向けに一般公開はされてないことがほとんとですが、社内でのみ利用できる状態になって実際にプロダクトを触る人たちの目線でレビューしてもらえるので、フィードバックや改善点も見つけることもできます。
せっかくの成果物を披露する祭りのような(?)会なので参加者が理解して質問や意見を出しやすいように個人的にもスプリントレビューでの説明には力を入れています。その結果ワイワイ楽しくスプリントレビューを迎えられています!
使いやすそう!早速使ってみたい!助かる!などの声が実際に聞ける機会なのでエンジニアとしても機能を作って本当に良かったなと感じられるスクラムイベントです。
レトロスペクティブ
スプリントの振り返りを行い、プロセスやチームワークを改善するための具体的なアクションを決定します。
スプリントの良かった点、悪かった点、改善すべき点を洗い出します。
改善のための具体的なアクションプランを設定してチーム全体で合意形成を図るといった具合です。
良かったことは勿体ぶらず称賛します!
上手くいかなかったことについては(個人への攻撃はNGで)素直に起こったこと、感じたことを書き出します。
改善についてはスプリント期間中のプロセスやスクラムイベント自体について話し合うこともあります。
- ドメイン知識が難しい機能については一人でやると難しいので今度はモブプログラミングをしよう
- リリース日の管理、把握が人によってずれていたので共有方法を変えよう
- 内容を忘れてしまうのでレトロスペクティブの開催をより細かく1週間毎に変えよう
etc
エンジニアの日々の開発
開発チームがどのように設計して開発しているのか紹介してきます。
(私はバックエンドメインで開発をしているのでバックエンドよりの話が多くなります)
まず機能を作るにあたってはプランニングです。先ほど紹介したスプリントプランニングの後の話です、もう少し詳細に紹介していきたいと思います。
スプリントプランニングではゴールを設定した後には具体的な設計に移っていきます。
技術スタック、開発スタイルとしてざっくり紹介しておくと以下のような感じです。
- Next.js
- Kotlin, Spring Boot
- GraphQL
- DDD, Clean Architecture
簡単な例を用いてどのように詳細プランニングをして開発していくか見ていきましょう。
GraphQL Schemaを考える
最初にやるのはGraphQL Schemaから考えていくことが多いです。
GraphQLについて詳しくは説明しませんが、フロントからAPIサーバーに問い合わせするクエリ言語として利用しています。
最初にGraphQL schemaから考えておくとフロントエンド側とバックエンド側でデータの型の認識が揃えた状態で開発を進められます。
ここからはフロント、バックは別れてプランニングを進めます。
バックエンドのデータ構造を決める
GraphQL schemaが固まった後はentityとrepositoryのinterfaceを一緒に決めていきます。
DB schemaに変更が必要であればmigrationファイルもこの段階で作ってmergeしてしまいます。
entityが決まれば他の方を決めやすくなります。
data class Company(
val id: CompanyId
val nameJa: CompanyNameJa,
val nameEn: CompanyNameEn,
val ...
) {
init {
// 命名に関するvalidationをしたり
}
// その他何らかのロジック
}
interface CompanyRepository {
suspend fun filterByIds(ids: List<CompanyId>): List<Company>
suspend fun create(company: Company): Company
}
だいたいはここまで一緒に集まってペアプロ、モブプログラミングすることが多いです。
後続の実装に取り掛かる
entityやrepositoryのinterfaceが決まればどうなるでしょうか?
- repository自体の実装に取り掛かることができます
- repositoryを呼び出すuse caseやDomain Serviceの実装を進めることができます
- Companyデータを作成するuse case
- Companyデータを取得するuse case
このように型, interfaceが決まると並行して実装を進められるようになるのでこの辺りから各々どのタスクを取っていくかを決めていきます。
後半はプレゼンテーション層と結合してUIとも繋げて挙動を確認していきます。
要件を確認しながら機能が動いているかをチェックして...プロダクトオーナーにレビューしてもらいます!
その他の改善に取り掛かる
ユーザーストーリーを開発するだけでなく改善にも目を向けています。
例えばですが、GraphQLのリクエストから行うテストコードについて提案してくれたエンジニアがいます。
*KotlinやSpringに詳しいので興味あれば彼をフォローしてあげてください(-_-)b
GraphQLのクエリはdeveloper toolのNetworkタブから見てもらうとわかりやすいですが文字列で送られています。そのクエリをAPIサーバー側でパースすることでリクエスト内容を受け取ります。
テストでも以下のように文字列を利用してリクエストさせていました。
文字列なのでGraphQLのクエリを定義している箇所へコードジャンプもできず誤字があってもテスト実行するまで気付けない、エラーが出てもどこが間違っているか分かりづらい等の問題がありました。
// クエリ内容を文字列で定義
val query = """
query {
company {
name
members {
name
code
...
}
}
}
""".trimIndent()
client.mutateWith(SecurityMockServerConfigurers.mockOidcLogin().oidcUser(oidcUser)).post()
.uri("/graphql")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(GraphQLRequest(query)) // ←リクエストのpayloadになる。
.exchange()
.expectStatus().isOk
.expectBody()
// assertion...
Kotlinはこのチームに入るまで触ったことがなかったのですがとても良い言語だと感じており、
中でもDSLを描きやすいなと感じています。実際に以下の様なタイプセーフなテストコードを書くことが可能になりました。
誤字があればエラーで気づくこともできますし、定義元にジャンプすることも可能になっています。
val query = graphQLBuilder {
CompanyQuery::company.asQuery {
::name.asObject{
::members.asObjects {
::name.asField()
::code.asField()
// ...
}
}
}
}
テスト以外のプロダクションコードに関しても宣言的にコードをかけるDSLを作り、バックエンドのコードのドキュメント性が上がった箇所がいくつもあります。
この様に既存のコードべースに対しても目を向け改善を施し、エンジニアがより快適に開発できる環境を整えています。
まとめ
この記事では、株式会社マネーフォワードの関西開発拠点、私のチームにおけるエンジニアチームの日常と開発プロセスをざっくばらんに紹介しました。
エンジニアが快適に開発できる環境を整え、ユーザーに価値を提供することを日々楽しんで開発している雰囲気を少しでも感じてもらえれば幸いです。
Discussion