建筑师之家IOS / NOTES
← 全部笔记

架构

功能模块不要互相引用

App 目标是组装的地方。功能之间只通过协议和路由模型说话。

模块切分的目的不是文件夹更好看,而是改一个功能时不用编译整个应用,也不会在无意中调用到另一个功能的内部类型。如果 FeatureA import FeatureB,边界就已经破了。

依赖方向

两个功能都要用的类型,先问它是不是真的稳定。用户 id、金额、一个通用的加载态,可以进基础库。某个信息流的卡片样式,留在那个功能里。过早共享,会让基础库成为所有人都能修改的上帝模块,编译时间和耦合一起变差。

接口放在谁那里

// Feed 模块定义自己需要什么,不定义账号模块的实现
protocol AccountSession: AnyObject {
    var userID: String? { get }
}

final class FeedStore {
    private let session: AccountSession
    init(session: AccountSession) { self.session = session }
}

账号模块提供一个符合 AccountSession 的类型。App 在启动时把它传给 FeedStore。Feed 的测试传一个假的 session,不需要把登录界面编进来。

Swift Package 还是内部框架

包的边界应该和编译边界一致。一个包里一百个 target,和一个 target 里一百个文件夹,前者只是更难打开。独立演进、需要单独测试、会被多个 App 使用的,再拆包。只在一个 App 里用的功能,可以是同一个工程里的 framework 或 package target,重点是 import 关系,不是仓库数量。

检查方式很具体:对功能模块搜 import,出现另一个功能的名字就处理。循环依赖不要用类型前向声明糊过去,那说明两边都拿了对方的具体类型。