Swift 在手淘商品评价的技术重构与实践

作者:王浙剑(柘剑)

手淘新版商品评价列表在经历一个半月的技术重构,几个月的迭代和放量,最终在 2021 年的双十一上,以 100% 的流量稳定的跑完了整个过程。我们不仅在业务上有了比较明确的提升,同时还沉淀了不少技术探索,比如沉淀基于 DinamicX + 事件链编排的轻模式研发框架、推动原生语言升级成 Swift/Kotlin,最终使得整体研发效率和稳定性有一个比较大的提升。(注:DinamicX 为内部自研动态化 UI 框架)

这篇文章,我会重点谈论关于 Swift 的部分。如果你想了解关于 Swift 如何提升研发效率/质量、现有项目/模块是否需要 Swift 作为原生语言如何选型、在商品评价落地 Swift 过程中我们遇到了哪些问题以及最后有哪些收益和结论的一些问题,希望这篇文章可以给你带来一些帮助。

首先是,我为什么会选择学习 Swift?

技术变革,未来已来

因为,我内心十分坚定,相比较于 OC,Swift 更能承载未来。

坚强后盾

最主要的原因就是它有一个坚强的后盾,Swift 作为 Apple 未来最重要的开发语言,光对外输出的 WWDC 内容就已经高达 73 个,包括但不限于语法、设计、性能、开发工具链等,具体内容如图所示:

回过头来看 Swift 这几年的发展,从 2014 年开始正式对外发布,到现在已经经历了 7 个年头了,在整个过程中,Apple 投入了大量精力建设 Swift,尤其是 Swift Only 框架的出现,也意味着 Apple 正在积极倡导各位投入到 Swift 开发中来。

三大优势

其次,Swift 有三个比较明确的优势: 更快、更安全且更具备表达性

更快 是指 Swift 在执行效率上做了很多优化。比如,Swift 系统库本身就采用了很多不需要引用计数的基础类型,无论是内存分配大小、引用计数损耗、方法派发静态分析等方面的问题都得到了一个有效的提升。具体细节这里就不展开分析,感兴趣的可以移步 Understanding Swift Performance 了解细节。

所谓的 安全 不等于不发生 Crash,而是指任何的输入都有一个比较明确的表现定义。Swift 设计初衷是希望开发者无需任何不安全的数据结构就能编写代码,因此 Swift 拥有一个十分健壮的类型系统,开发者几乎不需要考虑指针的问题,就能完成所有的开发工作。同时还提供了一系列前缀为 Unsafe 的类型或函数,用于与不安全语言(例如 C 语言)的高性能交互、操作原始内存等相对不安全的操作,一方面以 Unsafe 警惕开发者使用这些 API ,另外一方面是区分类型以保证大部分开发场景使用的都是安全的类型。

这里可以分享一个数据,我之前参与的一个 App 项目,是用 Pure Swift 编写的(99%+),我们的线上 crash 率常年持续在十万分之 8 左右,这对于一个小型团队(单端 4 人)来说,是一个十分可观的结果。我们几乎不使用 Unsafe 的 API,使得我们的大部分问题都能在编译期间避免,可选类型及可选绑定的设计强制开发者需要去思考如何处理值为空的场景,使得在软件发布之前就把开发者的错误扼杀在萌芽之中。

更具备表达性 简单点说就是用更少的代码来表达一段完整的逻辑。在 Swift Evolution 项目中已经有 330 个提案来增强 Swift 的表达性,也得益于这些特性,使得 Swift 的代码量比 OC 少了大概 30% - 50% 左右。我们举几个实际例子

  • Builder Pattern

当我们定义了一个有很多属性的复杂 model 时,我们不希望这个 model 的属性在初始化完成后可以被变更。我们就需要通过 builder 模式来解决,代码如下:

// OCDemoModelBuilder.h
@interface OCDemoModelBuilder : NSObject

@property (nonatomic, copy, nonnull) NSString *a;
@property (nonatomic, copy, nonnull) NSString *b;
@property (nonatomic, copy, nonnull) NSString *c;
@property (nonatomic, copy, nonnull) NSString *d;
@property (nonatomic, copy, nonnull) NSString *e;
@property (nonatomic, copy, nonnull) NSString *f;
@property (nonatomic, copy, nonnull) NSString *g;
@property (nonatomic, copy, nonnull) NSString *h;

@end

// OCDemoModelBuilder.m

@implementation OCDemoModelBuilder

- (instancetype)init {
    if (self = [super init]) {
        _a = @"a";
        _b = @"b";
        _c = @"c";
        _d = @"d";
        _e = @"e";
        _f = @"f";
        _g = @"g";
        _h = @"h";
    }
    return self;
}

@end

// OCDemoModel.h

@interface OCDemoModel : NSObject

@property (nonatomic, readonly, nonnull) NSString *a;
@property (nonatomic, readonly, nonnull) NSString *b;
@property (nonatomic, readonly, nonnull) NSString *c;
@property (nonatomic, readonly, nonnull) NSString *d;
@property (nonatomic, readonly, nonnull) NSString *e;
@property (nonatomic, readonly, nonnull) NSString *f;
@property (nonatomic, readonly, nonnull) NSString *g;
@property (nonatomic, readonly, nonnull) NSString *h;

- (instancetype)initWithBuilder:(void(^)(OCDemoModelBuilder *builder))builderBlock;

@end

// OCDemoModel.m

@implementation OCDemoModel

- (instancetype)initWithBuilder:(void(^)(OCDemoModelBuilder *builder))builderBlock {
    if (self = [super init]) {
        OCDemoModelBuilder * builder = [[OCDemoModelBuilder alloc] init];
        if (builderBlock) {
            builderBlock(builder);
        }
        _a = builder.a;
        _b = builder.b;
        _c = builder.c;
        _d = builder.d;
        _e = builder.e;
        _f = builder.f;
        _g = builder.g;
        _h = builder.h;
    }
    return self;
}

@end

// Usage

OCDemoModel *ret = [[OCDemoModel alloc] initWithBuilder:^(OCDemoModelBuilder * _Nonnull builder) {
    builder.b = @"b1";
}];

// ret = a,b1,c,d,e,f,g

但是 Swift 的 Struct 支持属性默认值和初始化构造器,使得 builder pattern 意义并不是很大,代码如下:

struct SwiftDemoModel {
    var a = "a"
    var b = "b"
    var c = "c"
    var d = "d"
    var e = "e"
    var f = "f"
    var g = "g"
    var h = "h"
}

// Usage

let ret = SwiftDemoModel(b: "b1")

// ret = a,b1,c,d,e,f,g
  • State Pattern

当一个函数的执行结果可能存在多种不同的状态时,我们通常会采用状态模式来解决问题。

例如我们定义一个函数执行结果可能存在 finish\failure\none 三种状态,由于存在一些关联值,我们不能使用枚举来解决。需要定义三个不同的具体类型,具体代码如下所示:

///  Executable.h
@protocol Executable <NSObject>

- (nullable NSDictionary *)toFormattedData;

@end

///  OCDemoExecutedResult.h
@interface OCDemoExecutedResult: NSObject<Execut
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值