Laravel模块划分按业务还是技术

wen PHP项目 2

本文目录导读:

Laravel模块划分按业务还是技术

  1. 按技术划分(不推荐)
  2. 按业务划分(推荐)
  3. 如何选择:什么时候用业务,什么时候用技术?
  4. 最佳实践:结合 Laravel 特性
  5. 常见问题及解决方案

在 Laravel 项目的模块划分上,强烈建议按业务划分,而不是按技术划分,这是大型项目保持可维护性和可扩展性的关键原则。

下面详细解释原因、对比两种方式,并给出最佳实践建议。


按技术划分(不推荐)

这是许多初学者或小型项目常见的结构,所有文件按“是什么”来归类。

示例结构:

app/
├── Http/
│   ├── Controllers/
│   │   ├── UserController.php
│   │   └── OrderController.php
│   └── Requests/
│       ├── StoreUserRequest.php
│       └── StoreOrderRequest.php
├── Models/
│   ├── User.php
│   └── Order.php
├── Services/
│   ├── UserService.php
│   └── OrderService.php
└── ...

问题:

  • 高耦合: 一个业务功能(如“用户注册”)的代码分散在多个目录中,难以定位和修改。
  • 难以复用: 如果想将“订单”模块移植到另一个项目,需要手动提取多个目录中的文件。
  • 扩展困难: 当项目变大,目录层级越来越深,查找文件变得困难。
  • 团队协作冲突: 多人同时修改同一个 Controllers 目录下的不同文件,虽然不会直接冲突,但逻辑上容易混乱。

按业务划分(推荐)

将每个独立业务单元(如用户、订单、支付)相关的所有代码放在一个模块目录下。

示例结构(使用 Laravel 的 ModulesDomains 目录):

app/
└── Modules/
    ├── User/
    │   ├── Controllers/
    │   │   └── UserController.php
    │   ├── Requests/
    │   │   └── StoreUserRequest.php
    │   ├── Models/
    │   │   └── User.php
    │   ├── Services/
    │   │   └── UserService.php
    │   ├── Routes/
    │   │   └── web.php
    │   └── Providers/
    │       └── UserServiceProvider.php
    ├── Order/
    │   ├── Controllers/
    │   │   └── OrderController.php
    │   ├── Requests/
    │   │   └── StoreOrderRequest.php
    │   ├── Models/
    │   │   └── Order.php
    │   ├── Services/
    │   │   └── OrderService.php
    │   ├── Routes/
    │   │   └── web.php
    │   └── Providers/
    │       └── OrderServiceProvider.php
    └── ...

优点:

  • 高内聚: 一个模块包含了完成该业务所需的所有组件(Controller、Model、Service、Route、Event、Listener等)。
  • 独立性: 每个模块可以独立开发、测试、部署,甚至可以由不同团队负责。
  • 易于复用: 整个 User 模块可以轻松复制到另一个项目。
  • 清晰导航: 查找“用户”相关代码,直接进入 Modules/User 目录即可。
  • 支持上下文边界: 可以防止模块之间的内部实现细节互相泄露(订单模块不应直接调用用户模块的模型,而应通过接口或事件通信)。

如何选择:什么时候用业务,什么时候用技术?

场景 推荐方式 原因
小型项目(1-2个开发者) 按技术划分(简单) 项目规模小,复杂度低,按技术划分更直观、快速。
中型/大型项目(多人团队) 按业务划分 模块化、高内聚、低耦合,便于并行开发和维护。
微服务架构 按业务划分(独立仓库) 每个业务模块直接是一个独立的服务。
共享基础设施(如日志、审计) 技术型模块(如 Core 将通用组件放在一个 CoreSupport 模块中,被其他业务模块引用。

最佳实践:结合 Laravel 特性

  1. 使用 nwidart/laravel-modules 扩展包:这是 Laravel 中最流行的模块化扩展包,它帮你创建 Module 目录,并自动处理命名空间、路由、配置等。

    composer require nwidart/laravel-modules
    php artisan module:make User
    php artisan module:make Order
  2. 或手动创建 app/Domains/ 结构:不想用第三方包,可以手动在 app 下创建 Domains 目录,并手动调整 composer.jsonautoload 配置。

    // composer.json
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "App\\Domains\\User\\": "app/Domains/User/"
        }
    }
  3. 模块内部结构灵活:每个模块内部可以继续按技术划分(Controllers, Models, Services),但模块之间必须按业务划分。

  4. 模块间通信

    • 通过接口/契约:为模块定义接口,其他模块通过接口调用,而不是直接依赖具体实现。
    • 通过事件/监听器:模块发出事件,其他模块监听处理(解耦)。
    • 通过 Facade/Service Container:依赖注入时,绑定到接口。

常见问题及解决方案

问:两个模块需要共享同一个 Model 怎么办?

答: 这表明模型可能不属于某个单一模块,而是核心实体,解决方案:

  • 将共享 Model 放在 CoreShared 模块中。
  • 或者将 Model 作为“聚合根”,只在一个模块中定义,其他模块通过接口或服务来访问。

问:模块之间的 Controller 名冲突怎么办?

答: 使用 Laravel 的命名空间自动解决。App\Modules\User\Controllers\UserControllerApp\Modules\Order\Controllers\OrderController 不会冲突。

问:按业务划分会不会导致目录过深?

答: 是的,但这是可接受的代价,可以通过 IDE 的“跳转到文件”功能(Ctrl+Shift+N)快速定位,或使用 php artisan module:list 查看所有模块。


维度 按技术划分 按业务划分
逻辑相关性 低(代码按“是什么”散落) (代码按“做什么”集中)
可维护性 低(修改某功能需跨目录操作) (修改某功能只需进一个模块)
可复用性 低(无法整体迁移) (整个模块可导出)
团队协作 容易冲突(逻辑上交叉) 并行开发(每个团队负责一个模块)
适合场景 小型项目、原型验证 中大型项目、企业级应用

最终建议: 除非你的项目只有几百行代码且不会再增长,否则永远选择按业务划分模块,这是从“能用”到“好维护”的关键一步。

抱歉,评论功能暂时关闭!