避坑 | 為什麼我總寫 Bug?

作者: 魚皮 來源:程式設計師魚皮

避坑 | 為什麼我總寫 Bug?

本文轉載自微信公眾號「程式設計師魚皮」,作者魚皮。轉載本文請聯絡程式設計師魚皮公眾號。

大家好,我是魚皮。

寫程式碼的過程中,難免會出現各種各樣的 Bug。但實際上,很多 Bug 產生的原因是類似的。於是我總結了一些自己學程式設計時寫 Bug 的誘因,希望大家引以為戒,在以後寫程式碼的時候能更多注意。

常見 Bug 誘因彙總

中文編碼

下面是兩行最最最簡單的 Java 程式碼,上面的程式碼能執行,下面的程式碼會報錯:

// 教程中的,能執行 System。out。println(“Hello!”); // 我寫的,會報錯 System。out。println(“Hello!”);

明明我的程式碼和教程中的一模一樣,為啥就是執行不了呢?

這是初學程式設計的同學總會遇到的一個問題,仔細一看,原來是行尾的分號誤用成中文的了。。。

這種 Bug 往往都是由於剛開始學程式設計時不注意或不習慣輸入法的切換而導致的,不過寫一段時間程式碼後,就會好很多。而且一般編輯器是能夠識別出錯誤位置的,根據報錯資訊去修改就好了。

避坑 | 為什麼我總寫 Bug?

編輯器識別出中文字元報錯

此外,有時我不小心把專案檔名從英文改成了中文,也會出現亂碼、無法讀取檔案之類的問題。

程式碼不規範

我以前不注意程式碼規範,覺得反正是我自己寫的程式碼,寫的快、寫的爽就完事了,管那麼多幹嘛?

但後來因為變數命名太過隨意,導致自己寫的程式碼自己都看不懂,更別提其他人來閱讀和協作開發了。

避坑 | 為什麼我總寫 Bug?

命名不規範

就連之前粗心拼錯的變數名也根本不敢亂改,生怕漏改了一個地方,就會報找不到變數的錯誤了!

避坑 | 為什麼我總寫 Bug?

複製貼上

複製貼上可以說是我寫程式碼時用的最多的技能了。

正常操作是:3 秒貼上一個檔案,隨便改兩下,程式碼能跑就行。

複製貼上雖然好,但稍有不注意,可能就會漏修改一些變數名或註釋,比如下圖的 student :

避坑 | 為什麼我總寫 Bug?

這樣的次數多了,往往會導致整個專案中出現很多相同的變數,其他同學要引入時,根本不知道應該選哪個!

避坑 | 為什麼我總寫 Bug?

硬編碼

寫程式碼時經常會用到一些常量,就是固定的值,比如網站的地址、最大最小值、機器的 IP 地址等。

有時,為了圖省事,我就是不單獨為這些值定義變數。哪裡用到這些值,我就複製貼上一遍,直接寫死到程式碼裡,比如:

// 連線資料庫,IP 寫死 DB db = new DB(“10。0。0。1”);

這樣雖然簡單粗暴,但假如哪一天這些死值需要修改了,就得從所有檔案中一個個去找用到這些值的程式碼,再一個個改掉,不僅麻煩,還很容易出現遺漏,從而產生 Bug。

未釋放資源

想從資料庫中獲取資料,就要先和資料庫建立連線,佔用連線資源。

避坑 | 為什麼我總寫 Bug?

資料庫連線

拿到需要的資料後呢,我就忘了要把資源進行釋放(close),結果導致資料庫連線很快被佔滿,其他程式想訪問都訪問不了,導致很多功能失效。

不僅是新手,甚至有幾年程式設計經驗的同學都可能會犯這個錯,因為不釋放資源並不會功能的可用性,而且不壓測的話很難發現這個 Bug。

此外,還有 HTTP 連線、檔案輸入輸出流,這些都是資源,都要注意是否需要手動釋放,稍有不慎,就會導致資源洩露的 Bug。

圈複雜度過高

圈複雜度是衡量程式碼複雜度的標準,簡單地說,if / else 分支越多,圈複雜度越大,往往表示程式碼越複雜。

避坑 | 為什麼我總寫 Bug?

圈複雜度

記得我就寫過一個特別複雜的邏輯,幾十個分支語句一層套一層:

if (xxx) { } else if (xxx) { if (xxx) { if (xxx) { } else if (xxx) { if (xxx) { } } } }

起初是懶得去最佳化程式碼,但等到後來意識到情況不妙,想最佳化程式碼時,卻發現這屎山已經動不得了。不光別人看不懂,我自己都看不懂了!

這種程式碼一旦要加增改邏輯,就很容易出現 Bug。所以建議在寫複雜邏輯前先畫流程圖,理清楚程式碼、多寫註釋,還可以適當地用抽象、封裝、設計模式之類的技術來減少程式碼的圈複雜度。

