做者:Reinder de Vries,原文连接,原文日期:2016/01/09
译者:pucca601;校对:靛青K;定稿:numbbbbb前端
编者注:这篇文章是由 Reinder de Vries 撰写,一个在 LearnAppMaking.com 的独立应用开发者。web
今年 1 月 28 号,Parse 宣布它将会关闭本身的服务。他们正在慢慢减小已提供的“后端服务”,打算在 2017 年 11 月 28 日全面撤出该服务。编程
对于从 2011 年开始就依赖该服务的超过 500,000 的开发者来讲这真是个坏消息。正如 Jameson 在他的博客帖子中指出的同样,开发者们感受被他们的信任背叛了。swift
Parse 在 2013 年被 Facebook 以八千五百万美圆收购,但如今“五巨头”之首冷血地切断了对开发者们应用的支撑服务。后端
在 2013 年,收购 Parse 其实有不小的风险,可是当时 Facebook 须要在移动市场立足,因此不得不买。Facebook 最新的收益报表显示,2016 年 Q4 的移动广告相比 2014 和 2015 年增加 52%,这代表他们已经在移动市场站稳了脚跟。安全
Amazon、Microsoft 和 Google 的云服务竞争愈来愈激烈,你可能以为 Facebook 再也不须要 Parse 。从商业的角度我是十分赞同的,但从开发者视角这是一个糟糕的决定。服务器
真的是这样吗?app
在我作应用以前,我一直在开发网站。不可胜数的网站。我学会了全部必备技能:HTML、CSS、JavaScript、PHP 和 MySQL。个人代码质量和优雅程度在当时会让你起鸡皮疙瘩,可是经过不断地试错,我最终掌握了输出高质量网站的技术。框架
年复一年,我时不时会开发一个 web 应用来保持技艺与时俱进。有许多更新更先进的工具出现,我在工做中也能够应用它们。我从 jQuery 迁移到 Angular 再到 React,期间接触了太多 JavaScript 框架,见证包管理工具以及 GitHub(SourceForge,还有谁?)的出现,还有 PHP 4 到 PHP 5 再到 PHP 5.6 以及即未来临的 PHP 7。个人 MySQL 表格撑爆了,因此我切换到 Elasticsearch 和 Mongo。编程语言
不久前我想要自动化时讯邮件注册和 TestFlight 的测试邀请。若是你订阅时讯而且确认了订阅,这个自动化流程会自动将你加入 TestFlight 的测试组。我对 FastLane 工具以及它的 boarding 组件有必定了解,这个图形化 boarding 组件的 HTML 页面必定有一个我能劫持的 POST URL 入口点。实际上,我会从个人表格中抓取订阅者的邮箱地址并将其放入 boarding 表格。Boarding 会完成剩下的事情,好比将订阅者添加到 TestFlight 的测试组。
这里只有一个问题: boarding 表格有 CSRF 保护,这意味着它须要每一个请求里包含一个独一无二的令牌。这些令牌是服务端生成的,在个人自动化流程里无法获取它们。
我能访问 boarding 的源代码,因此理论上我可让 CSRF 保护失效,从而解决这个问题。只有一点要先声明:源代码是 Ruby 写的,可是我在有生之年没有看过一行 Ruby 代码(好吧,也许有一行),更不用提写了。
多亏我有大量后端编程经验,我不惧怕上手一门不熟悉的技术。经年累月的反复试验和犯错让我对 web 如何运做有深刻的了解。我没有羞于接触这个一无所知的技术,相反,我挖得很深刻。
我翻阅了各类没有见过的库,以及它们相比之下很奇怪的名字(这算个事儿吗?)后,终于找到了管理 CSRF 保护特性的文件。最终我发现,关掉这个特性至关于将 controller 置空。
几乎每个成功的应用多少都会使用一种后端服务来链接用户,将用户数据在服务器上持久化。
不少我遇到和指导过的开发者对后端编程缺少扎实的理解。他们在极其简单的 Dashboard 上设置 Parse 的配置项,写一个查询语句,而后就认为数据“就在那里”。谁会想要知道云端发生了什么呢?
我经常将 Parse 解释为“应用的电子表格”。这是事实:Parse 为你的应用提供了后台服务,它的 Dashboard 和 Google Spreadsheets 同样简单。你甚至不须要写查询数据的语句,相反,你可使用下面这样简单的方法:
PFQuery(className: "Tweet").whereKey("user", currentUser);
这或许也是 Parse 的错。它们的 PFQueryTableViewController
用起来实在太简单,可是也至关危险:它直接将后端代码与你应用的 view controller(已是个 ViewModel)关联了。即便你想从 Parse 转到 Firebase,由于你的代码和后端紧密耦合,你不得不在迁移以前重写整个应用。
Parse 的 PFObject 类内置了映射,因此你能够像使用原生的 Swift String 对象同样直接使用字符串数据, Parse SDK 会在内部将这些数据转化成能够在互联网上输送的数据。若是你在面向用户的代码中使用了 PFObject 实例,那么将来要替换一套新的“后端即服务” SDK 会很难。
若是你要从头构建一个本身的后端,你须要知道例如 true(一个布尔值)在编码为 JSON 的时候会转化为 true
(一个字符串)。若是那个 JSON 数据抵达你的 app,你须要处理的是一个 String
实例而不是你指望的 Bool
类型。虽然 Swift 有一个难以置信的类型系统,可是 if let 可选类型绑定状态判断机制(optional binding statement)没法处理不匹配的类型——它并不能解决这个问题!
因此 Parse 的关闭对你有什么好处?这是又一次开始试验的好机会,你能够深刻挖掘后端黑盒,保护你的代码再也不遇到相似的事情。
下次你要开发应用时,请将下面这三个方法记在脑子里。你能够用它们保护你本身(的业务)以防 Parse 关闭这样的事情再次发生。不要 100% 信任一个对你应用持续发展和成功相当重要的第三方服务提供商。
Parse 有几个类似的提供商,好比 Firebase。可能在 Parse 关闭以前你都没据说过 Firebase。
最酷的事是:大多数这类服务知道你正在寻找它们。若是你 Google “parse shutdown(译者注:Parse 关闭)” 或者 “parse migration(译者注:Parse 迁移)”,你会正中许多高度相关的 Google AdWords 广告,叫你迁移至它们服务的广告。千万别这么作!
相反,你应该列一个替代品清单。尽可能熟悉外面的东西。列一个你须要依赖的服务商以及替代品清单,以防万一。就像超级市场会有备用牛奶供应商的清单以防他们主要的供应商破产,你也应该拥有一份和你有业务往来的公司清单。
固然,你还能够对清单上的替代供应商作一些和你相关的技术和 SDK 研究。我以前彻底没据说过 OneSignal,直到我开始寻找一个替代 Urban Airship 的免费推送供应商,由于我以为 Urban Airship 的费用太贵了。
虽然你已经听了一万遍:Model-View-Controller(译者注:模型-视图-控制器)仍是有道理的。咱们正渐渐习惯 Model-View-Whatever(译者注:模型-视图-任何东西),可是 MVC 的理念实际上是:你的 Controller 不能配置 View,你的 View 不该该操纵一个 Model。
Cocoa Touch 框架让人很难不使用 MVVM(Model-View-ViewModel),可是这不意味着你要将你的 Model 代码与 View Controller 代码紧耦合。
在编程理论中咱们有两条原则:耦合与封装。使用两个紧耦合类意味着 ClassA 做出了不少关于 ClassB 内部功能的假设。
想象一辆车和一位司机。司机坐在车里的前方位置,由于驾驶杆是与引擎直接相连的,若是司机忽然坐到车后方来驾驶呢?这样确定行不通。固然,相似这样的状况在现实生活里永远不会发生,可是这种状况在你的代码里一直存在。
应对紧耦合的一个保护措施就是封装。这意味着每个类有着一个严格定义的方法集合,好比 speedUp()
和 steerLeft()
。经过依赖可燃的引擎,你只须要让司机调用 speedUp()
,而不是让司机将更多的汽油注入燃烧室。用这种方式司机不须要知道有关引擎如何工做的复杂知识,只须要调用一个他知道安全的方法就能实现了。
当这种引擎被一个电动的不带燃烧室的引擎所替代,你也不须要修改司机的代码:他依赖一个暴露的 speedUp()
方法,而不是依赖 injectGasMixture()
、 gasMixture
和 sparkTimer
(译者注:注射混合汽油,混合汽油,电火花计时器)。
若是你以为解耦和封装难以理解,就将它们看做职责吧。谁的职责是驾驶?司机。谁的职责是使汽车向前移动?引擎。
当你正在编写一个有后端能力的应用时,要清楚地定义组件以及组件的职责。建立一个在后端代码和前端代码之间只起媒介做用的中间件。前端代码基于你本身的类构建,就像 Car,后端代码处理你用到的后端 SDK 而且使用相似 PFObject 的类。
中间件的工做是沟通前端和后端。假使你的后端代码过期,你能够替换中间件的代码让它使用新的后端 SDK,无需重写前端代码。
第三种也是最后一种方法是减小代码耦合。Adapter Pattern(适配器模式),比互联网自身还要老,是一个面向对象编程的模式。这是一套编程设计规则,能够用它来将两个不相容的类变得相容。
这相似于构造一个“ wrapper(封装器)”,不仅是暴露资源接口(像是封装一个 REST API ),它还会在两个不相容接口间制定一套规则。在不少编程语言里这些规则叫接口(JAVA 和 PHP),在 Swift 和 Objective-C 中它们叫 protocols(协议)。
你必定知道 Swift 的范型,对吗?若是有个东西游起来和叫起来像一只鸭子,那么它必定是只鸭子。Adapter Pattern(适配器模式)也有相似机制。要让 ClassA 和 ClassB 解除耦合,你须要构造一个 ClassA 的适配器,而不是直接在 ClassA 里调用 ClassB。
这个适配器类包含有关 ClassA 如何工做的复杂知识。适配器类也遵循一个协议。这个协议说:“你能够肯定我有 X,Y 和 Z 方法”。
ClassB 不知道 ClassA。它只知道它想要一个遵循适配器协议的实例。它不在意这个实例是否是个鸭子,只要它游起来叫起来像个鸭子就好了。
使用适配器有什么好处?假设你原来的 ClassA 代码废弃了,你只须要找另外一个类(例如另外一个 Parse 的替代品)而且为这个类写一个适配器。只要这个适配器遵循协议,也就是你以前制定的规则,ClassB 依旧可以工做。
事实上,你能够写一个带有下面这个签名的方法的适配器(MyTwitterAdapter
):
class MyTwitterAdapter:AnyTwitterServiceProtocol { func getTweetsWithUser(user:User, withPage page:Int = 0) { ...
协议(AnyTwitterServiceProtocol
)包含了与上面如出一辙的方法签名,可是它没有任何逻辑或者方法实现,只是定义了规则。
protocol AnyTwitterServiceProtocol { func getTweetsWithUser(user:User, withPage page:Int = 0); ...
前端代码(MyTweetsViewController
)有一个未定义类型的变量 twitter,这个工厂方法能够保证当你更换适配器的时候你只须要替换类的名字一次(或两次)。
若是你将 twitter 类型严格定义为 MyTwitterAdapter
,你的代码中可能还有不少耦合处。这样的话,若是你要将适配器替换为一个新的适配器,仍是须要更新大量代码。
一旦你设立了这段检查机制,就能够测试这个你正在工做的实例 twitter 是否遵循 AnyTwitterServiceProtocol
。
if let _twitter = twitter as? AnyTwitterServiceProtocol { // Yes, it conforms }
你的前端代码不再用关心 twitter
是不是 Car
、FooBar
或 Facebook
类型,只要它遵循了 AnyTwitterServiceProtocol
就行。它只想知道这个实例是否有一个方法叫 getTweetsWithUser:withPage:
。
注:假设你真的须要严格定义 twitter 的类型,可使用协议做为类型,这样你也能使用泛型。
如今你已经学会了怎么改善业务代码、怎么处理你依赖的供应商以及保护你的代码,我想你已经明白怎么应对相似的危机了。
你是否是正要转到 Firebase ?你应该知道 Firebase 属于“五巨头”中的 Google。虽然 Parse 关闭不意味着 Firebase 也会关闭,但依赖一个新的供应商会让你的应用和以前同样脆弱,除非你想办法保护你的代码。
学习后端编程是一个好办法。Parse 已经发布了一个优秀的替代产品,Parse Server,你能够在其上运行你本身的服务器(只要它能够运行 NodeJS 和 MongoDB)。在下面的文章中我会向你展现如何将一个简单的应用(包括 Heroku 和 MongoLab)从 Parse 迁移至 Parse Server。
继续阅读:指南: 如何将一个简单的应用(包括 Heroku 和 MongoLab)从 Parse 迁移至 Parse Server
另外一个相对容易的练习是将你的推送通知部署到两个服务中,不要把鸡蛋放在一个篮子里。实现推送服务供应商的客户端 SDK 相对来讲比较容易,一般你只须要发送惟一的 ID 并创建一个段。
使用 Adapter Pattern(适配器模式)去建立一个统一的接口,供你的前端使用。经过定义一个协议将实际的适配器从前端代码解耦。挑选一个备用的推送通知服务供应商(好比 Urban Airship, Mixpanel, Pusher 或 PushOver),写一个备用的适配器。确保这个适配器遵循这个协议,而后模拟一下服务崩溃,看看如何从新部署适配器。那么,你的问题解决了吗?
不要惧怕深刻黑盒。写你本身的后端 REST API 是个好办法,放手去作,你会学到不少东西。
你知道 Crashlytics 属于 Twitter 吗?任何服务均可能会关闭……搞清楚 Crashlytics 为你作了什么,以及它的工做原理。这是创建一个稳定可靠而且能一直赚钱的业务的惟一途径。
接下来,你要本身走进兔子洞了。
Reinder de Vries 是一个独立应用开发者,他在 LearnAppMaking.com 上教有志向的开发者以及市场营销者如何构建他们的应用。他已经开发了 50 多个应用,他的代码被全世界成千上万的用户使用。不写代码的时候,他喜欢浓缩咖啡(strong espresso)和旅行。
本文由 SwiftGG 翻译组翻译,已经得到做者翻译受权,最新文章请访问 http://swift.gg。