title: Writing Bug Free C code chapter 1 Understand Why Bugs Exist
date: 2017-06-13 18:26:31
tags:
本翻譯僅供參考/博客湊數(shù)/多數(shù)翻譯是意譯,拿不準的部分會加英語原文
Chapter 1: Understand Why Bugs Exist/理解為什么有bug
在軟件開發(fā)迭代中為啥老是有bug悄悄溜進來?花費時間來理解為什么bug存在是寫出bug-free代碼的第一步。第二步則是采取行動制定策略去減少問題/檢測問題。更重要的是要讓整個團隊明白這些新的策略。
筆者的一個好朋友工作在一個特別的公司,會對他寫的代碼和模塊使用運行時參數(shù)校驗(run-time parameter validation)。這是一個好主意,但這種強制的做法可能會使其他程序員不太情愿。有一天朋友修改了一點舊代碼,然后他加上了參數(shù)校驗。他測試了他的代碼然后就傳到代碼庫了,幾周之后這個代碼調(diào)用老代碼(一年前的)就會顯示參數(shù)錯誤了。但是有些程序員想把這個參數(shù)校驗去掉。他們認為有錯誤日志打印,不可能是老代碼有問題,肯定是新加的參數(shù)校驗錯了。
這就是個極端的例子,但也足夠說明在一個編程項目中必須讓團隊中每個人理解這種策略施行。
1.1 小項目 vs. 大項目
如果你需要寫一個hex dump工具 (就叫它DUMP),這個程序需要接收命令行上一個你想顯示的文件名字作為參數(shù),能寫出一個沒有bug的代碼嗎?或許是的,因為這個項目很小,定義良好且隔離沒有什么交互
因此如果你被要求寫一個項目(叫ALPHA),一個你們公司集中為其他公司攜的項目。這個項目需要幾百上千行代碼而且已經(jīng)有十個程序員已經(jīng)在這個項目上工作了。交付日期馬上就到了,公司需要你的聰明才智,你認為可以馬上跳進這個團隊并且寫出新的代碼并且不引入bug?我不能,要是沒有方法策略來捕捉錯誤的話任何新手都會引入bug。
思考一下你現(xiàn)在處理的最大的項目,有多少頭文件,并且頭文件里都有什么?有多少源代碼文件,并且里面都有什么?你處理DUMP這種小工具毫無問題,那為啥你處理這個大項目就這么難呢?為啥大項目不像十個一百個小項目那樣簡單?
編程原則必須新手友好,新手進入項目不至于引入新bug
咱們研究研究你的小項目。由幾個頭文件和實現(xiàn)文件組成,頭文件有函數(shù)原型,數(shù)據(jù)結(jié)構(gòu)聲明,宏定義,typedef定義等,你啥都知道,因為文件足夠少,你能處理掉,現(xiàn)在,把它乘十乘百,突然這個項目就變得不可管理了。
你的頭文件里有太多東西要管理,這個項目需要支持,你增加人數(shù)處理這個項目讓它更快完成,但是這只會加重問題,因為現(xiàn)在有更多的人向頭文件中加入信息且其他人需要了解,這就是所有大項目都會陷入的一個惡性循環(huán)。
1.2 頭文件里太多數(shù)據(jù)結(jié)構(gòu)
大項目有一個明顯的問題信息太多是需要花一段時間來熟悉數(shù)據(jù)結(jié)構(gòu)。如果能減少這些信息,這個過程可能會簡單,因為你需要了解的數(shù)據(jù)結(jié)構(gòu)少了。
根本問題是頭文件里面放了太多的信息,主要貢獻者就是數(shù)據(jù)結(jié)構(gòu)聲明。當你開始一個項目,你在頭文件里放幾個聲明,項目進行中,你就越放越多。等你反應(yīng)過來已經(jīng)是一團亂麻了。你的實現(xiàn)文件里面有數(shù)據(jù)結(jié)構(gòu)的
全部(The majority of your source files have knowledge of the data structures and directly reference elements from the structures.)
需要減少數(shù)據(jù)結(jié)構(gòu)的方法
考慮如果你改動多個數(shù)據(jù)結(jié)構(gòu)。就得把所有用到的地方都得重新編譯一邊。(Making changes in an environment where many data structures directly refer to other data structures becomes, at best, a headache. Consider what happens when you change a data structure. This change forces you to recompile every source file that directly, or more importantly indirectly, refers to the changed data structure. This happens when a source file refers to a data structure that refers to a data structure that refers to the changed data structure. A change to the data structure may force you to modify some code, possibly in multiple source files. )
在第四節(jié)用類來解決這個問題
1.3 技巧與規(guī)模無關(guān)
你的方法應(yīng)該是融洽的,項目規(guī)模無關(guān)
比如說一個程序員joe制定了一個規(guī)則,所有的數(shù)據(jù)聲明都得放在頭文件里,這樣所有的實現(xiàn)文件都能直接訪問,這佯為他贏得了速度優(yōu)勢,他的產(chǎn)品也更高級一些。
這樣可能在他產(chǎn)品的第一版有用,當他的產(chǎn)品的規(guī)模越來越大,達到臨界點,大量的公共公共數(shù)據(jù)聲明導(dǎo)致無法管理。他的工作有麻煩了。這個策略在小規(guī)模的項目上工作的很好,但是在大規(guī)模的項目中遺憾的失敗。優(yōu)秀的小項目早晚會變成大項目。
要明白你的編程方法應(yīng)該是融洽的,在大小項目上都行得通的。
1.4 太多全局變量
全局變量應(yīng)該盡量避免。這種用法在大的應(yīng)用上有局限。當一個較大的應(yīng)用變的越來越大,全局變量的數(shù)目變的越來越多。等你反應(yīng)過來,你的全局變量已經(jīng)多到你管不過來了。
當你用到全局變量的時候,想想為什么你需要直接訪問全局變量。把一個模塊函數(shù)調(diào)用放在變量那里效果不是一樣(Would a function call to the module where the variable is defined work just as well? )大多數(shù)情況都可以替代。如果一個全局變量被修改了,你需要問你自己這個全局變量的影響,如果被一個函數(shù)調(diào)用代替,那就把問題交給函數(shù)處理
暴漏給多個文件的變量應(yīng)該避免
有些全局變量影響不大,無論項目多大,全局變量都不應(yīng)該過多。
1.5 依靠debugger
在減少bug的技巧中debugger最有效,但是這通常是你的最后手段,出現(xiàn)了這種問題,你前面的bug-free技巧方法已經(jīng)出現(xiàn)問題了。
不要過分依賴debugger來捕捉bug,要用你自己之前設(shè)定的規(guī)則與技巧。
1.6 解決現(xiàn)象,而不是問題
比如你在你的代碼里遇到了個bug,//這段沒什么意思不翻譯了
改bug時要改掉隱藏在bug背后的原因不要僅僅改掉bug本身,
一個高級點的例子就是內(nèi)存泄露,大多數(shù)情況內(nèi)存泄露不會直接造成問題,直到內(nèi)存耗盡為止,內(nèi)存耗盡就是結(jié)果,你最終找到了導(dǎo)致內(nèi)存耗盡的那一行代碼并且回收了這塊內(nèi)存,看上去bug已經(jīng)fixed了,但是并沒有。
隱藏的內(nèi)存泄露問題仍然在你的代碼里。你需要一個堆管理模塊來告訴你哪里內(nèi)存泄露了,而不是自己花費時間來追蹤內(nèi)存泄露。徹底額的解決這個問題,堆管理模塊會告訴你具體到細節(jié),哪里出現(xiàn)了泄露。第五節(jié)會仔細討論這個問題
1.7 不可維護的代碼
通常遇到維護他人寫好的代碼,修改bug或者添加新功能,我不知道你怎么想,對我來說這不是什么愉悅的體驗,通常代碼不好理解需要花費時間來琢磨代碼流程究竟是什么。
堅持寫別人能理解的代碼
//正在翻譯的我不是這么認為的,我感覺需要有恰當?shù)淖⑨?
總之明白最后有人會看你的代碼,所以盡量寫的不要太模糊。除非注釋清晰文檔明確
//果然作者也是這么想的。
1.8 別用微軟的內(nèi)置調(diào)試器
不細說
1.9 總結(jié)
- The first step in writing bug-free code is to understand why bugs exist. The second step is to take action. That is what this book is all about.
- Programming methodologies that are developed to prevent and detect bugs must work equally well for both small and large programming projects.
- A technique that helps eliminate data structure declarations from include files needs to be found. Doing so will allow programmers to come up to speed on an existing project much quicker.
- Global variables that are known to more than one source file should be avoided. Global variables make it hard to maintain a project.
- Debuggers should be used only as a last resort. Having to resort to a debugger means that your programming methodologies used to detect bugs have failed.
- When you fix a bug, make sure you are really fixing the underlying cause of the bug and not just the symptom of the bug. Ask yourself how many times you have fixed the same type of bug.
- Strive to write code that is straightforward and easily understandable by others. Avoid writing code that pulls a lot of tricks.
- Finally, make sure that you use the Windows debug kernel all the time. It contains extra error checking that can automatically detect certain types of bugs that go undetected in the retail release of Windows