设计原则
我在写tasklist的时候,由于自己的知识储备还不够成熟,所以文件结构是糅杂混乱的💩(包括且不限于:不编写可复用组件、相关逻辑复制粘贴)
所以设计很重要。
为什么会糅杂呢🤔,我在对一个项目进行工程化设计的时候,需要注意哪些呢?
十项质量维度
可扩展性
定义:系统增加新功能或新模块时,对既有代码的改动量尽可能小。
要点:
- 目录分层 + 插件化构建(如 Vite/Rollup 插件钩子)
- 运行时微前端、动态 import、Feature Flag
- 面向接口编程:先抽象协议,后实现细节
反例:新增一个页面要把 webpack 配置从头改一遍。
可维护性
定义:缺陷定位、代码阅读、日常变更所需时间与人力成本持续可控。
要点:
- 统一编码规范(ESLint/stylelint/commitlint)
- 强制 Code Review + PR 模板
- 自动化测试 ≥ 80% 覆盖率(详见附录)
反例:半年前的业务代码没人敢动,一动就崩。
可复用性
定义:同一资产(组件、工具、配置)可在多个项目/模块中零成本或低成本复用。
要点:
- Monorepo + 私有 npm registry
- 原子化组件 + Storybook 文档
- 构建配置抽成共享 preset(如 @company/build-config)
反例:每个项目复制同一份 utils/date.js,出现 5 种不兼容的日期格式。
可读性
定义:开发者在最短时间内能从代码中还原出意图与业务规则。
要点:
- 语义化命名 + 分层抽象(UI / 业务 / 数据)
- JSDoc / TypeScript 类型签名
- 目录 README 与 ADR(Architecture Decision Record)
反例:变量名全是 a1、a2,新人三天看不懂,老人三天不敢改。
可测试性
定义:业务逻辑可在隔离环境中被自动、快速、重复地验证。
要点:
- 逻辑与 I/O 分离(Container/Presenter、Repository 模式)
- Jest/Vitest + Testing Library 语义查询(详见附录)
- MSW(Mock Service Worker) 模拟网络层
反例:所有逻辑写在组件生命周期里,无法打桩,只能人肉点 UI 回归。
可移植性
定义:代码或构建产物在不同运行时、构建工具、部署平台之间迁移的代价低。
要点:
- 遵循标准(ES 模块、Web API、容器化)
- 构建脚本抽象成 npm scripts + 环境变量
- 无宿主页依赖:避免 Node 私有 API、Webpack loader 魔法
反例:从 Webpack4 升级到 Vite 需要改 200 处插件配置。
可观测性
定义:在生产环境中能迅速、准确地回答“系统当前是否健康、哪里不健康”。
要点:
- 前端 Sentry 全局错误捕获 + SourceMap 上传
- Web-Vitals 上报 LCP/FID/CLS
- 自定义埋点 + 分布式链路追踪(trace-id)
反例:用户白屏 1 小时,监控面板一片绿色,全靠微博热搜发现。
可交付性
定义:代码到用户浏览器或终端的路径短、自动化、可回滚。
要点:
- CI/CD:MR → 自动化测试 → 镜像 → 灰度 → 全量
- 增量构建、HTTP/2 服务器推送、CDN 边缘缓存
- Feature Toggle + 一键回滚
反例:本地打包 20 min,手动 FTP 上传,回滚靠备份目录重命名。
鲁棒性
定义:在异常输入、网络抖动、依赖失效等场景下仍能提供降级体验。
要点:
- 运行时防御:try/catch、空值合并、网络重试、超时熔断
- 构建时防御:Schema 校验(zod/yup)、TypeScript 严格模式
- 静态兜底:Skeleton、离线包、Service Worker
反例:后端字段少返回一个 null,前端直接白屏 500。
安全性
定义:防止恶意输入、依赖漏洞、构建投毒对用户或企业造成损失。
要点:
- 依赖扫描(npm-audit / Snyk / OSV-Scanner)
- CSP、HTTPS、SameSite Cookie、防 XSS 模板转义
- 构建环境隔离:锁版本 (lockfile)、签名镜像、最小权限 CI token
反例:第三方包被植挖矿脚本,用户 CPU 狂转,公司收到云账单炸弹。
我们现在知道了一些标准,可是我们还是容易出现无法衡量设计得多好为合适,就好像我们git的commit信息有标准一样,设计也有一套标准,可以给我们一些参考✏️。
S.O.L.I.D原则
SOLID 是面向对象设计的五条基本原则的首字母缩写,目的是让代码在需求变化时易扩展、难破坏,简而言之就是只加代码,不改代码。
单一职责
- 单一职责:一个类/模块只做一件事,修改它的理由只有一个。
开放封闭
- 开放封闭:对扩展开放,对修改封闭。
里氏替换
- 里氏替换:子类必须能无感知替换父类。
接口隔离
- 接口隔离:不要把无关方法塞进一个接口;让类按需实现。
依赖倒置
- 依赖倒置:高层不依赖低层,二者都依赖抽象;细节依赖抽象。
如上,深入浅出,你大致应该知道设计该怎么做了😋。
在软件里,设计其实是:
- 结构的设计:模块、类、函数、目录、包、服务、数据流——它们的边界、关系、生命周期。
- 行为的设计:对外协议(API、事件、消息格式)、业务规则、状态迁移、异常与补偿策略。
- 过程的设计:构建、部署、回滚、监控、测试、灰度、权限、文档——让变化能被“安全地”推到生产。