フロントエンド開発で失敗しないために「一番初めに」気にしたいこと
ウェブシステムを新規開発する際、最初に決めるべきは「どのように開発を進めるか」というルールを決めることかなと思う今日この頃です。コードの品質、可読性、長期的なメンテナンス性を保証するコード基盤の構築は必須の事前準備です。
この手の準備は、PJによっては経験のない方もいるかもしれません。また、個人開発だとどうしても恩恵を感じにくい(規模にもよりますが)分野だと思ったので、開発に着手する前に気にしたいことをまとめてみました!
まあ当たり前だよね〜くらいの気持ちで読んでもらえれば幸いです。
1. リンター(Linter)とフォーマッター(Formatter)の選定と設定
これはもうど定番です。
ESLint + Prettierの黄金コンビは古今東西さまざまな方が記事を書いているので、ドキュメントを探す手間は皆無だと思います。
おさらい程度に、ESLintはコーディングのルールを決めてそのルールに当てはまっているチェックしてくれるツールです。わかりやすいのは「console.logを警告する」などですね。
Prettierはコードを成形します。引用符の統一(’ or “)なんかがわかりやすいですね。
これらはコードの品質を一定に保ち、チームメンバー間のスタイルを統一するための自動化されたルールセットになります。これにより、コードレビューの負担を減らしたり、潜在的なバグを未然に防げたりするわけですね。
これまでは黄金コンビが主流でしたが、最近はBiomeという何でも屋さんが登場したりもしています。この辺は時代に合わせて使うライブラリを選べばいいのですが、「コードのルール設定とフォーマットの自動化」は必ずプロジェクトを開始する前に考えたいですね。(実際に導入されていないPJもちらほらある)
これらを導入せずにある程度開発が進んでしまうと、とても保守しにくいプロジェクトになってしまいます。最悪後からでも入れた方が良いのでは、と私は思っています。(膨大な量の修正とトレードオフの関係ではありますが...)
| 役割 | ツール名 | 特徴と選択肢 | 最適解と導入のTips |
|---|---|---|---|
| リンター (Linter) | ESLint | JavaScript/TypeScriptのデファクトスタンダード。柔軟性が高く、拡張性(プラグイン)に優れています。設定ファイル(.eslintrc)で詳細な品質チェックが可能です。 |
推奨設定: [Airbnb] や [Standard] など、コミュニティで広く使われている実績ある設定をベースに導入を簡略化する。 |
| フォーマッター (Formatter) | Prettier | ほぼ全てのプロジェクトで推奨されるツール。インデント、引用符、改行など、見た目のスタイル統一に特化し、設定項目が少ないため導入が容易です。 | 導入の最適解: ESLintとPrettierの併用が標準です。ESLintのスタイル系のルールをPrettierと競合しないように設定し、役割を完全に分離する。 |
| 新興の選択肢 | Biome | Rust製で非常に高速なパフォーマンスを持つ、リンターとフォーマッターの統合ツール。単一のツールで全てを完結させたい、またはパフォーマンスを最優先する場合の代替案として注目されています。 | 検討のヒント: まだエコシステムやプラグインの豊富さではESLintに劣りますが、将来的な主流になる可能性を秘めています。 |
Gitフック(Husky + lint-stagedなど)を導入し、コミット前に自動でリンティングとフォーマットを実行する仕組みを確立することで、ルール違反のコードがリポジトリに入ることを防ぎます。現在稼働中のプロジェクトもこのような仕組みです。
2. TypeScript(TS)と JavaScript(JS)の決定
開発言語として、型を持つTypeScriptを採用するか、従来のJavaScriptを採用するかは、プロジェクトの安全性と将来的なメンテナンス性に大きく影響します。
おおよそのシステム開発はデータのやり取りが発生するためTypeScriptを選ぶことがほとんどだと思います。ですが、さまざまな要因でJavaScriptを選ぶこともありえます。
基本的にはTypeScriptを選んでおきたいですね。
✅ TypeScriptを採用するメリットと基準
現代のフロントエンド開発において、TypeScriptは型安全性(コンパイル時エラー検出)と開発効率(エディタ補完等)から、大規模開発や長期運用が想定されるプロジェクトの標準となっています。
-
TSを推奨する場合:
- プロジェクトの規模が大きい、または長期的な運用が想定される場合。
- 複数人のチームで開発する場合。
- 高い品質と安全なリファクタリングが求められる場合。
TypeScriptを学習したことのない方に説明するならば、「TypeScriptの方がミスを防ぎやすい」という認識が一番わかりやすいかもしれません。JavaScriptは良くも悪くも自由度が高いため、思わぬバグが発生したりします。一方、TypeScriptはデータの型という制約の元動くので型不一致などのエラーを未然に防ぐことができます。
⚠️ JavaScriptの需要が残るケース
TSが主流となる一方で、技術的な制約や特殊な要件から、JavaScriptが選択されるべき現実的な需要も存在します。
特に導入先の環境については事前によく確認した方が良いです。TypeScriptで作ったものの全く動かずJavaScriptで書き直し、というのは想像を絶する辛さがあります。
| 状況 | 選択理由 | 考慮すべき点 |
|---|---|---|
| レガシー環境/互換性 | 地方自治体や特定の企業システムなど、古いブラウザバージョン(例: IE11など)への対応が必須な場合。トランスパイルの複雑さを避けたい。 | ES Modulesを避ける、古いJSの書き方(ES5準拠)に制限するなど、ビルド設定で互換性を最優先する必要がある。 |
| 超小規模/プロトタイプ | 開発期間が極端に短い、または学習コストをかけずに即時開発に着手したい場合。 | あえてTSの導入を見送り、初期開発のスピードを優先する。ただし、後からTSへ移行する場合は追加の工数が発生する。 |
| チームの習熟度 | チームメンバー全員がTypeScriptに不慣れで、キャッチアップのための工数が取れない場合。 | 最初はJSでスタートし、将来的なTS移行を見据えて型定義コメント(JSDoc)を記述しておく手法が有効。 |
3. ディレクトリ構成の決定
ディレクトリ構成も大事です。「何をどこにしまうか」、そんな単純なことができずにどんどん読みにくいコードになっていく、なんてことが多々あります。また、一貫性のある構成ルールを定めることで、開発者はファイルを探しやすくなり、新規参入者もコードベースを素早く理解できます。
とはいえ自分で1からルールを考えるのは結構大変です。下記のようなパターンを模したり、周りの人の直近のプロジェクト内容を参考にしたりするのがいいと思います。
🏢 代表的な構成パターン
| パターン | 特徴 | 採用すべきケース |
|---|---|---|
| Feature-based (機能別) | アプリケーションの機能(例: user, cart, product)ごとにディレクトリを分ける。 |
大規模・機能中心のアプリケーション。ビジネスロジックが追いやすい。 |
| Type-based (種別別) | ファイルの種別(例: components, pages, hooks, utils)ごとに分ける。 |
小〜中規模のアプリケーション。シンプルな構造でコンポーネントを探しやすい。 |
| Atomic Design (アトミックデザイン) | UIを最小単位から階層的に定義(atoms molecules organismsなど)する。 |
デザインシステムの構築を重視する場合。再利用性の高いUIが必要な場合。 |
個人的にはFeature-basedとType-basedのミックス系がいいかもと思っています。アプリケーションの機能ディレクトリ配下に各ファイル種別ごとのディレクトリが格納されるイメージです。
📌 構成の際に便利な考え方
- 関心の分離: 特定の機能や役割(UI、ロジックなど)を1つのディレクトリ内に閉じ込める(Co-location)ことで、関連ファイルが散逸するのを防ぎます。
-
絶対パスの活用: 読み込み(import)時に、階層の深さに関わらずプロジェクトルートからの絶対パス(例:
@/components/Button)を使えるようにビルド設定(tsconfig.jsonなど)を行う。
また、一度決めたルールでもビジネスの都合等で開発方針が変わったりすると、手直しをする必要があるかもしれません。初めからルールを厳密にしすぎたり、あまりにも細分化しすぎると逆にわかりづらくもなります。
この辺りは開発チームの習熟度やメンバー間の相互認識を確認しつつ、チーム内でコミュニケーションを取りながら都度改善していくことも大切です。
4. ファイル名のルール(命名規則)
ファイル名やコンポーネント名のルールを定めることで、そのファイルが「何を表しているのか」を一目で判別できるようにします。
下記の例は各対象ごとに適用する命名規則を割り振ったものです。こちらが正解というわけではなく、こちらを参考にプロジェクトにあった形にカスタマイズしていくことが大切です。
🏷️ 必須のルールセット
| 対象 | 命名規則(Case) | 例 | 目的 |
|---|---|---|---|
| UIコンポーネント | PascalCase |
UserProfile.tsx、PrimaryButton.vue
|
コンポーネントであることを明示し、通常の関数/ファイルと区別する。 |
| スタイルファイル | kebab-case |
user-profile.module.css、_variables.scss
|
CSSの慣習に合わせる。 |
| カスタムフック/ユーティリティ | camelCase |
useFetchData.ts、formatDate.ts
|
関数や通常のJS/TSファイルであることを示す。 |
| ディレクトリ | kebab-case または camelCase |
user-profile または userProfile
|
チーム内でどちらか一方に統一し、ディレクトリ名は複数形(例: components)にするのが一般的。 |
🗃️ Indexファイル(index.ts)の活用
関連するファイルを一つのフォルダにまとめた後、そのフォルダのルートにindex.ts/jsを配置し、そこで必要な要素をまとめてexportすることで、インポートの記述を簡潔にできます。
// /components/atoms/Button/index.ts の例
export * from './Button';
export * from './types';
// 外部からのインポートが簡潔になる
// import { Button } from '@/components/atoms/Button';
まとめ
上記は本当の本当に最低限やっておきたいことです(個人の感想)。
まだまだコードを読みやすくする工夫はたくさんありますので、チームメンバーで協力し、意見を出し合って、読みやすい・保守しやすいコードに都度改良する意識が一番大事かもしれません。
意外と話し合ってみると、お互いの知らないアプローチがあったりするかもです。
また、個人で開発する際も上記のような基本的なルールは常に意識しておきたいですね。
いざ新規開発する場に立ち会うときに絶対に役に立ちます。
こういったアプローチは、すでにできる方にとっては当たり前すぎる話ですが、初めてチームで開発する方や未経験領域の方は意外と知らなかったりします。
ですので、まずは知ること、その次に実践、最終的に継続的な改良に繋がれば、コードの世界に平和が訪れることでしょう🕊️
Discussion