チーム開発の振り返り
投稿日: 2025年02月08日
ShiftBのカリキュラムの第13章、実務案件体験(=オリジナルアプリ開発後のボーナスステージのような位置付け)のなかで、初めて「チーム開発」に携わる機会をいただきました。そのなかで得られた気づき💡大変だったこと💦について振り返り、共有してみたいと思います。
今回、開発メンバーとして参加させていただいたのは、茜さんにより主機能が実装済みで、プロトタイプも既に稼働している「JS学習サービス」のプロジェクトでした。このプロジェクトに、 僕と tomoe さん(ShiftBの1期生の同期✨)が機能の追加のために途中参加する形でした。形態はフルリモートでした。
タスクとしては、ぶべさんからNotionで書かれた仕様(要件)とFigamaで描かれた仮デザインを受け取り、それに基づいて画面と機能(フロントエンド&バックエンド)を実装して、茜さん、ぶべさんによる2段階のコードレビューを受けて、developブランチに統合するというものでした。
個人開発では、実装はもちろん、設計から要求仕様まで基本的には全て自分で好きなように決めることができました。しかし、今回はチーム開発、とりわけ途中参加ということで(結果的には)次のようなことを意識して取り組むことが求められました(必要でした)。
既存のコードを読んで理解すること
まずはプロジェクトの全体像、つまりフォルダ構成、ファイル配置、使用ライブラリ、各種設定などを把握する必要がありました。また、そのような設計にしている意図についてもプロダクトの目的や特性から、自分なりに分析・考察してみること(ときには言語化して、べぶさんに確認してみること)も必要でした。
既存の機能を活用した実装をすること
すでに実装されている機能(型、関数、APIなど)を理解し、共通で使える部分は積極的に再利用することを心がけました。また、自分が書いたコードが再利用や拡張される可能性も考えてプログラムやコメントを書きました。あとは、既存のコードに変更を加える際は、既存のコードへの影響や、同時に開発を進めている tomoe さんとのコンフリクト(コードの競合)も考慮しながら、かなり慎重に行なう必要がありました。
チームのルールとスタイルに合わせること
ぶべさんが作成された「実装・レビュー手順」や「実装上の注意」を繰り返し確認して「実務体験」という目的を意識して開発のフローやルールの遵守を心がけました。また、既存のコードを参考に、変数やファイルの命名、配置、処理の流れ、エラー処理などについて、一貫性のある実装となるように(できるだけ)意識しました。
チーム開発におけるコメントとコミットについて、僕が実践した具体的な工夫を紹介します(たぶん、方向性は間違っていないハズ…盛大に間違っていたらDMください💦)。
個人開発では、コメントは「自分」のために書きます。それに対して、チーム開発では「チームメンバー」や「レビュワー」が読み手となります。そのため、コメントは「この処理は何をしているか」というよりは、「この関数はどのように使用するのか」や「なぜ、このような処理や設計にしているのか(意図・ねらい)」を意識して書くようにしました。
具体的には、こんな感じです・・・。
// // Stripeの価格IDは、NEXT_PUBLIC プレフィックス無しの環境変数として管理され
// フロントエンドからアクセスできないため、フロントエンド用とバックエンド用で
// 型を分けて定義している。
// フロントエンド用のプロダクト(購入可能なポイントパッケージ)の情報
export type PointProduct = {
name: string; // 表示名
price: number; // 価格(円)
point: number; // ポイント数
};
// バックエンド専用のプロダクト情報(Stripeの価格IDを追加)
export type StripePointProduct = PointProduct & {
stripePriceId: string;
};
/**
* Stripeによる支払い完了後のポイントチャージ処理
*
* @param points - チャージするポイント数(呼出し側で正の整数を保証)
* @param stripePaymentId - Stripeの支払いID(Webhookから取得)
* @returns ポイントチャージ後のユーザー情報
* @throws DBに対するポイントチャージ処理に失敗した場合
*/
public async chargePointByPurchase(
points: number,
stripePaymentId: string
): Promise<User> { ... }
// Webhook の受信自体は成功しているため(Webhookのリトライを防ぐため)、
// Stripe に対しては「正常受信」のレスポンス を返す。
return NextResponse.json({ received: true }, { status: 200 });
レビューを受けることを前提に、コードの変更を適切な単位でコミットすることを心がけました。具体的には、関連する一連の複数処理を実装して、その動作を十分に確認した後、変更全体を1つのコミットにするのではなく、機能的なまとまりごとに(独立した意味を持つ単位で)複数に小分けしてコミットしました。
ちなみに、大変だったことですが、これはまさに、茜さんが【チーム開発】技術的に大変だったことに書かれていることのまんまでした🤣
この「エンドポイント足りなくはないですか?」とか、「レスポンスに●●が必要なのにないです」とか、他の実務案件含めて実際結構あるんですけど私の間違いだったらいけないので確認するのに結構勇気が要ります。
他にもできなくはないけどここの型が一緒だったらPropsもっとシンプルになるのに違う・・でもできなくはないからと実装したらレビューでまとめて渡せと言われて、したいけど型が違うから出来ない旨伝えるとバックエンド変更になったこともありました。
設計や実装に気になる箇所があっても「 develop ブランチにあるということは、Masterぶべのコードレビューを通過しているものなので何か深い意図があるのかも…、でも、単に仮実装ぐらいの温度で書いているのかも…」のような🤨
これは、直接、確認するしかないわけですが、第13章の実務案件体験には「仕様の確認を除いて、講師やTAに技術的なサポートを受けること原則禁止」というルールがあって質問や相談の仕方にも工夫が必要でした。
つまり、単に「AAAは、なぜBBBのようになっているのですか?」ではなく、「AAAは、CCCのようにするとDDDのようなメリットが得られると考えています。現状のBBBをCCCのように変更しても問題ないでしょうか?ただ、BBBには、EEEのようなメリットがあることも理解しています。」のような提案や分析を含む形が期待されていると考え、これを言語化することが結構に大変でした(とはいえ、言語化の途中で自分の間違いに気づくこともあったり、別のアイデアがひらめいたりして、結果的にはとても良い勉強になりました)。実は、もっと気軽に聞いてもよかったのかもしれませんが(笑💦