主頁 > 軟體工程 > 實戰篇:一個核心系統 3 萬行代碼的重構之旅

實戰篇:一個核心系統 3 萬行代碼的重構之旅

2020-11-14 15:10:55 軟體工程

經典著作《重構》這本書中有這么一段話:

一開始,我所做的重構都停留在細枝末節上,隨著代碼趨向簡潔,我發現自己可以看到一些設計層面的東西了,這些是我以前理解不到的,如果沒有重構,我達不到這種高度,

重構,著實是一件讓程式員興奮的事情,

今年年初,我們團隊完成了一個復雜專案的重構作業,它屬于廣告系統最核心的引擎部分,大概有 300 多個檔案,3 萬多行代碼,

從技術方案設計到最終全量上線僅僅花了 1 個月左右的時間,而且沒有產生事故,

這應該是我 8 年程式生涯中,經歷過的最大型的同時最成功的一次重構專案:速度足夠快、計劃比較周全、質量過關,


01 先聊聊這個系統的歷史包袱

我們的廣告引擎在這次重構前大概經歷了1年半時間的迭代,初期針對的是搜索場景,業務單一,流程清晰,

2019年開始,公司的廣告業務開始快速擴張,收入幾乎是指數級的增長,在這個程序中,我們的廣告引擎面臨了兩個挑戰:

1、業務場景開始變得復雜,除了搜索廣告,還需要支持資訊流推薦以及相似推薦場景,

2、廣告流量開始快速增加,除了滿足功能性需求,還需要兼顧好性能,

經過梳理,整個引擎有大部分邏輯是可以公用的,因此我們定義了一個主體框架,同時將可擴展部分進行了抽象,這樣,各個場景能夠根據自身業務的特殊性實作某些公共介面即可,另外,從性能角度考慮,我們犧牲了一些代碼可讀性,把某些邏輯并行化了,

隨著業務的發展,搜索場景開始進入快速迭代期,新增策略越來越多,我們的主體框架也是在這個時候逐漸變得不靈活,

如果動主體框架,搜索以外的場景都需要跟著重構, 在業務的快速發展期,工期根本不允許,因此我們只能在現有框架上進行補丁式的開發, 這樣,帶來了兩個很明顯的問題:

1、為了兼容搜索的特殊邏輯,我們需要在其他場景中增加各種 if 判斷來繞過這些邏輯,

2、廣告策略越來越多,累計了幾十個,當框架失去清晰的結構后,有些策略的實作開始變得定制化,缺少層次化的劃分和可插拔式的抽象設計,

在這樣的背景下,隨著改動的積累,代碼開始偏離了設計的初衷,技術債務越來越重,但是,我們又始終找不到合適的時機進行重構,

轉機出現在 2019 年年底,由于廣告業務的特殊性,流量開始自然走低,另外產品運營團隊將重心放在了第 2 年的作業規劃上,因此給了我們非常好的視窗期開始此次重構,

我們將工期定成了 1 個月,最終僅比預期晚上線了一天,雖然出現了兩個線上問題,但是在灰度期都及時發現和修復了,并沒有造成線上事故,

總體來說,這是一次難度頗大并且比較成功的重構專案,下面詳細說一下我從這個專案中吸取到的寶貴經驗,

02 重構前,我們做了哪些準備作業?

這次重構的代碼量很大,3 萬多行,而且是廣告系統最核心的引擎部分,啟動前,我們能預期到下面這些困難:

1、業務側的阻力:廣告是極其以業務為導向的,本次重構雖然能帶來長期研發效率的提升,但是沒法直接提升業務收益,而且開發周期不會太短,如何才能得到業務同學的支持?

2、技術側的顧慮 :重構一旦引起線上事故,公司是有處罰制度的,如何讓大家輕裝上陣?同時,重構程序中如果還有非常重的業務迭代穿插,交付時間沒人敢保證,質量也很難得到控制,

針對這兩方的顧慮,我認為下面這幾項作業起到了很關鍵的作用,

1、讓所有人看到痛點

前面提到:隨著業務迭代,我們廣告引擎的主體框架已經變得模糊不清,另外幾十個廣告策略散落在不同的業務場景中,配置凌亂,

針對這兩個痛點,我們提前1個月啟動了現有業務的梳理,走讀舊代碼、同時翻閱以前的需求檔案,最終我們將不同場景的核心流程以及廣告策略歸類成了一張清晰的表格,

正是這一張表格,讓技術和產品第一次很清晰地看到了我們引擎部分的全貌,體會到了業務的復雜度以及當前技術上的瓶頸,

2、明確重構的目標和價值

讓所有人感受到痛點后,我們規劃了本次重構的兩個核心目標:

1、主體框架的重構:將主流程模塊化,重新定義上下層協議,確保介面清晰;各層級內部也需要做好抽象,具備良好的擴展性,

2、策略靈活可配置:將廣告策略按照業務意圖進行歸類抽象,策略的執行條件動態可配置,同時策略可任意插拔,

