如何從 Parse 手中拯救你的應用

來源:互聯網
上載者:User
作者:Reinder de Vries, 原文連結,原文日期:2016/01/09

譯者:pucca601;校對: 靛青K;定稿: numbbbbb

編者註:這篇文章是由 Reinder de Vries 撰寫,一個在 LearnAppMaking.com的獨立應用開發人員。

喔不! Parse 即將關閉…你打算怎麼辦呢?

今年 1 月 28 號,Parse 宣布它將會關閉自己的服務。他們正在慢慢減少已提供的“後端服務”,打算在 2017 年 11 月 28 日全面撤出該服務。

對於從 2011 年開始就依賴該服務的超過 500,000 的開發人員來說這真是個壞訊息。正如 Jameson 在他的 部落格文章中指出的一樣,開發人員們感覺被他們的信任背叛了。

Parse 在 2013 年被 Facebook 以八千五百萬美元收購,但現在“五巨頭”之首冷血地切斷了對開發人員們應用的支撐服務。

在 2013 年,收購 Parse 其實有不小的風險,但是當時 Facebook 需要在移動市場立足,所以不得不買。Facebook 最新的收益報表顯示,2016 年 Q4 的移動廣告相比 2014 和 2015 年增長 52%,這表明他們已經在移動市場站穩了腳跟。

Amazon、Microsoft 和 Google 的雲端服務競爭越來越激烈,你可能覺得 Facebook 不再需要 Parse 。從商業的角度我是十分贊同的,但從開發人員視角這是一個糟糕的決定。

真的是這樣嗎?

對開發人員來說, Parse 的關閉是一個機會

在我做應用之前,我一直在開發網站。不計其數的網站。我學會了所有必備技能:HTML、CSS、JavaScript、PHP 和 MySQL。My Code品質和優雅程度在當時會讓你起雞皮疙瘩,但是通過不斷地試錯,我最終掌握了輸出高品質網站的技術。

年複一年,我時不時會開發一個 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% 信任一個對你應用持續發展和成功至關重要的第三方服務提供者。

1. 列出一個替代品清單

Parse 有幾個相似的供應商,比如 Firebase。可能在 Parse 關閉之前你都沒聽說過 Firebase。

最酷的事是:大多數這類服務知道你正在尋找它們。如果你 Google “parse shutdown(譯者註:Parse 關閉)” 或者 “parse migration(譯者註:Parse 遷移)”,你會正中許多高度相關的 Google AdWords 廣告,叫你遷移至它們服務的廣告。千萬別這麼做!

相反,你應該列一個替代品清單。盡量熟悉外面的東西。列一個你需要依賴的服務商以及替代品清單,以防萬一。就像超級市場會有備用牛奶供應商的清單以防他們主要的供應商破產,你也應該擁有一份和你有業務往來的公司清單。

當然,你還可以對清單上的替代供應商做一些和你相關的技術和 SDK 研究。我之前完全沒聽說過 OneSignal,直到我開始尋找一個替代 Urban Airship 的免費推送供應商,因為我覺得 Urban Airship 的費用太貴了。

2. 解耦你的代碼

雖然你已經聽了一萬遍: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,無需重寫前端代碼。

3. 使用 Adapter Pattern(適配器模式)

第三種也是最後一種方法是減少代碼耦合。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,這個Factory 方法可以保證當你更換適配器的時候你只需要替換類的名字一次(或兩次)。

如果你將 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。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.