design-led-development

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Design-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:
  1. User outcome: "This helps [user] achieve [outcome] by [mechanism]"
  2. Anxiety/control: Does this reduce user anxiety or increase user control?
  3. Simplicity: Is this the simplest solution?
  4. Measurability: Can we measure success?
  5. Failure mode: What's the failure mode? If catastrophic, add safeguards
  6. Recovery: Can users recover from errors?
If you cannot articulate the user outcome in one sentence, do not code it yet.
在编写任何功能之前,按顺序回答以下问题:
  1. 用户成果:“这帮助[用户]通过[机制]达成[成果]”
  2. 焦虑/控制:这是否能减少用户焦虑或提升用户控制权?
  3. 简洁性:这是最简单的解决方案吗?
  4. 可衡量性:我们能否衡量成功与否?
  5. 故障模式:可能出现哪些故障?如果是灾难性故障,需添加防护措施
  6. 恢复能力:用户能否从错误中恢复?
如果你无法用一句话清晰阐述用户成果,暂时不要编写该功能。

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:
MetricBudget
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 padding
4px:  紧密分组(图标+标签)
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

动效

PurposeDurationEasing
Micro-interactions100-200msease-out
Screen transitions300-400msease-in-out
Loading states600ms+linear
Rules:
  • Animation explains, never decorates
  • Respect
    prefers-reduced-motion
  • Never delay user actions
用途时长缓动效果
微交互100-200msease-out
页面过渡300-400msease-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:
  1. Data collected: What data? (Collect minimum)
  2. Failure modes: What could go wrong? (Design failures first)
  3. Trust signals: How do I prove safety? (Make visible)
  4. Reversibility: Can users undo? (Preview before commit)
  5. Data fate: What happens to their data? (Explicit, not ToS)
每个功能必须回答以下问题:
  1. 收集的数据:收集了什么数据?(最少收集原则)
  2. 故障模式:可能出现哪些问题?(先设计故障处理)
  3. 信任信号:如何证明安全性?(可视化展示)
  4. 可逆性:用户能否撤销操作?(提交前预览)
  5. 数据去向:用户数据会如何处理?(明确说明,而非仅在服务条款中)

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:
TypeTimingExample
Immediate< 100msButton press visual
Progress> 1s operationsLoading indicator
CompletionAfter success"Saved" with next step
FailureOn errorWhat 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.
每一行代码都应切实改善用户的生活。
  • 如果你无法解释用户收益,不要发布
  • 如果你无法衡量成果,就添加埋点
  • 如果你无法维护,就简化它
  • 如果它不够自然,就重新设计
质量不容妥协。速度来自清晰,而非捷径。