日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

重构,还是重写?(2020版)

發布時間:2025/3/21 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重构,还是重写?(2020版) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Joel Spolsky (軟件隨想錄作者)曾經寫過一篇著名的文章, Things You Should Never Do (1)?,他在文章中斷言,你永遠不應該從頭開始重寫一個代碼庫。他舉了 Netscape 公司的例子,他們花了好幾年的時間重寫軟件,最終公司在這個過程中死亡。一年前,我重讀了那篇文章,但還是選擇了從頭開始重寫我們的應用,對,全部重寫。以下介紹為什么這么做,我們是如何成功的,以及一些關于你是否也應該這么做的啟發式分析。

故事要從 2019 年 1 月說起。當時,Remesh 還是一家比現在規模小得多的公司。當時招聘了一些工程師,有 5 名工程師專注于產品開發,還有一小部分工程師負責機器學習(ML)或 DevOps。盡管有這些工程師,但開發速度非常緩慢,簡單的功能需要很長時間才能完成,產品有很多已知的 bug 沒有修復,而且整個產品看起來很長時間沒有明顯變化。

了解為什么會有這些問題是很重要。假設問題不在人上面,我們有優秀的工程師(之后新版的成功也驗證了這一點)。問題主要出在代碼庫和流程上。我們所使用的歷史代碼庫,與團隊的技能和業務場景并不匹配,當時的流程也鼓勵和依賴工程師垂直領域的知識,也沒有 "全棧"工程師。

2019 年 1 月代碼庫的狀態

舊版應用的設計初衷與現在的版本截然不同。最初,Remesh 讓用戶在整個群之間或者一個人和一個群之間進行雙向對話。例如,你可以讓 Democrats 和 Republicans 各自對話,互相了解對方,尋找共同點。或者,你可以讓一個城鎮的市長和他們的市民對話,以更好地了解他們需要什么、相信什么、想要什么。然而,當我們找到了產品與市場的契合度后,用例也發生了變化。我們傾向于由一個單一的主持人與一群人交談。

需求變化的結果是,某些舊的設計方案不再有意義,schema 需要進行重大改變。除了數據庫之外,代碼庫本身也很難理解,因為這些功能都是在沒來得及進行大的重構的情況下,被開發人員用螺栓連接起來的。在最需要重構的地方,測試覆蓋率很差,因為這些代碼是最老的代碼,是在建立良好的測試實踐之前編寫的。

除此之外,語言和框架也不適合我們的團隊。后端代碼庫是用一種叫 Elixir 的語言開發,而開發人員很少有人熟悉 Elixir。其中一個前臺代碼庫是用非常老舊版 Angular(我甚至不想去了解到底是哪個版本,往事不堪回首),我們還有兩個前臺是用 React 寫的。但工程師幾乎沒人了解其中一項技術,更不用說這三個都會。使用的語言和框架并不適合團隊和我們的場景,這讓開發速度非常慢。

有哪些選擇?

毋庸置疑,我們的代碼庫需要一個重大的改變。當你面前擺著一堆代碼,很難往前推進時,大概有三個選擇:

  • 重構它,直到所有問題修復。

  • 一口氣全部重寫

  • 逐步小范圍重寫

對于前端,重構并不是一個合適的選擇,Angular 版本已經太老舊,以至于沒有任何明確的升級路徑可以升級到現代版本的 Angular(老實說,任何版本的 Angular 都興趣不大)。而且由于預計 UI 和 API 會有重大變化,所以重構是不可行的。因此,在前端,我們只能選擇一次性重寫,或者逐步小范圍重寫。

后端有一些需要解決的問題 — 當前的模式、語言和代碼庫都不適合我們的場景。我們使用了 Elixir,因為它有強大的并發支持,但我們最終不太需要這個功能,而且它反而陷住了我們:Erlang 虛擬機中處理并發的方式使得代碼分析變得非常困難,你知道計算的是什么,但不知道從哪里調過來的 — 祝你在性能調整方面好運。

Elixir 的代碼庫也限制了機器學習工程師對后端代碼庫的貢獻:他們每天都在 Python 中工作,沒有時間深入學習 Elixir。長話短說,我們想放棄 Elixir,轉而使用 Python 語言,因為這樣一來,整個團隊就可以參與貢獻后端代碼,這門語言可以解決我們的需求,而且分析代碼更加方便。

我們也有一些 "產品債務",老版本向用戶引入了一些新東西,他們接觸之后也逐漸喜歡上了這些理念,但最終效果并不理想。它們是局部的極端。如果我們要跳出這個局部極限,做出更好的東西。我們必須要做一次大的改版,在這個過程中,較小的迭代可能會不斷遇到用戶的阻力。去掉之前這些功能,需要同時做很多事情。

