チーム開発未経験でも大丈夫！個人開発で「チーム開発力」を高める7つの工夫

こんにちは、Naotoです。（久しぶりに記事書きました。）

現在私は、Web開発未経験からソフトウェアエンジニアへの転職を目指しておりますが、チーム開発の経験がなく、とても焦っております。
さらに、現職では残業が不定期なこともあり、他の人と時間を合わせてチーム開発をするのも難しい状況です。。

そこで、「個人開発でもチーム開発を想定してできることはないか」と思い、開発環境や運用ルールをチーム開発に近づける取り組みを行いました。

この記事では、その取り組みを紹介します！
同じように、**チーム開発経験を積みたいけど時間が取れない方**の参考になれば幸いです。

## チーム開発を意識した開発環境の構築

### ①GitHub Projectでのプロジェクト管理

まずはプロジェクト管理です。
「個人開発だからわざわざツールを使って管理しなくても頭の中で十分管理できる」と思っていましたが、使ってみると個人開発でも意外と便利でした。

GitHub Projectの概要については、こちらを参照ください。

https://docs.github.com/ja/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects

私は、主に「かんばん式」のテンプレートを使用し、「着手前（Todo）」、「対応中（In Progress）」、「完了（Done）」にタスクを分けて管理していました。（左下のTodoの「Add item」にて新規タスクを追加します。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/80754d2e-9ad3-42ef-a3be-b8d9f078b01b.png)

GitHub Projectにてタスクを追加するとIssueが自動作成されます。
また、Issueをクローズすると自動的にGitHub Projectのタスクが「完了（Done）」に移動します。（便利！）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/8f37499b-28f2-4744-96ba-d182a6f1b8b4.png)


### ②GitHubでのソースコード管理
GitHubでのソースコード管理は個人開発でも利用している人は多いのではないかと思います。
しかし、今まで私は、「mainを直接編集し、pushする」という、現場では絶対にあり得ない運用で開発をしていました。。笑
今回は、反省＆改善ということで、ブランチ運用、コミット、プルリクエストなどについて少しチーム開発っぽくしてみました。

#### ブランチ運用ルール
以下のようにブランチを作成し、運用しました。
- `feature/*`: 開発用  
- `develop`: 検証用  
- `main`: 本番用  

##### なぜこの運用にしたか？

- Git Flowを参考にしつつも、releaseブランチは作らず、Git FlowとGitHub Flowとの中間くらいの運用にすることで、スピード感と確実性のバランスを重視したかったからです。（Git Flowだとガチガチすぎる＋こまめにリリースしたかった。） 
- トランクベース開発は、短サイクルでmainにマージする手法であり、CIやコードの質がより重要となるため、自分のスキル的にリスクが高いと判断し採用しませんでした。

#### コミットメッセージのテンプレート作成
コミットメッセージの内容もルール化しました。
コミット種別はネット記事を参考にしながら、自分がしっくりくるように分類しました。
```bash
git commit -m "コミット種別: #Issue 変更の概要" -m "○○のため、○○をした。"
```
コミット種別
- fix: バグの修正
- feat: 新しい機能
- update：機能修正（バグではない）
- refactor: 仕様に影響がないコード改善(リファクタ)
- style: 空白、フォーマット、セミコロン追加など
- remove：機能削除
- test: テスト関連
- docs: ドキュメントのみの変更
- chore: その他、ビルド、補助ツール、ライブラリ関連など

#### プルリクエストのテンプレート作成
プルリクエストの内容もルール化しました。
こちらもネット記事を参考に、自分がしっくりくる構成にしました。
```bash
## Issue
Issueナンバーを記載

## 概要
変更の概要を記載

## 対応内容
変更の詳細を記載

## 動作確認内容
どのように動作確認したかを記載

## 影響範囲
変更が及ぼす影響を記載

## 未対応内容・課題
対応できなかったところ、今後対応すべき課題を記載

## レビュー観点
実装に不安があった部分など、レビューの際に注視して欲しい箇所を記載

## 補足
その他の特記事項を記載

```

### ③GitHubu ActionsでのCI構築
ほとんどの企業がCIを構築し、運用しているかと思いますが、私は全く知識がなかったので、初挑戦してみました。

今回は、`git push`をトリガーに発火するワークフローを作成してみました。
（ymlファイルの内容は割愛します。）

