自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

程序總出故障,這10個(gè)容易犯的編程錯(cuò)誤你避免了嗎?

譯文
開(kāi)發(fā) 開(kāi)發(fā)工具
為什么程序出故障?雖然自世界上第一位女程序員艾達(dá)·洛夫萊斯(Ada Lovelace)在上世紀(jì)第一次看到通用計(jì)算的潛力以來(lái)我們已取得了很大進(jìn)展,但是我們編寫的軟件還是錯(cuò)誤百出。這些年來(lái),盡管我們開(kāi)發(fā)出許多高級(jí)方法來(lái)確保代碼的成功,但是程序還是不斷的出故障。

【51CTO.com快譯】為什么程序出故障?雖然自世界上第一位女程序員艾達(dá)·洛夫萊斯(Ada Lovelace)在上世紀(jì)第一次看到通用計(jì)算的潛力以來(lái)我們已取得了很大進(jìn)展,但是我們編寫的軟件還是錯(cuò)誤百出。這些年來(lái),盡管我們開(kāi)發(fā)出許多高級(jí)方法來(lái)確保代碼的成功,但是程序還是不斷的出故障。

原因何在?

雖然這個(gè)問(wèn)題的答案多種多樣,但我們還是決定提供一個(gè)務(wù)實(shí)的答案。程序員難免犯錯(cuò)。他們有時(shí)馬虎了事。他們并不總是使用最佳工具或最佳實(shí)踐。

[[176050]]

我在加州大學(xué)伯克利分校教面向?qū)ο缶幊踢@門課,我在學(xué)校教優(yōu)秀編程實(shí)踐所花的時(shí)間與幫助學(xué)生理解代碼本身所花的時(shí)間相比只多不少。我在課堂上看到許多常犯的錯(cuò)誤,本文就介紹其中幾個(gè)常見(jiàn)錯(cuò)誤。

我還聯(lián)系上了西北理工大學(xué)工程學(xué)院的詹姆斯·A·康納(James A. Connor)教授,請(qǐng)他介紹其學(xué)生常犯的一些錯(cuò)誤。

我先來(lái)說(shuō)幾個(gè)。

第一個(gè)錯(cuò)誤:糟糕的注釋方法。

注釋是程序里面計(jì)算機(jī)并不執(zhí)行的那部分文本。它們被程序員寫成附注的形式,用來(lái)解釋代碼里面發(fā)生的情況。

我的好多學(xué)生避免給代碼添加注釋,也想不明白為何要占用實(shí)際編碼的時(shí)間去編寫一些注釋。我最實(shí)用的例子來(lái)自我自己的生活。

早在世紀(jì)之交前,我編寫了版本1.0的ZENPRESS,這是最古老的內(nèi)容管理系統(tǒng)之一。我預(yù)計(jì)它會(huì)帶來(lái)好幾年的文章。14年過(guò)后,它仍在管理許多文章,準(zhǔn)備好了75000篇文章和26億頁(yè)的內(nèi)容。

最后,它運(yùn)行所依賴的那個(gè)平臺(tái)過(guò)時(shí)了。我不得不回過(guò)頭去研究代碼。2009年,我把代碼從原始平臺(tái)移植到現(xiàn)代平臺(tái)。我最近不得不再次改動(dòng),因?yàn)镻HP一個(gè)關(guān)鍵的語(yǔ)言特性在版本升級(jí)后完全消失了。

[[176051]]

 

19年過(guò)后,我根本記不起所有這些代碼是怎么運(yùn)行的,但是由于我對(duì)代碼作了詳細(xì)的注釋,所以可以說(shuō)有了一份路線圖。我可以查看代碼,查看嵌入在代碼里面的注釋,然后進(jìn)行修改。

你在團(tuán)隊(duì)工作時(shí),或者你的軟件不歸你監(jiān)管時(shí),注釋也很重要。你的職業(yè)生涯可能發(fā)生變化,別人可能需要過(guò)來(lái)了解你的代碼。注釋將大有幫助。

第二個(gè)錯(cuò)誤:糟糕的變量命名。

