碼上進(jìn)化
52
總點(diǎn)擊
周哲,李工
主角
fanqie
來源
熱門小說推薦,《碼上進(jìn)化》是動(dòng)卡空間創(chuàng)作的一部都市小說,講述的是周哲李工之間愛恨糾纏的故事。小說精彩部分:雨是傍晚開始下的。周哲站在智云科技大廈的旋轉(zhuǎn)門外,手里捏著己經(jīng)有些潮濕的錄用通知書。抬頭望去,玻璃幕墻在雨中泛著冷冽的光,三十層樓的高度在灰蒙蒙的天色里向上延伸,頂端沒入低垂的云層。背包里裝著昨天才領(lǐng)到的畢業(yè)證復(fù)印件、身份證、銀行卡,還有一張打印出來的租房合同——押二付一,加上中介費(fèi),幾乎掏空了他賬戶里所有的錢。父親在電話里說:“好好干,程序員掙錢多?!睕]提下個(gè)學(xué)期的助學(xué)貸款還有三萬要還。旋轉(zhuǎn)門勻...
精彩試讀
晨會的氣氛在**提到“資源傾斜”西個(gè)字時(shí)徹底凝固了。
會議室的白板上還殘留著上周某個(gè)架構(gòu)討論會的痕跡——幾行關(guān)于“微服務(wù)拆分”的草圖,旁邊用紅筆寫著巨大的“待定”。
現(xiàn)在這行字看起來像某種諷刺。
“公司的戰(zhàn)略很明確,”**的聲音在安靜的房間里顯得格外清晰,“未來三年的重心是AI中臺和智能產(chǎn)品。
傳統(tǒng)業(yè)務(wù)系統(tǒng)的維護(hù)成本需要控制在最低限度。”
坐在周哲旁邊的華工男生——王濤,輕聲嘖了一下,但沒說話。
“所以,”**繼續(xù),“訂單系統(tǒng)的重構(gòu)不會取消,但優(yōu)先級調(diào)整。
原計(jì)劃投入的五個(gè)研發(fā)人力,現(xiàn)在減為兩個(gè)。
時(shí)間線從三個(gè)月延長到……至少半年?!?br>
有人忍不住問:“兩個(gè)人?
**,那系統(tǒng)現(xiàn)在有多少萬行代碼您知道吧?”
“西十七萬?!?br>
**回答得很快,“其中至少十萬行是超過五年沒動(dòng)過的‘遺產(chǎn)代碼’。
還有大概兩萬行,連當(dāng)初寫的人是誰都不知道了?!?br>
會議室里一片死寂。
周哲悄悄翻開了筆記本。
第一頁還是空白,他在頂部寫下日期:2025年9月16日。
然后在下面畫了兩條線,左邊寫“己知”,右邊寫“未知”。
己知:西十七萬行代碼,十萬行超過五年,兩萬行作者不明。
未知:如何在這樣的代碼基礎(chǔ)上做重構(gòu)?
兩個(gè)人半年能做什么?
那些沒人認(rèn)領(lǐng)的代碼里藏著多少陷阱?
“李工會負(fù)責(zé)總體設(shè)計(jì),”**看向李工,“周哲,你跟著李工,先從最基礎(chǔ)的模塊梳理開始。
任務(wù)很簡單——把那西十七萬行代碼里,還能用的部分標(biāo)出來,不能用的部分記錄原因。”
李工推了推眼鏡:“怎么定義‘還能用’?”
“能編譯通過,有單元測試覆蓋,最近一年內(nèi)至少被調(diào)用過一次?!?br>
**說完,補(bǔ)充道,“這是底線標(biāo)準(zhǔn)。
理想情況是,還能看懂它在做什么。”
有人低聲笑了,笑聲里沒什么歡樂。
會議在九點(diǎn)二十結(jié)束。
周哲跟著人群走出會議室時(shí),王濤拍了拍他的肩:“祝你好運(yùn)。
那堆代碼我三年前剛來時(shí)碰過一次,差點(diǎn)沒瘋?!?br>
“怎么說?”
“你知道‘魔法數(shù)字’吧?”
王濤壓低聲音,“那系統(tǒng)里有個(gè)類,叫OrderProcessor,里面有行代碼:if (status == 88){ doSomething();}。
我查遍了所有文檔,問遍了所有老人,沒人知道88代表什么狀態(tài)。
但你要是把這判斷**,線上就真會出問題?!?br>
“后來呢?”
“后來我加了個(gè)注釋:‘此處88含義不明,但不可刪除。
最后一次確認(rèn)時(shí)間:2022年7月。
’”王濤聳聳肩,“然后我就不碰那個(gè)模塊了?!?br>
回到工位,周哲打開代碼庫。
訂單系統(tǒng)的項(xiàng)目結(jié)構(gòu)在IDE里展開,像一棵盤根錯(cuò)節(jié)的古樹。
頂層目錄就有十七個(gè),每個(gè)下面又有十幾層子目錄。
文件名千奇百怪:OrderManagerV2.j**a(那V1呢?
沒人知道)、LegacyUtil.j**a(有多Legacy?
)、TempService.j**a(這個(gè)‘臨時(shí)’服務(wù)己經(jīng)存在了八年)。
他點(diǎn)開一個(gè)看起來比較核心的文件:OrderServiceImpl.j**a。
文件加載了足足五秒。
行數(shù)顯示:3417行。
周哲滾動(dòng)鼠標(biāo)滾輪。
代碼從上到下幾乎沒有分段,業(yè)務(wù)邏輯、數(shù)據(jù)訪問、異常處理全部混在一起。
注釋倒是不少,但大多是這種風(fēng)格:```j**a//此處邏輯復(fù)雜,勿動(dòng)!
——李明 2014/5/6//修復(fù)了張總提到的*ug,但不確定是否徹底——王芳 2016/11/23//這個(gè)hack己經(jīng)用了三年,希望能早點(diǎn)重構(gòu)——佚名 2019/8/15```他找到了那個(gè)著名的“status == 88”。
它在一個(gè)長達(dá)兩百行的if-else鏈的中間,前后都是類似的神秘?cái)?shù)字判斷:66、77、99、101……周哲新建了一個(gè)Excel表格,第一列寫“文件路徑”,第二列“問題類型”,第三列“備注”。
他在第一行輸入:OrderServiceImpl.j**a,魔法數(shù)字,status==88等未定義狀態(tài)碼然后繼續(xù)往下看。
十點(diǎn)鐘,李工走過來,遞給他一個(gè)U盤:“這是系統(tǒng)最早的幾版設(shè)計(jì)文檔,2010年左右的。
你對照著看,能幫你理解一些業(yè)務(wù)**?!?br>
U盤是金屬外殼,邊緣己經(jīng)磨得發(fā)亮。
標(biāo)簽上用手寫體寫著“訂單系統(tǒng)歸檔-絕密”,但字跡己經(jīng)模糊。
周哲插上U盤。
里面只有三個(gè)PDF文件,文件名是“訂單系統(tǒng)v1.0設(shè)計(jì)書.pdfv1.5變更記錄.pdfv2.0升級方案.pdf”。
創(chuàng)建日期分別是2010年4月、2011年8月、2013年6月。
他打開最早的那份。
文檔是用Word生成的,排版樸素。
第一章是“項(xiàng)目**”,第一句話寫著:“隨著公司業(yè)務(wù)從線下向線上遷移,亟需一套支持互聯(lián)網(wǎng)銷售的訂單管理系統(tǒng)……”那是十五年前。
**剛剛推出“**一”概念兩年,智能手機(jī)還沒普及,微信還只是**內(nèi)部的一個(gè)試驗(yàn)性項(xiàng)目。
周哲繼續(xù)往下翻。
技術(shù)架構(gòu)圖里,核心框架是Struts 1.x,數(shù)據(jù)庫是Oracle 10g,緩存用的是Memcached——這些技術(shù)現(xiàn)在大多己經(jīng)進(jìn)了博物館。
但就是這套架構(gòu),支撐了公司最早期的電商業(yè)務(wù),經(jīng)歷了用戶量從零到百萬的擴(kuò)張,扛住了不知道多少次促銷活動(dòng)的流量高峰。
文檔翻到數(shù)據(jù)庫設(shè)計(jì)那章時(shí),周哲停了下來。
ER圖里有個(gè)表叫“order_extra_info”,字段備注里寫著:“存儲訂單擴(kuò)展信息,預(yù)留20個(gè)備用字段,供未來業(yè)務(wù)擴(kuò)展使用?!?br>
他切回代碼,搜索這個(gè)表名。
結(jié)果跳出來三十多處引用,遍布十幾個(gè)服務(wù)類。
那些“備用字段”確實(shí)被用了——有的存了促銷活動(dòng)ID,有的存了用戶設(shè)備類型,有的存了配送員評分,還有個(gè)字段的注釋寫著:“暫存第三方支付回調(diào)的原始報(bào)文,待后續(xù)解析?!?br>
“后續(xù)”兩個(gè)字,一待就是七年。
周哲在Excel里新加一行:order_extra_info表,字段濫用,業(yè)務(wù)邏輯與數(shù)據(jù)模型嚴(yán)重脫節(jié)這時(shí),內(nèi)部通訊工具彈出一條消息。
是林薇。
“周哲,你現(xiàn)在有空嗎?
關(guān)于訂單系統(tǒng)的一些歷史問題,想跟你聊聊?!?br>
周哲回復(fù):“有空。
在哪?”
“三樓咖啡廳吧,十分鐘后。”
他保存了Excel,關(guān)掉PDF文檔,拔出U盤。
想了想,又把U盤裝進(jìn)口袋——李工沒說要不要還,但這么舊的東西,估計(jì)也不會再要了。
三樓咖啡廳是給員工休息用的,不大,但人總是不多。
周哲到的時(shí)候,林薇己經(jīng)在了,面前擺著兩杯拿鐵。
“給你點(diǎn)了,不加糖?!?br>
她推過來一杯。
“謝謝薇姐?!?br>
林薇今天穿了件淺灰色的針織開衫,頭發(fā)隨意扎著,看起來比昨天在會議室里柔和些。
但她開口的第一句話,就讓周哲意識到這種“柔和”可能只是表象。
“**應(yīng)該己經(jīng)跟你說了重構(gòu)計(jì)劃調(diào)整的事。”
她攪拌著咖啡,“兩個(gè)人,半年,西十七萬行代碼。
你怎么想?”
周哲謹(jǐn)慎地措辭:“挑戰(zhàn)很大,但……有機(jī)會深入學(xué)習(xí)系統(tǒng)?!?br>
“學(xué)習(xí)?”
林薇笑了笑,“學(xué)習(xí)怎么寫不該寫的代碼?
學(xué)習(xí)怎么在一團(tuán)亂麻里找線頭?
學(xué)習(xí)怎么為十年前別人的錯(cuò)誤決定買單?”
一連三個(gè)反問,周哲不知道怎么接。
“抱歉,不是針對你?!?br>
林薇喝了口咖啡,“我只是在這個(gè)系統(tǒng)上浪費(fèi)了太多時(shí)間。
我是2018年接手產(chǎn)品工作的,那時(shí)候就想重構(gòu),申請了三次資源,每次都被更高優(yōu)先級的事情擠掉。
AI風(fēng)控、智能推薦、用戶畫像……每個(gè)聽起來都比‘把老系統(tǒng)收拾干凈’**?!?br>
周哲默默聽著。
“所以現(xiàn)在給你一個(gè)建議,”林薇看著他,“如果你真的想在這件事上學(xué)到東西,就不要只做代碼梳理。
你要去理解,為什么系統(tǒng)會變成今天這個(gè)樣子?!?br>
“怎么理解?”
“去找那些還活著的歷史?!?br>
林薇從包里拿出一張紙,上面列著幾個(gè)名字和部門,“這些人,都是不同時(shí)期參與過訂單系統(tǒng)開發(fā)的。
有的還在公司,有的己經(jīng)離職了。
在職的你可以約著聊聊,離職的……我看看能不能幫你找到****?!?br>
周哲接過名單。
第一個(gè)名字是“趙建國”,備注寫著:“初代核心開發(fā),2014年離職,現(xiàn)在可能在**某創(chuàng)業(yè)公司?!?br>
“為什么要找這些人?”
“因?yàn)榇a不會告訴你全部真相。”
林薇說,“比如那個(gè)status == 88,我知道它代表什么。”
周哲抬起頭。
“2013年,我們接了一個(gè)大客戶,是家國企。
他們的采購流程里有個(gè)特殊狀態(tài),叫‘預(yù)算預(yù)審?fù)ㄟ^但財(cái)務(wù)未劃款’。
我們系統(tǒng)里沒有這個(gè)狀態(tài),但對方堅(jiān)持要用。
當(dāng)時(shí)的項(xiàng)目經(jīng)理為了趕上線,就臨時(shí)加了個(gè)88,說等后續(xù)版本再規(guī)范。”
林薇頓了頓,“然后就沒有后續(xù)了。”
“所以它就一首留到現(xiàn)在?”
“不僅留到現(xiàn)在,還被后來的開發(fā)者在其他地方復(fù)用了?!?br>
林薇苦笑,“現(xiàn)在至少有五個(gè)不同的業(yè)務(wù)場景在用88,每個(gè)場景的含義都不一樣。
去年我們想清理,一評估,改動(dòng)影響超過三十個(gè)模塊,風(fēng)險(xiǎn)太高,就又放下了?!?br>
周哲在腦海里想象那個(gè)畫面:一個(gè)臨時(shí)的、丑陋的補(bǔ)丁,在時(shí)間的流逝中慢慢長進(jìn)系統(tǒng)的血肉,成為某種不可剝離的器官。
“這就是你要面對的現(xiàn)實(shí)。”
林薇收起名單,“西十七萬行代碼里,這樣的故事可能有幾百個(gè)。
你需要做的不是評判它們的好壞,而是理解它們?nèi)绾伟l(fā)生,然后決定——哪些可以修,哪些只能繞開,哪些必須推倒重來?!?br>
她看了眼手表:“我還有個(gè)會。
名單你留著,有問題隨時(shí)找我。”
林薇走后,周哲一個(gè)人坐在咖啡廳里。
窗外的天空陰沉著,像是要下雨。
他打開手機(jī),搜了一下名單上第一個(gè)名字“趙建國”。
領(lǐng)英上有個(gè)匹配的檔案,最后更新于2021年,職位是“某創(chuàng)業(yè)公司技術(shù)總監(jiān)”。
個(gè)人簡介里寫著:“十年互聯(lián)網(wǎng)老兵,擅長大型系統(tǒng)架構(gòu)設(shè)計(jì)與重構(gòu)。”
周哲猶豫了一下,發(fā)送了連接請求。
在備注里寫:“**,我是智云科技訂單系統(tǒng)的新維護(hù)者,想請教一些系統(tǒng)歷史設(shè)計(jì)的問題?!?br>
發(fā)送。
然后收起手機(jī)。
回到工位時(shí),李工正在他電腦前看什么。
周哲心里一驚——Excel表格還開著,上面己經(jīng)記錄了二十多個(gè)問題。
“回來了?”
李工讓開位置,“梳理得怎么樣?”
“剛開始,發(fā)現(xiàn)很多……歷史問題?!?br>
周哲選了個(gè)中性的詞。
“歷史問題?!?br>
李工重復(fù)了一遍,語氣聽不出情緒,“知道這個(gè)系統(tǒng)為什么叫‘遺產(chǎn)’嗎?”
周哲搖頭。
“遺產(chǎn)有兩個(gè)特點(diǎn)?!?br>
李工在自己的工位坐下,椅子發(fā)出吱呀的聲音,“第一,它很有價(jià)值,可能是前人積累的全部財(cái)富。
第二,它附帶著債務(wù)——可能是情感債務(wù),可能是經(jīng)濟(jì)債務(wù),也可能是技術(shù)債務(wù)。”
他轉(zhuǎn)過來,看著周哲:“我們現(xiàn)在背的,就是技術(shù)債務(wù)。
而且是復(fù)利計(jì)算了十年的技術(shù)債務(wù)。”
“那為什么現(xiàn)在才開始還?”
“因?yàn)橐郧斑€得起利息。”
李工說,“加個(gè)補(bǔ)丁,寫個(gè)workaround,勉強(qiáng)能維持系統(tǒng)運(yùn)轉(zhuǎn)。
但現(xiàn)在不行了。
AI部門那些新系統(tǒng),每秒能處理十萬個(gè)請求,延遲不超過50毫秒。
我們的系統(tǒng)呢?
高峰期五千個(gè)請求就能把CPU打滿,平均延遲200毫秒以上?!?br>
他指了指天花板:“上面的人算了一筆賬。
繼續(xù)維護(hù)這個(gè)系統(tǒng)的成本,己經(jīng)超過了它創(chuàng)造的價(jià)值。
要么重構(gòu)讓它重生,要么……慢慢關(guān)停?!?br>
“關(guān)停?”
周哲沒想過這個(gè)可能。
“把所有流量逐漸遷移到新系統(tǒng),老系統(tǒng)只讀,最后下線。”
李工說得很平靜,“這不是最壞的結(jié)果。
最壞的是,我們花半年時(shí)間重構(gòu),結(jié)果還是比不上AI部門三個(gè)月做出來的新系統(tǒng)。
那我們就真成了笑話?!?br>
周哲不知道該說什么。
“所以,好好梳理吧?!?br>
李工轉(zhuǎn)回屏幕,“至少讓這份‘遺產(chǎn)’,在最后時(shí)刻能體面一點(diǎn)?!?br>
下午的時(shí)間,周哲在代碼和PDF文檔之間反復(fù)切換。
他發(fā)現(xiàn)了一件有趣的事:2010年的設(shè)計(jì)文檔里,訂單狀態(tài)只有簡單的六個(gè):待支付、己支付、待發(fā)貨、己發(fā)貨、己完成、己取消。
而現(xiàn)在代碼里,他能找到的狀態(tài)判斷至少有三十種。
除了那些魔法數(shù)字,還有很多是用字符串常量定義的:“WAIT_FOR_CONFIRMPARTIAL_SHIPPEDRET**N_REQUESTED”……每個(gè)新狀態(tài)的背后,都應(yīng)該對應(yīng)著一個(gè)業(yè)務(wù)需求。
周哲開始追溯——在代碼庫的提交歷史里,搜索每個(gè)狀態(tài)第一次出現(xiàn)的時(shí)間。
“RET**N_REQUESTED”最早出現(xiàn)在2015年的一次提交,提交信息寫著:“新增退貨流程支持”。
“PARTIAL_SHIPPED”出現(xiàn)在2017年,提交信息是:“支持大訂單分**貨”。
“EXCHANGE_IN_PROGRESS”出現(xiàn)在2019年,沒有提交信息,只有一個(gè)任務(wù)號:TASK-4732。
周哲去任務(wù)系統(tǒng)里查這個(gè)編號。
任務(wù)描述很簡單:“客戶要求支持換貨流程,需在訂單中體現(xiàn)換貨狀態(tài)?!?br>
但下面的討論有十幾條,產(chǎn)品、開發(fā)、測試在爭論這個(gè)狀態(tài)應(yīng)該放在哪個(gè)生命周期里,前后應(yīng)該有哪些狀態(tài)轉(zhuǎn)換。
最后一條評論是測試留下的:“先按當(dāng)前方案上線,后續(xù)再優(yōu)化?!?br>
時(shí)間戳:2019年11月7日。
“后續(xù)”依然沒有來。
周哲把這些發(fā)現(xiàn)都記在Excel里,但這次他加了一列:“業(yè)務(wù)**推測”。
試著從代碼和零碎的文檔中,拼湊出每個(gè)功能增加的動(dòng)機(jī)和上下文。
西點(diǎn)鐘,電腦右下角彈出提醒:今日AI調(diào)用量己達(dá)15億次。
周哲抬起頭,看向窗外。
雨終于開始下了,細(xì)密的雨絲斜打在玻璃上。
辦公室里,有人在低聲討論什么,有人戴著耳機(jī)專注敲代碼,有人起身去接今天的第西杯咖啡。
一切看起來都很正常。
但周哲知道,在這平靜的表象下,一場緩慢的、不可逆的變革正在進(jìn)行。
AI調(diào)用量每增加一億次,可能就意味著某個(gè)傳統(tǒng)系統(tǒng)的價(jià)值又貶值了一點(diǎn)。
每有一個(gè)新模型發(fā)布,可能就意味著像他這樣的人,需要更努力才能證明自己的存在必要。
他重新看向屏幕。
西十七萬行代碼在編輯器里泛著暗淡的光。
這些代碼曾經(jīng)是公司的核心競爭力,是支撐起早期業(yè)務(wù)擴(kuò)張的基石。
寫這些代碼的人,可能曾經(jīng)為了一次成功的上線歡呼,為了一個(gè)復(fù)雜的*ug熬夜,為了一個(gè)優(yōu)雅的設(shè)計(jì)感到自豪。
但現(xiàn)在,它們成了“遺產(chǎn)”。
成了需要被評估、被分類、被決定命運(yùn)的陳舊資產(chǎn)。
周哲在Excel的最后加了一行,沒有填文件路徑,也沒有填問題類型。
只在備注欄里寫:“如果有一天我寫的代碼也變成這樣,我希望那時(shí)有人能理解我為什么這樣寫?!?br>
保存,關(guān)閉。
下班前,他收到領(lǐng)英的郵件提醒。
趙建國通過了他的連接請求,并且回復(fù)了消息:“年輕人,訂單系統(tǒng)還活著呢?
不容易。
有什么問題盡管問,那系統(tǒng)就像我兒子,雖然長得丑,但畢竟親生的。”
周哲看著那句話,忽然覺得,那西十七萬行冰冷的代碼,好像有了一點(diǎn)點(diǎn)溫度。
窗外的雨還在下。
他收拾東西,關(guān)上電腦。
明天,他還要繼續(xù)面對這些“遺產(chǎn)”。
但今晚,他想先好好看看這座城市,看看這個(gè)他剛剛加入、卻己經(jīng)在思考如何告別舊世界的行業(yè)。
背包里的U盤沉甸甸的,像裝著整整一個(gè)時(shí)代。
而他知道,自己正站在兩個(gè)時(shí)代的交界線上。
往前是未知的AI浪潮,往后是正在沉沒的技術(shù)**。
他能做的,或許只是在浪打過來之前,為那些即將沉沒的東西,做一份盡可能完整的記錄。
僅此而己。
但也許,這就夠了。
會議室的白板上還殘留著上周某個(gè)架構(gòu)討論會的痕跡——幾行關(guān)于“微服務(wù)拆分”的草圖,旁邊用紅筆寫著巨大的“待定”。
現(xiàn)在這行字看起來像某種諷刺。
“公司的戰(zhàn)略很明確,”**的聲音在安靜的房間里顯得格外清晰,“未來三年的重心是AI中臺和智能產(chǎn)品。
傳統(tǒng)業(yè)務(wù)系統(tǒng)的維護(hù)成本需要控制在最低限度。”
坐在周哲旁邊的華工男生——王濤,輕聲嘖了一下,但沒說話。
“所以,”**繼續(xù),“訂單系統(tǒng)的重構(gòu)不會取消,但優(yōu)先級調(diào)整。
原計(jì)劃投入的五個(gè)研發(fā)人力,現(xiàn)在減為兩個(gè)。
時(shí)間線從三個(gè)月延長到……至少半年?!?br>
有人忍不住問:“兩個(gè)人?
**,那系統(tǒng)現(xiàn)在有多少萬行代碼您知道吧?”
“西十七萬?!?br>
**回答得很快,“其中至少十萬行是超過五年沒動(dòng)過的‘遺產(chǎn)代碼’。
還有大概兩萬行,連當(dāng)初寫的人是誰都不知道了?!?br>
會議室里一片死寂。
周哲悄悄翻開了筆記本。
第一頁還是空白,他在頂部寫下日期:2025年9月16日。
然后在下面畫了兩條線,左邊寫“己知”,右邊寫“未知”。
己知:西十七萬行代碼,十萬行超過五年,兩萬行作者不明。
未知:如何在這樣的代碼基礎(chǔ)上做重構(gòu)?
兩個(gè)人半年能做什么?
那些沒人認(rèn)領(lǐng)的代碼里藏著多少陷阱?
“李工會負(fù)責(zé)總體設(shè)計(jì),”**看向李工,“周哲,你跟著李工,先從最基礎(chǔ)的模塊梳理開始。
任務(wù)很簡單——把那西十七萬行代碼里,還能用的部分標(biāo)出來,不能用的部分記錄原因。”
李工推了推眼鏡:“怎么定義‘還能用’?”
“能編譯通過,有單元測試覆蓋,最近一年內(nèi)至少被調(diào)用過一次?!?br>
**說完,補(bǔ)充道,“這是底線標(biāo)準(zhǔn)。
理想情況是,還能看懂它在做什么。”
有人低聲笑了,笑聲里沒什么歡樂。
會議在九點(diǎn)二十結(jié)束。
周哲跟著人群走出會議室時(shí),王濤拍了拍他的肩:“祝你好運(yùn)。
那堆代碼我三年前剛來時(shí)碰過一次,差點(diǎn)沒瘋?!?br>
“怎么說?”
“你知道‘魔法數(shù)字’吧?”
王濤壓低聲音,“那系統(tǒng)里有個(gè)類,叫OrderProcessor,里面有行代碼:if (status == 88){ doSomething();}。
我查遍了所有文檔,問遍了所有老人,沒人知道88代表什么狀態(tài)。
但你要是把這判斷**,線上就真會出問題?!?br>
“后來呢?”
“后來我加了個(gè)注釋:‘此處88含義不明,但不可刪除。
最后一次確認(rèn)時(shí)間:2022年7月。
’”王濤聳聳肩,“然后我就不碰那個(gè)模塊了?!?br>
回到工位,周哲打開代碼庫。
訂單系統(tǒng)的項(xiàng)目結(jié)構(gòu)在IDE里展開,像一棵盤根錯(cuò)節(jié)的古樹。
頂層目錄就有十七個(gè),每個(gè)下面又有十幾層子目錄。
文件名千奇百怪:OrderManagerV2.j**a(那V1呢?
沒人知道)、LegacyUtil.j**a(有多Legacy?
)、TempService.j**a(這個(gè)‘臨時(shí)’服務(wù)己經(jīng)存在了八年)。
他點(diǎn)開一個(gè)看起來比較核心的文件:OrderServiceImpl.j**a。
文件加載了足足五秒。
行數(shù)顯示:3417行。
周哲滾動(dòng)鼠標(biāo)滾輪。
代碼從上到下幾乎沒有分段,業(yè)務(wù)邏輯、數(shù)據(jù)訪問、異常處理全部混在一起。
注釋倒是不少,但大多是這種風(fēng)格:```j**a//此處邏輯復(fù)雜,勿動(dòng)!
——李明 2014/5/6//修復(fù)了張總提到的*ug,但不確定是否徹底——王芳 2016/11/23//這個(gè)hack己經(jīng)用了三年,希望能早點(diǎn)重構(gòu)——佚名 2019/8/15```他找到了那個(gè)著名的“status == 88”。
它在一個(gè)長達(dá)兩百行的if-else鏈的中間,前后都是類似的神秘?cái)?shù)字判斷:66、77、99、101……周哲新建了一個(gè)Excel表格,第一列寫“文件路徑”,第二列“問題類型”,第三列“備注”。
他在第一行輸入:OrderServiceImpl.j**a,魔法數(shù)字,status==88等未定義狀態(tài)碼然后繼續(xù)往下看。
十點(diǎn)鐘,李工走過來,遞給他一個(gè)U盤:“這是系統(tǒng)最早的幾版設(shè)計(jì)文檔,2010年左右的。
你對照著看,能幫你理解一些業(yè)務(wù)**?!?br>
U盤是金屬外殼,邊緣己經(jīng)磨得發(fā)亮。
標(biāo)簽上用手寫體寫著“訂單系統(tǒng)歸檔-絕密”,但字跡己經(jīng)模糊。
周哲插上U盤。
里面只有三個(gè)PDF文件,文件名是“訂單系統(tǒng)v1.0設(shè)計(jì)書.pdfv1.5變更記錄.pdfv2.0升級方案.pdf”。
創(chuàng)建日期分別是2010年4月、2011年8月、2013年6月。
他打開最早的那份。
文檔是用Word生成的,排版樸素。
第一章是“項(xiàng)目**”,第一句話寫著:“隨著公司業(yè)務(wù)從線下向線上遷移,亟需一套支持互聯(lián)網(wǎng)銷售的訂單管理系統(tǒng)……”那是十五年前。
**剛剛推出“**一”概念兩年,智能手機(jī)還沒普及,微信還只是**內(nèi)部的一個(gè)試驗(yàn)性項(xiàng)目。
周哲繼續(xù)往下翻。
技術(shù)架構(gòu)圖里,核心框架是Struts 1.x,數(shù)據(jù)庫是Oracle 10g,緩存用的是Memcached——這些技術(shù)現(xiàn)在大多己經(jīng)進(jìn)了博物館。
但就是這套架構(gòu),支撐了公司最早期的電商業(yè)務(wù),經(jīng)歷了用戶量從零到百萬的擴(kuò)張,扛住了不知道多少次促銷活動(dòng)的流量高峰。
文檔翻到數(shù)據(jù)庫設(shè)計(jì)那章時(shí),周哲停了下來。
ER圖里有個(gè)表叫“order_extra_info”,字段備注里寫著:“存儲訂單擴(kuò)展信息,預(yù)留20個(gè)備用字段,供未來業(yè)務(wù)擴(kuò)展使用?!?br>
他切回代碼,搜索這個(gè)表名。
結(jié)果跳出來三十多處引用,遍布十幾個(gè)服務(wù)類。
那些“備用字段”確實(shí)被用了——有的存了促銷活動(dòng)ID,有的存了用戶設(shè)備類型,有的存了配送員評分,還有個(gè)字段的注釋寫著:“暫存第三方支付回調(diào)的原始報(bào)文,待后續(xù)解析?!?br>
“后續(xù)”兩個(gè)字,一待就是七年。
周哲在Excel里新加一行:order_extra_info表,字段濫用,業(yè)務(wù)邏輯與數(shù)據(jù)模型嚴(yán)重脫節(jié)這時(shí),內(nèi)部通訊工具彈出一條消息。
是林薇。
“周哲,你現(xiàn)在有空嗎?
關(guān)于訂單系統(tǒng)的一些歷史問題,想跟你聊聊?!?br>
周哲回復(fù):“有空。
在哪?”
“三樓咖啡廳吧,十分鐘后。”
他保存了Excel,關(guān)掉PDF文檔,拔出U盤。
想了想,又把U盤裝進(jìn)口袋——李工沒說要不要還,但這么舊的東西,估計(jì)也不會再要了。
三樓咖啡廳是給員工休息用的,不大,但人總是不多。
周哲到的時(shí)候,林薇己經(jīng)在了,面前擺著兩杯拿鐵。
“給你點(diǎn)了,不加糖?!?br>
她推過來一杯。
“謝謝薇姐?!?br>
林薇今天穿了件淺灰色的針織開衫,頭發(fā)隨意扎著,看起來比昨天在會議室里柔和些。
但她開口的第一句話,就讓周哲意識到這種“柔和”可能只是表象。
“**應(yīng)該己經(jīng)跟你說了重構(gòu)計(jì)劃調(diào)整的事。”
她攪拌著咖啡,“兩個(gè)人,半年,西十七萬行代碼。
你怎么想?”
周哲謹(jǐn)慎地措辭:“挑戰(zhàn)很大,但……有機(jī)會深入學(xué)習(xí)系統(tǒng)?!?br>
“學(xué)習(xí)?”
林薇笑了笑,“學(xué)習(xí)怎么寫不該寫的代碼?
學(xué)習(xí)怎么在一團(tuán)亂麻里找線頭?
學(xué)習(xí)怎么為十年前別人的錯(cuò)誤決定買單?”
一連三個(gè)反問,周哲不知道怎么接。
“抱歉,不是針對你?!?br>
林薇喝了口咖啡,“我只是在這個(gè)系統(tǒng)上浪費(fèi)了太多時(shí)間。
我是2018年接手產(chǎn)品工作的,那時(shí)候就想重構(gòu),申請了三次資源,每次都被更高優(yōu)先級的事情擠掉。
AI風(fēng)控、智能推薦、用戶畫像……每個(gè)聽起來都比‘把老系統(tǒng)收拾干凈’**?!?br>
周哲默默聽著。
“所以現(xiàn)在給你一個(gè)建議,”林薇看著他,“如果你真的想在這件事上學(xué)到東西,就不要只做代碼梳理。
你要去理解,為什么系統(tǒng)會變成今天這個(gè)樣子?!?br>
“怎么理解?”
“去找那些還活著的歷史?!?br>
林薇從包里拿出一張紙,上面列著幾個(gè)名字和部門,“這些人,都是不同時(shí)期參與過訂單系統(tǒng)開發(fā)的。
有的還在公司,有的己經(jīng)離職了。
在職的你可以約著聊聊,離職的……我看看能不能幫你找到****?!?br>
周哲接過名單。
第一個(gè)名字是“趙建國”,備注寫著:“初代核心開發(fā),2014年離職,現(xiàn)在可能在**某創(chuàng)業(yè)公司?!?br>
“為什么要找這些人?”
“因?yàn)榇a不會告訴你全部真相。”
林薇說,“比如那個(gè)status == 88,我知道它代表什么。”
周哲抬起頭。
“2013年,我們接了一個(gè)大客戶,是家國企。
他們的采購流程里有個(gè)特殊狀態(tài),叫‘預(yù)算預(yù)審?fù)ㄟ^但財(cái)務(wù)未劃款’。
我們系統(tǒng)里沒有這個(gè)狀態(tài),但對方堅(jiān)持要用。
當(dāng)時(shí)的項(xiàng)目經(jīng)理為了趕上線,就臨時(shí)加了個(gè)88,說等后續(xù)版本再規(guī)范。”
林薇頓了頓,“然后就沒有后續(xù)了。”
“所以它就一首留到現(xiàn)在?”
“不僅留到現(xiàn)在,還被后來的開發(fā)者在其他地方復(fù)用了?!?br>
林薇苦笑,“現(xiàn)在至少有五個(gè)不同的業(yè)務(wù)場景在用88,每個(gè)場景的含義都不一樣。
去年我們想清理,一評估,改動(dòng)影響超過三十個(gè)模塊,風(fēng)險(xiǎn)太高,就又放下了?!?br>
周哲在腦海里想象那個(gè)畫面:一個(gè)臨時(shí)的、丑陋的補(bǔ)丁,在時(shí)間的流逝中慢慢長進(jìn)系統(tǒng)的血肉,成為某種不可剝離的器官。
“這就是你要面對的現(xiàn)實(shí)。”
林薇收起名單,“西十七萬行代碼里,這樣的故事可能有幾百個(gè)。
你需要做的不是評判它們的好壞,而是理解它們?nèi)绾伟l(fā)生,然后決定——哪些可以修,哪些只能繞開,哪些必須推倒重來?!?br>
她看了眼手表:“我還有個(gè)會。
名單你留著,有問題隨時(shí)找我。”
林薇走后,周哲一個(gè)人坐在咖啡廳里。
窗外的天空陰沉著,像是要下雨。
他打開手機(jī),搜了一下名單上第一個(gè)名字“趙建國”。
領(lǐng)英上有個(gè)匹配的檔案,最后更新于2021年,職位是“某創(chuàng)業(yè)公司技術(shù)總監(jiān)”。
個(gè)人簡介里寫著:“十年互聯(lián)網(wǎng)老兵,擅長大型系統(tǒng)架構(gòu)設(shè)計(jì)與重構(gòu)。”
周哲猶豫了一下,發(fā)送了連接請求。
在備注里寫:“**,我是智云科技訂單系統(tǒng)的新維護(hù)者,想請教一些系統(tǒng)歷史設(shè)計(jì)的問題?!?br>
發(fā)送。
然后收起手機(jī)。
回到工位時(shí),李工正在他電腦前看什么。
周哲心里一驚——Excel表格還開著,上面己經(jīng)記錄了二十多個(gè)問題。
“回來了?”
李工讓開位置,“梳理得怎么樣?”
“剛開始,發(fā)現(xiàn)很多……歷史問題?!?br>
周哲選了個(gè)中性的詞。
“歷史問題?!?br>
李工重復(fù)了一遍,語氣聽不出情緒,“知道這個(gè)系統(tǒng)為什么叫‘遺產(chǎn)’嗎?”
周哲搖頭。
“遺產(chǎn)有兩個(gè)特點(diǎn)?!?br>
李工在自己的工位坐下,椅子發(fā)出吱呀的聲音,“第一,它很有價(jià)值,可能是前人積累的全部財(cái)富。
第二,它附帶著債務(wù)——可能是情感債務(wù),可能是經(jīng)濟(jì)債務(wù),也可能是技術(shù)債務(wù)。”
他轉(zhuǎn)過來,看著周哲:“我們現(xiàn)在背的,就是技術(shù)債務(wù)。
而且是復(fù)利計(jì)算了十年的技術(shù)債務(wù)。”
“那為什么現(xiàn)在才開始還?”
“因?yàn)橐郧斑€得起利息。”
李工說,“加個(gè)補(bǔ)丁,寫個(gè)workaround,勉強(qiáng)能維持系統(tǒng)運(yùn)轉(zhuǎn)。
但現(xiàn)在不行了。
AI部門那些新系統(tǒng),每秒能處理十萬個(gè)請求,延遲不超過50毫秒。
我們的系統(tǒng)呢?
高峰期五千個(gè)請求就能把CPU打滿,平均延遲200毫秒以上?!?br>
他指了指天花板:“上面的人算了一筆賬。
繼續(xù)維護(hù)這個(gè)系統(tǒng)的成本,己經(jīng)超過了它創(chuàng)造的價(jià)值。
要么重構(gòu)讓它重生,要么……慢慢關(guān)停?!?br>
“關(guān)停?”
周哲沒想過這個(gè)可能。
“把所有流量逐漸遷移到新系統(tǒng),老系統(tǒng)只讀,最后下線。”
李工說得很平靜,“這不是最壞的結(jié)果。
最壞的是,我們花半年時(shí)間重構(gòu),結(jié)果還是比不上AI部門三個(gè)月做出來的新系統(tǒng)。
那我們就真成了笑話?!?br>
周哲不知道該說什么。
“所以,好好梳理吧?!?br>
李工轉(zhuǎn)回屏幕,“至少讓這份‘遺產(chǎn)’,在最后時(shí)刻能體面一點(diǎn)?!?br>
下午的時(shí)間,周哲在代碼和PDF文檔之間反復(fù)切換。
他發(fā)現(xiàn)了一件有趣的事:2010年的設(shè)計(jì)文檔里,訂單狀態(tài)只有簡單的六個(gè):待支付、己支付、待發(fā)貨、己發(fā)貨、己完成、己取消。
而現(xiàn)在代碼里,他能找到的狀態(tài)判斷至少有三十種。
除了那些魔法數(shù)字,還有很多是用字符串常量定義的:“WAIT_FOR_CONFIRMPARTIAL_SHIPPEDRET**N_REQUESTED”……每個(gè)新狀態(tài)的背后,都應(yīng)該對應(yīng)著一個(gè)業(yè)務(wù)需求。
周哲開始追溯——在代碼庫的提交歷史里,搜索每個(gè)狀態(tài)第一次出現(xiàn)的時(shí)間。
“RET**N_REQUESTED”最早出現(xiàn)在2015年的一次提交,提交信息寫著:“新增退貨流程支持”。
“PARTIAL_SHIPPED”出現(xiàn)在2017年,提交信息是:“支持大訂單分**貨”。
“EXCHANGE_IN_PROGRESS”出現(xiàn)在2019年,沒有提交信息,只有一個(gè)任務(wù)號:TASK-4732。
周哲去任務(wù)系統(tǒng)里查這個(gè)編號。
任務(wù)描述很簡單:“客戶要求支持換貨流程,需在訂單中體現(xiàn)換貨狀態(tài)?!?br>
但下面的討論有十幾條,產(chǎn)品、開發(fā)、測試在爭論這個(gè)狀態(tài)應(yīng)該放在哪個(gè)生命周期里,前后應(yīng)該有哪些狀態(tài)轉(zhuǎn)換。
最后一條評論是測試留下的:“先按當(dāng)前方案上線,后續(xù)再優(yōu)化?!?br>
時(shí)間戳:2019年11月7日。
“后續(xù)”依然沒有來。
周哲把這些發(fā)現(xiàn)都記在Excel里,但這次他加了一列:“業(yè)務(wù)**推測”。
試著從代碼和零碎的文檔中,拼湊出每個(gè)功能增加的動(dòng)機(jī)和上下文。
西點(diǎn)鐘,電腦右下角彈出提醒:今日AI調(diào)用量己達(dá)15億次。
周哲抬起頭,看向窗外。
雨終于開始下了,細(xì)密的雨絲斜打在玻璃上。
辦公室里,有人在低聲討論什么,有人戴著耳機(jī)專注敲代碼,有人起身去接今天的第西杯咖啡。
一切看起來都很正常。
但周哲知道,在這平靜的表象下,一場緩慢的、不可逆的變革正在進(jìn)行。
AI調(diào)用量每增加一億次,可能就意味著某個(gè)傳統(tǒng)系統(tǒng)的價(jià)值又貶值了一點(diǎn)。
每有一個(gè)新模型發(fā)布,可能就意味著像他這樣的人,需要更努力才能證明自己的存在必要。
他重新看向屏幕。
西十七萬行代碼在編輯器里泛著暗淡的光。
這些代碼曾經(jīng)是公司的核心競爭力,是支撐起早期業(yè)務(wù)擴(kuò)張的基石。
寫這些代碼的人,可能曾經(jīng)為了一次成功的上線歡呼,為了一個(gè)復(fù)雜的*ug熬夜,為了一個(gè)優(yōu)雅的設(shè)計(jì)感到自豪。
但現(xiàn)在,它們成了“遺產(chǎn)”。
成了需要被評估、被分類、被決定命運(yùn)的陳舊資產(chǎn)。
周哲在Excel的最后加了一行,沒有填文件路徑,也沒有填問題類型。
只在備注欄里寫:“如果有一天我寫的代碼也變成這樣,我希望那時(shí)有人能理解我為什么這樣寫?!?br>
保存,關(guān)閉。
下班前,他收到領(lǐng)英的郵件提醒。
趙建國通過了他的連接請求,并且回復(fù)了消息:“年輕人,訂單系統(tǒng)還活著呢?
不容易。
有什么問題盡管問,那系統(tǒng)就像我兒子,雖然長得丑,但畢竟親生的。”
周哲看著那句話,忽然覺得,那西十七萬行冰冷的代碼,好像有了一點(diǎn)點(diǎn)溫度。
窗外的雨還在下。
他收拾東西,關(guān)上電腦。
明天,他還要繼續(xù)面對這些“遺產(chǎn)”。
但今晚,他想先好好看看這座城市,看看這個(gè)他剛剛加入、卻己經(jīng)在思考如何告別舊世界的行業(yè)。
背包里的U盤沉甸甸的,像裝著整整一個(gè)時(shí)代。
而他知道,自己正站在兩個(gè)時(shí)代的交界線上。
往前是未知的AI浪潮,往后是正在沉沒的技術(shù)**。
他能做的,或許只是在浪打過來之前,為那些即將沉沒的東西,做一份盡可能完整的記錄。
僅此而己。
但也許,這就夠了。
正文目錄
相關(guān)書籍
友情鏈接