#### ジョブの内容
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/58f35b88-b0fe-4b15-bdeb-14b893786807.png)
- SlackでCI開始通知
- TypeScriptのコンパイルチェック
- Buildチェック
- ユニットテスト（Vitest）
- E2Eテスト（Playwright）
- SlackでCI終了通知（成功 or 失敗）

こんな感じでSlackに通知が来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/cd528b0e-438a-43c7-8f1e-3d762adde746.png)

### ④ESlintの設定
チーム開発をする上では、コーディングスタイルの統一、ルール化も重要です。
今回は、以下のように、いくつかの推奨ルールを継承した上で、独自のルールを設定しました。
特に、TypeScriptでの「Type」or「Interface」や、「アロー関数」or「function宣言」のような、どっちでも書けるよ系の文法を統一するように意識しました。（チーム開発する上で書きっぷりが統一されていることは大事だと思ったため。）

flat configで書けていない点は見逃してください。。。

```bash
{
  "env": {
    "browser": true, //window, alert
    "node": true, //process
    "es6": true //import, const, let
  },

  "parser": "@typescript-eslint/parser", //tsのルールを適用するパーサー(js→tsの文法を解析する)

  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module",
    "projectService": true, //tsの型チェックサービスに各ソースファイルの型情報を要求することを示す
    "tsconfigRootDir": "/Users/naoto/Library/Mobile Documents/com~apple~CloudDocs/Engineering/Application/chiritsumo-14" //プロジェクトのルートディレクトリの絶対パスをパーサーに伝える
  },

  "root": true, //ESLint がこのディレクトリを超えて構成ファイルを検索しないことを示す

  "plugins": [
    "@typescript-eslint", //tsのルールを適用するプラグイン
    "import" //importのルールを適用するプラグイン
  ],

  "extends": [
    "eslint:recommended", //eslintのルール
    "plugin:@typescript-eslint/strict-type-checked", //tsのルール（文法、ロジック）
    "plugin:@typescript-eslint/stylistic-type-checked", //tsのルール（スタイル）
    "next/core-web-vitals", //nextのルール（Reactのルールも継承）
    "plugin:prettier/recommended" //prettierのルール
  ],

  "rules": {
    /** 命名規則に関するルール */ ////////////////////////////////////
    "@typescript-eslint/naming-convention": [
      "error",
      {
        // 変数名
        "selector": "variable",
        "format": ["camelCase", "PascalCase"]
      },
      // ブール値の変数名
      {
        "selector": "variable",
        "types": ["boolean"],
        "format": ["PascalCase"],
        "prefix": ["is", "should", "has", "can"]
      },
      {
        // classやtype,interfaceなど
        "selector": "typeLike",
        "format": ["PascalCase"]
      },
      {
        // 関数のパラメータ名
        "selector": "parameter",
        "format": ["camelCase"]
      }
    ],
    /** 型定義に関するルール */ ////////////////////////////////////
    // 型定義はTypeで強制
    "@typescript-eslint/consistent-type-definitions": ["error", "type"],

    /** 関数に関するルール */ ////////////////////////////////////
    // 関数はアロー関数で強制
    "func-style": ["error", "expression"],
    // 関数コンポーネントもアロー関数で強制
    "react/function-component-definition": [
      "error",
      { "namedComponents": "arrow-function" }
    ],

    /** exportに関するルール */ ////////////////////////////////////
    // named exportの強制
    "import/no-default-export": "error",

    /** その他のルール */
    /** ==, != の使用禁止 */ ////////////////////////////////////
    "eqeqeq": ["error", "always"]
  },

  "overrides": [
    // Next.jsにて用意された以下ファイルにはdefault exportを使用する
    {
      "files": [
        "**/page.{js,jsx,tsx}",
        "**/layout.{js,jsx,tsx}",
        "**/loading.{js,jsx,tsx}",
        "**/not-found.{js,jsx,tsx}",
        "**/error.{js,jsx,tsx}",
        "**/global-error.{js,jsx,tsx}",
        "**/route.{js,ts}",
        "**/template.{js,jsx,tsx}",
        "**/default.{js,jsx,tsx}"
      ],
      "rules": {
        "import/no-default-export": "off",
        "import/prefer-default-export": "error"
      }
    }
  ]
}
```