我會(huì)繼續(xù)探討這個(gè)主題:通過(guò)語(yǔ)言讓代碼一目了然。我會(huì)用一個(gè)例子來(lái)表明這點(diǎn)。假設(shè)你駕駛一輛每加侖汽油跑20英里的汽車,開(kāi)了100英里。請(qǐng)問(wèn)你用掉了多少汽油?

這是個(gè)簡(jiǎn)單的例子,但是適用于我們的用途。假設(shè)你遇到了a = b/c這一行。a指什么?b和c又指什么?它們與你的其余代碼有何關(guān)系?在編寫程序十分鐘后,你會(huì)記得一干二凈。更不用說(shuō)別人過(guò)來(lái)修改代碼或編寫更新版了。

現(xiàn)在看看這個(gè)表達(dá)式:加侖 = 英里/每加侖行駛英里數(shù)。每一個(gè)變量的具體用途就一目了然。一個(gè)代表加侖,一個(gè)代表英里,另一個(gè)代表每加侖行駛英里數(shù)。很清楚。

想一想為變量賦予清楚的英語(yǔ)(或者其他任何母語(yǔ))名稱與注釋之間的關(guān)系。假設(shè)你從別人那里接過(guò)了一段代碼,看到a = b/c。這代碼用來(lái)干嘛?你有何頭緒嗎?

務(wù)必以一種代表其功能的方式來(lái)命名變量。那樣可以節(jié)省大量的時(shí)間,減少許多頭痛的問(wèn)題。

 

第三個(gè)錯(cuò)誤:沒(méi)有實(shí)驗(yàn)筆記(lab notes)。

我在1997年年中開(kāi)始編寫ZENPRESS,它在1998年1月份上線。遺憾的是,我當(dāng)時(shí)匆忙完成了項(xiàng)目,沒(méi)有花時(shí)間為這第一個(gè)版本編寫實(shí)驗(yàn)筆記。此后我懊悔多次。從1999年6月份開(kāi)始(當(dāng)時(shí)我開(kāi)始編寫版本2),我就經(jīng)常做實(shí)驗(yàn)筆記了。

[[176052]]

實(shí)驗(yàn)筆記是代碼注釋之外的記錄??茖W(xué)家一直在使用實(shí)驗(yàn)筆記,作為其研發(fā)過(guò)程的日志或?qū)υ拑?nèi)容。實(shí)驗(yàn)筆記用來(lái)證明科學(xué)發(fā)現(xiàn)歸誰(shuí)所有,因?yàn)檠芯窟^(guò)程常常記錄在科學(xué)家用來(lái)記錄進(jìn)度的每天日志中。

實(shí)驗(yàn)筆記對(duì)程序員來(lái)說(shuō)同樣是一種有效的工具。我為ZENPRESS編寫的上一份實(shí)驗(yàn)筆記是在今年3月份編寫的,當(dāng)時(shí)我不得不把ZATZ歸檔從一家主機(jī)托管提供商遷移到另一家。我還經(jīng)常對(duì)自己的其他項(xiàng)目做實(shí)驗(yàn)筆記,由于能夠回過(guò)頭去查閱筆記,好多次幫了大忙。

如果你還沒(méi)有做實(shí)驗(yàn)筆記,現(xiàn)在就開(kāi)始做。記下你做的任何變化,你的理由,你考慮后丟棄的代碼,參考的實(shí)用資源,以及將來(lái)幫助你的任何其他內(nèi)容。你還能幫助將來(lái)的同事或接手人――如果你需要證明歸屬權(quán),實(shí)驗(yàn)筆記還能起到證明的作用。

第四個(gè)錯(cuò)誤:不用一種人類語(yǔ)言編寫。

我的學(xué)生要考試過(guò)關(guān),不僅僅要編程,他們還要編寫討論區(qū)帖子,證明他們熟知某些編程概念。

我們提出這個(gè)要求出于兩個(gè)原因。當(dāng)然,首先是為了證明熟悉概念。但是更為重要的是需要所有專業(yè)人員都有編寫能力。

我在這方面遭到學(xué)生們的反對(duì)。每學(xué)期都有學(xué)生高喊:“我想成為程序員,而不是編寫者。”但是編程、工程、IT和幾乎所有專業(yè)工作都不可能在真空狀態(tài)下存在。

