【2026年版】フリーランス単価UPに効くLaravel設計力|サービス層・DI・DTOでMVCを超える実務パターン
はじめに:設計力でフリーランス単価が月20万変わる理由
同じLaravelエンジニアでも、月単価40万円の案件もあれば月90万円の案件もあります。この差を分けるのは「書けるコード量」ではなく「保守性の高い設計ができるか」です。
フリーランスは一度プロジェクトに入ったら、短期で結果を出し信頼を積まねばなりません。MVCで雑に書いても動くLaravelだからこそ、設計力の差がプロのフリーランスとそうでない人を分けます。
この記事では、Laravelを使いながらフリーランス高単価案件で通用する設計力の第一歩として、サービス層・DI・DTOの3つを実装例付きで解説します。
Laravelを使って開発をしていると、ある段階で「Controllerが太ってきた」「テストがしづらい」「再利用できない」といった課題に直面することがあるのではないでしょうか?それは、MVCの枠組みだけでプロジェクトが進行している場合に起こりやすい問題です。
本記事では、Laravelを使いながらアプリケーションをより保守性の高いものにするための第一歩として、サービス層、DI(依存性注入)、**DTO(データ転送オブジェクト)**の3つを中心に解説します。
MVCだけではつらくなる理由
Laravelの公式チュートリアルや多くの初学者向け記事では、Controller内にロジックをまとめて記述するスタイルがよく見られます。しかし、以下のような状況になると限界がやってきます:
- フォームからのリクエストをそのまま使い、バリデーション、保存処理、通知などすべてControllerでやっている
- Controllerのメソッドが300行近くに膨らんでいる
- 似たようなロジックを他のControllerでも書いている
このような状況を「Fat Controller」と呼び、保守性・拡張性・テスト性が著しく低下します。
サービス層とは何か?
定義と目的
サービス層(Service Layer)とは、アプリケーションのビジネスロジックをControllerから切り離して、再利用可能な形で定義する場所です。
例えば、「ユーザーを登録して、メールを送って、ログを残す」という一連の処理をControllerにベタ書きするのではなく、UserServiceクラスにまとめます。
役割
- 複数の操作を1つのロジックとしてまとめる
- ControllerはHTTPの受け口として最低限の処理に専念
- ビジネスロジックの単体テストが容易になる
実装例
// app/Services/UserService.php
class UserService
{
public function register(array $data): User
{
$user = User::create($data);
// メール送信やログ処理などもここに
return $user;
}
}
// app/Http/Controllers/UserController.php
public function store(Request $request)
{
$user = $this->userService->register($request->validated());
return redirect()->route('users.index');
}
このようにすることで、Controllerは「依頼」だけを行い、処理はServiceに任せる構成になります。
DI(依存性注入)とは?
LaravelにおけるDI
Laravelでは、クラスのコンストラクタで依存クラスを指定すると、自動的にインスタンスを注入(インジェクション)してくれます。これがサービスコンテナ(Service Container)と**IoC(Inversion of Control)**の恩恵です。
なぜDIが必要か?
- テスト時にMockやStubを渡せるようになる
- サービスを切り替えることが容易になる(例えば、開発用と本番用)
- 依存の管理が明示的になり、コードの読みやすさが向上
実例
// UserController.php
class UserController extends Controller
{
public function __construct(
protected UserService $userService
) {}
public function store(StoreUserRequest $request)
{
$user = $this->userService->register($request->validated());
return redirect()->route('users.index');
}
}
DIにより、UserServiceのインスタンス生成を自分でやる必要がなくなり、テスタブルかつ疎結合なコードになります。
DTO(データ転送オブジェクト)とは?
配列渡しの限界
Laravelでは、Requestクラスから配列でデータを受け取り、それをそのままServiceに渡すことが多いですが、これだと以下のような問題があります:
- 渡す側と受け取る側で項目が合っているか曖昧
- リファクタ時に不整合が発生しやすい
- 自己完結性がなく、可読性が低い
DTOの役割
DTO(Data Transfer Object)とは、ある処理に必要なデータだけを集めて運ぶ専用のクラスです。
// RegisterUserDto.php
class RegisterUserDto {
public function __construct(
public string $name,
public string $email,
public string $password,
) {}
public static function fromRequest(Request $request): self
{
return new self(
$request->input('name'),
$request->input('email'),
$request->input('password')
);
}
}
DTOを使ったService層の例
public function register(RegisterUserDto $dto): User
{
return User::create([
'name' => $dto->name,
'email' => $dto->email,
'password' => Hash::make($dto->password)
]);
}
MVC + Service + DTO の構成例
app/
├── Http/
│ └── Controllers/UserController.php
├── Services/
│ └── UserService.php
├── DTOs/
│ └── RegisterUserDto.php
このように役割を分けることで、Controllerが驚くほどスリムになります。また、DTOが明示的になることで、IDEの補完や型チェックも働きやすくなります。
設計の改善がもたらす未来
サービス層、DI、DTOを取り入れるだけでも、以下のような恩恵があります:
- 保守性の向上:修正が局所的で済む
- 再利用性:同じロジックを別の場所で簡単に呼び出せる
- テストしやすさ:Service単体でテスト可能
- 読みやすさ:コードの責務が明確になる
これらはすべて、「1人プロジェクト」でも「チーム開発」でも効果を発揮します。
次に進むなら:UseCase層・ドメイン層・クリーンアーキテクチャへ
今回紹介した設計は、いわば設計の第一歩です。これをきっかけに、次のような概念へとステップアップしていくとよいでしょう:
- UseCase層の導入:Service層と業務ロジックを分けることで責務を明確に
- ドメインモデルの導入:ビジネスルールを表現するクラス構造
- クリーンアーキテクチャ:依存の方向性を意識し、永続層やUI層からロジックを切り離す
Laravelでも十分にクリーンアーキテクチャは実現できます。
設計力が単価に直結する3つの理由
なぜサービス層・DI・DTOを使える人の単価が高いのか。発注者視点で3つの理由を解説します。
① 保守コストが半減する(=長期案件になる)
Fat Controller のコードは3ヶ月後に手を入れるのに1機能あたり3日かかります。一方Service層分割されたコードは半日。発注者にとって継続開発コストが半減するのは強力な価値提案。結果、月契約が1年続く長期案件に化けます。
② テストコードが書ける(=バグ修正に自信が持てる)
Service層をDIで切り出せばPHPUnit単体テストが書けます。テスト可能=バグ回帰を自信を持って防げる。これはジュニアエンジニアとの大きな差別化ポイントで、「シニア単価」の根拠になります。
③ 新規参画エンジニアを早く立ち上げられる(=スケール案件に呼ばれる)
設計が整ったコードベースは、新しいメンバーが2週間で立ち上がります。発注者が5人体制にスケールしたい時、設計リードできるフリーランスはPM級の単価(90万〜120万)で指名されます。
フリーランスLaravelエンジニアの単価レベル表
設計力別に、現場で求められるスキルと単価レンジを整理しました。自分の現在地と目標を確認してください。
レベル | 月単価 | 求められる設計力 | 典型的な役割 |
|---|---|---|---|
初級 | 30〜50万円 | Controller/Model で機能実装 | タスク実装・バグ修正 |
中級 | 60〜80万円 | Service層・Repository・DI・DTO | 機能設計・コードレビュー |
上級 | 80〜120万円 | UseCase層・ドメイン層 | 技術選定・PM兼務・採用面接 |
この記事で解説したサービス層・DI・DTOは「中級(月60〜80万円)」のラインです。初級との差は約30万円/月=年間360万円の違い。1〜2ヶ月の設計学習で元が取れる投資です。詳しい単価相場はフリーランスエンジニアの単価相場と交渉術 2026を参照してください。
よくある質問(FAQ)
Q. 既存プロジェクトの Fat Controller を全部書き直すべき?
全部書き直しは工数が爆発するので非推奨。新規機能から Service 層で書く + 大きな変更を加える既存機能だけリファクタがベストプラクティスです。既存コードを一気に触ると「動いていたバグ」が顕在化し、信頼を失います。
Q. UseCase 層まで入れるべき?
月5万PV以上のサービス、または3人以上のチーム開発なら UseCase 層導入推奨。小規模(1人開発)なら Service 層までで十分です。設計は「将来のスケール見込み」で選びましょう。
Q. フリーランスでLaravelの案件はまだ多い?
2026年時点でフリーランス案件の約40%がPHP/Laravelです(エージェント公開案件ベース)。LaravelはECサイト・業務システム・SaaS基盤で定番となっており、今後5年は案件豊富と見ています。詳しくはフリーランスエンジニアエージェントおすすめ7選を参照。
まとめ
Laravelは非常に柔軟なフレームワークですが、その柔軟さゆえに「すべてControllerに書いても動く」ことが混乱を招く原因になります。
今回紹介したサービス層・DI・DTOは、保守性・可読性・テスタビリティの面で非常に効果的です。
プロジェクトにアサインされると、どのようなフレームワークを使っているかよりもどのような設計になっているのかを見極めることがとても重要になります。わたしもそこが最初理解できていなかったため、慣れるのに非常に時間がかかりました。でもこれがわかっていると、言語が変わったとしても新しいプロジェクトに入った時に比較的早く馴染むことができます。
あなたがもしLaravelアプリを作っていて何かがが足りたいと思うようであれば、より成長に耐えられる構造になるよう、まずはControllerからビジネスロジックを外に出すことから始めてみるのはいかがですか。
関連記事
👉 フリーランスエンジニアの単価相場と交渉術 2026
👉 【2026年版】フリーランスエンジニアエージェントおすすめ7選
👉 会社員エンジニアがフリーランスになる完全手順 2026
👉 【2026年版】Webエンジニアロードマップ
👉 【2026年版】プログラミング言語選び完全ガイド