一个人做多端产品,怎么少写一遍代码

"小程序 + H5 + App + PC 后台,四个端都要。"

这句话在小项目里出现得特别频繁,而且通常伴随着一个不切实际的预算。一个人接这种活,第一反应就是:哪三端能少写一点。

我做过两个四端项目,形态很像:服务端一套,C 端用 uni-app 编出小程序 + H5 + App,后台单独一套 Web 前端。 回头看,省下时间的从来不是"少写界面"------界面是整件事里最不难的部分。

但真正浪费时间的,从来不是界面。同一个业务规则在四个地方各写一遍,然后慢慢漂移出四个版本 ------ 这才是多端项目里最贵的那部分。

先定一件事:业务逻辑只能有一份

无论选什么技术方案,这条都是前提:业务逻辑写在服务端,端上不做业务判定。

反过来做(逻辑散在各端)会出什么样的问题?最典型的一种:

小程序算出来 88 折,App 算出来 9 折,H5 又不一样。

这种 bug 极难排查 ------ 每个端单看都对,只有对比的时候才看得出。而且不是逻辑写错了,是同一个逻辑被写了三遍,写的时候各差一点。

所以价格、库存扣减、优惠判定、订单状态流转、权限判断,这些一律放在服务端。端上只做三件事:

  1. 收集输入(用户填了什么、点了什么)
  2. 展示输出(服务端给了什么就显示什么)
  3. 调用平台能力(支付、登录、分享、推送)

三条路线,和它们的取舍

路线一:一套代码跨端(uni-app 这类)

写一份,编出小程序 + H5 + App。

  • 优点:开发速度最快,一套逻辑三端复用;改一处三端都改
  • 缺点:平台能力深度受限;性能不如原生;遇到平台差异仍然要写条件分支
  • 适合:交互以表单、列表、详情为主,没有重度动画或设备调用的业务

路线二:各端原生,只共用 API

每端用自己最合适的技术写,服务端统一。

  • 优点:体验和平台能力最好
  • 缺点:有多少端就有多少份界面工作量,且每端的迭代都要单独排期
  • 适合:对体验或设备能力有硬要求的场景

路线三:混合 ------ 主体跨端,关键页面原生

大部分页面走跨端方案,只有少数关键页面(例如需要高性能或深度调用设备的)单独实现。

  • 优点:把"省时间"和"体验"分配到不同的页面上去
  • 缺点:架构多一层,团队要能接受这种不一致

一个人做项目,路线一通常是默认答案 ------ 但前提是先确认平台能力的硬约束。比如支付、登录、分享、推送这几项,每个平台的实现方式都不一样,这些是一定要单独写的,不会因为你用了跨端框架就省掉。

分层:把"能共用"和"必须各写"分开

我的分法是这样三层:

层 内容 是否共用
业务内核 价格、库存、优惠、状态机、权限 服务端一份
契约层 API 的入参出参约定 服务端定义,所有端遵守
端差异层 交互流程、页面结构、平台能力调用 各端各写

中间那一层最容易被忽略,但它其实是省时间的真正来源。接口约定定清楚之后,端上只需要"照着接";约定含糊,每个端就会各自猜,猜出来的三份都不一样。

实际操作里,契约层的收益在加端的时候最明显:加一个新端,如果契约清楚,只是"接一遍接口";如果契约不清楚,就要重新读服务端代码,把业务逻辑再理解一遍。

契约层落到代码里,就是一张接口约定表。它不需要多复杂,但每个字段要写清三件事:这个值是谁定的、端上能不能改、改了会怎样。 举个订单接口大概的样子(字段形状是通用的,不是某个具体系统):

json 复制代码
{
  "price":        { "value": 12800, "unit": "分", "by": "server" },
  "stock":        { "value": 37, "by": "server" },
  "discount":     { "value": 0.88, "rule_id": "R-012", "by": "server" },
  "can_cancel":   { "value": true, "reason": "发货前可取消", "by": "server" }
}

关键在 by 这一列。端上拿到 price 只能显示,不能改;它要改价格,走的是"发起一个请求",而不是改本地这个数。rule_id 的意义也在这:优惠规则变了,端上不需要同步任何逻辑,还是调同一个接口 ------ 因为判定在服务端,端上只负责"显示服务端给的东西"。

