“Have We Forgotten How to Design?”——这个问题放在今天格外刺耳。前端有 Ant Design、Arco Design、Element UI,芯片有 Design Compiler、Design Entry,桌面端有 Qt Design Studio,架构圈把 Domain-Driven Design 奉为圭臬,连光学设计都有 Zemax 和 Mathematica 的完整教材。工具越来越强,模板越来越全,但一个尴尬的事实是:很多团队只是把设计工作外包给了组件库、示例工程和预设流程。设计能力并没有体现在产出里,而是消失在了“能用就行”的默认选项里。
这篇文章不打算讨论哲学。我会把“设计”拆到几个具体的技术领域里看:前端组件选型、HDL 库设计、Design Compiler 综合流程、Zemax 光学建模、DDD 领域建模、Qt Design Studio 协作,以及 AI 辅助芯片设计。你会发现一件事:每个领域的“设计失语”症状几乎一样——工具流程跑通了,但设计决策没有发生。文末会给出一套可落地的回归清单,无论你做前端、硬件还是系统架构,都能直接用。
1. 前端设计:组件库时代,是提效还是同质化?
先抛一个最现实的场景。现在做 PC 端前端开发,很多人会在 Vue 生态里选 Element UI 还是 Ant Design Vue,React 生态里选 Ant Design 还是 Arco Design。搜索引擎上这类对比文章很多,结论通常是“看项目规模”“看团队熟悉度”。但真正该问的是:你选它,是因为它适合你的业务场景,还是因为它是默认选项?
组件库解决了 80% 的常规界面问题:表格、表单、弹窗、布局、日期选择器。但组件库也悄悄收走了视觉和交互的设计权。你会发现不同公司用同一套组件库做出来的后台管理系统,长得几乎一样。这不算错,但如果你的产品核心价值在于差异化体验,组件库默认样式反而会成为天花板。
更值得关注的是设计令牌(Design Tokens)。团队如果能把颜色、间距、圆角、字体、阴影这些基础变量抽象成一套 JSON 或 CSS 变量,再映射到组件库主题里,才算真正接过了设计权。下面是一个最小可用的设计令牌示例:
{ "color": { "brand": { "default": "#1677ff", "hover": "#4096ff", "active": "#0958d9" }, "bg": { "page": "#f5f5f5", "container": "#ffffff" } }, "radius": { "small": "4px", "medium": "8px", "large": "12px" }, "spacing": { "xs": "4px", "sm": "8px", "md": "16px", "lg": "24px" }, "font": { "size": { "caption": "12px", "body": "14px", "h6": "16px" } } }Ant Design Vue 和 Element UI 都支持主题变量覆盖,Arco Design 更是把设计令牌作为一等公民。用 JSON 管理令牌后,业务代码里尽量少写魔法值,组件属性只引用令牌,这样品牌换色、夜间模式、多主题切换就变成纯数据操作,而不是全局搜索替换样式。
前端设计的核心判断是:哪些用组件默认值,哪些必须定制。我的建议是,交互频繁的高频模块、面向外部用户的产品页面,必须做设计评审;内部中后台的 CRUD 页面,用组件库默认样式加少量令牌覆盖即可。这样既不会让产品泯然众人,也不会让开发效率被设计流程拖死。
2. 电路设计入门:Design Entry 与 HDL 库的设计方法
再看硬件领域。很多 FPGA 或 IC 初学者接触的第一个概念就是 Design Entry——设计的“入口”。它通常指两种方式:原理图输入和 HDL 文本输入。原理图直观,适合小规模、教学场景;HDL 适合复杂逻辑、可参数化、可复用。现代工程里,Design Entry 基本特指用 Verilog 或 VHDL 写设计源文件。
但这恰恰是设计能力流失最严重的地方。很多人会写assign语句,能跑通仿真,但做出来的模块难以复用、难以维护、难以综合。原因是他们把 HDL 当成了“高级 C 语言”,而没有按硬件设计的思维来组织代码。
HDL 库的设计方法,核心是三条:层次化、参数化、文档化。层次化强调模块划分,底层模块只做一件事,上层模块只做组合;参数化强调用parameter或localparam表达位宽、数量、延迟,而不是写死;文档化强调每个模块必须有接口说明、时序说明和设计约束。
以 Verilog 为例,一个可复用的同步 FIFO 或简单的参数化计数器,应该这样组织:
module counter #( parameter WIDTH = 8, parameter MOD = 256 ) ( input wire clk, input wire rst_n, input wire en, output reg [WIDTH-1:0] q ); always @(posedge clk or negedge rst_n) begin if (!rst_n) q <= {WIDTH{1'b0}}; else if (en) q <= (q == (MOD - 1)) ? {WIDTH{1'b0}} : q + 1'b1; end endmodule这里WIDTH和MOD是参数,调用时用#(...)例化。这样同一个计数器可以被用在时钟分频、定时器、地址生成多个场景。
嵌入式里经常看到的 S32 Design Studio,本质上是把 NXP 芯片的引脚配置、外设初始化、代码生成做成可视化入口,降低了裸机开发的入门门槛。但它的代码生成器只能帮你搭骨架,核心的状态机设计、时序设计、异常处理还是要自己写。IDE 能提升的是“输入效率”,不是“设计质量”。
Design Entry 阶段最容易犯的错是:先写代码再想结构。正确顺序是先画模块框图,定义每个模块的输入输出、时序约束、跨时钟域策略,再动手写 HDL。画图不是为了画图,而是为了在硬件实现之前完成最关键的设计决策。
3. 数字芯片综合:Design Compiler 中的时序、面积与功耗权衡
进到数字 IC 设计流程,Synopsys Design Compiler 是所有数字后端工程师绕不开的工具。它把 RTL 代码映射到工艺库里的标准单元,输出门级网表,同时完成时序、面积、功耗的初步约束与优化。
很多初学者卡在第一步:启动时提示design compiler is not enabled。这个报错通常不是脚本写错,而是环境变量或 license 没有正确配置。Design Compiler 是商业 EDA 工具,需要 license 文件,还需要在 shell 里 source 好synopsys_dc.setup文件,设置好DC_HOME、SYNOPSYS、LM_LICENSE_FILE等环境变量。如果你在学校的 lab 环境里跑,还需要确认交错的 lab 服务器和 license 端口是否正确。
另一个常见问题是:Design Compiler 的官方 lab workshop 的例子放在哪。Synopsys 官方培训材料通常提供.tar.gz或.zip的 lab 包,解压后会有lab/目录,里面有 RTL 源文件、约束文件、脚本文件。学习时不要只跑完流程看是否通过,重点要看report_qor和report_timing报告里的关键路径、违例项、时序裕量。
下面是一个最小可用的综合脚本模板:
# 设置库路径,实际路径以项目环境为准 set TARGET_LIB "/path/to/your/lib/typical.db" # 读取 RTL read_file -format verilog {./rtl/design.v} current_design design # 约束时钟和输入输出延迟 create_clock -period 10.0 -name clk [get_ports clk] set_input_delay 2.0 -clock clk [all_inputs] set_output_delay 2.0 -clock clk [all_outputs] # 编译 compile_ultra # 报告 write -format verilog -output ./output/design_gate.v report_timing report_area report_power这里compile_ultra是高优化选项,适合面积和性能要求高的设计;如果只是跑通流程,用compile也能出结果。
Design Compiler 里的设计本质是约束的艺术。时序约束不是凭空写的,它来自模块的功能需求、接口协议、时钟频率目标。set_input_delay、set_output_delay、set_clock_uncertainty每一个约束都对应真实硬件边界。如果这步靠猜,后端布局布线一定会出问题,到时候返工成本远高于综合阶段多花的时间。
官方 lab workshop 的价值在于:它刻意预设了缺失约束、错误对象、多余约束的 case,让你在报告里看到违例,再倒推原因。这才是设计的训练,而不是跑通脚本的训练。
4. 光学系统设计:Zemax 实例与天文光学建模中的权衡
光学设计可能是“传统设计方法”保留得最好的领域,因为物理约束无法被 UI 模板掩盖。像《Introduction to Lens Design with Practical Zemax Examples》这类教材教的就是一套流程:先定系统规格,再选初始结构,然后逐项优化像差,最后做公差分析。
Zemax(现在叫 OpticStudio)是主流的光学设计软件。它用序列模式做成像系统设计,用非序列模式做照明和杂散光分析。Zemax 本身自带优化器,可以用评价函数自动迭代透镜曲率、厚度、玻璃材料。但这不是“一键出设计”,因为评价函数里每一项权重都是设计决策。
另一个相关方向是天文光学系统设计。《Theory and Design of Astronomical Optical Systems Using Mathematica》展示了如何用 Mathematica 做解析计算与系统建模,再配合仿真软件验证。这种做法的优势是:用数学表达设计理论,不依赖某个商业软件的 GUI,便于参数扫描和自动寻优。
如果想把 Zemax 和 Python 结合起来做批量参数扫描,可以通过zospy(第三方 Python 封装)调用 Zemax 的 API。基本流程是:打开一个 zemax 文件,修改镜头参数,执行光线追迹,读取评价函数结果。下面是一个通用思路示例:
# 伪代码示例,实际 API 以 zospy 版本为准 import zospy as zp # 连接 Zemax 独立模式应用 zos = zp.ZOS() zos.wakeup() oss = zos.get_primary_system() # 读取当前镜头数据 surface = oss.LDE.GetSurfaceAt(0) print(surface.Radius) # 修改曲率后重新追迹 oss.LDE.GetSurfaceAt(5).Radius = -123.456 oss.SystemEfficiency = True result = zp.analyses.paraxial.first_order(oss) print(result)光学系统的设计决策不止是像质最优。视场角、相对孔径、工作波段、公差敏感度、重量、成本,这些指标互相冲突。Zemax 里优化出来的结构可能对公差极敏感,工厂稍微偏一点装配,实拍就崩。因此,真正的光学设计要同时看像差曲线、点列图、MTF 和公差分析。你的设计能力体现在:知道哪些参数可以放松,哪些必须卡死。
天文光学更极端:环境温差、重力形变、镜面支撑都会破坏像质。所以设计时要引入结构、热、力学约束。这也是为什么真正的大型望远镜项目,光学设计只是系统工程里的一环。
5. 系统架构设计:Domain-Driven Design 与业务边界
软件架构领域里的“Have We Forgotten How to Design?”,最典型的对应是 Domain-Driven Design(DDD)。DDD 这个概念从 Eric Evans 的书出版到今天,热度一直很高,GitHub、社区、技术博客都在讨论。但很多团队落地时做的只是“画了张限界上下文图”,代码里该耦合还是耦合。
DDD 的核心是区分“核心域、支撑域、通用域”,然后为每个域建立独立的模型和边界。它强调用统一语言(Ubiquitous Language)描述业务规则,用聚合(Aggregate)保证业务一致性,用领域事件(Domain Event)完成跨限界上下文的通信。这些不是文档摆设,是要直接落进代码结构的。
看一个极简的领域模型示例。假设有订单和库存两个限界上下文,订单下单时要扣减库存。初期很多人会把库存表字段直接放到订单模块里,订单服务直接改库存表,看起来快,但后面库存规则一变,就会牵连订单代码。
DDD 的做法是拆分两个上下文,把库存扣减的职责收进库存上下文,订单上下文只发布“OrderPlaced”领域事件:
# order/domain/events.py @dataclass class OrderPlaced: order_id: str items: list[OrderItem] # inventory/domain/services.py def handle_order_placed(event: OrderPlaced): for item in event.items: stock = stock_repo.get(item.sku) stock.deduct(item.quantity) stock_repo.save(stock)这样订单不必知道库存表结构,库存也不必知道订单创建流程。领域边界就是设计边界。
但要注意,DDD 不是银弹。很多项目不需要完整的事件溯源、CQRS、聚合设计。对中小型业务,最忌讳“为 DDD 而 DDD”——把简单需求拆成十个限界上下文,每个上下文里只有一个贫血模型。DDD 的取舍本身也是设计能力的一部分:什么地方该建聚合,什么地方该用事务脚本,什么场景该上消息队列,都要根据业务复杂度和团队维护成本判断。
所以学习 DDD,别盯着“电子版 PDF”找工作区,而是先在一个真实业务模块里,把实体、值对象、仓储、应用服务这四层职责理清楚。设计能力是在代码边界和业务规则互相拉扯时练出来的,不是在概念图里练出来的。
6. 桌面端设计:Qt Design Studio 中的设计与开发协作
桌面端开发里,Qt Design Studio 是连接设计师和开发者的工具,它允许在 UI 设计阶段直接产出可在 Qt 运行时里加载的 QML 工程。你不再需要设计师出切图、开发再“照着还原”,而能直接把设计文件转成可以交互的高保真原型。
QML 是声明式语言,写界面很像写 JSON 和 JavaScript 的混合体。下面的代码展示了一个简单的卡片界面:
import QtQuick 2.15 import QtQuick.Controls 2.15 Rectangle { width: 320 height: 120 radius: 8 color: "#ffffff" Column { anchors.centerIn: parent spacing: 4 Text { text: "Design System" font.pixelSize: 18 font.bold: true } Text { text: "Qt Design Studio Demo" font.pixelSize: 13 color: "#666666" } } }Qt Design Studio 不只画界面,还能定义状态、动画、交互逻辑。它的设计文件可以和开发共享同一套 QML 代码,避免“设计稿一套、实现一套”的经典脱节问题。但工具再好,也只是协作链路的一环。设计师仍然需要理解 QML 的布局机制、性能开销和平台差异;开发也需要在接入真实业务时,把临时数据替换成真实数据模型,把假交互变成真逻辑。
桌面端设计最容易忽略的是多窗口、多分辨率、键盘操作、字体渲染差异。Qt 的布局引擎和隐式尺寸(implicitWidth/implicitHeight)机制,比 Web 的 flexbox 更接近 GUI 原生逻辑。设计评审时,要靠真机或虚拟机看不同 DPI 下的排版表现,而不是只看设计软件里的效果图。
7. AI 辅助设计:从对话式设计到开源芯片设计项目
再回到那个尖锐的问题:AI 会不会让设计能力进一步流失?现在 GitHub 上有不少关于 AI 芯片设计的开源项目,试图用机器学习辅助布局布线、功耗预测、版图生成;日常开发里,Claude、GPT 这类对话式 AI 也能根据自然语言生成前端代码、Verilog 模块、甚至提供架构建议。
我的观点是:AI 会放大你的设计能力,但不会替你补上设计能力。如果你对需求边界、约束条件、行业规范没有判断力,AI 生成的代码只是看起来像代码的“正确废话”。在 IC 设计里,AI 能帮的更多是搜索空间巨大的优化任务,比如布局布线里的布线拥塞预测、功耗热点识别。这类问题人很难靠经验枚举,适合交给模型学习。
但“AI 辅助 IC 设计”的实际落地门槛不低。它需要标准化的数据集、工艺库接口、验证环境,还得保证生成结果的可解释性。对大多数团队来说,现阶段更可行的做法是:用 AI 做约束文件的批量生成、报告解读、脚本片段推荐,把精力留在设计本身上。
不要让 AI 成为新的“默认组件库”。如果你连需求规格、验收标准和边界条件都说不清,AI 能给你一个看起来合理的答案,但那恰恰是最危险的设计陷阱。设计的第一责任永远是定义问题,而不是生成解决方案。
8. 设计失语的常见问题与排查思路
很多“不会设计”的问题,表面是技术能力不足,实际是设计流程缺失。下面列一个跨领域对照表,适合在项目复盘、代码评审、方案评审时用:
| 问题现象 | 可能原因 | 排查方向 | 处理建议 |
|---|---|---|---|
| 前端页面风格千篇一律 | 直接套组件库默认样式,没有令牌层 | 检查项目里是否定义了设计令牌 | 建立 tokens 文件,统一主题变量 |
| Copy 代码跑通,但一改需求就崩 | 模块没有参数化、没有设计文档 | 查看模块接口是否清晰,参数是否可配 | 重构模块,补充接口注释 |
| 综合报告时序违例高 | 约束写得过于宽松或缺失 | 检查 create_clock、input/output delay | 重新核对接口协议,修正约束 |
| 光学系统优化出来但无法量产 | 公差分析缺失 | 检查评价函数里是否包含公差项 | 补充公差分析,重新优化 |
| 微服务边界混乱,改一处挂一片 | 领域模型没有收敛到限界上下文 | 查看跨服务调用图 | 按业务域拆分上下文,收敛依赖 |
| Qt 界面在部分机器上字体重影 | 未考虑字体渲染差异 | 对比系统字体设置和 DPI | 在理想目标平台验证,调整布局策略 |
| AI 生成的代码无人能维护 | 设计评审缺失,AI 输出直接进主干 | 检查 PR 评审记录 | 要求提交者说明设计依据,补测试 |
这张表的核心是:把每个“翻车”都当成设计流程的 bug,而不是“某某工具不行”。工具换来换去,问题还会复发,因为设计决策没有发生在正确的位置。
9. 保持设计能力的通用实践
最后给一套不区分技术栈的实践清单。无论你是前端工程师、数字 IC 工程师、光学工程师还是架构师,都可以按这个框架校准自己的工作方式。
第一,需求阶段先写“设计输入”,再写“实现方案”。设计输入包括:目标用户、核心使用场景、关键约束、成功标准。比如设计一个计数器模块,不是“我要写个计数器”,而是“我需要一个可配置位宽、支持使能、可同步复位的计数器,周期误差小于 1%”。约束写清楚,设计决策才有依据。
第二,代码之前先出结构图。画图本身不是目的,但画图强迫你把问题拆解成可组合的单元。前端画组件树,硬件画模块图,架构画上下文图。一旦某个模块需要承担两种以上职责,就要停下来考虑是否拆分。
第三,把设计评审做成例行机制。每个方案在动手前都找一个人问三个问题:这个设计解决了什么问题?有没有更简单的方案?边界条件是什么?评审不是走过场,是让设计决策被追问。
第四,用文档沉淀设计决策。即使不在大厂,也要在代码仓库里保留一份简洁的design.md,记录方案 A、B、C 的取舍原因。半年后你再看这份文档,会比看代码更容易理解当初为什么这样写。
第五,保留“最小可运行”配置。项目里准备一套不依赖外部资源、能快速启动的最小示例。无论是综合脚本、前端 demo 还是 Zemax 示例文件,这套配置能让你在任何时间快速验证设计直觉,不用等完整环境恢复。
10. 总结与下一步
回到标题:我们是否已经忘记了如何设计?答案是:设计能力没有被真正忘记,只是被工具流程和默认选项掩盖了。组件库、综合脚本、建模软件、AI 助手都在降低“实现”门槛,但“定义需求、评估取舍、验证边界”这些设计基本功,必须回归到工作流的中心。
如果你现在不知道该从哪里开始,建议先做三件事:
第一,挑一个正在进行的项目,补写它的设计输入文档。写不清的问题,就是你没想清楚的设计盲区。
第二,找到项目里最容易被替换的“默认组件”(比如前端主题、模块的参数化接口、云原生的部署模板),增加一层可控的抽象,让团队真正拥有决策权。
第三,安排一次设计评审,用一个具体场景去质疑现有方案。不要等到跑不通了才做设计。
工具永远在变,但“设计”的内核——在约束中做决策、在不确定中做取舍——不会变。无论你是刚入门还是在做大型系统,保持对设计的敏感,比熟练使用任何一个工具都更重要。