harlan-rn-architecture-2

star 0

Harlan 的 iOS/React Native 架构设计风格指南与 Skill。当 Harlan 需要设计新的 SDK、模块、Bridge、原生服务层、CocoaPods 库、或任何跨平台调用链时,使用此 Skill 确保产出符合他一贯的架构思维和设计偏好。 触发场景:设计新模块、评审架构方案、规划 SDK 结构、设计 Bridge 层、拆分子系统职责、设计协议/接口规范、规划目录结构、设计原生与 JS 通信机制、CocoaPods podspec 设计、服务注册与依赖注入设计。即使 Harlan 没有明确说"按我的风格",只要涉及上述话题,也应主动参考本 Skill。

DargonLee By DargonLee schedule Updated 6/5/2026

name: harlan-rn-architecture-2 description: Harlan 的 iOS/React Native 架构设计风格指南与 Skill。当 Harlan 需要设计新的 SDK、模块、Bridge、原生服务层、CocoaPods 库、或任何跨平台调用链时,使用此 Skill 确保产出符合他一贯的架构思维和设计偏好。

触发场景:设计新模块、评审架构方案、规划 SDK 结构、设计 Bridge 层、拆分子系统职责、设计协议/接口规范、规划目录结构、设计原生与 JS 通信机制、CocoaPods podspec 设计、服务注册与依赖注入设计。即使 Harlan 没有明确说"按我的风格",只要涉及上述话题,也应主动参考本 Skill。


Harlan 架构设计风格 Skill

本 Skill 从 @ninebot/open-sdkNBRouter 设计文档中提炼,不局限于该功能本身,而是对 Harlan 设计思维的系统性总结。


一、核心设计哲学

1.1 统一入口 + 内部分发(Facade + Dispatcher)

Harlan 极其强调对外零认知负担。无论内部多复杂,调用者只需要一个入口、一套接口:

NBRouter.open({ module, func, params })  ← 唯一入口
    ↓
内部自动:校验 → 检测环境 → 分发到对应平台

设计原则:外部 API 越简单越好,复杂性向内收敛。对调用者屏蔽平台差异、版本差异、实现细节。

推广到其他场景

  • CocoaPods 库设计:对外暴露最小化 API,内部 subspec 或实现细节不泄露
  • 原生服务层:统一通过 NBVAppManager.shared.resolve(Protocol.self) 访问,调用者不 import 实现类
  • TurboModule:JS 侧只看到 callNative(params) 这一个方法

1.2 协议驱动(Protocol-First Design)

先定义协议,再写实现。协议即契约,实现可替换:

// 先有协议
protocol NBScannerProtocol {
    func openQRScan(_ config: [String: Any], completion: @escaping (String) -> Void)
}

// 再有实现(可测试、可 mock、可替换)
final class NBScannerService: NSObject, NBScannerProtocol { ... }

推广:TypeScript 接口先行、Swift Protocol 先行,永远不让调用方依赖具体类。

1.3 标准化消息格式(Normalized Protocol)

跨层通信必须有标准化的消息格式,不允许各处自定义:

// 统一请求结构
{ module: string, func: string, params?: object }

// 统一响应结构  
{ success: boolean, data?: object, error?: string }

这个思想贯穿 RN Bridge、H5 Bridge、原生分发全链路。格式标准化是可扩展性的基础。


二、分层架构模式

2.1 标准四层模型

Harlan 的跨平台项目天然形成四层:

┌─────────────────────────────────┐
│   SDK 层(npm / JS 统一入口)     │  ← 对外暴露,平台无关
├─────────────────────────────────┤
│   Bridge 层(平台适配)           │  ← RN/H5/Mini 各自实现
├─────────────────────────────────┤
│   原生服务层(Protocol + Service) │  ← Swift/ObjC 功能实现
├─────────────────────────────────┤
│   基础设施层(AppManager/DI)     │  ← 服务注册、依赖注入
└─────────────────────────────────┘

每层职责单一,层间通过协议/接口通信,不跨层调用。

2.2 层间通信机制选型

场景 Harlan 的选择 原因
RN JS → 原生 TurboModule(New Arch) 类型安全、同步性能好
原生内部解耦 NotificationCenter 模块间零依赖、广播式解耦
原生服务定位 Protocol + DI(NBVAppManager) 可测试、可替换实现
H5 → 原生 WKScriptMessageHandler 官方 WebView 标准方案
原生 → H5 回调 evaluateJavaScript 同上,标准回调路径

三、设计习惯与偏好

3.1 环境自动检测,不让调用方传平台参数

// ✅ Harlan 的风格:自动检测
const result = await NBRouter.open({ module, func, params });

// ❌ 反模式:让调用方传平台
const result = await NBRouter.open({ module, func, params, platform: 'rn' });

detectPlatform() 封装在内部,运行时自动判断,SDK 对调用方透明。

3.2 Optional Peer Dependencies + 动态导入

Harlan 不强制依赖,而是用 optional peerDependencies + 动态 import 处理可选依赖:

// 动态导入,不在非 RN 环境报错
const { callNative } = await import('rn-callnative');

这让同一个 SDK 可以在 RN、H5、小程序三端无感安装。

3.3 单包优于分包

行业对比后 Harlan 选择单包:

考量 结论
用户体验 一个 import,不需要感知平台
维护成本 单仓库,公共代码不重复
设计初衷符合度 "平台分发"本身就是 SDK 的核心价值

