代码优先 vs 设计优先的选型

解读

在国内一线互联网公司与中小型创业团队的 PHP 面试中,"代码优先还是设计优先"并不是非黑即白的哲学题,而是考察候选人能否根据业务阶段、团队规模、交付周期、技术债务与运维成本做出权衡。面试官通常会用开放性问题引导你还原真实决策链路:需求模糊时如何快速交付?需求稳定后如何重构?高并发场景如何防止"先跑起来"变成"先炸起来"?回答时要体现"场景驱动 + 量化指标 + 可落地的 PHP 技术栈"。

知识点

  1. 代码优先(Code-First)
    典型场景:MVP 验证、活动页、小程序接口、低代码平台。
    技术特征:

    • 直接写 PHP 脚本,甚至一个 index.php 搞定路由、DB 查询、HTML 输出。
    • 用 Laravel 的 migrate 快速生成表结构,模型用 $fillable 先跑通流程。
    • 部署用 Docker + php-fpm + nginx,OPcache 开起来,QPS 到 500 以内基本够用。
      风险:字段随意追加、索引缺失、Service 层循环依赖、Controller 膨胀到 2000 行,半年后重构成本 > 重新开发。
  2. 设计优先(Design-First)
    典型场景:电商主站、金融账务、SaaS 多租户、P0 级中台。
    技术特征:

    • 先输出 PRD、接口契约、领域模型、时序图,再写 PHP。
    • 用 Swagger / OpenAPI 3.0 定义契约,Laravel 用 swagger-php 注解反向生成路由,单元测试用 PHPUnit + DataProvider 把边界值跑满。
    • 数据库先画 ER 图,评审完再建表;字段类型、索引、分库分片规则、唯一约束、乐观锁版本号一次性到位。
    • 引入 DDD 分层:ApplicationService、DomainService、Repository、PO、DTO、VO,配合 Composer PSR-4 自动加载,CI 用 GitLab-Runner 做 phpcs、phpstan、phpmd 三件套,质量门禁卡到 90 分才合并。
      风险:前期重文档、重评审,交付周期长;若需求频繁变更,设计文档容易"一稿过时"。
  3. 量化决策指标

    • 需求稳定度:两周内变更 ≤1 次可设计优先,>3 次先代码迭代。
    • 并发预期:峰值 RPS < 300 且日单 < 1 万,代码优先;峰值 RPS > 2000 或涉及资金,必须设计优先。
    • 团队规模:PHP 研发 ≤3 人且全栈,代码优先;横向拆成 3 个以上小组,必须设计优先,否则接口联调爆炸。
    • 技术债务容忍度:创业融资窗口 ≤6 个月,可先债务;上市公司财报季,P0 系统不允许故障,设计优先。
    • 合规要求:等保三级、PCI-DSS、金融审计,必须设计优先,代码优先无法通过评审。
  4. PHP 生态工具链

    • 快速代码优先:Laravel + Octane + RoadRunner,一条命令启动,内存常驻,MVP 神器。
    • 设计优先:Symfony Bundle 化、API-Platform、DDD 插件、Messenger 队列、EventSourcing 组件,配合 phpDocumentor 自动生成文档。
    • 灰度重构:用 PHP-Parser 写自动化脚本,把 God Class 拆成 PSR 服务;再引入 Rector 做类型加强,一次重构 5 万行代码可回滚。

答案

示例回答(可直接用于面试):

"我在上一家公司做社区电商,经历两次选型。第一次是拼团秒杀 MVP,时间只有 10 天,采用代码优先:用 Laravel 快速 scaffold,Controller 里直接写库存扣减,MySQL 行锁 + Redis 原子减,QPS 压到 400 够用,提前上线验证市场。上线后日均订单从 2 千涨到 2 万,出现超卖 37 单,于是启动第二次重构,转为设计优先:先输出领域模型,把库存拆成独立聚合根,用乐观锁版本号 + 队列异步扣减,接口契约用 OpenAPI 定义,PHPUnit 补了 92% 分支覆盖,重构后压测 8 k QPS 无超卖,代码量反而减少 18%。总结:国内 PHP 项目我遵循‘三问三量化’——问需求稳定度、并发预期、合规要求;量化变更频次、峰值 RPS、技术债务利率。指标低于阈值就代码优先,高于阈值必须设计优先,并在上线后 30 天内安排度量复盘,保证债务可追踪、可偿还。"

拓展思考

  1. 微服务拆分临界点:单体 PHP 项目何时拆服务?可监控 P99 延迟 > 500 ms 且单机 CPU 利用率 > 70% 持续一周,就考虑用设计优先方式拆用户、订单、库存三个域,接口用 gRPC + Protobuf,PHP 侧通过 Swoole 的 gRPC 插件实现,避免传统 fpm 的阻塞。
  2. 低代码平台的"设计"与"代码"融合:国内很多低代码产品先用可视化设计生成 JSON Schema,再动态生成 PHP 代码。此时设计即代码,代码即设计,版本管理要用 Git 对 Schema 做 diff,回滚时同时回滚 PHP 与 Schema,防止"页面正常、后台爆炸"。
  3. 设计优先下的"过度工程"陷阱:PHP 团队若盲目照搬 Java 的六边形架构,会出现 Repository 接口 7 层继承、一个查询 15 个类的情况。面试时可补充"适度设计"原则:类数量 ≤ 业务用例数 ×1.2,接口文件行数 < 200,用 phpmetrics 监控复杂度,高于 50 就拆,低于 10 就合并。