design-led-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDesign-Led Development
以设计为导向的开发
Build systems that feel inevitable, trustworthy, and delightful. Every line of code serves a human outcome.
构建给人自然、可靠且愉悦体验的系统。每一行代码都服务于用户的实际需求。
Core Decision Framework
核心决策框架
Before writing any feature, answer these questions in order:
- User outcome: "This helps [user] achieve [outcome] by [mechanism]"
- Anxiety/control: Does this reduce user anxiety or increase user control?
- Simplicity: Is this the simplest solution?
- Measurability: Can we measure success?
- Failure mode: What's the failure mode? If catastrophic, add safeguards
- Recovery: Can users recover from errors?
If you cannot articulate the user outcome in one sentence, do not code it yet.
在编写任何功能之前,按顺序回答以下问题:
- 用户成果:“这帮助[用户]通过[机制]达成[成果]”
- 焦虑/控制:这是否能减少用户焦虑或提升用户控制权?
- 简洁性:这是最简单的解决方案吗?
- 可衡量性:我们能否衡量成功与否?
- 故障模式:可能出现哪些故障?如果是灾难性故障,需添加防护措施
- 恢复能力:用户能否从错误中恢复?
如果你无法用一句话清晰阐述用户成果,暂时不要编写该功能。
Code Principles
代码原则
Clarity Over Cleverness
清晰优先于技巧
typescript
// ✅ DO: Name for humans reading at 2am
const userAuthenticationStatus = checkAuth(userId);
const formattedOrderDate = formatDate(order.createdAt);
// ❌ DON'T: Clever but obscure
const x = chk(u);
const d = fmt(o.c);Comments explain why, not what. Red flag phrases: "just", "simply", "obviously".
typescript
// ✅ 推荐:为凌晨2点阅读代码的开发者命名
const userAuthenticationStatus = checkAuth(userId);
const formattedOrderDate = formatDate(order.createdAt);
// ❌ 禁止:看似巧妙但晦涩难懂
const x = chk(u);
const d = fmt(o.c);注释要解释为什么,而不是做什么。需要警惕的表述:"just"、"simply"、"obviously"。
Explicit Error Handling
显式错误处理
typescript
// ✅ DO: Error states as return types
type Result<T> =
| { success: true; data: T }
| { success: false; error: UserFacingError };
async function fetchUser(id: string): Promise<Result<User>> {
try {
const user = await api.getUser(id);
return { success: true, data: user };
} catch (error) {
return {
success: false,
error: {
message: "Unable to load user profile",
action: "Please try again or contact support"
}
};
}
}
// ❌ NEVER: Generic errors or silent failures
throw new Error("Something went wrong");typescript
// ✅ 推荐:将错误状态作为返回类型
type Result<T> =
| { success: true; data: T }
| { success: false; error: UserFacingError };
async function fetchUser(id: string): Promise<Result<User>> {
try {
const user = await api.getUser(id);
return { success: true, data: user };
} catch (error) {
return {
success: false,
error: {
message: "无法加载用户资料",
action: "请重试或联系支持人员"
}
};
}
}
// ❌ 绝对禁止:通用错误或静默失败
throw new Error("Something went wrong");Network Resilience
网络韧性
typescript
// ✅ DO: Exponential backoff with jitter
const retryWithBackoff = async <T>(
fn: () => Promise<T>,
maxRetries = 3
): Promise<T> => {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.min(1000 * 2 ** i + Math.random() * 1000, 10000);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Max retries exceeded');
};
// ✅ DO: Timeout promises
const withTimeout = <T>(promise: Promise<T>, ms: number): Promise<T> =>
Promise.race([
promise,
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('Request timeout')), ms)
)
]);typescript
// ✅ 推荐:带抖动的指数退避重试
const retryWithBackoff = async <T>(
fn: () => Promise<T>,
maxRetries = 3
): Promise<T> => {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.min(1000 * 2 ** i + Math.random() * 1000, 10000);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Max retries exceeded');
};
// ✅ 推荐:为Promise设置超时
const withTimeout = <T>(promise: Promise<T>, ms: number): Promise<T> =>
Promise.race([
promise,
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('Request timeout')), ms)
)
]);Performance Budgets
性能预算
Set these before coding:
| Metric | Budget |
|---|---|
| Cold start | < 2s on median device |
| Interaction response | < 100ms perceived |
| Animations | < 16ms per frame (60fps) |
| API calls (p95) | < 500ms |
Treat performance regressions as P0 bugs. Profile on low-end devices.
在编码前设置以下指标:
| 指标 | 预算 |
|---|---|
| 冷启动 | 中端设备上<2秒 |
| 交互响应 | 感知延迟<100ms |
| 动画 | 每帧<16ms(60fps) |
| API调用(p95) | <500ms |
将性能退化视为P0级bug。在低端设备上进行性能分析。
UI Component States
UI组件状态
Every interactive component MUST handle all states:
✅ Default (idle)
✅ Hover (pointer devices)
✅ Active/pressed
✅ Focus (keyboard navigation)
✅ Disabled (with explanation why)
✅ Loading (with progress indication)
✅ Error (with recovery action)
✅ Success (with next step)
✅ Empty (with helpful onboarding)每个交互式组件必须处理所有状态:
✅ 默认(空闲)
✅ 悬停(指针设备)
✅ 激活/按下
✅ 聚焦(键盘导航)
✅ 禁用(需说明原因)
✅ 加载(带进度指示)
✅ 错误(带恢复操作)
✅ 成功(带下一步指引)
✅ 空状态(带实用引导)Visual System
视觉系统
Spacing (8pt Grid)
间距(8pt网格)
4px: Tight grouping (icon + label)
8px: Related items (form fields in group)
16px: Section separation
24px: Component boundaries
32px: Major sections
48px: Screen-level padding4px: 紧密分组(图标+标签)
8px: 关联项(组内表单字段)
16px: 区块分隔
24px: 组件边界
32px: 主要区块
48px: 屏幕级内边距Typography Scale
排版层级
H1: 32-40px, bold, line-height 1.2
H2: 24-28px, semibold, line-height 1.3
H3: 20-24px, semibold, line-height 1.4
Body: 16-18px, regular, line-height 1.5
Caption: 14px, regular, line-height 1.4
RULE: Never below 14px for body text (accessibility)H1: 32-40px,粗体,行高1.2
H2: 24-28px,半粗体,行高1.3
H3: 20-24px,半粗体,行高1.4
正文: 16-18px,常规体,行高1.5
说明文字: 14px,常规体,行高1.4
规则:正文字号绝不能小于14px(可访问性要求)Motion
动效
| Purpose | Duration | Easing |
|---|---|---|
| Micro-interactions | 100-200ms | ease-out |
| Screen transitions | 300-400ms | ease-in-out |
| Loading states | 600ms+ | linear |
Rules:
- Animation explains, never decorates
- Respect
prefers-reduced-motion - Never delay user actions
| 用途 | 时长 | 缓动效果 |
|---|---|---|
| 微交互 | 100-200ms | ease-out |
| 页面过渡 | 300-400ms | ease-in-out |
| 加载状态 | 600ms+ | linear |
规则:
- 动效用于解释逻辑,而非装饰
- 尊重设置
prefers-reduced-motion - 绝不能延迟用户操作
Accessibility Requirements
可访问性要求
Non-negotiable checklist:
- Semantic HTML with ARIA labels
- Keyboard navigation for all interactions
- Color contrast: 4.5:1 minimum (7:1 for body text)
- Touch targets: 44x44pt minimum
- Screen reader tested
- Respects
prefers-reduced-motion - Respects
prefers-color-scheme
不可妥协的检查清单:
- 带ARIA标签的语义化HTML
- 所有交互支持键盘导航
- 颜色对比度:最低4.5:1(正文需7:1)
- 触摸目标:最小44x44pt
- 已通过屏幕阅读器测试
- 尊重设置
prefers-reduced-motion - 尊重设置
prefers-color-scheme
Trust Architecture
信任架构
Every feature must answer:
- Data collected: What data? (Collect minimum)
- Failure modes: What could go wrong? (Design failures first)
- Trust signals: How do I prove safety? (Make visible)
- Reversibility: Can users undo? (Preview before commit)
- Data fate: What happens to their data? (Explicit, not ToS)
每个功能必须回答以下问题:
- 收集的数据:收集了什么数据?(最少收集原则)
- 故障模式:可能出现哪些问题?(先设计故障处理)
- 信任信号:如何证明安全性?(可视化展示)
- 可逆性:用户能否撤销操作?(提交前预览)
- 数据去向:用户数据会如何处理?(明确说明,而非仅在服务条款中)
Privacy Defaults
隐私默认设置
typescript
// ✅ DO: Default private, opt-in sharing
const defaultSettings = {
shareAnalytics: false,
publicProfile: false,
dataRetention: 'minimum'
};
// ✅ DO: Redact PII in logs
logger.info('user_action', {
action: 'profile_update',
userId: hashUserId(user.id), // Never raw PII
duration_ms: 234,
success: true
});typescript
// ✅ 推荐:默认私有,可选共享
const defaultSettings = {
shareAnalytics: false,
publicProfile: false,
dataRetention: 'minimum'
};
// ✅ 推荐:在日志中脱敏PII
logger.info('user_action', {
action: 'profile_update',
userId: hashUserId(user.id), // 绝不能使用原始PII
duration_ms: 234,
success: true
});Form Validation
表单验证
- Validate on blur, not on every keystroke
- Show errors inline, near the field
- Preserve user input on errors (never clear)
- Auto-save drafts for long forms
- Disable submit only if invalid, explain why
- 在失焦时验证,而非每次按键
- 在字段附近内联显示错误
- 错误时保留用户输入(绝不清空)
- 长表单自动保存草稿
- 仅在无效时禁用提交按钮,并说明原因
Feedback Loops
反馈循环
Every user action needs acknowledgment:
| Type | Timing | Example |
|---|---|---|
| Immediate | < 100ms | Button press visual |
| Progress | > 1s operations | Loading indicator |
| Completion | After success | "Saved" with next step |
| Failure | On error | What happened + how to fix |
Never blame the user in error messages.
每个用户操作都需要确认:
| 类型 | 时机 | 示例 |
|---|---|---|
| 即时反馈 | <100ms | 按钮按下的视觉反馈 |
| 进度反馈 | 操作耗时>1s | 加载指示器 |
| 完成反馈 | 成功后 | “已保存”并给出下一步指引 |
| 失败反馈 | 出错时 | 说明问题+修复方法 |
错误信息绝不能指责用户。
Anti-Patterns
反模式
Code Anti-Patterns (Never Do)
代码反模式(绝对禁止)
❌ Magic numbers without constants
❌ Functions over 50 lines
❌ God objects over 300 lines
❌ Mutable global state
❌ Side effects not in function name
❌ Catching errors without handling
❌ Copy-pasted code❌ 无常量定义的魔法数字
❌ 超过50行的函数
❌ 超过300行的上帝对象
❌ 可变全局状态
❌ 函数名未体现副作用
❌ 捕获错误但不处理
❌ 复制粘贴的代码UX Anti-Patterns (Never Do)
UX反模式(绝对禁止)
❌ Forced account creation before value
❌ Dark patterns (hidden costs, trick questions)
❌ Generic error messages ("Error 500")
❌ Modal dialogs for everything
❌ Destroying data without confirmation
❌ Disabling paste in password fields
❌ Auto-playing video/audio
❌ Infinite scroll without pagination option❌ 先强制创建账号再提供价值
❌ 暗黑模式(隐藏费用、诱导问题)
❌ 通用错误信息(如“Error 500”)
❌ 所有场景都用模态对话框
❌ 无确认就销毁数据
❌ 禁止在密码框中粘贴内容
❌ 自动播放视频/音频
❌ 无限滚动但无分页选项Security Checklist
安全检查清单
- Sanitize all user input (XSS prevention)
- Parameterized queries (SQL injection prevention)
- Rate limit all endpoints
- CSRF tokens for state-changing operations
- Encrypt PII at rest (AES-256)
- TLS 1.3 for all network traffic
- Hash passwords with bcrypt/Argon2
- HttpOnly, Secure, SameSite cookies
- sanitize所有用户输入(防止XSS)
- 参数化查询(防止SQL注入)
- 所有端点设置速率限制
- 状态变更操作使用CSRF令牌
- 静态PII加密(AES-256)
- 所有网络流量使用TLS 1.3
- 使用bcrypt/Argon2哈希密码
- 使用HttpOnly、Secure、SameSite类型的Cookie
Quality Gates (Before Ship)
发布前质量门
- Lighthouse score > 90
- Zero critical/high security vulnerabilities
- Core flows work offline or degrade gracefully
- Keyboard navigation works
- Screen reader tested (VoiceOver + NVDA)
- Error states tested
- Load tested at 2x expected peak
- Mobile tested on real devices
- Privacy review completed
- Rollback procedure documented
- Lighthouse评分>90
- 无严重/高危安全漏洞
- 核心流程可离线工作或优雅降级
- 键盘导航正常工作
- 已通过屏幕阅读器测试(VoiceOver + NVDA)
- 错误状态已测试
- 已按2倍预期峰值进行负载测试
- 已在真实移动设备上测试
- 隐私审核已完成
- 回滚流程已文档化
Final Mandate
最终要求
Every piece of code should make someone's life measurably better.
- If you cannot explain the user benefit, do not ship it
- If you cannot measure the outcome, instrument it
- If you cannot maintain it, simplify it
- If it does not feel inevitable, redesign it
Quality is not negotiable. Speed is achieved through clarity, not shortcuts.
每一行代码都应切实改善用户的生活。
- 如果你无法解释用户收益,不要发布
- 如果你无法衡量成果,就添加埋点
- 如果你无法维护,就简化它
- 如果它不够自然,就重新设计
质量不容妥协。速度来自清晰,而非捷径。