参考:微信、抖音 JS SDK 都是单包。

3.4 新增模块有标准 SOP

Harlan 会将扩展路径标准化,降低团队协作成本:

Step 1: 实现 Service(遵守 Protocol)
Step 2: 注册到 AppManager
Step 3: 添加 RN 通知监听
Step 4: 添加 H5 methodList 分发

这说明他有流程文档化的习惯,模块扩展是可以 copy-paste 的 SOP,不是靠口头约定。

3.5 目录结构即架构表达

Harlan 的目录结构本身就是架构的外在表达:

src/
├── core/       # 平台无关的核心逻辑(类型、校验、检测)
├── modules/    # 功能模块(NBRouter、Device、Ble...)
├── bridges/    # 平台适配层(rn、h5、mini、mock)
└── utils/      # 工具函数

目录命名语义化,职责边界清晰。看目录结构就能理解架构意图。

3.6 Mock Bridge 作为一等公民

在 bridges/ 里预留了 mock.ts,说明 Harlan 在设计阶段就考虑了可测试性,开发/测试环境不需要真实原生环境也能跑通。


四、文档化风格

4.1 调用链驱动的文档结构

Harlan 的文档按调用链顺序组织,不按模块组织:

1. SDK 入口 → 2. 协议解析 → 3. 平台分发 → 4. Bridge → 5. 原生服务 → 6. 完整调用链

这让读者能沿着一次请求的完整路径理解系统,比"模块 A"、"模块 B"平铺更直观。

4.2 贯穿示例(Running Example)

文档开头就声明贯穿示例:NBScanner.openQRScan,之后所有代码片段都围绕这个例子展开。读者不会在"抽象概念"和"具体代码"之间来回跳跃。

4.3 Mermaid 流程图 + Sequence Diagram 双视角

  • Flowchart:展示分发决策流程
  • Sequence Diagram:展示完整时序(包括异步回调路径)

两种图配合,覆盖"做什么"和"怎么做"两个维度。

4.4 对比表格辅助决策

重要的架构决策(单包 vs 分包)都有对比表格,不只写结论,还写推导过程。


五、Claude 在为 Harlan 设计时应遵守的规则

5.1 必须做

  • 先定义接口/协议,再写实现:TypeScript interface 或 Swift protocol 先行
  • 标准化消息格式:输入输出统一结构,不允许各处自定义
  • 分层清晰:明确每层职责,层间通过协议通信
  • 统一入口:无论内部多复杂,对外暴露最少 API
  • SOP 化扩展路径:新增模块/功能的步骤要能被 copy-paste 复用
  • 文档按调用链组织:从入口到出口,沿请求路径展开

5.2 不应该做

  • 让调用方感知平台差异(不要 if platform === 'rn' 暴露在外部)
  • 强制依赖可选模块(应用 optional peer + 动态导入)
  • 跨层直接调用(不能 SDK 层直接 import 原生 Service)
  • 文档只写结论不写推导(重要决策要有对比分析)
  • 模块扩展靠口头约定(必须有文档化 SOP)

5.3 推荐补充(Harlan 风格的延伸)

以下是在 Harlan 现有风格基础上,值得加入的增强点:

① 错误分类与错误码体系

现有 NBRouterResult.error 只是字符串,建议:

interface NBRouterError {
  code: ErrorCode;   // 枚举:INVALID_REQUEST / PLATFORM_NOT_SUPPORTED / NATIVE_ERROR / TIMEOUT
  message: string;
  cause?: unknown;
}

统一错误码让调用方能精确处理,也方便日志分析。

② 中间件/拦截器机制

在 dispatch 前后可以插入 middleware,比如:

NBRouter.use(loggingMiddleware);
NBRouter.use(authMiddleware);
NBRouter.use(metricsMiddleware);

不改动核心分发逻辑,就能扩展能力(日志、鉴权、埋点)。

③ 超时与重试策略

Promise 默认不超时,原生调用可能 hang 住。建议在 Bridge 层加超时:

const result = await withTimeout(callNative(request), 5000);

④ 请求队列 / 并发控制

某些原生能力(如摄像头)不支持并发,可在 Bridge 层加队列:

class QueuedBridge {
  private queue = new PQueue({ concurrency: 1 });
  call(req) { return this.queue.add(() => callNative(req)); }
}

⑤ 版本协商机制

跨 App 版本调用时,原生能力可能不存在。可在 module/func 注册时加 minVersion:

{ module: 'scanner', func: 'openQRScan', minAppVersion: '6.6.9' }

SDK 在分发前校验,给出友好降级而非 crash。


六、快速参考卡片

Harlan 设计三问(设计任何新功能时先问):

1. 调用方需要知道什么?(最小化暴露)
2. 层的边界在哪里?(协议定义边界)
3. 新人怎么扩展这个功能?(SOP 化)
标准消息结构(任何跨层通信都用这套):

Request:  { module, func, params? }
Response: { success, data?, error? }
目录结构模板:

src/
├── core/      # 类型、校验、检测(平台无关)
├── modules/   # 功能模块(对外 API)
├── bridges/   # 平台实现(rn/h5/mini/mock)
└── utils/     # 工具
Install via CLI
npx skills add https://github.com/DargonLee/My-Skills --skill harlan-rn-architecture-2
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator