程序員在代碼里面“埋炸彈”這件事情其實(shí)已經(jīng)屢見不鮮了,所謂“炸彈”其實(shí)就是比較嚴(yán)重的BUG,而我們公司最近新上的一個(gè)項(xiàng)目就遇到了這種事情,負(fù)責(zé)這個(gè)項(xiàng)目某個(gè)模塊的程序員竟然一不小心埋了一個(gè)特大的“炸彈”,最后老板連夜讓公司財(cái)務(wù)給程序員買機(jī)票,說什么也要在這個(gè)“炸彈”爆炸前把問題給處理掉,到底發(fā)生了什么事情呢?

打開網(wǎng)易新聞 查看精彩圖片

先說下這個(gè)程序員老A吧,老A在運(yùn)動(dòng)控制領(lǐng)域其實(shí)已經(jīng)深耕多年了,但是不代表他就不會(huì)出現(xiàn)比較嚴(yán)重的錯(cuò)誤!

老A負(fù)責(zé)的這個(gè)模塊實(shí)際上是一個(gè)運(yùn)動(dòng)控制模塊,模塊主要任務(wù)就是通過程序來操縱軸到指定位置進(jìn)行生產(chǎn),您可以把客戶那邊需要生產(chǎn)的東西看作“棋盤”,老A需要做的就是把“棋子”準(zhǔn)確得放到“棋盤”的每一個(gè)格子上。

但是,理想很豐滿,現(xiàn)實(shí)很骨感,客戶在實(shí)際生產(chǎn)過程中,“棋子”其實(shí)很難做到100%準(zhǔn)確落到格子的正中心,所以,老A還需要做一件事情,就是根據(jù)客戶那邊視覺系統(tǒng)的檢測(cè)結(jié)果,對(duì)每次“棋子”的落點(diǎn)進(jìn)行校正處理。

具體的做法,就是每次在“落子”之前,都要檢查上一次“棋子”落的位置,然后跟“棋盤”標(biāo)準(zhǔn)點(diǎn)的位置進(jìn)行比較,然后進(jìn)行校正。

簡(jiǎn)單描述整個(gè)系統(tǒng)的運(yùn)行過程,大致就如上所說,但是實(shí)際上這個(gè)校正邏輯是非常復(fù)雜的,需要配合算法來實(shí)現(xiàn),而老A埋的“炸彈”其實(shí)就是在算法代碼里!

其實(shí),這個(gè)“炸彈”理解起來并不復(fù)雜,這需要從校正邏輯說起。

校正邏輯非常復(fù)雜,為了便于理解,我們直接跳過中間過程,看看邏輯最終需要實(shí)現(xiàn)的目的,而這個(gè)目的,就是要讓軸在每一次生產(chǎn)完一個(gè)產(chǎn)品后都往某一個(gè)方向偏移一點(diǎn),直至每個(gè)“棋子”的落點(diǎn)都離“格子”盡量得近位置為止。但是,在這個(gè)過程中,可能往單一方向移動(dòng),會(huì)出現(xiàn)判斷錯(cuò)誤的情況,因此,當(dāng)移動(dòng)特定次數(shù)以后,“棋子”的落點(diǎn)依然不標(biāo)準(zhǔn),反而和標(biāo)準(zhǔn)點(diǎn)的距離越拉越大的時(shí)候,需要往反方向移動(dòng),以此類推。

老A的邏輯就是這樣的,我們?cè)ǖ姆桨甘敲看紊a(chǎn)完一個(gè)產(chǎn)品,把軸往左邊偏移指定的距離,一共移動(dòng)10次,如果10次偏移完以后,檢測(cè)結(jié)果還是不好的,那么就反過來,把軸往右邊偏移10次。

在代碼里面,處理起來也很簡(jiǎn)單,就是每次生產(chǎn)完的時(shí)候,往數(shù)據(jù)庫(kù)存一個(gè)移動(dòng)次數(shù)的值,再存一個(gè)方向的值,當(dāng)次數(shù)大于等于10的時(shí)候,把次數(shù)清零,把方向值反過來即可。

那么,老A到底埋了一個(gè)怎樣的“炸彈”,要讓老板連夜組織人手去處理這個(gè)問題呢?