这张约定表我一般就放在仓库里一份,端和服务端都对着它写。它不是文档,是可被两边同时引用的契约 ------ 谁先改,谁先提,另一边跟着对齐。省时间的就发生在这里。

什么不该共用

共用是手段,不是目标。下面这些硬要共用,反而更慢:

  • 交互流程:手机和 PC 的用户预期本来就不同,强行一套 UI 会两边都别扭
  • 平台能力:支付、登录、分享、推送 ------ 统一封装的抽象层通常比直接写更难维护
  • 管理后台:PC Web 后台的形态和 C 端完全不一样,它只是"又一个客户端",不必套用 C 端的组件体系

后台端最常见的做法是独立一套前端框架(例如 Vue + 组件库),但共用同一个业务内核。这也是我做过的大多数项目里的实际形态:前端不止一套,服务端只有一套。

这不是偷懒。后台和 C 端的用户不是同一批人 ------ 操作密度、信息密度、容错要求都不一样,强行统一一套组件体系,结果通常是两边用着都别扭。

数据一致性:把判定权收回来

多端项目出问题,除了逻辑重复,还有一个来源是端上自己算。

举几个典型场景:

  • 端上根据本地缓存的库存判断"还能不能下单" → 服务端库存早变了
  • 端上算优惠金额 → 规则更新后端上还是旧公式
  • 端上判断订单能不能取消 → 服务端的状态机已经不允许了

统一做法是:端上算的东西只用于显示,不用于决定。 所有能改变数据状态的操作,都要让服务端再判一次。端上算错了只是显示错,服务端判错才是事故。

这类问题在商城类项目里特别容易发生,因为多端上线时间往往不一致:先上小程序,H5 和 App 后补。后补的那两端如果按"上一版的规则"写,就会和服务端悄悄分叉。等到有人发现同一个商品在两端算出来的价格不一样,通常已经过去几周了。

顺带一个副作用:服务端集中判定之后,加端变得很轻 ------ 新端不需要重新实现规则,只要调用同一个接口。

落到排查上,有一条很省事的判据:当两个端对同一份数据算出不一样的结果时,先别怀疑某个端写错了,先怀疑这件事根本不该放在端上算。 把判定收回到服务端之后,这类"哪端算错"的争论就直接消失了 ------ 因为每个端都不算,它们只是显示同一个接口的返回。

多端分三层:业务内核 / 契约层 / 端

什么时候别搞共用

有两种情况,共用是纯亏:

  • 只有一个端:没有第二个端要复用,抽象出来的层就是纯粹的额外复杂度
  • 两个端的业务差异远大于共性:如果"共用"的结果是代码里塞满条件分支,那还不如各写各的

判断标准很简单:共用省下的工作量,要大于维护这层抽象的成本。 端数越多、业务规则越复杂,这个值越大;端少、规则简单的时候,直接写更快。

小结

多端"少写一遍"的关键,不在选哪个跨端框架,而在两件事:

  1. 业务判定集中在服务端 ------ 消除规则漂移
  2. 接口契约先定 ------ 让每一端都只是"接一遍"

跨端框架省的是界面代码。而真正吃掉工期的,是同一个规则被写四遍之后,你花在对比四份实现上的时间。

相关推荐
一线数智1 小时前
朱鹰:人的判断力,比算力更重要
大数据·人工智能
IT_陈寒1 小时前
Java性能优化完全指南
前端·人工智能·后端
雨中飘荡的记忆1 小时前
Claude Code 入门必会:@、!、Slash Commands,一篇讲清楚
人工智能·后端
满眼星河1 小时前
RAG应用功能边界
人工智能
阿里云大数据AI技术1 小时前
Hologres Agent:让数仓运维、开发和分析更高效
人工智能·agent
诚小纯1 小时前
qwen-deep-research 接入实录:两阶段调用、SSE 解析、报告结构与 35 处不可追溯的引用
人工智能·github
RaaS1001 小时前
Agent Skills 进了 Linux Foundation:2.8 亿次安装,但装 skill 还没有安全规范
人工智能·算法·架构
Hone1 小时前
一套让 7 个 AI Agent 共享同一份 Skills 的方案(Windows Junction 实战)
人工智能·程序员
烬羽1 小时前
PostgreSQL:AI 时代原生的"隐型"向量数据库 — 用 pgvector 给消息表加上长期记忆
数据库·人工智能·程序员