超越Objective-C,超越Swift

purplepanda 发布于2年前
0 条问题

当苹果在发布iOS 4向我们介绍ARC时,我接触iOS开发还不到一年。不过即便在如此短的时间里,我也经常挣扎于内存的手动管理(保留和释放),因此我立刻就理解了ARC的重要性。我将永远不会忘记transition guide documentation中的模型:

超越Objective-C,超越Swift

它完美的描述了ARC能带来的好处。ARC并不是通过语法细节和压缩的表达式的方式让代码变短,而是在工程中移除相关的整块代码,它们原本易于出错,而现在被隐藏到实现细节当中,对开发者几乎是不可见的,开发者也无需操心它们。

ARC是这么的棒,以至于听上去甚至有些不太真实。事实上,直到今天仍然有些地方的内存管理需要手动操作,但在大多数地方ARC就像魔法一样神奇――特别是对那些在ARC出现之前编写iOS应用程序的人来说。

进步是冒犯的

在引入ARC的头几年,资深iOS开发者能够引以自豪的一点,是他对于旧式编程风格的掌握程度。使用ARC,在他们看起来并不是真正的Objective-C编程。他们说:“瞧瞧那些使用ARC的小孩儿们。”不过这种态度没有持续多长时间,在苹果将OS X过渡到ARC之后,对ARC的非议统统消失了。

软件开发技术的进步,对于被取代的技术的那些从业者来说,无疑是冒犯的。在他们眼中,新的技术和自己掌握的相比,简直简单到幼稚。即使这么概括起来可能太笼统,我认为这种反应是很自然的。当你对你做的事非常有激情的时候,你会不知不觉的爱上工作对象和它的特质,即使事实上它可能过于累赘。

软件开发技术的进步来源于抽象。对于通常的开发场景来说,低层级基础设施的最佳实践是被编码、自动化、以及优化的,开发者甚至无需感知到它们。但正是这个抽象和简化,它们是冒犯旧风格拥趸的元凶。新技术能自动处理之前需要重重计划和努力才能完成的任务,当然前提是新技术工作正常,但没有人希望看到他们的专长变得没用了――直到他们意识到,他们眼中很简单的抽象,其实是搭建更高一层复杂事物的积木,而这种复杂事物在之前是无法使用旧的工具完成的。

上面的这种进步,是我希望从Objective-C替代品中获得的东西,但是我并没有从Swift得到它们。

对Swift的失望

许多人已经是Swift的忠实粉丝,其他人要么心情矛盾,要么充满怀疑,要么就是干脆反对。我把我自己放到心情矛盾的那一组里。我还没有清楚的表达过我的想法和感受,现在我准备说一下了。

Swift有许多招人喜爱的地方。我尤其喜欢枚举类型、字符串处理,和Playground REPL。Swift显然是在深入仔细的思考之后设计出来的,但即使如此,仍然无法改变我的失望的感觉。如果用一句话来描述就是:

Swift解决的问题我并不拥有,而我最关心的问题Swift并没有解决。

为何创造出Swift语言这个问题,让我们以苹果的Swift官方主页的权威指南作为答案。下面是苹果列出的Swift几项特性(它们不包含Objective-C已经有的特性,比如自动内存管理)

  • 类型推断(Inferred types) �C 类型推断让代码更清晰以及更少的错误

  • 模块(Modules) �C 模块移除了头文件并提供命名空间

  • 闭包和函数(Closures & Functions) �C 闭包和函数指针相匹配

  • 元组(Tuples) �C 元组和多重返回值

  • 泛型(Generics) �C 泛型带来的好处是不言而喻的。

  • 结构体(Structs) �C 支持方法、扩展、接口的结构体。

  • 函数式编程模式(Functional Programming Patterns) �C 比如map和filter。

这些都是在Objective-C基础上显而易见的改进。让我们将关于泛型的好处、类型推断、函数式编程等等的争论放到一边,干脆的同意Swift在许多地方比Objective-C要优越。

那为什么我还是失望呢?我对Swift的失望的原因,是因为上面的清单里所有的事物都是迭代式的改进,没有一个特性直面了我作为开发者的最大挑战。为了解释原因,下面我先描述我工作的方式,然后再回到Swift上来。

我的工作方式:空气编程

我按照一种我称为“空气编程(coding in the air)”的方式来构建我所有的软件程序。它开始于一个富有成效的合作――与我在Streamweaver和Riposte的同事Jamin Guy一起。我们会坐在Jamin的客厅,开始讨论架构的具体内容。有时这种交流会持续5到6个小时,在这期间我们不会去碰键盘。我们会在头脑中创建并分解API,连珠炮似的反复讨论需要的类名、属性清单以及方法签名,每一次都会有些小小的不同。我们会不断地说同一个词直到口干舌燥,直到最后正确的模式自然的浮现出来。

在这些交流的结尾,我们脑海中的程序的实现方法是如此清晰,让实际写代码的过程变成了单纯的打字而已。

使用这种方法开发程序需要无比集中的注意力,但它值得这么做――特别是当你拥有一个志趣相投的合作者的时候,它将最大程度上发挥合作者的好处。与一般开发需要不被打扰的连续时间块用来编程相比,空气编程没有任何实质上的消耗。当一个想法不能实现的时候,它自然消失了,没有代码需要重写,也没有文件需要删除。

空气编程让你的关注点从实现细节转移到架构上。在任何项目中,架构总是最难也是最重要的部分。它需要花费最多的时间来实现,也是需要最多的时间来重新实现的地方――当你被早期糟糕的假设逼入困境,你将不得不重写它们。空气编程减少了你需要重新实现架构的风险。