此外,我們將這兩個核心目標完成后可帶來的預期收益進行了細化:

1、技術收益:代碼結構更清晰,更容易理解和維護;可擴展性增強,引擎的開發效率將進一步提升,

2、業務收益:策略能做到更細粒度的配置和擴展,對業務支持更友好;研發提效后能進一步加快業務的迭代速度,

將重構的價值同步給大家后,進一步提升了所有人的興奮度,讓大家有了更強的動力參與進來,

3、整體節奏的把控

整體節奏的把控也是非常重要的一環,能讓所有人對這件事情有一個時間上的預期,

首先,我們將工期定成了 1 個月,一方面考慮了業務側可以接受的最大周期,技術上也希望速戰速決;另一方面,春節即將來臨,我們必須趕在公司封網前上線,同時預留出1-2周的 buffer 以防意外情況發生,

此外,我們和業務側達成了一致:重構期間,引擎部分的非緊急需求一律不接,這樣可最大限度地減少并行開發和代碼沖突,讓團隊精力更集中,


03 執行程序中有哪些可分享的經驗?

這次重構能夠實施得如此順利,有 4 點我認為很有價值的經驗跟大家分享下,

1、高質量的技術設計方案

這一點得益于日常的要求,針對開發周期超過3天的專案我們都會進行技術方案設計,本次重構當然也不例外,

框架部分的整體架構、模塊之間的協議設計、以及策略的可擴展性設計是本次技術方案的重點,團隊前后討論了不下3次,

在大方案定稿后,團隊進一步對資料庫、介面欄位、快取結構、日志埋點等公共部分進行了細化,因為涉及到多人協作開發,團隊約定以檔案作為溝通界面,檔案始終保持和代碼同步,

在這樣的高要求下,團隊產出了 5000 多字的技術方案檔案,合計 36 頁,這些為整體質量的保障打下了很好的基礎,

2、 預重構出框架性代碼

這一個 PR 非常關鍵,是我們從技術方案落地到代碼最重要的一步,我們把重構后的包結構、模塊劃分、各層之間的API定義、不同廣告策略的抽象進行了梳理,先忽略實作的細節,

這樣主體代碼基本成型,能很清楚地描繪出我們理想中的框架,然后,我們組織了多次集中代碼審查,最終形成了統一意見,

這一步能很好地避免過早陷入實作細節,導致主體框架關注不夠、代碼不穩固,后期再返工反而會拖累效率,

3、 頻繁溝通和成對代碼 Review 機制

進入到細節實作階段后,很重要的一點是:對現有邏輯的理解,引擎代碼經過一年半的迭代,歷史上被很多人開發過,但是本次只有 3 個同學參與重構,

整個程序中,我們遇到任何代碼邏輯不明確的地方,都是反復溝通和求證,不主觀猜想,這一份謹慎其實很關鍵,

另外在代碼審查上,我們按模塊分配了對這塊業務比較熟悉的同學來負責,成對搭配,機制靈活,

4、 有效的測驗方案

重構未動,測驗先行,這個原則是《重構》一書中重點強調的,也是我們本次技術方案討論的重點,我這里單獨拎出來詳細展開下,

首先,我們前期便約定好:不動任何老代碼,完全建新的 package 進行重構,這樣方便比對重構前后的結果,同時進行線上灰度實驗,


測驗方案上,以下 4 點值得借鑒:

1、端到端測驗:本次重構不涉及功能性的調整,因此外層API的行為是不會有任何變化的,這樣端到端的測驗方法最為有效,這個是研發和QA測驗最主要的手段,

2、冒煙測驗:QA同學提供冒煙 Case,由研發同學進行冒煙,研發提測前必須保證所有冒煙 Case 執行通過,這一點在大部分互聯網公司都不常見,但是對于大型專案絕對有效,

3、沙箱環境雙流程驗證:前面提到我們重構前后的代碼都保留了,因此可以通過腳本抓取線上環境的入參作為case,然后用自動化的方式對 API 的回傳欄位進行逐一比對,

4、線上環境灰度實驗:灰度對于重構非常重要,我們利用已有的ABTest平臺,逐步放開灰度流量,從5%、到10%、到30%、最后到100%,制定了很謹慎的放量節奏,然后通過日志以及業務指標監控進行驗證,


寫在最后

回顧整個重構的程序,總結成下面 7 個關鍵點:

1、把握好重構時機

2、前期梳理很重要,先找到痛點

3、明確出目標和價值,讓大家興奮起來

4、不宜長線作戰,不宜和業務并行

5、需要高質量的技術方案

6、重構未動,測驗先行

7、小心求證,為每行代碼負責

當然,最關鍵的因素還是人,大型專案重構極其考驗團隊的協作能力,如果每個人都很靠譜,重構就已經成功了一半,



作者簡介:985碩士,前亞馬遜工程師,現58轉轉技術總監

歡迎掃描下方的二維碼,關注我的個人公眾號:IT人的職場進階

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/215158.html