你需要通過(guò)編寫來(lái)解釋概念、推銷想法、獲得資金、要求澄清、準(zhǔn)備提議,或者甚至為拿到更好的分?jǐn)?shù)據(jù)理力爭(zhēng)。開(kāi)源項(xiàng)目的參與者在非常龐大的團(tuán)隊(duì)協(xié)同工作,他們保持同步的唯一手段就是編寫清楚的、易于理解的信息。

結(jié)論很簡(jiǎn)單:如果你想要從事專業(yè)工作或從事任何重要的項(xiàng)目,就需要用一種人類語(yǔ)言(比如英語(yǔ))來(lái)編寫,而不僅僅是用一種編程語(yǔ)言來(lái)編寫。

第五個(gè)錯(cuò)誤:糟糕的代碼格式。

毫無(wú)疑問(wèn),這里的一個(gè)主題就是:讓代碼易于了解。代碼維護(hù)起來(lái)極耗費(fèi)時(shí)間和財(cái)力。坦率地說(shuō),這也不是很有趣。最好還是能夠把寶貴的工作時(shí)間用來(lái)添加功能,而不是花幾周來(lái)鉆研舊代碼,試圖搞清楚你(或者交給你代碼的那個(gè)人)想要完成什么任務(wù)。

本人就遇到過(guò)這種事,不僅僅是來(lái)自我的舊代碼,還來(lái)自從別人手里接過(guò)的代碼。我接手被丟棄的WordPress 開(kāi)源插件作為一個(gè)副帶項(xiàng)目。據(jù)我所知,我接手的插件比其他任何人都要多。每個(gè)插件都是由別人開(kāi)發(fā)的,為了保持插件可以正常使用,我不得不鉆研陌生人的代碼。

幸好,那些開(kāi)發(fā)人員都是高手,深諳編程之道。要不然,我也就無(wú)法接手這些項(xiàng)目了。但即便如此,要盡快上手還是困難重重。你能想象要是他們編寫的代碼結(jié)構(gòu)很糟糕,那會(huì)有多難嗎?

我所說(shuō)的結(jié)構(gòu)是指代碼的布局方式。我為學(xué)生制作了這方面的一段視頻。有興趣的話,大家可以上YouTube觀看(https://youtu.be/0u-I016Hxlw)。

想一想你在網(wǎng)上讀到的文章。一些文章格式優(yōu)美,每一個(gè)段落之間有一行,一切都保持一致??墒怯行┪恼露加靡粋€(gè)大大的blob來(lái)排列,沒(méi)法看清。

每個(gè)程序員(或項(xiàng)目)都往往有一種編程風(fēng)格。你的風(fēng)格是什么樣不是同樣重要,只要保持一致就行。你需要讓代碼格式來(lái)幫助引導(dǎo)。

比如說(shuō),在我的代碼中,我堅(jiān)持代碼段之間的空行不得超過(guò)一行。如果我看到一段更大的空白區(qū),我立即就知道這一點(diǎn):哪里出現(xiàn)了異常,這個(gè)空白區(qū)里面可能有錯(cuò)誤。

你在深入研究代碼時(shí),要關(guān)注貴企業(yè)有沒(méi)有編程風(fēng)格??紤]為你的所有程序員定義一種編程風(fēng)格,堅(jiān)持采用清楚、易于維護(hù)的那一種風(fēng)格。

第六個(gè)錯(cuò)誤:糟糕的錯(cuò)誤檢查。

某位著名的將軍曾經(jīng)說(shuō)過(guò),遇到敵人時(shí),計(jì)劃根本不管用。我在此基礎(chǔ)上改動(dòng)一下,遇到用戶時(shí),你的代碼根本不管用。盡管你認(rèn)為自己知道用戶會(huì)如何使用代碼,但你其實(shí)并不知道,相信我。

用戶會(huì)搞壞你的代碼。

正確的處理方式就是借助測(cè)試和錯(cuò)誤檢查。錯(cuò)誤檢查是指這種做法:檢查代碼中每一次操作的結(jié)果。確保它符合你的預(yù)期,或者確保你的代碼可處理意外的結(jié)果。

