- 原文地址:When a rewrite isn’t: rebuilding Slack on the desktop
- 原文做者:Slack Engineering
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:cyz980908
- 校對者:Ultrasteve, githubmnume
新版本的 Slack 將面向桌面用戶推出,從頭開始構建,更快,更高效,易用性更強。前端
廣泛的觀點認爲你不該該從頭重寫代碼,這是個好建議。花時間重寫已經被使用的東西,並不能使咱們的客戶的工做生活更簡單、更愉快、更富有成效。運行代碼也知道一些事情:經過數十億小時的累積使用和數萬個 bug 修復得到的知識是來之不易的。react
不過,軟件代碼具備生命週期。Slack 的桌面版是咱們最老的客戶端,成長於咱們公司早期的快速發展和試驗階段。在那期間,隨着客戶對產品的使用和指望的增加,咱們一直在優化產品的市場適應性,並在不斷的衝刺中跟上客戶的步伐。android
現在,通過五年多的快速發展,Slack 被數以百萬計的人使用,他們所在的公司規模比五年前更大,處理的數據比咱們剛開始時想象的還要多。多少能夠預見,桌面客戶端的基礎開始出現一些內部問題。此外,技術格局已經偏離了咱們在 2012 年末選擇的工具(jQuery,Signals,以及直接操做 DOM),目前的程序趨向於採用可組合的接口和更乾淨的程序抽象。即便咱們盡最大努力保證敏捷,但很明顯,須要進行一些根本性的改變,才能發展桌面應用程序,併爲下一波產品開發作好準備。ios
現有的桌面應用程序的體系結構有許多缺點:git
前兩個問題是隨着時間的推移咱們能夠逐步改進的,可是,在一個 Electron 進程中運行多個工做區意味着要改變原始設計的一個基本假設,即一次只運行一個工做區。儘管咱們爲擁有大量空閒工做空間的人們作了一些漸進式的改進 額外的改進,可是真正解決多進程問題意味着從零開始重寫 Slack 的桌面客戶端。github
忒修斯之船是一個思想實驗,這個實驗考慮的是,當一個物體每一部分隨着時間的流逝被逐個替換時,這個物體還會不會是原來的物體。若是一艘船上的每一塊木頭都被替換了,那麼這是同一艘船嗎? 若是一個應用程序中的每個 JavaScript 片斷都被替換了,它仍是同一個應用程序嗎?咱們固然但願如此,由於這彷佛是最好的作法。redux
咱們的計劃是:後端
最後一步,對咱們來講也是最重要的一步 —— 是建立一個新版的 Slack,它開始時不完整,但隨着模塊和接口的更新,逐漸向功能完整性發展。架構
去年的大部分時間裏,咱們一直在內部使用這個只有新版本的應用程序,如今它正在推廣給客戶。app
首先要作的是建立新的代碼庫。雖然這只是咱們代碼庫中的一個新子目錄,但它有三個由約定和工具強制執行的重要規則,每一個規則都旨在解決咱們現有應用程序的一個缺點:
前兩條規則,雖然耗費時間,但實現相對簡單。然而,轉向多工做空間架構是一項艱鉅的任務。咱們不能指望每一個函數調用都傳遞一個工做區 ID ,咱們也不能只設置一個全局變量來講明當前哪一個工做區是可見的,由於不管用戶當前正在查看哪一個工做區,程序內部仍然發生着許多事情。
咱們方法的關鍵在於 Redux,咱們已經在用來管理咱們的數據模型。在 redux-thunk 庫的幫助下咱們進行了一些斟酌,咱們可以在 Redux 存儲上模擬幾乎全部的動做或查詢,容許 Redux 圍繞單個工做空間的概念提供一個方便的抽象層。每一個工做空間都有本身的 Redux 存儲區,其中包含全部內容 —— 工做空間的數據、關於客戶機鏈接狀態的信息、用於實時更新的 WebSocket —— 應有盡有。這個抽象圍繞每一個工做區建立了一個概念容器,而沒必要將該容器保存在它本身的 Electron 進程中,這正是過去客戶端所作的。
有了這些認識後,咱們就有了新的架構:
關於這一點,咱們有一個咱們認爲可行的計劃和架構,咱們已經準備好經過現有的代碼庫,對全部內容進行更新改造,直到咱們留下一個全新的 Slack。因此只有最後一個問題要解決。
咱們不能隨便用新代碼替換舊代碼;若是沒有某種類型的結構將新舊代碼分開,它們將會無可救藥地糾纏在一塊兒,咱們就永遠不會有新代碼。爲了解決這個問題,咱們在一個名爲 legacy-interop 的概念中引入了一些規則和函數:
將新代碼導出到舊代碼很簡單。咱們最初的代碼沒有使用 JavaScript 模塊化或導入導出。相反,咱們將全部內容保存在名爲 TS 的頂級全局變量上。導出新代碼的過程僅僅意味着調用一個輔助函數,該函數使新代碼能夠在全局空間的一個特殊的 TS.interop 部分中使用。例如,TS.interop.i18n.t() 將調用咱們新的、多工做區感知的字符串本地化函數。因爲 TS.interop 命名空間只在咱們的遺留代碼庫中使用,它一次只加載一個工做區,因此咱們能夠在後臺對工做區 ID 做簡單的查詢,而不須要遺留代碼擔憂它。
爲新代碼調整舊代碼就沒有那麼簡單了。當咱們運行舊版本的 Slack 時,新代碼和舊代碼都會被加載,但新版本只會包含新代碼。咱們須要找到一種方法,在適當地利用舊代碼同時不會在新代碼中形成錯誤,而且咱們但願這個過程對開發人員是儘量透明的。
咱們的解決方案稱爲 adaptFunctionWithFallback,它在咱們的舊 TS 對象上運行一個函數路徑,並且若是咱們在僅使用新的代碼的代碼庫中運行,可使用這個函數。這個函數默認爲空操做,這意味着若是底層舊代碼不存在,那麼試圖調用它的新代碼將沒有任何效果 —— 而且不會產生任何錯誤。
有了這兩種機制,咱們可以認真地開始咱們的更新新舊代碼工做。舊代碼能夠在更新時訪問新代碼,新代碼能夠訪問舊代碼直到更新時。正如您所想的那樣,隨着時間的推移,新代碼庫中舊代碼的使用愈來愈少,而且在咱們準備發佈時趨向於零。
這個新版本的 Slack 已經推出很長時間了,它包含了過去兩年來一直致力於向客戶不斷推廣的數十人的貢獻。它成功的關鍵是咱們在項目早期採用的增量發佈策略:隨着代碼的更新和功能的重建,咱們將它們發佈給咱們的客戶。Slack 應用程序的第一個「新」部分是咱們的表情符號選擇器,咱們在兩年多前發佈了它 —— 以後是頻道側邊欄,消息窗格和許多其餘功能。
若是咱們等到 Slack 所有被重寫後再發布它,咱們的用戶在發佈一個「爆炸的」替代品以前,就會對錶情符號、消息、頻道列表、搜索和無數其餘功能有着更糟糕的平常體驗。增量發佈容許咱們儘快向客戶交付真正的價值,幫助咱們專一於持續改進,並經過最大限度地減小客戶首次使用的全新代碼量,下降了新客戶的發佈風險。
廣泛的觀點認爲,最好避免重寫,但有時好處也很大,不容忽視。咱們的主要指標之一是內存使用狀況,新版 Slack 提供:
這些結果驗證了咱們在新版 Slack 中所作的全部工做,咱們期待着繼續迭代,並隨着時間的推移使它變得更好。
在策略規劃的指導下,以明智的發佈爲調和,以及有才華的貢獻者的鼓舞,逐漸的重寫是糾正過去錯誤、爲本身打造一艘嶄新的船的絕佳方式,並使您的用戶的工做生活更簡單,更愉快,更有成效。
咱們熱心於分享更多關於咱們在此過程當中學到的知識。在接下來的幾周,咱們將會在 slack.engineering 上撰寫更多文章:
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。 譯