打破常規,重立新規;
01
開始想聊這個話題的時候,我是打算放棄的;因為這個話題涉及范圍之廣,內容之多,讓我犯怵;
近幾年,待過兩家公司;一家經歷過重構,另一家也打算重構......
其實要下定決心,推翻重來,是一個很有勇氣的決定;
歸根結底,不到萬不得已,誰想這么玩,誰愿意花費大精力去做這些臟活、累活;
所以究其原因,也只能說是一種綜合因素吧,就像古話說的,天時、地利、人和;
至于為什么這是個很有勇氣的決定,因為做重構這事的團隊風險極高;上至業務高層,下至底層碼農,都有可能一個不小心就被刀;
我曾經待過的一個團隊,經歷過一次重構,不過那是一次失敗的經歷;
開發預估了兩個多月的時間,業務大佬決定,期間直接對新需求停滯;但是,最終上到生產的系統,老問題還在,然后又多了很多的新問題;
再后來啊,業務大佬和技術主管都被刀了;然后系統回退成老版本,重新承接新需求,并且開發時間被嚴重壓縮,導致技術部門沒日沒夜的加班;
下面,我大致做了歸檔和整理,從這八個方面重新聊一聊系統重構;

02
【重構原因】
其實上面也提到過,這是一個綜合因素,可能是各種各樣的因素疊加,造成一個不得不重構的結果;
下面,聊一聊我所碰到過的因素;要是沒聊到的地方,也歡迎大家補充;
第一個,可以歸結為系統的穩定性或可用性:不管吹得怎么天花亂墜,你的系統總要可用吧,所以說可用和穩定是一個系統的最基本要求,開發一個需求還要全服務停用嗎?業務量增長,系統還能抗下所有嗎?那么問題來了,怎么保證可用和穩定?
首先,如果你是單服務系統,那么為了保障可用和穩定,需要對服務進行擴展,加入更多的機器來分擔系統的性能壓力,也就是常說的“服務集群”;
但是,往往我們的系統并不是單服務的,也就是我們常說的分布式微服務;這種情況下,就不得不扯到分布式的三大法寶:限流、熔斷、快取,相信要實作這三個法寶,有很多成熟的框架和工具等,這里就不過多闡述了;
第二個,開發規范問題:這也考驗了團隊leader對底下成員的約束力,以及是否存在代碼review的環節;
假設一個團隊,leader確實沒有對成員強制約束開發規范,更別提代碼的review了;最終導致的問題就是,各寫各的,每個人都有自己的一套開發習慣和開發規范;最終就是一個大寫的“亂”;
這樣榷訓月累,一代目埋坑,一代目撤,二代目上,二代目撤...... 系統不知道經了多少開發人員的手,最終,新入職的冤種某天需要排查一個產線問題,仿佛誤入了代碼的迷宮,深陷其中,無法自拔;
第三個,推翻原先核心業務,重立新規:這個要解釋起來比較麻煩,也碰到會比較少,然而,我恰恰就遇到了;
某天,業務大佬宣布,目前做的這套業務規則要被廢棄了,他們重新擬定了一套全新的規則,意味著先前不知道幾手的代碼已經失去意義了,幾乎90%都需要重新寫;
都到這一步了,那就大刀闊斧的改革吧;出事了,emmm,業務的鍋;
03
【重構會議】
既然已經確定要進行專案的重構,那么拉成員例會是必不可少的,不然就會一片迷茫,不知道干點啥;
第一次會議,由技術老大牽頭,叫上業務負責人,技術主管,開發全員,測驗,產品,運維;
一般,第一次這種全體會議是沒有結果,但是又非常必要的;因為上級領導需要知曉整個重構涉及到的點,影響的方面,開發的時間,以及整體的技術方案,參與的人員,還有需要的資源等等;
第一次會議消化完后,很快就是第二次會議;這個會議也是由技術老大牽頭,參會的主要是技術主管和參與開發的人員和運維;主要是對系統重構進行總體的技術選型,討論用到的框架,組件,實作的方案,部署方案等等;
這個會議持續的時間會比較久,大家搬好小板凳,準備打持久戰,可能從上班開始,到下班點了都還不能結束;當然,還是會有中場休息時間的;基本可以各抒己見,提出自己的意見和看法;主要是圍繞做什么?怎么做?做多久?這三個疑問點討論;
接下來,就是由技術主管組織的技術部內部會議了;由于之前已經確定好了統一的技術堆疊和實作方案,這一次討論都是在此基礎上展開的;
當然這一次會議可能需要更久的時間,因為涉及到是微服務的話,就避免不了一個問題:“服務拆分”;
大家都知道,微服務是需要根據業務去進行拆分的;那么問題來了,業務的劃分界限是什么?為什么A業務部分要包含A1,A2,A3;其實這里就需要大家達成一個統一的認知,也是這次會議要達成的最終目的;
這次會議最后,服務已經劃分完畢,但是缺少去維護這些服務的人;那就需要對開發人員進行分組,每組有對應的負責人,看人員情況而定(如果就兩三個,甚至更少的開發,那就沒必要分組什么的了,就是冤種,活都得你干),每組對N個服務的開發和維護;
分組過后,組長會進行簡短的組內會議,這次其實就是派活會議,認領各自的作業;也會明確一點,大家要干些什么?誰干哪些?每個人干完都需要多久的時間?
最后,會整理一份排期計劃,上面每個人的名字赫然在列,當然還有任務串列,工時,等等;