具体实现是瓶颈

最终当启动Xcode的时机到来时,整个项目的实现已经在我脑海里非常清楚了。但这才是我在本文中的问题真正开始的地方。我所参与的每一个项目都有一些部分需要重写相同的实现,但这部分代码是不能重用的,比如:

数据库与持久化 �C FMDB和Core Data这种框架是能够重用的,但真正使用这些框架的类并不如此。这些类总是需要编写从框架中插入、更新,以及获取项目特定的对象的代码。另外还需要编写其他的类来为这些对象提供唯一化和执行的缓存。如果你需要table views在滚动完成后才显示挂起的改变,你需要不同于NSFetchedResultsController的类库来管理这些变化。你的app和数据之间也需要model controller层作为中间层提供服务,这部分也是需要重写的。更别提处理多线程数据库连接、迁移以及合并了。

JSON和RESTful API �C 网络连接工具如NSURLSession和AFNetworking是可重用的,但使用它们的类不是如此。数据必须转换成字典格式、然后字典被转换成对象。在这个过程当中的每一步都充斥着潜在错误,这些错误需要被安全的捕捉、响应,并且传播到程序的顶层。同样的复杂性存在于截然相反的过程当中,比如发送本地数据到远程API。

触发器和响应 �C 触发响应的事件,必须被绑定到项目特定的控件上。KVO呢,当使用正确时,会涉及到大量的模板。通知呢,必须被发送,并且需要附加正确的用户信息。并且任何需要这些通知的地方都必须编写观察对象。如果你在使用KVO或通知时犯了一个错误,程序可能会崩溃。甚至很多时候,程序就是不工作,而静态检查也不会报错。你最大的希望是设置UI Automation的集成测试并且祈祷你的应用设计不会太多的超出测试之外。ReactiveCocoa作为一个第三方方案来解决这些实现问题,至少它的勇气值得称赞。

UI布局 �C 不管你使用springs & struts或者AutoLayout,每种方法都需要你明确相关视图如何排列。你需要花大量的时间编写和修正这些排列,特别是现在有这么多设备需要适配的情况下。没有什么是自动写好的,UI布局依赖于对细节的不断调整。那种感觉就像教导一个蒙住眼睛的人如何开飞机,而每个app都是一个新飞机。

这些只是我们在编写Objective-C程序时需要面对的耗时任务的其中一部分。它们需要花费长时间来进行调优,并且涉及到大量重复性和蛮力性的工作。这些任务会耗尽有限的资源:程序员的时间,而这些时间是一个初创企业账单上最大的花费项。对于企业来说,这些任务就像精神和物理上的双重税收。它们让开发者难以保持关注最核心的问题:如何创造一个用户喜欢的东西。

回到Swift

Swift没有减少开发程序时我们在那些样板代码里花费的时间和精力。甚至如果我们分解Swift的陡峭的学习曲线,我们会发现它仅仅只是将运行时的调试转移到编译时,所以只是看上去入门简单了。它解决了Objective-C里的一些通常的实现错误,但并没有让程序更快的实现。说Swift让程序员更轻松就像说iOS 8 Extensions让iPad更易用了――这是Federico Viticci说iOS 8改进了他的工作流的说法,可能extension的确让事情更直观了,但整个工作流还是一样复杂。

对于Swift,从搜索引擎得到的结果将会是这样:Objective-C开发者将花费接下来的数年时间以过渡到Swift的语法和功能当中。不过,即使过渡结束了,我们还是会和2014年一样,花费长时间编写关于持久化、网络、触发器和响应,以及布局的具体实现代码,这些代码也还是会和以前一样无聊、容易出bug、并且无法重用。

我想要的

如果我们用从算盘到穿孔卡片再到Objective-C的全局眼光来看,Swift不过是Objective-C的一个迭代改进。也许有一天Swift会成为我想看到的那种语言,为一些我想要的解决方案做支撑,但目前来说它还不太够格。不管它将如何演进,这里是一些我希望看到的东西:

自动持久化 �C 我再也不想思考如何实现持久化了。在我的想法里,将模型对象直接扔到一个bucket里,然后它就能自动的对数据进行存储、缓存、合并以及唯一化。我应当关注于描述对象间的属性和联系,以及我希望它们分组的方式。其他的实现细节都应该是不可见的。

自动RESTful API �C 一旦我给程序发出指令,将一个API响应对应到一个数据对象,网络和JSON转换应该被自动完成。我只想关注如何将JSON中那些项目展示给用户。

有表现力的触发器和响应 �C 我想用源于响应意图(Intent)的语法来描述事件的响应和触发器,我不关心它们间的连接是如何实现的,并且这些连接也不应该在重构时出错。

所见即所得的UI编辑 �C 我不想关心视图层级背后的数字计算,就像Disney动画家只用铅笔画出关键帧,然后将它们交给实习大军来补完,我只想在少数edge case的时候手动定位视图,而让Xcode处理所有的具体实现,这才是真正的AutoLayout。

我想象中的Objective-C的继承者,它要能够像之前ARC在内存管理所做的一样,从整体上移除复杂的架构来简化应用开发。我知道我所要求的超出了一个编程语言的范围,但这是因为,阻碍Objective-C开发最大的问题不在于语言本身,我们需要的不是一个新的Objective-C,我们需要的是一种新的开发范式。

(source:aredsinclair.com


需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。