### ⑤Prettierの設定
ESlintは、コードの内容を検査し、統一してくれますが、Prettierは、コードの内容ではなく、書きっぷりを統一してくれます。
（ESlintでも書きっぷりの統一は可能だが、責務を分けるために書きっぷりはPrettierにお願いした方が分かりやすい。）
見やすいコード、統一されたコードを実現するには、こちらも重要です。

以下のように、設定してみました。

- インデントの大きさや、セミコロン、クォーテーションなど、基本的なフォーマットの設定
- プラグインを使用した、import順を並び替える設定と、tailwindのプロパティ順を並び替える設定（とても見やすくなるのでおすすめです。）

```bash
{
  "tabWidth": 2,
  "singleQuote": true,
  "semi": true,
  "trailingComma": "none",
  "importOrder": [
    "^(react/(.*)$)|^(react$)",
    "^(next/(.*)$)|^(next$)",
    "<THIRD_PARTY_MODULES>",
    "",
    "^types$",
    "^@/(.*)$",
    "^[./]"
  ],
  "importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"],
  "plugins": [
    "@ianvs/prettier-plugin-sort-imports", //import順を並び替えるプラグイン
    "prettier-plugin-tailwindcss" //tailwindのプロパティ順を並び替えるプラグイン
  ]
}
```

### ⑥Huskyを導入し、commit時にLinterとFormatterを回す
Huskyは、Gitのフックを簡単に管理・実行できるツールです。
たとえば`commit`や`push`などのフックに任意のスクリプトを登録することで、特定のGit操作の直前に処理を実行できます。
詳しくは以下を参照ください。

https://typicode.github.io/husky/

今回は、`git commit`したタイミングで、上記のESlintとPrettierによるコード品質チェクを行うように設定しました。
設定方法は以下のShinCodeさんの動画を参照ください。

https://www.youtube.com/watch?v=TTutJJUGMbY&t=1854s

上記設定を行うことで、以下を実現しました。
- コードレビュー前にHuskyにより静的チェックが自動で行われるため、レビューの質が向上する。
- Lint・Formatの実行結果に問題がある場合はコミットが中止されるため、ミスの混入を防止できる。

これでコードの品質を大幅にUpできます。

### ⑦Sentryによるエラー監視
本番環境のエラー状況を監視するためのツール「Sentry」を導入しました。
個人開発とは言いつつも、リリースし、多くの人たちに使ってもらいたいアプリだったため、本番環境でのエラーを可能な限りキャッチできるように導入を決めました。

まだあまり使いこなせていませんが、一応エラーはキャッチできる状態にはできたので、今後はカスタマイズ等にも挑戦してみようと思いまます。

https://sentry.io/welcome/

他ツール（Data Dogなど）もある中でSentryを選んだ理由は以下です。
- 導入が簡単だったから。
    - 無料で開始できる。
    - next.js用のwizardを提供してくれているため、コマンドを実行するだけでSentryに必要なファイルを自動で生成し、設定までしてくれる。
- 情報量が多そうだったから。
- 機能も良さそうだったから。
    - エラー監視だけでなくパフォーマンスの計測が可能。
    - 画面録画でなく、収集したイベント情報からユーザー画面を再現しており、エラー発生前後の挙動が分かりやすい。
    - 通知対象をエラーの重要度や頻度等で条件指定し、フィルタリングできる。S

## チーム開発を意識した開発フロー
上記にて紹介した７つの開発環境を構築し、以下の通り開発を進めています。

1. GitHub Projectでタスクを作成（＋Issue紐付け）
2. feature/* ブランチでローカル開発
3. commit時に ESLint / Prettier によるコードチェック
4. pushすると CI が実行される（開発環境での確認）
5. feature → develop へPR作成・レビュー
6. develop へマージし、再度CIで検証
7. 1〜6を繰り返す
8. リリースのタイミングで develop → main へPR作成
9. main へマージ後、自動で本番デプロイ（CI/CD）
10. エラーはSentryで監視

※私はデプロイ先をVercelにしているため、mainにマージされたら自動でデプロイされるVercelのデフォルトのCDを使用しています。

## 最後に
以上の取り組みから、「チーム開発経験ができない＝諦める」ではなく、個人開発でも工夫次第でチーム開発を意識した経験は積めると感じました。

この記事が、同じような状況の方の参考になれば嬉しいです。

ご質問や感想など大歓迎です！
最後まで読んでいただきありがとうございました！