title: Writing Bug Free C code chapter 1 Understand Why Bugs Exist
date: 2017-06-13 18:26:31
tags:
本翻譯僅供參考/博客湊數(shù)/多數(shù)翻譯是意譯,拿不準(zhǔn)的部分會加英語原文
Chapter 1: Understand Why Bugs Exist/理解為什么有bug
在軟件開發(fā)迭代中為啥老是有bug悄悄溜進(jìn)來喉悴?花費(fèi)時間來理解為什么bug存在是寫出bug-free代碼的第一步鳄抒。第二步則是采取行動制定策略去減少問題/檢測問題拜轨。更重要的是要讓整個團(tuán)隊明白這些新的策略连茧。
筆者的一個好朋友工作在一個特別的公司,會對他寫的代碼和模塊使用運(yùn)行時參數(shù)校驗(yàn)(run-time parameter validation)郊艘。這是一個好主意声旺,但這種強(qiáng)制的做法可能會使其他程序員不太情愿。有一天朋友修改了一點(diǎn)舊代碼舰蟆,然后他加上了參數(shù)校驗(yàn)趣惠。他測試了他的代碼然后就傳到代碼庫了狸棍,幾周之后這個代碼調(diào)用老代碼(一年前的)就會顯示參數(shù)錯誤了。但是有些程序員想把這個參數(shù)校驗(yàn)去掉味悄。他們認(rèn)為有錯誤日志打印草戈,不可能是老代碼有問題,肯定是新加的參數(shù)校驗(yàn)錯了侍瑟。
這就是個極端的例子唐片,但也足夠說明在一個編程項目中必須讓團(tuán)隊中每個人理解這種策略施行。
1.1 小項目 vs. 大項目
如果你需要寫一個hex dump工具 (就叫它DUMP),這個程序需要接收命令行上一個你想顯示的文件名字作為參數(shù)丢习,能寫出一個沒有bug的代碼嗎牵触?或許是的,因?yàn)檫@個項目很小咐低,定義良好且隔離沒有什么交互
因此如果你被要求寫一個項目(叫ALPHA),一個你們公司集中為其他公司攜的項目揽思。這個項目需要幾百上千行代碼而且已經(jīng)有十個程序員已經(jīng)在這個項目上工作了。交付日期馬上就到了见擦,公司需要你的聰明才智钉汗,你認(rèn)為可以馬上跳進(jìn)這個團(tuán)隊并且寫出新的代碼并且不引入bug?我不能鲤屡,要是沒有方法策略來捕捉錯誤的話任何新手都會引入bug损痰。
思考一下你現(xiàn)在處理的最大的項目,有多少頭文件酒来,并且頭文件里都有什么卢未?有多少源代碼文件,并且里面都有什么堰汉?你處理DUMP這種小工具毫無問題辽社,那為啥你處理這個大項目就這么難呢?為啥大項目不像十個一百個小項目那樣簡單翘鸭?
編程原則必須新手友好滴铅,新手進(jìn)入項目不至于引入新bug
咱們研究研究你的小項目。由幾個頭文件和實(shí)現(xiàn)文件組成就乓,頭文件有函數(shù)原型汉匙,數(shù)據(jù)結(jié)構(gòu)聲明,宏定義生蚁,typedef定義等噩翠,你啥都知道,因?yàn)槲募銐蛏偈厣欤隳芴幚淼粢锩耄F(xiàn)在,把它乘十乘百尼摹,突然這個項目就變得不可管理了见芹。
你的頭文件里有太多東西要管理剂娄,這個項目需要支持,你增加人數(shù)處理這個項目讓它更快完成玄呛,但是這只會加重問題阅懦,因?yàn)楝F(xiàn)在有更多的人向頭文件中加入信息且其他人需要了解,這就是所有大項目都會陷入的一個惡性循環(huán)徘铝。
1.2 頭文件里太多數(shù)據(jù)結(jié)構(gòu)
大項目有一個明顯的問題信息太多是需要花一段時間來熟悉數(shù)據(jù)結(jié)構(gòu)耳胎。如果能減少這些信息,這個過程可能會簡單惕它,因?yàn)槟阈枰私獾臄?shù)據(jù)結(jié)構(gòu)少了怕午。
根本問題是頭文件里面放了太多的信息,主要貢獻(xiàn)者就是數(shù)據(jù)結(jié)構(gòu)聲明淹魄。當(dāng)你開始一個項目郁惜,你在頭文件里放幾個聲明,項目進(jìn)行中甲锡,你就越放越多兆蕉。等你反應(yīng)過來已經(jīng)是一團(tuán)亂麻了。你的實(shí)現(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ù)聲明都得放在頭文件里包蓝,這樣所有的實(shí)現(xiàn)文件都能直接訪問,這佯為他贏得了速度優(yōu)勢企量,他的產(chǎn)品也更高級一些养晋。
這樣可能在他產(chǎn)品的第一版有用,當(dāng)他的產(chǎn)品的規(guī)模越來越大梁钾,達(dá)到臨界點(diǎn),大量的公共公共數(shù)據(jù)聲明導(dǎo)致無法管理逊抡。他的工作有麻煩了姆泻。這個策略在小規(guī)模的項目上工作的很好,但是在大規(guī)模的項目中遺憾的失敗冒嫡。優(yōu)秀的小項目早晚會變成大項目拇勃。
要明白你的編程方法應(yīng)該是融洽的,在大小項目上都行得通的孝凌。
1.4 太多全局變量
全局變量應(yīng)該盡量避免方咆。這種用法在大的應(yīng)用上有局限。當(dāng)一個較大的應(yīng)用變的越來越大蟀架,全局變量的數(shù)目變的越來越多瓣赂。等你反應(yīng)過來榆骚,你的全局變量已經(jīng)多到你管不過來了。
當(dā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本身揪惦,
一個高級點(diǎn)的例子就是內(nèi)存泄露,大多數(shù)情況內(nèi)存泄露不會直接造成問題罗侯,直到內(nèi)存耗盡為止器腋,內(nèi)存耗盡就是結(jié)果,你最終找到了導(dǎo)致內(nèi)存耗盡的那一行代碼并且回收了這塊內(nèi)存钩杰,看上去bug已經(jīng)fixed了纫塌,但是并沒有。
隱藏的內(nèi)存泄露問題仍然在你的代碼里讲弄。你需要一個堆管理模塊來告訴你哪里內(nèi)存泄露了措左,而不是自己花費(fèi)時間來追蹤內(nèi)存泄露。徹底額的解決這個問題避除,堆管理模塊會告訴你具體到細(xì)節(jié)怎披,哪里出現(xiàn)了泄露。第五節(jié)會仔細(xì)討論這個問題
1.7 不可維護(hù)的代碼
通常遇到維護(hù)他人寫好的代碼瓶摆,修改bug或者添加新功能凉逛,我不知道你怎么想,對我來說這不是什么愉悅的體驗(yàn)群井,通常代碼不好理解需要花費(fèi)時間來琢磨代碼流程究竟是什么状飞。
堅持寫別人能理解的代碼
//正在翻譯的我不是這么認(rèn)為的,我感覺需要有恰當(dāng)?shù)淖⑨?
總之明白最后有人會看你的代碼,所以盡量寫的不要太模糊诬辈。除非注釋清晰文檔明確
//果然作者也是這么想的酵使。
1.8 別用微軟的內(nèi)置調(diào)試器
不細(xì)說
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