花了四年遷移到TypeScript,我們總結出了這些經驗教訓

四年多以前,一家名爲Heap的創業公司開始使用TypeScript取代CoffeeScript。儘管公司內部的工程師普遍都很喜歡TypeScript,但遷移的速度還是很慢,當時也沒有一條明確的途徑可以實現100%的TypeScript代碼庫。本文是Heap公司在遷移過程總結出的經驗教訓,希望對廣大開發者有所幫助。

實際上,如果說我們的目標是完全切換到TypeScript上,彼時我們卻走在了錯誤的道路上。我們當時正在添加TypeScript代碼,但我們添加CoffeeScript代碼的速度卻更快。TypeScript和CoffeeScript的目標都是同一個Node.js運行時,我們希望這個運行時可以簡化過渡工作,雖然大家都在期待轉型,但我們卻並沒有積累那麼多動力,我們也沒有向着徹底拋棄CoffeeScript的未來前進。

在2019年初,我們又一次開始了從CoffeeScript切換爲TypeScript的努力。這一次,我們決定讓遷移工作恢復生機,這需要我們重新考慮轉換現有代碼的策略。在這樣的理念引導下,我們有了一套新的指導原則。我們依照這些原則,將一個看似棘手的難題變成了一個易於管理、易於理解的過程,並設法顯著改變下面這些曲線的形狀:

那麼我們是怎麼做到的呢?本文就是我們的經驗之談。

人和技術同等重要

我們重新開始這項工作時最重要的體會就是,成功的遷移必須以人爲本,要關注的不只是技術。作爲工程師,我們很容易被技術潮流以及(尤其是)遷移的細節所吸引:我們都覺得遷移到TypeScript可以增強對代碼的信心,並且都非常樂意花費大量時間來精心調整TypeScript配置。

事實證明,更重要的因素在於等式中人員的這一側:我們如何讓同事認同這種新範式?這個問題還引發了其他許多疑問。例如:在這個新模型中,我們如何讓開發人員幹勁十足?爲了突出新範式的優勢,有哪些障礙或摩擦是可以消除的?

沿着這些問題的思路,我們開發了一種新的遷移流程,並對其感到非常自豪。

開發體驗必須明顯改善

我們很快意識到,要讓整個團隊都參與進來,必須讓開發人員體會到,他們在編寫TypeScript時會更有效率。如果團隊只是將遷移看作是從一種語法換成另一種差不多的語法,他們永遠都不會產生認同感。如果遷移之後他們的日常工作效率並沒有提升,那麼就算工程師們往往更喜歡編寫類型化代碼,也敵不過舊習慣的巨大慣性。

我們首先找出代碼庫中有哪些區域在轉換後將帶來生產力的大幅提升,因爲我們知道,有計劃地轉換文件比隨機轉換更具說服力。例如,我們的數據訪問層(“ORM”)無處不在,並且大多數文件都會以某種方式來使用它。在數據訪問層中引入類型會產生效率層面的乘數效應。今後轉換的幾乎所有文件都將從類型完善的數據庫模型和實用工具中受益。

我們還將工具鏈和配置作爲優先事項來對待。大多數開發人員使用的編輯器就是那麼幾種而已,因此我們創建了可以直接使用的編輯器配置,添加了調試配置,從而可以輕鬆設置斷點和單步執行代碼。

最後,我們整理了一套取得共識的linting規則,這些規則使我們能夠在整個組織中以統一的樣式編寫代碼,並讓開發人員對遷移行動更加滿意。

當團隊開始看到這些轉換工作的成果時,整個項目也就得到了認可,前進動力也會更足了。當我們的工程師開始將類型化數據訪問視爲必不可少的工具後,他們就能更好地意識到,代碼庫的其它部分也會平穩地轉換完畢。

打破阻礙轉換的技術障礙

當我們開始分析TypeScript的推廣模式時,有一件事情很明顯:對我們的工程師來說,使用TypeScript並不是一個無縫的過程,他們經常需要導入特殊的實用工具(ts-node/register)或創建CoffeeScript中間層文件,僅僅是爲了導入這些CoffeeScript代碼的TypeScript等效內容。簡而言之,確實存在一個關於互操作的故事,但是它需要大量的樣板,並且需要經歷太多的嘗試和錯誤才能走上正軌。

這些摩擦點是阻礙遷移的主要因素嗎?很難說,但是我們知道,阻力最小的途徑是一種強大的力量,如果我們想讓人們支持轉換,就需要使TypeScript成爲簡單而明顯的選擇。

爲此我們優先做了一些工作,允許開發人員在任何服務或組件中編寫TypeScript。無論是後端、前端、腳本還是devops任務,我們都希望工程師能夠使用TypeScript來編寫代碼,並使它正常工作。我們最後使用了NODE_OPTIONS環境變量與-r ts-node/register,以便現有的工作流(使用coffee命令運行CoffeeScript文件)能繼續運作。