[[176053]]

比如說(shuō),我的學(xué)生經(jīng)常有一項(xiàng)任務(wù):閱讀文件。幾乎所有的學(xué)生編寫代碼時(shí)會(huì)調(diào)用文件讀取例程。他們檢查用戶是否取消對(duì)話框,但是很少查看文件是否實(shí)際上被讀入,或者是否存在某種類型的系統(tǒng)錯(cuò)誤。要是他們?cè)噲D編寫文件,那就更糟糕了。他們幾乎從不真正查看文件是不是實(shí)際上保存起來(lái)。真是要命。

不難發(fā)現(xiàn)這會(huì)有多糟糕。為了對(duì)付這種情形,你總是要考慮能不能絕對(duì)預(yù)測(cè)行為,然后認(rèn)識(shí)到你不能絕對(duì)預(yù)測(cè)行為。你需要測(cè)試。測(cè)試并不是僅僅指你自己運(yùn)行代碼。測(cè)試意味著讓實(shí)際用戶(即行為可能無(wú)法預(yù)測(cè)的那些人)運(yùn)行你的代碼。

你會(huì)發(fā)現(xiàn)這會(huì)提供大量的信息。

第七個(gè)錯(cuò)誤:使用打印輸出語(yǔ)句,而不是真正的調(diào)試器。

這些年來(lái)我發(fā)現(xiàn),使用不同語(yǔ)言的程序員往往有不同的文化??偟膩?lái)說(shuō),那是由于他們構(gòu)建不同種類的解決方案、使用不同的工具。

這方面的一個(gè)例子就是我的C#編程學(xué)生和與我一起開(kāi)發(fā)一些項(xiàng)目的開(kāi)源PHP開(kāi)發(fā)人員之間的區(qū)別。幾乎沒(méi)有一個(gè)C#程序員會(huì)考慮不使用一種符號(hào)調(diào)試器來(lái)調(diào)試代碼。那是由于, C#本身是使用Visual Studio作為編程環(huán)境來(lái)編寫的,調(diào)試器內(nèi)置在里面。

相比之下,我見(jiàn)到許多PHP開(kāi)發(fā)人員認(rèn)為只要插入echo語(yǔ)句或var_dump就足以幫助自己調(diào)試代碼了。這一方面是由于,大多數(shù)PHP程序員往往在編輯器里面編程,而不是在開(kāi)發(fā)環(huán)境里面編程。兩者之間的一大區(qū)別就是調(diào)試器。

那么,調(diào)試器是什么東東?簡(jiǎn)而言之,這種工具讓你可以在代碼運(yùn)行時(shí)查看代碼內(nèi)部的情況。它就好比是代碼的X光、超聲波或MRI??梢灾噶钫{(diào)試器在某些點(diǎn)停止,檢查所有變量的狀態(tài)。還可以指令調(diào)試器在某些條件下停止。你可以更改值,可以查看和分析值(不過(guò)分析有時(shí)是另一種工具)。

工作效率方面的差異很大。如果你想更快速、極其準(zhǔn)確地完成工作,就要確保使用一種真正的符號(hào)調(diào)試器。

以上就是我所介紹的幾個(gè)常見(jiàn)錯(cuò)誤,下面看看詹姆斯·康納教授介紹的幾個(gè)。

第八個(gè)錯(cuò)誤:使用魔數(shù)(magical number)。

許多程序員認(rèn)為,他們只要編寫一次代碼,代碼就能完美無(wú)缺。然而,為了優(yōu)化企業(yè)軟件和工業(yè)軟件的長(zhǎng)期生命周期成本,有必要編寫能夠抵御不斷變化的條件的代碼。

這方面的一個(gè)典例就是魔數(shù)這個(gè)想法。我所說(shuō)的魔數(shù)是指程序員認(rèn)為總能經(jīng)受得住時(shí)間考驗(yàn)的數(shù)字。

以可能基于客戶的采購(gòu)數(shù)量的傭金計(jì)算為例。截至截稿時(shí),傭金比例可能是三個(gè)百分點(diǎn),即0.03。

現(xiàn)在,設(shè)想一下會(huì)如何編寫這段代碼:傭金= .03 *銷售額。在這個(gè)上下文中,這個(gè)魔數(shù)就是0.03。由于程序員認(rèn)為這會(huì)是永遠(yuǎn)神奇地有效,他將0.03這個(gè)數(shù)字硬編碼到代碼中。

這一切很好,但是每年的傭金往往發(fā)生變化。如果下一年傭金漲了0.5%,漲到0.035,那么就很難在成千上萬(wàn)行代碼中找到它。

切忌使用魔數(shù),而是在一個(gè)地方定義變量或常量,讓代碼使用那些變量。如果你預(yù)先定義commission_rate,那么commission = commission_rate * sale之類的代碼就不需要改動(dòng)。

要考慮的另一個(gè)方面是,無(wú)論你在何處找到魔數(shù),都應(yīng)該找到想要提供給用戶的選項(xiàng),以便用戶可以在偏好設(shè)置部分可以設(shè)置。

第九個(gè)錯(cuò)誤:馬虎對(duì)待的日期和時(shí)間。

這里有個(gè)難題:一年有幾天?365天也許是平常的回答,但今年當(dāng)然有366天。一天會(huì)有365.25天嗎?這不可能。

但我的一些學(xué)生認(rèn)為,既然閏年每四年就出現(xiàn)一次,所以每年平均下來(lái)因此是365.25天。在進(jìn)行日期計(jì)算時(shí),他們使用這個(gè)平均值;因而,結(jié)果根本不正確。

常常更好的辦法是使用系統(tǒng)庫(kù)來(lái)計(jì)算日期,因?yàn)槟阌?jì)算的日期可能不是西方日歷日期。