一切準備作業就緒,最后就是開干了,當然后面開發程序中還有一些不明確的點,也會臨時組織一些會議,讓大家達到統一的認知;
04
【并行需求】
在系統重構的開發程序中,因為占用的周期會很長,投入的資源會比較多,所以難免還會遇到這樣一個問題;
一天產品經理急沖沖的跑過來說,現在有一些需求很著急,需要將重構停一停,先把這些需求排期上線;至于為什么會這么著急,咱也不知道,咱也不敢問呀;
這時候就會面臨一個惡心的局面,這次開發的需求,肯定需要在原先的服務中進行開發,那么重構的服務中,是不是還需要再寫一遍?
王德發!說歸說,罵歸罵,辦法總比困難多!這時候有一種方式,那就是派出個談判專家,以三寸不爛之舌,動之以情,曉之以理;多說說技術難點、痛點,占用的資源,實作的難度等等,去打動他,說服他,讓這次需求排在重構后面;
如果你成功了,那么恭喜你,這次重構任務,大家幫你分擔一半;
什么?產品經理不同意;那就沒有辦法,只能在改動老服務的基礎上,記錄調整的點,最終在寫新服務業務代碼的時候,將改動的點一并加上去;
最后在提測的時候,通知測驗同學,這些需求相關的地方,在重構的新服務上線之前都需要重新走一遍流程;
當然,還有一種情況,就是像我之前說的,需求即伴隨著重構;這種需求也肯定是大版本,開發周期較長;這種情況是最理想化的,只需要按部就班的進行開發即可;
05
【技術選型】
這個話題,在上面的會議模塊已經提到過了,這里再來詳細的聊一聊;
當然,這次也僅限于比較流行的分布式微服務的技術選型;單服務的話,額,暫且不說吧;
其實也沒什么好爭議的,對于Java系統而言,無非就是spring全家桶無腦往上堆,服務器資源拉滿;就像買汽車一樣,越豪華的車,堆的配置越多,價格越貴,但是舒適性和操控性也就越好;
但是還需要考慮一些因素:成本、產品開源與否、技術社區活躍度、產品的成熟度、結合實際情況等等;
成本:時間成本、學習成本、金錢成本;
事情是人做的,代碼也是人敲的;需要考慮團隊成員擅長哪些技術堆疊,如果一門技術只有少部分人會或者都不會,那就需要結合開發時間,去斟酌需不需要用它,即便是熱門的技術;
當然啦,如果老板愿意出錢,直接買各種付費的技術就行,我們只需要搭好基礎的框架,然后往里面填充業務代碼即可;如果不行,那就老老實實看看免費版,出了啥問題,只能自己排查去解決;
產品開源與否:說到這個,開源是關鍵,最香的詞“開源免費”;
就像上面說的,一旦遇到了什么問題,其實有必要去看這門技術的原始碼去解決的;比如典型的SpringBoot自定義starter,需要定義“META-INF/spring.factories”檔案,將檔案中配置的型別資訊加載到 Spring 容器;
一旦你閉源,那怎么玩?我怎么知道你內部怎么去實作的?只能看官方檔案,看你自己吹什么什么功能;
技術社區活躍度:這個因素其實和產品開源可以歸為一類,都講的是一旦這個框架或產品出了問題,我們就可以去它的官方社區上找類似的解決方案;如果一個產品連社區都沒,或者活躍度很低,那也就意味著你只能靠自己去解決了,那花的時間成本可就......
產品的成熟度:我們選用一款合適的產品,首先它得符合我們主要的需求,而后它才有其他額外的功能,這當然是最好的;因為一旦咱有一些特殊的業務場景,恰巧這些額外功能正好符合你這個場景,豈不美哉;這樣就不必要接入額外的產品或組件了;
比如Redis,大家都不陌生;相信這個工具大家最多的是用它做快取,它確實也是一款優秀的快取工具;
但是,我之前在做OA軟體時,碰到這么一個需求;用戶申請一個會議,并且指定了參會人員,當在會議開始前15分鐘,前5分鐘,分別對參會人員發送一個提醒;
典型的發布、訂閱的模式,然后正好Redis就有現成的功能,當時就是用了Redis的這個功能;
但Redis適合小型應用,如果是大型架構,相信還是會使用rabbitMQ或者kafka等更專業的MQ佇列軟體
結合實際情況:說到這個,有句老話說:“只有適合自己的才是最好”;在考慮需要用到哪項技術時,最理想的情況那就是直接付費購買,出啥問題,都是有技術支持滴,我出錢了,你得為我解決,但是,成本有限啊;
當然,有些人會說,技術選型這玩意,那是技術主管或者技術總監他們決定的,我們小碼農只管擰好螺絲就行;是的,往往很多時候就是這樣;但是,你不去大膽說出你的想法和意見,你怎么知道他們不會聽取呢?格局打開,往上一層考慮就對了;
06
【服務劃分】
這塊內容其實可聊的沒多少,但是,也是最難的一塊;
首先,劃分;怎么分?按什么標準去分?分多少服務合適?分好之后怎么去管理?安排那些人去管理?等等一堆問題;
我也只能淺談下我之前做過的一次劃分經歷,因為每個公司遇到業務和場景是不同的,最終得到的結果也是不同的;而且,服務并不是一次劃分就能結束,它是一個持續不斷的程序;
當時我們是全部參與這次重構的開發一起拉會議的,在此之前,已經確定好了技術堆疊,就是熱門的springcloud全家桶;技術主管先是淺談一波他自己的想法,然后讓大家在他劃分服務的基礎上,提出自己的看法,并且每個人都要說,因為不可能想法都是一致的;
我記得比較清楚的是,他劃分中,有個序列號的服務,就是這個服務專門去生成序列號;后面幾個人都點名這個服務也包括我;其實當時想的是,我們的系統業務里沒那么大,能省一個服務,也是省一點資源;最終大家統一共識,將這種場景寫一個工具類去處理;
最終討論后,達到的共識,也只是一個初步的共識;隨著業務需求的增長,一部分業務服務必將變得臃腫,那時候第二波拆分也就隨之到來了;
07
【開發規范】
上面提到,造成系統重構的因素有很多,其中一個因素就是代碼混亂,大家各有各的習慣和規范;
其實不難發現問題了,并不是每個人不知道開發規范,而是大家沒有統一的一套規范,大家只是沒有達成共識;
那就來解決這個問題,制定一套統一的標準,讓大家都沒有異議的一套規范;
這時候就不得不提到阿里的規范,現在廣為流傳的《阿里巴巴Java開發手冊》,甚至基于這套規范,在IDEA上還有專門的檢查插件可以安裝;
當然,這樣做確實省事,省去了leader對代碼的review時間,包括我之前待過的一家公司,也確實就是這么做的;
其實仔細用過幾次這款插件就會發現,有些檢測其實大可不必,但是你又不得不去遵守它的規則,這時候反而徒增作業量;
遇到這種情況就需要看上級了,可以把這個疑問點反饋給他,或者反饋給身邊其他的小伙伴,起碼讓他們GET到你要表達的點,引起大家的共鳴;相信越來越多的人反饋這些問題,上級不會坐視不管的;那么恭喜你,又去掉一塊大家都認為不合適的規范,讓你開發不繞彎路;
總之,總結起來就是一句話:沒有標準,大家統一認可的就是標準犯規;
08
【資料、介面遷移】
談到這個,除非開發的是0-1的專案,否則在平時開發中,或多或少都是會遇到的,而非重構會單獨遇到的問題;
而我們在入職一家新公司,或者長期在一家公司干活,遇到0-1的專案幾乎沒有;如果有,那么你的運氣很好;
就拿我上面的經歷來說,業務推翻了之前的規則,重新制定了新的業務規則,那就不得不引出一個問題,之前的老資料怎么辦?
這個時候就需要跟業務確認,這批老資料是否可以按照某種默認的規則,做統一的處理;或者說,直接廢棄不管;一般來說,按前者處理的方案居多;
考慮到重構,往往你的表也是重新設計過的,也有可能是老表和新表公用,一般來說后者的情況居多;
其實,說白了就是在老表里面去修改資料,在新表里面去新增資料,而我們要考慮的是這批資料怎么去調整比較合適;
按我們之前的處理方式,如果涉及到的表,欄位等較少,存盤結構也頗為簡單,是可以直接用SQL腳本去解決的;另外,還需要考慮如果表資料較多,SQL執行快慢的問題;
還有一種情況,要是涉及到的場景很多,處理的表也居多,可以考慮寫程式去解決;比如,寫個任務,去手動執行這個任務,處理掉這批資料;當然,也得考慮資料量的問題,如果資料量大,用多執行緒跑批,或者多服務跑批等方式;
下面,來談談重構中的介面遷移;
要保證一個原則,就是對介面的出入參保持不動;不然,前端直接飛過來跟你聊人生;
但是,老服務的介面很多怎么辦?還能怎么辦,分工處理;
上面提到過,我們是分組的方式,每個組負責一部分服務,分工比較明確,所以相對來說,也比較快;
大家整理檔案,老介面的URL是什么,新介面的URL是什么,出參,入參能不變就不變;如果真的需要調整的,需要給出合理的解釋,大家一致通過后,然后自行跟前端去battle;
有些老服務還會運行一段時間,所以并不是所有介面都會涉及到遷移,這種介面,那就相安無事;
在遷移的程序中,肯定也會遇到各種問題;比如舉個簡單的例子,之前老服務的分頁插件使用的是PageHelper;而在新服務中,由于用上了Mybatis Plus框架,那自然也就用它框架自帶的分頁插件了;這個時候就涉及到修改,你只能自己內部消化了;
最后,當你覺得一切介面都遷移完畢的時候,別忘記對自己遷移的介面,進行一次自測;不要怕麻煩,這個自測對于后面的聯調和提測流程,都可以免去很多不必要的問題,也可以大大提高團隊的效率;
09
【實作方案】
最后還有一點,業務場景的實作方案;這個聽著有點抽象,其實在上面說的會議中,也會涉及;
不要以為這只是技術的決定,其實產品的參與也是很有必要的;你品,你細品;
我拿一個經典場景舉例,A賬戶往B賬戶打錢,然后系統是微服務,很熟悉吧;
沒錯,就是分布式事務的一個經典場景,要保證資料的一致性,A被扣錢的同時,B要加上相應的錢;
分布式事務我不多說,相信很多同學隨便一查,各種五花八門的方案;
但是這里我只講一點,達到資料一致的時間節點;你是要什么時候保證這個資料達到一致,也就是說,強一致性還是最終一致性;
要求強一致必然是犧牲掉一部分性能的,要求最終一致性就有可能在一段時間內產生資料不一致的問題;
這個時候,就需要拉上產品經理,跟他闡述其中的緣由,說明技術方案上無法規避的點,讓他做取舍;
有的時候,好的設計往往能規避技術上的難點,也可以節省開發的成本和時間;
所以,在討論這塊內容的時候,必須要有產品經理在場,提出設計上不合理之處;我們不能只局限于研究技術問題,其實換個角度,或者你質疑的點,就不存在了;
記得實習的時候,公司的老板講過一句話“人人都是產品經理”,現在回過頭一想,還真是那么回事;
大膽的提出自己的意見,做一個有自己主見的小碼農;
10
對于系統重構,我就以一句話結尾吧,這也是參考了一位大佬的話,“對公司現有的資源和戰略妥協,在技術堆疊和方案之間取舍”,
編程檔案:
https://gitee.com/cicadasmile/butte-java-note
應用倉庫:
https://gitee.com/cicadasmile/butte-flyer-parent
Gitee主頁: https://gitee.com/cicadasmile/butte-java-note
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/547439.html
標籤:Java