確保轉換過程簡單、安全和自動化

語言遷移可能會帶來風險:CoffeeScript和ES6/TypeScript之間一些看似等效的語法可能根本就不是一回事。開發人員可能會認爲轉換是重構(或更糟的是重寫)的好機會,但這會讓遷移工作本來就有的風險雪上加霜。

爲了減輕這種風險,我們需要一個規範的流程來轉換文件,其不會引入迴歸,也不會誘導工程師去做多餘的事情。這個流程還要能快速執行。

我們確定了一個分爲兩部分的流程:首先自動轉換CoffeeScript文件,然後立即手動添加基本類型註解和與linter相關的更改。關鍵在於抵制(不管是什麼方式)重構代碼的誘惑。這樣一來,轉換工作就成爲了簡單、遵循安全規則的機械活動,不會影響運行時行爲。

對於初始轉換而言,我們使用了將.coffee文件轉換爲.ts文件的腳本。在幕後,我們使用decaffeinate(https://decaffeinate-project.org/)來從CoffeeScript轉換爲ES6 JavaScript。由於所有ES6 JavaScript在語法上都是有效的TypeScript,因此我們有了一個正常工作的文件。(我們發現decaffeinate是一種非常成熟且可靠的工具。)我們用Git歷史中的一次獨立提交來表示這一步驟。

不過這項工作尚未完成。我們在嚴格模式下使用TypeScript,因此“隱式any”等功能都已關閉。我們利用這個轉換窗口爲無法進行類型推斷的事物創建了類型註解。我們避免在此階段使用any,而選擇了更嚴格的unknown。此階段的目標是實施不會導致運行時行爲變化的更改。我們沒有做出任何形式的重構,而只是做了最小限度的工作,來讓代碼進入準備編譯、lint和通過測試的狀態。

如果模塊的依賴項已經轉換爲TypeScript,則幾乎不需要做任何工作:大多數類型是通過導入的模塊來處理的。這樣最後會產生滾雪球效應,轉換的模塊越多,轉換工作就會變得越來越容易和安全。

第二個步驟也是一次獨立提交;這大大簡化了代碼審覈過程,因爲在decaffeinate的步驟完成之後,審閱者可以輕鬆地看到所做的更改。

整個流程都記錄在一份TypeScript轉換指南中。Heap的所有開發人員都可以在最短5分鐘內,轉換一個文件並打開拉取請求將其合併。

給團隊成員提問和討論的去處

應對這種遷移意味着要讓你的同事們放棄一種舒適而有效的工作方式。這裏的理念是,新方法將帶來更多的生產力。但是要達到這一目標需要付出時間和精力。我們最不想看到的是一種失敗的轉換模式:在這種模式下,開發人員最後會陷入破損的工具、混亂的錯誤消息以及難以理解的編譯器錯誤的爛攤子中。因此,我們的下一個優先事項是想辦法引導整個團隊提升專業水平。

爲此,我們在Slack中創建了一個#typescript頻道,讓遇到困難的開發人員能夠獲得幫助。推動遷移工作的開發人員可以隨時在頻道里回答問題,監測常見的問題和障礙。如果同樣的問題不斷重現,他們就會知道哪些地方應該着重改進。

開發人員需要知道,他們所遇到的任何語言和工具問題都將得到及時解答。我們決定讓“TypeScript冠軍”在完成他們自己的工作之前優先處理同事的問題。雖然這減慢了他們的工作進展,但同時也消除了遷移中面臨的許多潛在的重大障礙。

追蹤進度

從一開始,我們就知道不可能在一夜之間完成遷移任務,並且可能需要一年或更長時間才能完成此過程。這也是很好的:我們認爲進步比完美更重要。

我們發現,長時間跟蹤我們的工作進展是很有意義的。我們可以觀察一段時間內的穩定進展,進而瞭解我們是否仍在進步。我們使用Grafana來可視化代碼行數。下面是另一個可視化圖像,顯示了隨時間推移的文件計數:

領導要尊重工程師

不幸的是,在這類項目中取得成功最重要的因素之一是領導是否願意爲你提供執行這些任務的空間。在我們的案例中,遷移項目是自下而上的工作:一開始,我向團隊負責人和工程經理提出計劃,一旦獲得批准,我們就可以自由地找出實現此目標的最佳方法。雖然我們正在討論的轉換將涉及成千上萬行代碼,但遷移是100%內部驅動的。

一般來說,這類項目的最佳擁護者往往是那些每天都在使用有問題工具的團隊。在Heap,我們很幸運地遇上了認同這種理念的領導層,他們也認同領導力在對工程師賦權並最終擺脫困境時是非常有意義的。在繼續遷移的過程中,我們希望繼續學習,並利用這些知識來簡化下一個大型項目。

原文鏈接https://heap.io/blog/engineering/migrating-to-typescript

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章