こんにちは、ゆきおです。
今回は、この夏にフロントエンドの開発フェーズから参画した案件で学んだことや気づいたこと、考えたことなどを走り書きレベルでザーッとアウトプットしておこうと思います。
コーディング
コーディングに関してはクリーンアーキテクチャに則り実装を進めていきました。
・UI層
各ページ名をフォルダ名にし、最終的にエクスポートするビュー自体は全て「index.tsx」というような形にしました。
Login/index.tsxみたいな形ですね。
コンポーネントも同じく、最終的なエクスポートはindex.tsxで統一しています。
index.tsxはあくまでコンポーネントの呼び出しとエクスポートに専念し
実際の実装はLoginForm.tsxといった名前で実装するようにしました。
src/
└── components/
├── Login/
│ ├── Login.tsx
│ └── index.tsx
└── App.tsx (例)
こうすることで実装と外部への公開(エクスポート)が分離され、とても管理しやすくなります。
またページによってはコンポーネントが3つとかになり複雑化していくため、そういう場面でもエクスポート用のindex.tsxがあるとコードを追っかけやすくなります。
src/
├── components/
│ ├── Header/
│ │ ├── Header.tsx
│ │ └── index.tsx
│ ├── MainContent/
│ │ ├── MainContent.tsx
│ │ └── index.tsx
│ └── Footer/
│ ├── Footer.tsx
│ └── index.tsx
│
├── pages/
│ └── SamplePage/
│ ├── SamplePage.tsx
│ └── index.tsx
│
└── App.tsx
こんな感じですね。
他にもメリットとして、index.tsxに統一することでコンポーネントを呼び出す際にインポート文をファイル名まで書かなくていいのでシンプルになります
import { Header } from '@/components/Header';
import { MainContent } from '@/components/MainContent';
import { Footer } from '@/components/Footer';
・ロジック層
ロジックの実装にはtanstackqueryなど定番のライブラリを使用しました。
実装は単純にrepository,usecaseとよくあるパターンです。
・repositoryはバックエンド側とやり取りするだけ
・usecaseでデータの整形やユーザーの動き、エラーハンドリングを実装する
といった形です。
バックエンドから取得した値のモデル(型)に関してはrepository内にtypes.tsとして実装しました。
APIで取得した生データの型はそれを扱うrepositoryに、変換後の型はdomainディレクトリに実装するようにしました。
usecaseでは「読み込み系」「書き込み系」「キャッシュ」の3ファイルに分かれています。
ここで表示できる形の型に変換(スネークケースからキャメルケースへ)、エラーハンドリング、キャッシュの利用などを担当します。
repositoryとusecaseの役割を完全に分離させることで、UI側はrepositoryのことを全く意識せず、必要なusecaseの呼び出しだけしてればいいという実装になります。
こちらもファイル名は統一しており
src/
├── repository/
│ └── user/
│ ├── repository.ts // 🧑🍳 APIとの通信のみ担当
│ └── types.ts // 🚚 APIの型定義(スネークケース)
│
├── usecases/
│ └── user/
│ ├── Reader.ts // 📖 読み取り系のロジック
│ ├── Writer.ts // ✍️ 書き込み系のロジック
│ └── Cache.ts // 🗄️ キャッシュ管理(シンプルな例)
│
└── components/
└── UserProfile.tsx // 🖥️ Usecaseを利用するUIコンポーネント
大体ですがこんな形になっています。
なるべく細かく役割分担を決め、ディレクトリ名やファイル名のルールを一本化することでメンバー間の齟齬を減らすことができると思います。
他にもコーディングルールとして「なるべくletは使わない」とか、「classは使わずcustom hooksや関数でできないか考える」とか、ガイドラインをまとめてGithubのWikiに記載していました。
リーダーの方が経験豊富ですごく出来る方だったので詳しくルール設定されていました。
この辺はとにかくアンチパターンやベストプラクティスの勉強ですね。
こういった設計の仕方はWebフロントエンドだけでなく、モバイルにも応用できそうだなと思いました。
Github運用
・ブランチの命名規則や開発ブランチなどの作成
ブランチを開発用やステージング用、本番用と分けてデフォルトのブランチは開発用ブランチにしておく。これでクローン時やPRをマージする先を開発用ブランチにできるので事故防止になる。
・PRテンプレートの作成
Gitと連携することで作成される.githubフォルダ内にテンプレートファイルを作成することでPR作成時に自動的にそれが適用されるので活用する。
・Assignees ,Reviewerの設定
Assigneesに自分を設定し、チームメンバーをReviewersに設定する
・Labelsの設定
レビューして欲しい、レビュー終わりましたなどをぱっと見で判断できるようなラベルを作成する
・マージするまでの流れを設定する
レビューでApproveをもらわないと基本的にマージは出来ないようにする。
今回は基本的にApprove2つでマージできるように設定しました。
・再レビュー依頼
要修正のレビューの対応後、Reviewersのアカウントのところにぐるぐる矢印みたいなマークがつくのでそれを押すと通知が行きます。
レビューのたびにSlackなどでやりとりしていると他の会話がどんどん流れてしまうのでこのようなやりとりになりました。
・CI/CD環境
作成したPRに型エラーやタイポ、ビルドエラーなど問題がないかをGithubが自動でチェックしてくれるようにActionsを作成する。
これは調べると記事が多く出てきますね。
基本的にGithubのルール策定の目的は、実装した内容に問題がなく他のメンバーに影響が波及しないかとか、うっかりマージする先を間違えた!とか、そういった事故防止のための対策を初期にやっておきます。
また、決め事はリポジトリのWikiにまとめておくと後から入ってきた人にもわかりやすくなります。
その他
・コミット時のチェック
huskyというライブラリを使って、コミット時などに走るコマンドを登録しておきました。
中身はbiomeによるフォーマットとリント、cspellによるタイポチェックです。
これらが引っかかるとそもそもコミット出来ないという仕組みになっています。
メンバー間での実装のバラつきや、うっかりミスがほぼ無い状態でGithub上に送られます。
VSCodeを使用していたので、拡張機能もそれに合わせて導入します。
・Backlog
タスクの管理はBacklogを使っていました。
UIの実装とロジックの実装を分けてチケット作成していたのですが、この辺は運用していく上で結構大事なポイントになるなと思いました。
UIの実装者とロジックの実装者が違うと少々ややこしくなるなあと思ったので、画面ごとにチケットを分けてUI実装〜ロジック実装までを一つの親課題としてやってみるのはどうかなと思いました。
UI,ロジック,モックを使った繋ぎ込みまでを1つの親課題としておくと、各画面の実装がどの程度進んでいるのかがわかりやすいのかなと思いました。(もちろん規模によりますが
終わり
ざっと今回の経験の中で参考になるなあと思ったことをまとめました。
開発の初期段階でこういうことを細かく決めておけば、後々の開発がスムーズに行えます。
またアプリの設計に関しても今後モバイルやWebフロントエンドで横断的に使えそうな設計を考えようかなと思ういいきっかけになりました。
今後そういった記事も書いていこうと思います。