Controller 只管"接客"、Service 只管"算账"、Model 只管"翻账本"——我这套拆分规矩被新来的实习生一天打破三次

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
站长杂谈 117 浏览 0 回复

上周招了个后端实习生,简历上写着"熟悉 MVC"。我心想行啊,分层这活儿总算有人能分担了。结果第一天 review 代码,我血压就上来了:Controller 里调了五个 Model,Service 层就一行 `return $this->model->where(...)->select()`,Model 里塞了段发邮件的逻辑。

我跟他说,分层不是把代码从 A 文件挪到 B 文件就完事的。咱得先定好规矩:谁该管啥,边界画在哪。不然三个月下来,项目就变成"三层都是泥"。

先说说我现在的拆法,不一定对,但至少目前没把自己绕进去。

Controller:门口迎宾,别进厨房

Controller 我就让它干三件事:接参数、做格式校验、决定返回什么格式。别的?别碰。以前我也犯过错,图省事在 Controller 里直接 `Db::table(...)`,后来接口要复用,复制粘贴一堆,改个字段名全站报错。

现在我的 Controller 长这样:拿到 request,抽参数,扔给 Service,Service 返回啥我包一层 JSON,完事。最多加个 `try-catch` 兜个底。超过二十行?肯定哪层偷懒了。

Service:算账先生,别自己跑仓库

Service 是我花心思最多的地方。它的活儿是"业务逻辑"——这个词太虚,我具体点:算价格、拼数据、调外部接口、控制事务。但有个红线:Service 不直接碰 SQL,要查要改找 Model。

有个坑我踩过两次。之前做电商项目,下单逻辑里既要扣库存又要写订单还要清购物车。我把这些全塞一个 Service 方法里,事务是包了,但方法长到我自己都怕。后来拆成 `OrderService::create()` 调 `StockService::deduct()` 和 `CartService::clear()`,通过依赖注入进来。每个方法就几十行,单元测试也好写了。

不过这里有个争议点:Service 之间能不能互相调?我的做法是允许,但禁止循环依赖。实在要解耦,用事件或者消息队列。不然 A 调 B、B 调 C、C 又调 A,调试的时候跟追谍战片似的。

Model:仓库管理员,别操心生意经

Model 层我只放数据访问相关的东西:定义关联、写 scope、封装常用的查询条件。以前我把"根据用户等级算折扣"也塞 Model 里,觉得反正跟用户有关。后来发现这逻辑在后台管理也要用,但后台走的是另一套权限体系,Model 里越写越乱。

现在我的 Model 尽量"薄"。复杂查询用 scope,比如 `User::scope('active')->scope('vip')` 这种链式调用。但如果是"算折扣"这种业务规则,上升到 Service。Model 只管"能不能查到",不管"查到之后怎么算"。

那 Validator 和中间件算哪层?

这个我也纠结过。现在我的做法是:参数格式校验(手机号是不是 11 位、密码有没有特殊字符)放 Validator 或者中间件,业务规则校验(这个手机号有没有注册过、库存够不够)放 Service。这样 Controller 更干净,Service 也能拿到已经清洗过的数据直接干活。

实习生那堆代码我怎么改的

把他 Controller 里的五个 Model 调用全抽出来,建了个 `PostFlowService`。发帖要干的事:校验敏感词、扣积分、写主表、写关联表、发通知。全进 Service,Controller 就一行 `$this->postFlow->execute($data)`。

Model 里那段发邮件的逻辑?扔到 `NotificationService` 里,通过事件触发。发帖成功抛个 `PostCreated` 事件,监听者去发邮件,主流程不用等。

改完我让他对比下前后两份代码。他说:"好像……没什么大变化?"我说你过两个月回来改需求就知道了。现在加"发帖送徽章"功能,我只要在事件里加个监听;以前?你得去 Controller 里找那段 `if ($post->save()) { ... }` 往里面硬塞。

最后说句实在的

分层这玩意儿没有标准答案,但一定要有"答案"——就是团队得达成共识。我见过最离谱的项目,三个后端各写各的,一个把逻辑全堆 Controller,一个 Service 里直接 `DB::raw`,一个 Model 继承了三层基类。代码合到一起,跟三个方言对话似的。

我现在每个项目开头先写个 `docs/layer-convention.md`,哪怕就几百字。新人入职先看这个,review 代码有依据。规矩是死的,但没规矩,代码就是活的灾难。

你们团队的分层是怎么定的?有没有那种"一开始觉得多此一举,后来真香"的规矩?

评论0
回复 · 0
还没有回复
微信客服 微信客服