歸根結底,重寫的理由其實歸結為以下幾個因素:

  • 希望團隊的每個成員都能為后端代碼庫做出貢獻,而 Python 既容易學習,又能在團隊中得到廣泛的認可,所以很適合我們。

  • 舊代碼庫非常脆弱,測試量少,重構代碼庫是一個艱難的過程。

  • 通過轉移到像 Django 這樣的強大的框架來提高效率,同時也能很多現成的東西節省時間(如 Django Admin)。

  • 有機會根據從用戶那里了解到的東西制作一個全新的版本,然后可以輕松升級到新的版本,而不是在每一次小改動花時間與客戶解釋,持續一個 12 個月的拉力戰。這也使我們的客服團隊和銷售團隊的培訓在最后成為一次性的批量培訓,而不是不斷地引入新概念。

為了達成這個決定,我們做了相當廣泛的規劃。雖然整天談論敏捷和精益什么的,但這次實際是一個瀑布式的開發 — 不是因為我們要實施瀑布式的計劃,而是我們發現重寫應用程序需要不少時間,但重構或零散地重寫需要更長的時間,而且不確定性要高得多。如果走重構路線的話,我們要冒的風險會更大。

最后,我們對自己的決定很有信心,而且公司的各個層面都支持我們。我們決定重寫,在讓產品向前發展的同時,修復過去幾年來的錯誤。

讓重寫開始吧。

進展情況

我們在 2019 年 2 月開始重寫,在規劃出功能范圍之后,就開始啟動重寫,作為盡職工作的一部分,我們圍繞著我們要開發的功能,制定了一個非常堅實的計劃。這違背了敏捷的教條,但有了一個可以調整的計劃,有助于指導我們前進的道路,看看是否偏離了軌道。當我們與用戶(內部用戶和一些外部客戶)在進行測試的階段,我們最終確實偏離了不少計劃,更多的內容會在后面說。

在經歷了一開始的坎坷之后,構建新版本的實際過程還算順利。對于工程師來說,切換到一個新的技術棧是痛苦的。雖然我們選擇了 Python 來達到最低的切入成本,但仍然有一些人需要學習。而且我們的后端工程師也沒接觸過 Django(但我們的首席前端工程師對 Django 有很深的了解)。同樣,在前端方面,很多人都知道 React,但很少有人對 TypeScript 有深入的經驗,我們選擇 TypeScript 語言(這有一些故事要留待后文會說)。有了一些初步的學習時間后,我們都很快就有了相當大的收獲。

這是我們第一個驗證得到的經驗:即使在這個新的技術棧中經驗較少,也能更快地構建功能。要確定生產力的提高是來自于新的技術棧和新的代碼庫,而不是僅僅是一個空項目,這需要更長的時間,但我們最終還是達到了目標。

首先做的一件事就是讓大家接觸數據庫。由于我們的目標之一是減少信息孤島,讓工程師盡可能了解整個技術棧,所以我們引導一些對數據庫設計沒有什么經驗的前臺開發人員,讓他們去思考和設計最初的數據訪問版本,然后和整個團隊一起迭代。這使他們有能力去參與數據庫方面的問題。盡管他們已經很久沒有參與這方面工作,但仍然表現出了這方面能力,并能提出一些真正具有挑戰性的問題。

在這之后,我們快速前行持續了幾個月,重寫了舊版本中熟悉的和感興趣的東西,并在不斷的優化,使其更加好用。我們在合理的時間內完成了一個非常好的項目。一開始,時間表非常樂觀,直到 6 月左右,我們一直在按計劃進行。不過后來增加和改變了一些功能,因為我們知道沒有這些功能,新版本就不會成功。這讓項目速度慢了下來,但來自內部研究人員、客服團隊和一些值得信賴的用戶的真實反饋,對我們項目成功是必要的。

在整個過程中,我們取得了一些我引以為傲的成績,不全是技術方面的。

  • 團隊急劇增長。我們從最初的 4 個產品開發工程師開始,到現在的 9 個,這還不包括招聘了一個完整的 QA/SDET 團隊,增加了機器學習工程團隊的人員,以及招聘了 DevOps 工程師。而在這個急劇增長的過程中,并沒有因為增加人員而帶來通常的項目延遲 —— 相反,我們加快了速度(我認為這主要得益于這是一個全新項目)。

  • 改善了整個公司對工程團隊的看法。剛開始一段時間,我們在新功能的交付上有點慢,但至少可以快速地重寫已有的功能,并看到新功能也很快地被添加。有一次,我們做了一個很酷的演示,對 Django 的 Admin 進行了實時編碼,以證明現在可以做的事情比以前快很多。雖然只是一個小小的演示,但很有效。

  • 從一個有多個服務的面向服務的架構,變成了一個只依賴一個服務的單體架構,我們從一開始就開始設計容錯和橫向可擴展性。這在之前是一個很大的痛點。

  • 極大地提高了迭代速度,很大程度上是因為我們有了一個新的架構,這個架構適合我們的場景,而且是在一個大家(現在)都很樂意參與的技術棧中。錦上添花的是,機器學習團隊現在可以也確實偶爾給生產后端提交代碼。

