代碼重構有兩大難點,一個是「考古」,也就是如何快速梳理出代碼的原有邏輯,還有一點就是「發佈」,如何讓新的代碼能夠穩定的發佈到線上,而不產生故障。下面咱們就聊聊我一個朋友的故事,看看他是怎麼把代碼穩定搞上線的。爲了表達更爲親切,你如今就是我那個朋友。
重構代碼對不少人來講,絕對是一件髒活、累活。沒有能夠大幅度提效的方法,難以沉澱有效的體系化的可複用的技術抓手,對業務來講沒有明顯的增量,精力和時間消耗巨大,沒有測試用例,也不必定能獲得測試的支持,自測很難作到充分,最後開發完了很難上線,主要緣由是懼怕!固然並非咱們不自信,是真的恐懼。javascript
你重構的代碼是誰的?鬼知道是誰的!能讓你重構的代碼大機率不是你寫的代碼,並且是遠古代碼,用的是一種過期的技術棧。固然通常狀況下,當年的開發、測試、甚至產品早已不見了蹤影,只能在註釋的代碼裏看見了了數語。言語中透露着無奈,用一個程序員的良心提醒着後來人,「當心前面的髒東西」。看了這些話,你只能收回口中立刻要吐出的芬芳,默默離開工位,倒點熱水。前端
今後你會發現,註釋不只可以幫你讀懂代碼,還能有警示做用,告訴你重構代碼的同時,記得把 bug 一併改了。你想要經過註釋來梳理出原始需求的願望宣告失敗,接下來你只能死磕了,祈禱千萬不要漏掉業務邏輯。java
別覺得大公司制度完善,測試都有完整的測試用例,現實會狠狠的夾你腦門。頻繁的迭代,功能早已面目全非,老的用例根本不可用,更況且根本找不到老的測試用例。沒有用例怎麼自測呢?全靠我的想象。程序員
多一我的多一分力量,讓一個有經驗的測試參與到功能迴歸中來,無疑會給你的重構事業吃上定心丸,但真實的狀況是,測試同窗根本不想參與這種髒活累活。他本身手裏的需求還測不過來,怎麼會把時間奉獻給一個前端發起的重構工做上呢。無增量,無抓手,純體力,他們一樣心知肚明。編程
在沒有上述保障的前提下,若是你還能硬着頭皮上線,就會遇到更大的難題,如何上線?直接全量替換嗎?若是線上出問題怎麼辦?好在前端的回滾是很是迅速的,可是即便再迅速的回滾,從發佈完成到發現問題回滾,在提醒用戶從新刷新頁面,這個過程也足以形成難以估量的後果,尤爲是那些高頻使用,且極易產生髒數據的場景。這就是沒有一個有效的發佈方案所致使的常見後果,這個後果還有可能致使你背上故障,這一年加過的班,熬過的夜,掉的頭髮,什麼也換不來,只能催生你換個地方從新作人的念頭。canvas
綜上因素直接致使開發者極度缺少安全感,一個不敢上線本身代碼的程序員,就像半夜被本身一個月大孩子的哭聲吵醒,那時那刻你只想裝死摸魚。更況且你的工做每每不是隻有重構這一件事,寫寫新需求他不香嗎?就這樣你眼看着一個頁面重構了兩個星期,遲遲不能收尾,你變得愈來愈不自信,愈來愈懼怕了起來,不敢面對那些重構了一半的代碼,開始恐懼老闆的問題:「重構搞的怎麼樣了?」,你簡直不像個程序員。後端
終於到了年末,你的重構事業還未完成,更可怕的是,這件事還被打上了「承諾型」OKR 的標,因而你痛定思痛,作了個夢。安全
時間回到年初你剛剛接到重構任務的時候。
你的重構工做是把 177 個 jQuery 頁面用 React 重寫一遍。你立馬想到,本身一我的一年時間,必定是作不完的,此時此刻,切記不要滿口答應,必定實事求是,甚至向着最壞的方向想,讓老闆充分認識到這項任務的艱鉅性,不要抱有過高的指望。最重要的是保證人力的投入,必須有更多的同窗一塊兒參與進來,有效的分工纔有可能完成這項艱鉅的任務。有人蔘與進來,也只是基礎,由於他們極有可能會像上面描述的同樣,從興致勃勃到惟惟諾諾,所以必定要確保時間的投入,必要時把老闆也拉進來跟你一塊兒作,老闆一旦參與進來,就會更有體感,能體會到你們的不易。接下來,就應了那就老話,「別忘了,你是一個 owner!」作好基礎設施建設,讓每一個同窗有趁手的工具,有安全的保障,去除他們的後顧之憂相當重要。所以,你要作下面幾件事。數據結構
你經過細緻的研究發現,這些頁面中,有 77 個頁面是用戶使用較多的頁面,也是相對比較複雜的頁面,剩下的 100 個頁面,大部分是給開發用的增刪改查頁面,用戶的使用頻率不高。因而你作了以下劃分:
優先級劃分好優先級之後,就要對不一樣優先級的頁面使用不一樣的穩定發佈策略。運維
複雜高頻頁面:重兵壓上,細緻還原原始需求,摳代碼,拉測試同窗一塊兒整理測試用例,按照測試用例自測,測試同窗迴歸全部功能。但其實這部分頁面中,也能夠分爲兩種頁面:
將頁面劃分完畢後,你會發現重構的工做量下降了不少,由於本着「無需求,勿變動」的原則,不少頁面均可以不須要重構。且上述重構完的頁面都必須作灰度發佈。
前端不太喜歡寫單測,你大概總結了一下,主要有下面幾方面的緣由:
你發現前端不喜歡寫單測,有各類各樣的緣由,可是當你重構那些複雜頁面,尤爲是 jQuery 技術棧重構爲 React 技術棧的時候,單測真的很是有用。
好比這裏有一個編輯頁面,包含兩部分:基本信息和運行邏輯,在重構運行邏輯時候,你首先要保證的是重構事後的頁面在保存的時候,保存的數據結構必須跟以前的接口參數必須一致,因此在重構運行邏輯這個組件的時候就會有不少數據轉換邏輯。
能夠看到爲了保證你的新組件不影響保持原有功能,就要保證原始數據經過新組件的一頓操做最終保留了原來的結構,此時你就能夠寫單測來保證這個過程。
describe('utils', () => { it('流程圖:轉換爲提交的數據 transformForm', () => { const result = transformForm(canvasData); expect(result).toEqual(settingData); }); it('流程圖:轉換爲須要的數據 parseRuleSetData', () => { const [result] = parseRuleSetData(settingData, rules); expect(result).toEqual(canvasData); }); it('流程圖:反覆轉換 transformForm - parseRuleSetData', () => { const [result] = parseRuleSetData(visualSettings, rulesData); const newResult = transformForm(result); expect(newResult).toEqual(visualSettings); }); });
前端單元測試寫起來複雜,其實只是 UI 的單測複雜而已,若是你把代碼作好了足夠的拆分,拆出更多函數,更多 hooks ,單測就是垂手可得了。
你在的團隊,一直測試資源都不是充足,測試用例彷佛一直都是一種可遇不可求的東西,尤爲是在敏捷開發的趨勢下,產品功能變更快,不多有測試會一直去維護那個最初的測試用例,每每是寫過用過就再也找不到了。但測試用例在重構這個場景下,真的很是重要,他解決的核心問題是把測試同窗拉到重構的質量保障中,一塊兒梳理老的邏輯。
這份寶貴的測試用例,能夠成爲你自測的依據,也能夠爲你提供對於同一個功能的不一樣視角,若是你經過代碼看到的是實現細節的邏輯,那測試看到的就是整個鏈路的流程圖。不少中後臺系統都有管理態和運行態之分,管理態,前端是很是熟悉的,可是運行態,測試每每更加熟悉。
拿到測試用例,你就能夠自測了,可是這裏有個坑,就是若是你徹底依賴測試同窗給你的測試用例。只要保證測試用例驗證經過就好了,這種想法會出大問題,由於負責這塊功能的測試多是個新手,可能並非一直負責這塊功能的測試,他們的測試用例可能只是浮於表面的。因此你須要把經過代碼考古發現的測試用例裏沒有的邏輯,暴露給測試同窗,並補充到測試用例裏。而且若是發現有一些看不懂的邏輯,就應該搞懂他,那些你不懂的死角,每每上線後就會有大問題,不要心存僥倖。
自測很是重要,可是每每你會以爲開發完了,就算是把這個事作完了,而後就去忙別的事了,並無好好的自測,心想還有測試呢,等他們提問題,我再改吧。這是一種很廣泛的程序員心理,其實很難避免,畢竟事情有不少。這個時候你能夠找同組的開發同窗幫你點一點,先解決那些顯而易見的問題,也算是一個認真負責的程序員了,不要讓測試同窗給你提太多低級 bug。
能有測試同窗幫你作功能的迴歸測試真是一件可遇而不可求的事,必定要珍惜,拿出你的大塊時間配合好。這其中最重要的就是多交流,測試同窗也不必定知道全部的邏輯,在作迴歸測試的時候,就須要開發和測試反覆覈對每一個邏輯死角,弄清楚,纔敢上線。
固然,可以有測試幫你迴歸的功能都是極易引發故障的功能,這裏就有一個技巧就是如何拉測試參與你的重構中來。像這樣重要的功能若是測試知道里面的邏輯,你能夠懷着請教的心態去問對方,若是對方並不瞭解,那你就能夠講給他聽,一個負責任的測試,應該都很是想了解本身負責系統的重要模塊的前因後果。
即便你作了再多的測試,都有可能有沒有考慮到的遺漏點,這個時候灰度就很是重要了,灰度就必需要有灰度工具才行。重構通常是以頁面或者區塊爲粒度按照人來進行的。因此你的灰度工具必需要包含這些功能:
灰度配置頁面,新老動態路由的參數須要保持一致,這樣才能把參數傳遞下去。
展現灰度提示,並提供一個快速「返回舊版」的按鈕,爲了更快速解決問題,能夠給出開發者聯繫方式。
當用戶訪問老路由的時候,按照灰度配置驗證當前用戶是否在灰度中,若是在灰度中,則當即跳轉到新的路由,並顯示灰度提示。若是重構的是頁面中的區塊,則能夠提供灰度命中的方法,在頁面調用區塊的部分作判斷。
灰度策略能夠按照如下用戶級別分佈進行:
發佈後,注意觀察打點數據:
打點的時候須要注意,要按照動態路由來打點,並分紅命中灰度的,點擊使用舊版的,不在灰度內的三個維度來看數據,同時天天調整灰度用戶,這樣就能保證頁面是有人用的。若是有不少用戶使用了返回舊版的功能,那你就得找找這些用戶瞭解下狀況了,究竟是有 bug 仍是交互不舒服,一對一的解決用戶問題,在反覆去優化你的頁面,慢慢擴大用戶灰度範圍,直到老的路由訪問數據 PV 爲 0。
全量上線並非灰度全部人,而是真正下線老的頁面,並刪除老的代碼,只有到這一步纔算重構完成了。
經歷千難萬險,你終於把重構好的頁面上線了,經歷了這個過程,感慨良多,只求之後不再要作重構了,好好作需求不香嗎?後頭看看整個過程,要想重構的頁面上線,不只要下苦功夫,還要克服人性的一些弱點,要作到這幾點:
致敬每一位重構路上的勇士。
做者:ES2049 / 黑石
文章可隨意轉載,但請保留此原文連接。
很是歡迎有激情的你加入 ES2049 Studio,簡歷請發送至 caijun.hcj@alibaba-inc.com 。