不妨看一下時(shí)間方面的類似問(wèn)題。每幾年,由于地球轉(zhuǎn)速減慢,有一天會(huì)多出一秒來(lái),通常是在6月30日或12月31日那天。這叫作閏秒,因而,時(shí)鐘可能從11:59:59走到11:59:60再走到12:00:00。

這是第二個(gè)時(shí)間挑戰(zhàn)。在使用夏令時(shí)的地方,交易的進(jìn)行有可能亂套。比如說(shuō),先置入交易A,但是隨后時(shí)間被向后重置1小時(shí),那么就置入交易B。然而,如果你在時(shí)間序列方面很馬虎,它就會(huì)記錄為交易B先發(fā)生。這種類型的時(shí)間錯(cuò)誤會(huì)導(dǎo)致產(chǎn)生不必要的罰款,還會(huì)導(dǎo)致其他各種各樣的混亂。

再次,有許多好的語(yǔ)言和系統(tǒng)庫(kù)可以處理這兩種時(shí)間問(wèn)題。常常更好的辦法是使用現(xiàn)有的庫(kù),而不是編寫自己的時(shí)間計(jì)算代碼。

第十個(gè)錯(cuò)誤:沒(méi)有選擇合適的數(shù)據(jù)結(jié)構(gòu)。

數(shù)據(jù)結(jié)構(gòu)是表示程序中數(shù)據(jù)的一種機(jī)制。許多人聽(tīng)說(shuō)過(guò)鏈表、樹(shù)和數(shù)組之類的術(shù)語(yǔ)。這每一個(gè)術(shù)語(yǔ)都是數(shù)據(jù)的邏輯表示,對(duì)應(yīng)于你試圖表示的數(shù)據(jù)的一些架構(gòu)結(jié)構(gòu)。

我看到程序員(無(wú)論編程高手還是菜鳥(niǎo))最常犯的錯(cuò)誤之一就是,很少注意數(shù)據(jù)結(jié)構(gòu)方面的選擇。由于你的幾乎所有代碼都建立在選擇的那種數(shù)據(jù)表示方法上,一旦選錯(cuò)數(shù)據(jù)結(jié)構(gòu),會(huì)在將來(lái)帶來(lái)嚴(yán)重的影響。

下面這個(gè)例子可以表明這種設(shè)計(jì)錯(cuò)誤:選擇一個(gè)簡(jiǎn)單的堆?;蜿?duì)列,而不是循環(huán)隊(duì)列。堆棧就好比是一堆盤子。你取下底部盤子,然后放上另一只盤子,再取下另一只盤子,依次類推。