標籤:其他

上一篇:請教,第四點怎么做?

下一篇:實戰篇:一個核心系統 3 萬行代碼的重構之旅

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • Git本地庫既關聯GitHub又關聯Gitee

    創建代碼倉庫 使用gitee舉例(github和gitee差不多) 1.在gitee右上角點擊+,選擇新建倉庫 ? 2.選擇填寫倉庫資訊,然后進行創建 ? 3.服務端已經準備好了,本地開始作準備 (1)Git 全域設定 git config --global user.name "成鈺" git c ......

    uj5u.com 2020-09-10 05:04:14 more
  • CODING DevOps 代碼質量實戰系列第二課,相約周三

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。**《DevOps 代碼質量實戰(PHP 版)》**為 CODING DevOps 代碼質量實戰系列的第二課,同時也是本系列的 PHP ......

    uj5u.com 2020-09-10 05:07:43 more
  • 推薦Scrum書籍

    推薦Scrum書籍 直接上干貨,推薦書籍清單如下(推薦有順序的哦) Scrum指南 Scrum精髓 Scrum敏捷軟體開發 Scrum捷徑 硝煙中的Scrum和XP : 我們如何實施Scrum 敏捷軟體開發:Scrum實戰指南 Scrum要素 大規模Scrum:大規模敏捷組織的設計 用戶故事地圖 用 ......

    uj5u.com 2020-09-10 05:07:45 more
  • CODING DevOps 代碼質量實戰系列最后一課,周四發車

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。 **《DevOps 代碼質量實戰(Java 版)》**為 CODING DevOps 代碼質量實戰系列的最后一課,同時也是本系列的 ......

    uj5u.com 2020-09-10 05:07:52 more
  • 敏捷軟體工程實踐書籍

    Scrum轉型想要做好,第一步先了解并真正落實Scrum,那么我推薦的Scrum書籍是要看懂并實踐的。第二步是團隊的工程實踐要做扎實。 下面推薦工程實踐書單: 重構:改善既有代碼的設計 決議極限編程 : 擁抱變化 代碼整潔代碼 程式員的職業素養 修改代碼的藝術 撰寫可讀代碼的藝術 測驗驅動開發 : ......

    uj5u.com 2020-09-10 05:07:55 more
  • Jenkins+svn+nginx實作windows環境自動部署vue前端專案

    前面文章介紹了Jenkins+svn+tomcat實作自動化部署,現在終于有空抽時間出來寫下Jenkins+svn+nginx實作自動部署vue前端專案。 jenkins的安裝和配置已經在前面文章進行介紹,下面介紹實作vue前端專案需要進行的哪些額外的步驟。 注意:在安裝jenkins和nginx的 ......

    uj5u.com 2020-09-10 05:08:49 more
  • CODING DevOps 微服務專案實戰系列第一課,明天等你

    CODING DevOps 微服務專案實戰系列第一課**《DevOps 微服務專案實戰:DevOps 初體驗》**將由 CODING DevOps 開發工程師 王寬老師 向大家介紹 DevOps 的基本理念,并探討為什么現代開發活動需要 DevOps,同時將以 eShopOnContainers 項 ......

    uj5u.com 2020-09-10 05:09:14 more
  • CODING DevOps 微服務專案實戰系列第二課來啦!

    近年來,工程專案的結構越來越復雜,需要接入合適的持續集成流水線形式,才能滿足更多變的需求,那么如何優雅地使用 CI 能力提升生產效率呢?CODING DevOps 微服務專案實戰系列第二課 《DevOps 微服務專案實戰:CI 進階用法》 將由 CODING DevOps 全堆疊工程師 何晨哲老師 向 ......

    uj5u.com 2020-09-10 05:09:33 more
  • CODING DevOps 微服務專案實戰系列最后一課,周四開講!

    隨著軟體工程越來越復雜化,如何在 Kubernetes 集群進行灰度發布成為了生產部署的”必修課“,而如何實作安全可控、自動化的灰度發布也成為了持續部署重點關注的問題。CODING DevOps 微服務專案實戰系列最后一課:**《DevOps 微服務專案實戰:基于 Nginx-ingress 的自動 ......

    uj5u.com 2020-09-10 05:10:00 more
  • CODING 儀表盤功能正式推出,實作作業資料可視化!

    CODING 儀表盤功能現已正式推出!該功能旨在用一張張統計卡片的形式,統計并展示使用 CODING 中所產生的資料。這意味著無需額外的設定,就可以收集歸納寶貴的作業資料并予之量化分析。這些海量的資料皆會以圖表或串列的方式躍然紙上,方便團隊成員隨時查看各專案的進度、狀態和指標,云端協作迎來真正意義上 ......

    uj5u.com 2020-09-10 05:11:01 more
最新发布
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:41:12 more
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:35:34 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:05:44 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:00:18 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:20:31 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:55 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:18:51 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:00 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:17:55 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:12:06 more