問題就出在移動(dòng)次數(shù)上,簡(jiǎn)單地說,老A其實(shí)在代碼里面判斷得很嚴(yán)謹(jǐn),但是最終在存儲(chǔ)移動(dòng)次數(shù)時(shí)卻沒存儲(chǔ)成功,這是咋回事呢?

道理其實(shí)很簡(jiǎn)單,那就是老A在存儲(chǔ)移動(dòng)次數(shù)時(shí),走得是更新數(shù)據(jù)庫(kù)表的邏輯,但是這個(gè)移動(dòng)次數(shù)表字段是后加的,而更新前需要將表數(shù)據(jù)先查出來,然后逐個(gè)字段更新,但是在數(shù)據(jù)庫(kù)更新語句里并沒有把這個(gè)字段的更新語句給加上去,最終導(dǎo)致這個(gè)字段的值始終都為0!

這會(huì)導(dǎo)致什么問題呢?那就是老A代碼中的對(duì)于偏移次數(shù)的判斷就失效了,這會(huì)導(dǎo)致軸會(huì)一直往一個(gè)方向偏移,最終“撞機(jī)”!

在運(yùn)動(dòng)控制領(lǐng)域,“撞機(jī)”是個(gè)很嚴(yán)重的問題,運(yùn)動(dòng)軸一般只在指定區(qū)域里作業(yè),軸如果超過一定的區(qū)域限制,那么就會(huì)產(chǎn)生很嚴(yán)重的后果。

那么“撞機(jī)”怎么理解呢?其實(shí)我們可以把運(yùn)動(dòng)軸看作一條船,船只能在水域行駛,“撞機(jī)”就好比船撞到了岸邊或者已經(jīng)駛上了岸,這肯定是不被允許的。

我們也可以想象一下,兩個(gè)都在工作的機(jī)械臂如果撞到了一起,會(huì)產(chǎn)生什么后果吧!所以“撞機(jī)”在很多情況下,后果非常嚴(yán)重。

當(dāng)然了,為了防止“撞機(jī)”出現(xiàn),設(shè)備在設(shè)計(jì)之初就已經(jīng)設(shè)計(jì)了“防撞”功能,會(huì)增加一定的限位措施,還是以船舉例子,您可以把限位措施看作有人在岸邊擺上了一層輪胎或者氣墊,當(dāng)船要撞上岸邊時(shí),這些輪胎或者氣墊可以給船起到緩沖作用,對(duì)船起到保護(hù)作用,此時(shí)船只要正確駛離岸邊即可。

但是,老A的代碼里面偏移次數(shù)這個(gè)變量的失效,當(dāng)發(fā)生第一次“撞機(jī)”以后,設(shè)備會(huì)進(jìn)行報(bào)警,但因?yàn)槊看纹贫纪粋€(gè)方向偏移,因此,即使報(bào)警取消了,設(shè)備下一次還會(huì)“撞機(jī)”報(bào)警,最終導(dǎo)致設(shè)備無法進(jìn)行正常生產(chǎn)。

好在客戶那邊到現(xiàn)在沒有反饋設(shè)備有“撞機(jī)”的情況出現(xiàn),就說明老A的那段有問題的代碼還沒被觸發(fā),說明客戶生產(chǎn)情況良好。但是,如果一旦出現(xiàn)某次檢測(cè)結(jié)果不好,觸發(fā)了老A的那段代碼邏輯,這個(gè)隱患就會(huì)出現(xiàn),所以,這個(gè)問題不能等!

結(jié)語

后來,老A趕了最早的飛機(jī)飛到客戶那里,隨便扯了個(gè)謊把程序給更新了,這個(gè)事情到現(xiàn)在老A都心有余悸,如果真的出現(xiàn)“撞機(jī)”的情況,用老A自己的話說:“真怕晚節(jié)不保了!”。

不過說起來,老A埋的這個(gè)“炸彈”其實(shí)還是挺低級(jí)的,只要仔細(xì)測(cè)試檢查就可以測(cè)試出來,也從側(cè)面證明了,不管是多么資深的程序員,也是會(huì)寫出低級(jí)錯(cuò)誤的代碼的!不出事,就是最大的幸運(yùn)了!讓我們引以為戒!