因?yàn)槟壳盎旧弦呀?jīng)解決了于老爺子的和熙熙的問題,所以蕭天也是繼續(xù)去編寫代碼去了。
畢竟之前那個任務(wù)是完成了,但是畢竟人家價格提升上來了,新通訊模塊還沒有黑人家重新編寫一個。
而之前那解決問題的三天時間里面,蕭天也是在解決上面這個BUG的嘗試中,才發(fā)覺TCL這種語言先天不足。
因?yàn)橐坏┏绦蜻壿嫃?fù)雜,它那變量無需聲明、變量無類型等等對初學(xué)者來說不可多得的“優(yōu)點(diǎn)”就成了致命缺陷。
這會讓人不得不付出比C/C++之類“正規(guī)語言”多得多的努力去跟蹤去區(qū)分?jǐn)?shù)據(jù)類型。
而且為了避免錯誤,蕭天也不得不把數(shù)據(jù)類型也“打包”進(jìn)數(shù)據(jù),然后在程序入口寫代碼分辨它——尤其是,這些數(shù)據(jù)類型還是動態(tài)的,是從輸入數(shù)據(jù)識別出來的;不結(jié)合輸入誰都不知道某個數(shù)據(jù)在某個時刻會是什么。
這使得代碼幾乎無法靜態(tài)分析;而測試用例很難覆蓋每一條執(zhí)行路線——不要忘了,這個程序“吃”進(jìn)去的數(shù)據(jù)是多變的,幾乎不可能列出所有情況。
這使得蕭天又產(chǎn)生了一個想法。
那就是,要給它增加一些功能,把專業(yè)語言的core dump、變量先聲明后使用等等功能搞出來,使得出現(xiàn)類似高危行為時可以得到提醒甚至直接對相關(guān)不良行為報錯。
當(dāng)然,蕭天沒有這么自覺的,只是蕭天跟他們說了,他們立刻就又私發(fā)了一個六萬的懸賞讓蕭天幫忙!
原本蕭天是不愿意的,因?yàn)槟侨煲呀?jīng)夠累的了,晚上都熬到凌晨三四點(diǎn),每天就睡三四個小時,這讓蕭天深刻的明白為什么程序員容易頭禿了。
雖然蕭天不愿意,但是奈何對面又把這個六萬的金額又加了四萬……
嗯,蕭天覺得這個功能也不是那么難,熬夜那就熬夜唄……
所以蕭天也是立刻就進(jìn)入狀態(tài)了,TCL號稱一切都是字符串,這甚至可以把系統(tǒng)庫函數(shù)/運(yùn)算符/關(guān)鍵字都給rename掉,然后自己寫一個替代品。
這給了它的用戶極大的自由度。
比如iTCL就是用命名空間模擬的面向?qū)ο笳Z法——這種語言仍然是面向過程的;但你可以自己定義一個class關(guān)鍵字(實(shí)質(zhì)上是一個過程),把它變得和一個真正的面向?qū)ο笳Z言幾乎一模一樣。
蕭天首先盯上的是它的過程/函數(shù)聲明關(guān)鍵字proc。
在這種語言里,你聲明一個函數(shù)fun,格式就是
proc fun(arg){
#body
}
它看似一個關(guān)鍵字;但TCL里一切都是字符串,因此這個proc實(shí)質(zhì)上是個函數(shù),它接受函數(shù)名、參數(shù)列表、函數(shù)體三個參數(shù)……
蕭天也是把系統(tǒng)的proc改名叫_sys_proc,自己寫了個proc;這樣當(dāng)用戶聲明一個函數(shù)/過程時,他的聲明將以字符串格式先傳給他。
這樣子的話蕭天就可以做一些修改,把一些邏輯插進(jìn)用戶編寫的代碼中,然后再把修改后的代碼傳給_sys_proc。
通過這種方式,蕭天就接管了TCL的一切;然后修改了它的異常/返回流程,識別出“用戶未捕捉的異常”。
畢竟蕭天是記錄了每個函數(shù)在某次被調(diào)用時、在調(diào)用鏈上所處的層級。尤其接近頂層尚未捕獲就會影響到當(dāng)前測試用例、當(dāng)前測試套甚至引起整個程序過早退出,這些都是要記錄的。
現(xiàn)在,當(dāng)程序出錯時,如果通過異常處理程序解決了問題、允許程序繼續(xù)執(zhí)行了,那么蕭天就不做任何動作。
但如果沒有處理異常、使得測試失敗甚至程序退出,那么蕭天就能在執(zhí)行下一條語句之前把整個調(diào)用鏈打印出來——從函數(shù)調(diào)用關(guān)系到每個函數(shù)的局部變量內(nèi)容、再到異常傳遞路徑,巨細(xì)靡遺。
這個設(shè)計相當(dāng)于函數(shù)返回時會多執(zhí)行幾條語句,把局部變量等信息保存在內(nèi)存中;只要程序不崩潰,那么這些信息就自動丟棄;而一旦程序要崩潰,它就會寫到磁盤文件中——蕭天自己搞了個日志滾動機(jī)制,專門記錄最近十次崩潰信息,并不會無限侵占磁盤空間。
通過這個東西,再付出微不可察的時間代價,蕭天給所有TCL程序增加了core dump功能。
這顯然是個重大利好。
這就是為什么他們?yōu)槭裁丛敢饣ㄙM(fèi)十萬請蕭天也幫忙做這個功能。
天井市,羽然科技公司。
“老大,我不理解,為什么你要花十萬給天天去做這個功能啊?我們自己也可以做啊?”
問話的是一個戴著眼鏡,頭發(fā)稀疏的年輕人。
“小李啊,那這個功能是誰提出來的?”
“是……天天……但是他只是提出來一個概念罷了啊。”
老大叫錢志海,是一個中年人了,他自己開了這個羽然科技公司,員工總共也就只有二三十位,其中程序組就只有四個人,加上他自己兼任總編程,相當(dāng)于是五個人,他的頭發(fā)已經(jīng)稀疏的不成樣子了,不過有個假發(fā)戴著,還是和一個油光滿面的中年人一樣。
錢志海看著小李,也就是他的程序組的大將,擁有著中級程序員實(shí)力的李明,語重心長的說道,“你不理解來問我,沒有錯,那你知道為什么老王老楊不來問我?”
“因?yàn)樗麄冎溃覀兂绦騿T也是有人情世故的,不是說一輩子和計算機(jī)打交道,就不需要人情世故,實(shí)際上,和計算機(jī)打交道的我們,不在本行業(yè)的人不需要人情世故那是很正常,但是在本行業(yè)里面,不知道人情世故,那是真的很可怕的一件事情,我希望你永遠(yuǎn)不會明白。”
“就簡單的說,你覺得天天技術(shù)怎么樣?”
李明皺了皺眉頭,最后也是嘆了口氣,“比我強(qiáng)很多,是個大神。”
“是啊,所以你要知道,如果我們向外求一個應(yīng)用的創(chuàng)意功能,也大概需要花費(fèi)五六萬,那我如果給你們做的話,你們的確是也能夠做得出來,但是確定有這個天天本人知道的更清楚嗎?而且就技術(shù)而言,你們覺得做完這個功能會沒有BUG嗎?”
“如果有BUG,那你有把握找的出來嗎?”
“我知道你想說有把握,但是我們的這個時間花費(fèi)在這里,是不是不太值得?”錢志海笑了笑,“而我用十萬懸賞交給這個天天去做,不但能做的更好一點(diǎn),以后要是功能出現(xiàn)BUG了,那也不需要我們?nèi)フ遥藛幔慷夷阋彩强戳诉@個天天的個人資料吧,最近才開始瘋狂接任務(wù),我們將這個給他,也是相當(dāng)于給了他一個人情,一個大神的人情,你覺得怎么樣呢?”
李明這才有點(diǎn)明白過來,老大為什么是老大,那是因?yàn)槔洗笠呀?jīng)不僅僅是技術(shù)人員,他同時還是一名合格的老板。
…………
另一邊的蕭天自然是不知道,哪怕知道了,也覺得這是對雙方都有利的,不過有一點(diǎn)有些人猜錯了,他不是為了錢,而是他熟悉一下能力而已。
不過也不阻礙蕭天想著為什么,“可能想讓我有售后服務(wù)吧……畢竟我在他們眼里就相當(dāng)于大神一樣的人物。”
接下來的幾天,蕭天就繼續(xù)的忙碌著他的功能開發(fā)了。
這個功能也挺實(shí)用的,如果你不想使用,那么不要import DebugTools即可——就是把它做到了debug工具庫中,你導(dǎo)入這個庫,它就立即起作用;你不導(dǎo)入,那就不需要付出任何代價。
因此,這個功能肯定一寫出來就會受到歡迎的。
之后的幾天,蕭天發(fā)現(xiàn)了這個功能要比想象中的要好編寫。
完成的速度很快,蕭天覺得應(yīng)該是牛人程序員經(jīng)驗(yàn)知識幫他少走了不少路,所以才能夠這么快速大大的縮短了時間。
所以也就在三天后,蕭天就已經(jīng)完成了這個功能的編程,當(dāng)然也是離不開他的熬夜歷程。
所以在提交懸賞之后,蕭天終于是松了一口氣,他也覺得新能力不錯,是時候得籌備自己的公司了。
而另一邊,天井市,羽然科技公司。
錢志海就利用這個功能,便通知相關(guān)項目組,讓他們在自己的項目開頭import DebugTools。
剛好有個測試任務(wù)。
所以沒一會兒,他們就排查到了因?yàn)檫@個功能而意外收獲的另外一個輔助庫的BUG。
錢志海等幾人大眼瞪小眼。
尤其是李明,用目瞪口呆都不為過,“這個功能怎么像個利器一樣啊,我們沒有找他,他都額外的給我們發(fā)現(xiàn)了輔助庫另外的漏洞。”
錢志海也是心中一動,他非常的想把這個天天給拉到他們的公司來,這妥妥的都是大公司精英級別的程序員啊!
他們這個小公司雖然發(fā)展的也還行,但是也僅僅是還行罷了,如果能夠讓天天加入他們,錢志海相信他們的公司絕對能夠再創(chuàng)一個新高!
但是……
像天天這樣的大神,工資肯定是很高的,就比如那些大公司里面的精英程序員,月入十萬都是保底,而且還有獎金分紅,而他錢志海能拿出什么來籠絡(luò)天天大神呢?
不說其他的,就光一個月薪十萬,錢志海就拿不出手,也不是說出不起,只是公司還有其他方方面面也要打點(diǎn),這十萬一拿,他們的現(xiàn)金流就更加的不便了。
所以,想要邀請?zhí)焯齑笊瘢X志海也就只能在心里面想一想,不過他還是看了一眼自己的這幾個骨干程序員,“天外有天,人外有人,我們還需要努力啊。不過現(xiàn)在既然發(fā)現(xiàn)了這個BUG,那就趕緊給它解決吧。”
幾個人頓時開始來修復(fù)漏洞,首先拿到調(diào)用棧信息之后,一會兒時間就很容易的追查到了根源。
錢志海一行人看著這個,都是有些面面相覷。
“怎么是這個……”
這是當(dāng)年羽然科技公司實(shí)現(xiàn)時的疏忽:在某個函數(shù)中,他們聲明了一個局部變量,這個變量和同一命名空間的另一個變量名字極為相似,但命名風(fēng)格(首字母是否大寫之類)和其他代碼不太一致。
當(dāng)時他們是為了規(guī)避不同作用域的命名沖突才這樣命名的。
但到了后面,他們?nèi)匀涣?xí)慣性的用了“正常”的命名,也可能是選錯了編輯器自動提示選項。
這就相當(dāng)于丟開局部變量,用了命名空間的外部變量;但從上下文看,這里就不應(yīng)該碰外部那個同名變量。
用偽碼表示大概是這樣:
class OneClass {
packageNameItems = null;
....
void funName1(arg){
//initial packageNameItems
packageNameItems = arg;
//other...
}
string funName2(){
PackageNameItems = extractPureInfo(packageNameItems);
//do sth
....
result = getItemFrom(packageNameItems, itemName)//1
//do sth
....
return result
}
}
從那里分析,在//1處,本應(yīng)該是從已經(jīng)解包過的PackageNameItems中,取它的第N項;但這里誤傳入了解包前的packageNameItems。
似乎輸入文本可能會發(fā)生幾種情況,當(dāng)然多數(shù)情況不需要進(jìn)一步處理,直接用外部那個變量就行,此時兩個變量內(nèi)容一致,不會觸發(fā)bug;但少數(shù)情況下,外部那個變量需要進(jìn)一步處理,這才能提取到正確的內(nèi)容。
這種情況下,兩個變量內(nèi)容不同,誤用了前一個變量就讀不到正確數(shù)據(jù)了。
這是個極為隱蔽的邏輯錯誤。
其實(shí)和變量作用域相關(guān)的故障都很隱蔽。
李明拿著整個調(diào)用鏈的詳細(xì)記錄,也是看了好幾遍才發(fā)覺這兩個變量的名字似乎有些意思,這才沿著這條線追查下去……
總之,意外的輸出信息弄得他們一臉懵逼,因?yàn)檫@時候根本就不應(yīng)該有這種信息,也幸好檢查條件設(shè)的比較窄,只有正常返回可通過,其他一概拋異常崩掉——于是這個異常就被葉新晨的debug工具抓到,自動記錄了調(diào)用棧信息。
所以說為什么之前錢志海等幾人會驚訝,因?yàn)檫@個功能給他們抓到了一個BUG。
還好這是個極為簡單的bug,只需把最后那次訪問時,首字符小寫的變量名改成大寫,故障就不再復(fù)發(fā)。
其實(shí)就這么簡單個首字符大小寫搞錯、誤訪問了外部變量的BUG,羽然科技公司在黑土平臺上的懸賞單也是掛了有兩三年了,前前后后換了很多人經(jīng)手,但就是沒人能抓到它。
最終,這個簡單又奇葩的bug竟然被天天大神的一個功能給抓住了。
不得不說這真的是意外之喜。
“真想見識見識天天這樣的大神是什么樣的……”
………