依賴衝突

依賴 是指我們專案中要用到的框架、類庫等等別人寫好的程式碼和工具。

像我以前做專案圖省事,要用到什麼庫都往專案裡塞,而且都用最新版本的。直到工作後才發現,對於一個大專案,很多人同時開發,往往要引入很多很多依賴,稍有不慎就產生 依賴衝突 。

避坑 | 為什麼我總寫 Bug?

各種專案依賴

比如我給類庫 A 引入了類庫 C 的 1。0 版本,類庫 B 引入了類庫 C 的 2。0 版本,那如果專案要同時引入類庫 A 和類庫 B,到底該用類庫 C 的哪個版本呢?

依賴衝突的後果往往就是專案起不來,更嚴重的是直到專案執行到衝突的函式時才突發 Bug。

不區分環境

以前,我做網站時為了方便,在自己電腦上開發時,和已上線的專案用的是同一套環境,連線的是同一個資料庫。

結果有一天,我就忘記了這個事,在開發時造了一條假的不行的假資料,還不小心上傳了我的玉照:

避坑 | 為什麼我總寫 Bug?

結果大意了,這條資料實際上被插入到了線上的資料庫中,導致線上幾萬個使用者全都能看見。

這還是小事,萬一你在本地開發時寫了個 Bug,不小心把線上資料全給刪了,那真的是要欲哭無淚了!

不做自測

企業開發中,測試是很重要的。一般情況下,除了測試同學要設計用例外、開發同學也要寫單元測試來自測。

像我以前就很自信,自己寫好的程式碼能跑就行,從來不測試,就是一把梭!

但進入企業工作後,我發現不寫單元測試真的很容易出現各種細節問題。可能下個版本改了行程式碼,之前正常的功能就突然報錯了。

而且越往後發現問題,修改的成本就越大,要花更多時間去排查和修改 Bug,加班也在所難免。

不做評估

以前在學校寫程式碼,我一般就是學什麼技術就用什麼、會什麼就用什麼,也不去管是否能滿足效能、資料量的要求。

進入大公司後,才意識到系統評估和技術選型的重要性。一般要評估系統的併發量、資料的量級、介面時延等,根據這些來選擇合適的技術。

比如公司有一個千萬資料量的專案,如果我不做評估和選型,無腦用 MySQL 資料庫、並且不做任何最佳化,那這個系統估計分分鐘掛掉。

避坑 | 為什麼我總寫 Bug?

自作主張

在學校的時候習慣了單兵作戰,想改什麼程式碼就改什麼,也不去思考對現有系統、對其他系統的影響。

但在企業中,尤其是呼叫關係很複雜的鏈路系統中,如果你修改了介面的返回值,或者改變了介面的併發量、返回時長等。分分鐘,依賴你介面的同事就都來登門拜謝了。

為了預防這種情況,建議整理下自己的介面依賴哪些介面、又被哪些介面呼叫。在你需要改動程式碼時,需要評估改動對於其他系統的影響,並且及時通知相關負責人。而不是自作主張,只關注自己的一畝三分地。

文件讀不全

現在的技術框架啥的,一般都提供了非常詳細的使用文件。

避坑 | 為什麼我總寫 Bug?

技術文件

但我以前讀文件時,為了追求效率,只要看到有自己需要的函式,立刻就直接複製過來用了,而不是選擇把文件完整讀完。

結果呢,因為盲目自信,很多文件中重點強調的注意事項沒有看到,導致了很多傻不拉幾的低階 Bug,還在網上到處搜解決方案,浪費時間。

版本號錯誤

讀文件和看教程學技術可不一樣,不要盲目追求最新的,而是要根據實際情況,選擇和自己專案中引入一致的版本。

記得我剛開始跟著文件學程式設計時,寫的很多 Bug 都是因為閱讀文件前沒有注意版本號,導致很多使用到的語法不是被淘汰了就是還不支援,然後就會懷疑人生。

避坑 | 為什麼我總寫 Bug?

注意選擇版本號

不瞭解需求

寫程式碼之前,一定要了解需求,就是要做什麼?為什麼要做?

否則就會像我剛進入公司時,有個功能點沒搞懂,也不去問、不敢問產品同學,全靠自己自由發揮。就最後哪怕我的程式碼能執行、沒 Bug,但並不是使用者想要的,那不就表示:我程式的存在本身就是個 Bug?

不做設計

寫程式碼和蓋房子一樣,一定要先想好怎麼寫程式碼,再去寫。

尤其是業務流程複雜的時候,不要仗著自己聰明或者經驗豐富,就不寫方案、不做設計,而是直接開啟編輯器就寫程式碼。

這樣做很容易遺漏一些要考慮的關鍵點,說不定直到最後,才發現有大問題,結果整段邏輯都要全部刪掉重新寫!效率反而更低。