主要經驗

我們相信我們是成功的,當然過程中也犯了一些相當大的錯誤。

之所以成功,是因為我們一開始就對我們要打造的東西有一個清晰的愿景(一個真正的 MVP,我們知道舊產品是 "可行的",所以我們必須達到這個目標或更少),我們根據需要削減范圍,以保持清晰的目標。雖然我們沒有 "按時交付",但也沒有變成 Netscape 的方式。項目總工期不到預計的兩倍(基于完全復制舊產品功能的預期時間),但我們最終得到了一個更好的產品,并且有一些新的功能,比如上傳和發送視頻的能力,以及下載自動生成的 PowerPoint 報告等。

成功的另一個關鍵是盡早并經常獲得反饋。在重寫過程中,我們經常在內部使用產品,發現關鍵的 bug 和性能問題。我們還定期舉行全公司的演示會,從幫助客戶成功、銷售、研究,以及從能夠容忍各種問題的早期試用用戶那里快速獲得反饋。

做錯的事情有哪些?我們曾經引入兩個我們以前不怎么熟悉的技術。我們之前在一個原型中使用過 TypeScript,但我們對它沒有很深的專業知識。進展雖然馬馬虎虎,但我們仍然不相信生產率會更高,缺陷率會更低;時間會證明,靜態類型的語言會更佳(如果有人對此有確切的研究,我很樂意你把它們發給我)。

另一個失誤是使用 GraphQL。我們在 REST 和 Redux 方面有相當高的經驗,但之前只在一個原型中使用過 GraphQL。現在回想起來,GraphQL 讓最初的原型開發速度快了很多,但長期的代價是,Apollo 中有些關鍵的設計決策我們并不認同(比如沒有在前端暴露出檢測訂閱中斷開/重連的能力),而且在其后端的性能調優經歷也是一言難盡……那是我人生中非常艱難的一兩個月,我再也不想回去了。我們現在正在從 GraphQL 中遷移出來,對于性能關鍵的東西,會快速地進行遷移,然后再慢慢遷移那些對請求性能容忍度較高的調用。

最后需要注意的是,在重寫的時候,你的團隊以及士氣會受到影響,你必須要積極應對。一開始啟動一個新項目是相當令人興奮的,但接下來的事情就是構建已有的功能和修復 bug,過了一段時間就會覺得很累。很欣慰看到我的團隊從構建我們已有的功能到開發新的功能,我也意識到重寫工作真的很耗費精力。

我們成功地完成了重建,其中的一部分原因是平衡了新功能開發與舊代碼遷移。話雖如此,我希望我們在平衡方面能做得更好。下一次,我將集中精力確保我們有一個早期的 alpha 測試計劃,與幾個值得信賴的用戶一起進行測試,以獲得定期的反饋和鼓勵,并讓大家對重建保持興奮。我還會確保我們在早期就加入大量的新功能,而不是發現大家都有點疲憊,才開始引入新功能。有些單調是不可避免的,但你可以減輕它。

你應該這么做嗎?

根據我的經驗,你也許不應該像我這么做,如果你深信重寫永遠不會是正確的決定那些文章。無論如何,你應該默認為 "不重寫" 的立場,然后非常努力地推進,并證明不重寫是正確的。

但有幾種情況,重寫可能是合理的。

  • 如果你的架構或模式與你的需求嚴重脫節,而且沒有明確的遷移路徑,漸進式更新架構或模式變得非常困難。

  • 如果這些問題嚴重拖累了你的團隊

  • 如果你目前的技術棧限制了很多工程師的代碼貢獻,并且技術棧培訓也不太可行。

即使所有這些都符合你的情況,你也要進一步考慮企業的實際情況,考慮到這對你的公司、你的團隊是否有意義。

有可能在更多的情況下,重寫是有道理的。辯解這一點很難,但它可能是值得走的一條路,而且可以成功地完成。

?

  • https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/

  • ?

    英文原文:

    https://remesh.blog/refactor-vs-rewrite-7b260e80277a

    總結

    以上是生活随笔為你收集整理的重构,还是重写?(2020版)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。