如果你想拿走一只盤子,你從最上面拿走。這就叫后進(jìn)先出??蓡?wèn)題,如果你需要拿走早些時(shí)候放的東西,就很麻煩了。假設(shè)一堆棧盤子有10只盤子。想找到第一只盤子,你就得先拿走其他所有的盤子。

現(xiàn)在,不妨想象一下隊(duì)列。如果你在銀行排隊(duì),就處于隊(duì)列中。第一個(gè)進(jìn)去的也是第一個(gè)出來(lái)的。一旦第一個(gè)人得到了服務(wù),下一個(gè)人跟上,然后該人得到服務(wù)。出現(xiàn)的另一種情況是,每個(gè)人都向前邁一步,在隊(duì)列中向前移動(dòng)位置。

要是許多人來(lái)排隊(duì),會(huì)出現(xiàn)什么情況?要么他們被拒之門外,要么隊(duì)伍排到門外面。第一個(gè)人叫到后,所有這些人都要往前移動(dòng)。

如果你有大量數(shù)據(jù),這種隊(duì)列就會(huì)極其低效。每當(dāng)從隊(duì)列的開(kāi)頭獲取數(shù)據(jù),所有數(shù)據(jù)都要移動(dòng)。我們置身于大數(shù)據(jù)時(shí)代,有源源不斷的數(shù)據(jù)從我們的系統(tǒng)通過(guò)。

在這種環(huán)境下,一種更好的辦法也許是實(shí)施循環(huán)隊(duì)列。在這種情況下,數(shù)據(jù)根本不動(dòng)。相反,設(shè)置的指針指向隊(duì)列的開(kāi)頭和末尾;在內(nèi)部,隊(duì)列首尾相連,那樣數(shù)據(jù)以圓環(huán)、而不是隊(duì)列的方式來(lái)加以組織。當(dāng)數(shù)據(jù)元素使用、從圓環(huán)中移除后,就不需要移動(dòng)圓環(huán)中的所有數(shù)據(jù)。發(fā)生的只是第一個(gè)元素的指針指向圓環(huán)中的新元素。

有許多例子可以表明選擇正確的數(shù)據(jù)結(jié)構(gòu)會(huì)給你代碼的效率帶來(lái)重大影響,這僅僅是其中一個(gè)。

但愿你在看完本文后,會(huì)成為一名更高效的程序員,避免其中一些嚴(yán)重錯(cuò)誤。

原文標(biāo)題:Software bugs? Avoid these 10 costly programming mistakes,作者:David Gewirtz

【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com】

責(zé)任編輯:陶家龍 來(lái)源: 51CTO
相關(guān)推薦

2018-02-27 09:57:50

數(shù)據(jù)容量危機(jī)

2022-05-17 09:32:24

Bash編程Linux

2011-05-31 15:38:37

CSS

2016-01-21 10:00:38

2018-09-29 16:10:02

編程語(yǔ)言Java程序員

2016-11-02 12:56:58

Linux新手錯(cuò)誤

2018-07-23 12:48:44

編程學(xué)習(xí)開(kāi)發(fā)

2022-06-28 10:13:09

Pandas錯(cuò)誤Python

2013-07-09 13:52:31

程序員Android

2018-08-10 08:35:49

2018-05-28 14:55:56

職業(yè)錯(cuò)誤程序員

2015-08-26 10:00:31

獨(dú)立游戲cp錯(cuò)誤

2011-07-06 08:49:05

程序員

2019-04-24 08:56:34

Java開(kāi)發(fā)人員常犯錯(cuò)誤

2016-11-30 14:15:34

網(wǎng)絡(luò)布線錯(cuò)誤

2011-04-18 12:55:04

JavaScript開(kāi)發(fā)者

2022-12-26 11:02:06

云計(jì)算CIOIT

2019-11-01 14:19:02

大數(shù)據(jù)機(jī)器學(xué)習(xí)工具

2018-06-27 13:10:22

程序員面試易犯錯(cuò)誤

2021-08-06 09:20:41

IT管理IT領(lǐng)導(dǎo)者CIO
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)