避坑 | 為什么我總寫 Bug ?
本文轉載自微信公眾號「程序員魚皮」,作者魚皮。轉載本文請聯系程序員魚皮公眾號。
大家好,我是魚皮。
寫代碼的過程中,難免會出現各種各樣的 Bug。但實際上,很多 Bug 產生的原因是類似的。于是我總結了一些自己學編程時寫 Bug 的誘因,希望大家引以為戒,在以后寫代碼的時候能更多注意。
常見 Bug 誘因匯總
中文編碼
下面是兩行最最最簡單的 Java 代碼,上面的代碼能運行,下面的代碼會報錯:
- // 教程中的,能運行
- System.out.println("Hello!");
- // 我寫的,會報錯
- System.out.println("Hello!");
明明我的代碼和教程中的一模一樣,為啥就是運行不了呢?
這是初學編程的同學總會遇到的一個問題,仔細一看,原來是行尾的分號誤用成中文的了。。。
這種 Bug 往往都是由于剛開始學編程時不注意或不習慣輸入法的切換而導致的,不過寫一段時間代碼后,就會好很多。而且一般編輯器是能夠識別出錯誤位置的,根據報錯信息去修改就好了。
編輯器識別出中文字符報錯
此外,有時我不小心把項目文件名從英文改成了中文,也會出現亂碼、無法讀取文件之類的問題。
代碼不規范
我以前不注意代碼規范,覺得反正是我自己寫的代碼,寫的快、寫的爽就完事了,管那么多干嘛?
但后來因為變量命名太過隨意,導致自己寫的代碼自己都看不懂,更別提其他人來閱讀和協作開發了。
命名不規范
就連之前粗心拼錯的變量名也根本不敢亂改,生怕漏改了一個地方,就會報找不到變量的錯誤了!
復制粘貼
復制粘貼可以說是我寫代碼時用的最多的技能了。
正常操作是:3 秒粘貼一個文件,隨便改兩下,代碼能跑就行。
復制粘貼雖然好,但稍有不注意,可能就會漏修改一些變量名或注釋,比如下圖的 student :
這樣的次數多了,往往會導致整個項目中出現很多相同的變量,其他同學要引入時,根本不知道應該選哪個!
硬編碼
寫代碼時經常會用到一些常量,就是固定的值,比如網站的地址、最大最小值、機器的 IP 地址等。
有時,為了圖省事,我就是不單獨為這些值定義變量。哪里用到這些值,我就復制粘貼一遍,直接寫死到代碼里,比如:
- // 連接數據庫,IP 寫死
- DB db = new DB("10.0.0.1");
這樣雖然簡單粗暴,但假如哪一天這些死值需要修改了,就得從所有文件中一個個去找用到這些值的代碼,再一個個改掉,不僅麻煩,還很容易出現遺漏,從而產生 Bug。
未釋放資源
想從數據庫中獲取數據,就要先和數據庫建立連接,占用連接資源。
數據庫連接
拿到需要的數據后呢,我就忘了要把資源進行釋放(close),結果導致數據庫連接很快被占滿,其他程序想訪問都訪問不了,導致很多功能失效。
不僅是新手,甚至有幾年編程經驗的同學都可能會犯這個錯,因為不釋放資源并不會功能的可用性,而且不壓測的話很難發現這個 Bug。
此外,還有 HTTP 連接、文件輸入輸出流,這些都是資源,都要注意是否需要手動釋放,稍有不慎,就會導致資源泄露的 Bug。
圈復雜度過高
圈復雜度是衡量代碼復雜度的標準,簡單地說,if / else 分支越多,圈復雜度越大,往往表示代碼越復雜。
圈復雜度
記得我就寫過一個特別復雜的邏輯,幾十個分支語句一層套一層:
- if (xxx) {
- } else if (xxx) {
- if (xxx) {
- if (xxx) {
- } else if (xxx) {
- if (xxx) {
- 💩
- }
- }
- }
- }
起初是懶得去優化代碼,但等到后來意識到情況不妙,想優化代碼時,卻發現這屎山已經動不得了。不光別人看不懂,我自己都看不懂了!
這種代碼一旦要加增改邏輯,就很容易出現 Bug。所以建議在寫復雜邏輯前先畫流程圖,理清楚代碼、多寫注釋,還可以適當地用抽象、封裝、設計模式之類的技術來減少代碼的圈復雜度。
依賴沖突
依賴 是指我們項目中要用到的框架、類庫等等別人寫好的代碼和工具。
像我以前做項目圖省事,要用到什么庫都往項目里塞,而且都用最新版本的。直到工作后才發現,對于一個大項目,很多人同時開發,往往要引入很多很多依賴,稍有不慎就產生 依賴沖突 。
各種項目依賴
比如我給類庫 A 引入了類庫 C 的 1.0 版本,類庫 B 引入了類庫 C 的 2.0 版本,那如果項目要同時引入類庫 A 和類庫 B,到底該用類庫 C 的哪個版本呢?
依賴沖突的后果往往就是項目起不來,更嚴重的是直到項目執行到沖突的函數時才突發 Bug。
不區分環境
以前,我做網站時為了方便,在自己電腦上開發時,和已上線的項目用的是同一套環境,連接的是同一個數據庫。
結果有一天,我就忘記了這個事,在開發時造了一條假的不行的假數據,還不小心上傳了我的玉照:
結果大意了,這條數據實際上被插入到了線上的數據庫中,導致線上幾萬個用戶全都能看見。
這還是小事,萬一你在本地開發時寫了個 Bug,不小心把線上數據全給刪了,那真的是要欲哭無淚了!
不做自測
企業開發中,測試是很重要的。一般情況下,除了測試同學要設計用例外、開發同學也要寫單元測試來自測。
像我以前就很自信,自己寫好的代碼能跑就行,從來不測試,就是一把梭!
但進入企業工作后,我發現不寫單元測試真的很容易出現各種細節問題。可能下個版本改了行代碼,之前正常的功能就突然報錯了。
而且越往后發現問題,修改的成本就越大,要花更多時間去排查和修改 Bug,加班也在所難免。
不做評估
以前在學校寫代碼,我一般就是學什么技術就用什么、會什么就用什么,也不去管是否能滿足性能、數據量的要求。
進入大公司后,才意識到系統評估和技術選型的重要性。一般要評估系統的并發量、數據的量級、接口時延等,根據這些來選擇合適的技術。
比如公司有一個千萬數據量的項目,如果我不做評估和選型,無腦用 MySQL 數據庫、并且不做任何優化,那這個系統估計分分鐘掛掉。
自作主張
在學校的時候習慣了單兵作戰,想改什么代碼就改什么,也不去思考對現有系統、對其他系統的影響。
但在企業中,尤其是調用關系很復雜的鏈路系統中,如果你修改了接口的返回值,或者改變了接口的并發量、返回時長等。分分鐘,依賴你接口的同事就都來登門拜謝了。
為了預防這種情況,建議整理下自己的接口依賴哪些接口、又被哪些接口調用。在你需要改動代碼時,需要評估改動對于其他系統的影響,并且及時通知相關負責人。而不是自作主張,只關注自己的一畝三分地。
文檔讀不全
現在的技術框架啥的,一般都提供了非常詳細的使用文檔。
技術文檔
但我以前讀文檔時,為了追求效率,只要看到有自己需要的函數,立刻就直接復制過來用了,而不是選擇把文檔完整讀完。
結果呢,因為盲目自信,很多文檔中重點強調的注意事項沒有看到,導致了很多傻不拉幾的低級 Bug,還在網上到處搜解決方案,浪費時間。
版本號錯誤
讀文檔和看教程學技術可不一樣,不要盲目追求最新的,而是要根據實際情況,選擇和自己項目中引入一致的版本。
記得我剛開始跟著文檔學編程時,寫的很多 Bug 都是因為閱讀文檔前沒有注意版本號,導致很多使用到的語法不是被淘汰了就是還不支持,然后就會懷疑人生。
注意選擇版本號
不了解需求
寫代碼之前,一定要了解需求,就是要做什么?為什么要做?
否則就會像我剛進入公司時,有個功能點沒搞懂,也不去問、不敢問產品同學,全靠自己自由發揮。就最后哪怕我的代碼能運行、沒 Bug,但并不是用戶想要的,那不就表示:我程序的存在本身就是個 Bug?
不做設計
寫代碼和蓋房子一樣,一定要先想好怎么寫代碼,再去寫。
尤其是業務流程復雜的時候,不要仗著自己聰明或者經驗豐富,就不寫方案、不做設計,而是直接打開編輯器就寫代碼。
這樣做很容易遺漏一些要考慮的關鍵點,說不定直到最后,才發現有大問題,結果整段邏輯都要全部刪掉重新寫!效率反而更低。