開發(fā)者常見的十種不良編程習(xí)慣
譯文【51CTO.com快譯】常言道:嘴上說不要,習(xí)慣卻很誠實。朋友,您是否捫心自問過:有過多少次違背了編程的基本規(guī)范?或許您根本就沒有意識到自己會常犯的那些不良編程習(xí)慣。實際上,我們在交付已編譯好的代碼后,客戶是不會在使用中馬上發(fā)現(xiàn)到程序的缺陷。
通常,編程規(guī)則只會規(guī)定程序員在編寫代碼時,需要遵守的準(zhǔn)則、以及建議采用的風(fēng)格,而不是那些細(xì)枝末節(jié)需要遵循的、一成不變的指令。因此,就算您偶有“犯規(guī)”也并不可怕??膳碌氖遣蝗フJ(rèn)真總結(jié),甚至置若罔聞。下面,我將和您討論十種常見的不良編程習(xí)慣。
不良的編程習(xí)慣1:直接復(fù)制操作
請不要直接將他人的代碼整塊地復(fù)制、粘貼到自己的程序中,特別是那些已經(jīng)標(biāo)記了版權(quán)信息的專有代碼。請最好在理解的基礎(chǔ)上,動手鍵入自己的版本。畢竟,您的老板或客戶并不是花錢來請你專門進(jìn)行復(fù)制、粘貼的。
當(dāng)然,從代碼的可靠性來說,我們通常應(yīng)當(dāng)從信譽良好的來源,獲取那些經(jīng)過原創(chuàng)作者深思熟慮、以及反復(fù)測試的源代碼。為了避免重復(fù)造輪子,許多原始創(chuàng)作者會在各種在線編程論壇上共享、并開放自己的源代碼。不過,有時候他們可能會帶有許可證(如BSD或MIT)、以及使用范圍的限制。
另外,有些程序往往是針對某個特定的棘手問題所開發(fā)的。其中難免會存在著一些未被發(fā)現(xiàn)的錯誤、或是對具體情況的假設(shè)與限制條件。如果您只是將其簡單地添加到自己的代碼段中的話,很有可能會出現(xiàn)空指針、或是死循環(huán)之類的潛在錯誤。而由于原始代碼并未預(yù)見到您的使用環(huán)境,因此可能會出現(xiàn)“水土不服”,甚至是實現(xiàn)效果并不理想的情況。
不良的編程習(xí)慣2:非功能性的代碼
在過去的十年間,功能性范式有了長足進(jìn)步。有多項研究證明:使用嵌套函數(shù)調(diào)用程序來構(gòu)建程序的方法,與舊式的變量和循環(huán)模式相比,程序代碼本身會更加安全,錯誤也會更少。因此,資深程序員往往會通過審查代碼、以及推拉請求的方式,來發(fā)現(xiàn)那些非功能性的代碼,進(jìn)而讓程序的結(jié)構(gòu)更為合理且協(xié)調(diào)。
請不要妄想一次性設(shè)計出全面的架構(gòu)。畢竟,精心的分層設(shè)計、復(fù)雜的界面導(dǎo)航、以及用于構(gòu)建的配套代碼,都需要事先向程序員提供充裕的時間、以及昂貴的費用。因此,為了確保所有必要的數(shù)據(jù)能夠正確地被定義,并能夠通過準(zhǔn)確的途徑進(jìn)行傳遞,進(jìn)而讓整個系統(tǒng)能夠以高效的方式運行起來,我們應(yīng)當(dāng)盡量保持代碼的簡潔與直觀,不要遺留各種冗長的非功能性代碼。
不良的編程習(xí)慣3:非標(biāo)準(zhǔn)的間距
眾所周知,除了諸如Python之類少數(shù)編程語言使用空格間距來標(biāo)識代碼塊之外,大多數(shù)程序中的空格一般都不會影響軟件的行為效果、以及整體性能。盡管如此,我們依然需要抱著“強迫癥”的態(tài)度,苛求自己不要寫出“非標(biāo)的代碼(Non Standard Code)”,特別是在等號的兩側(cè)不要留下空格,以至于違反了ESLint space-infix-ops規(guī)則。
有時候,過多的空格會導(dǎo)致數(shù)據(jù)庫的過載,甚至是由于空指針導(dǎo)致了程序運行的崩潰。因此,在某些要求嚴(yán)格的軟件開發(fā)企業(yè)中,他們會專門成立標(biāo)準(zhǔn)委員會,以規(guī)范各種空格、或制表符在代碼、以及頁面中所允許出現(xiàn)的位置。
在實際編程過程中,開發(fā)人員往往更專注于程序的功能與效果,而忽略了間距與空格之類的格式問題。不過,值得慶幸的是:目前有好幾種工具可以幫助您自動化地規(guī)范代碼的格式,并能遵守各種預(yù)先定義的插入規(guī)則。
不良的編程習(xí)慣4:goto的使用
人們使用goto的歷史可以追溯到那些早于結(jié)構(gòu)化編程工具的時代。當(dāng)時,如果程序員們想創(chuàng)建一個循環(huán),或是跳轉(zhuǎn)到另一個例程,就需要鍵入goto、且后面跟上行號。若干年后,編譯器出現(xiàn)了,它允許程序員使用字符串標(biāo)簽,而不再是行號。當(dāng)時,此類功能曾經(jīng)被認(rèn)為是一種熱門技能。
如今,有越來越多的人將此類編程習(xí)慣所產(chǎn)生的代碼稱為“意面式代碼(spaghetti code)”。此類混為一團(tuán)的線程糾纏在一起,他人完全無法讀懂,而且其本身很可能會陷入遵循執(zhí)行的路徑。結(jié)構(gòu)程序設(shè)計之父Edsger Dijkstra曾經(jīng)針對此現(xiàn)象發(fā)表了《Goto聲明顯然有害(Goto Statement Considered Harmful)》的文章。
作為解決方案,您可以巧妙地使用break或return,來清晰地聲明代碼執(zhí)行到此處的后繼行為。當(dāng)然,我們有時候也可以把goto添加到case語句中,將產(chǎn)生比級聯(lián)“if-then-else”塊結(jié)構(gòu),更為正確的列表,以及更容易理解的內(nèi)容。
作為一個反例,您也許聽說過蘋果SSL堆棧中的“goto fail”安全漏洞。如果我們能夠謹(jǐn)慎地避免case語句與循環(huán)相關(guān)的棘手問題,只插入break或return之類有效的絕對跳轉(zhuǎn),那么就會讓整個問題容易處理得多。
不良的編程習(xí)慣5:未聲明的類型
有經(jīng)驗的程序員都知道:只有為每個變量的數(shù)據(jù)類型都添加清晰的聲明,我們才能編寫出更優(yōu)秀,bug更少的代碼。我們只有提前完善了類型的聲明,編譯器在執(zhí)行程序代碼時,才不會碰到某些“愚蠢”的錯誤。這種編程習(xí)慣的養(yǎng)成雖然可能很痛苦,但是它絕對會讓您受益。
當(dāng)然,隨著技術(shù)的發(fā)展,如今許多新式的編譯器已經(jīng)足夠聰明,能夠通過查看代碼的上下文,來推斷變量是否屬于string、int或其他類型。如果編譯器實在無法推斷出正確的類型,它也會拋出相應(yīng)的錯誤。
不良的編程習(xí)慣6:yo-yo代碼
“yo-yo代碼”是指:作為字符串存儲的數(shù)值被解析為整數(shù),接著又被轉(zhuǎn)換回了字符串。顯然,這是一種非常低效的方式。它額外地耗費了大量的CPU資源。因此,經(jīng)驗豐富的碼農(nóng)會通過合理的程序結(jié)構(gòu),來大幅減少轉(zhuǎn)換所需的工作量,進(jìn)而提升代碼的運行效率。
如今我們時常聽到業(yè)界有人談?wù)搩斶€“技術(shù)債”的說法。它在此處可以被理解為:程序員通過重寫所有現(xiàn)有的代碼,清除yo-yo代碼,以最大限度減少數(shù)值類型轉(zhuǎn)換的成本與時間。
不良的編程習(xí)慣7:編寫自己的數(shù)據(jù)結(jié)構(gòu)
一些初出茅廬的程序員往往喜歡自行編寫某種用于存儲數(shù)據(jù)的代碼。而這些數(shù)據(jù)結(jié)構(gòu)難免存在著他們考慮不周的潛在漏洞。其實他們應(yīng)該明白:作為一種成熟的編程語言,各種常見的數(shù)據(jù)結(jié)構(gòu)已有前人提前準(zhǔn)備好了。而且這些程序代碼往往與語言捆綁在一起,經(jīng)過了多年的測試與檢驗,開發(fā)者可以放心大膽地免費使用。
當(dāng)然,有時候現(xiàn)成的數(shù)據(jù)結(jié)構(gòu)庫為了標(biāo)準(zhǔn)化的需要,而在存放之前迫使我們重新配置輸入的數(shù)據(jù)。因此,我們可以適當(dāng)?shù)蒯槍€程鎖等功能進(jìn)行代碼級別的調(diào)整,去除不必要的、數(shù)據(jù)格式化之類的代碼,以使得整體結(jié)構(gòu)更加簡潔。
不良的編程習(xí)慣8:老式循環(huán)
很久以前,C語言的締造者希望將所有的抽象可能性都封裝到一個簡單的構(gòu)造之中,這就導(dǎo)致了每次調(diào)用都需要循環(huán)地進(jìn)行各項操作,并需要告知操作的完成。顯然,這會讓程序的可讀性變得很差。如今,人們更趨向具備功能性的范式(paradigm),直接將功能函數(shù)應(yīng)用到列表中,將計算模板映射給某些數(shù)據(jù),而不再使用循環(huán)。
在只有一個整潔的函數(shù)和一個數(shù)組的時候,使用不帶循環(huán)的方法會讓程序變得更加易讀且簡潔。但是在需要首次找到匹配項就立即停止搜索的場景下,老式的循環(huán)仍然會讓程序既簡單又高效。
當(dāng)然,映射函數(shù)更適合您對數(shù)據(jù)執(zhí)行多項操作。例如:您想先取絕對值,然后取每個數(shù)字的平方根。那么最快的方法就是:先映射第一個函數(shù),然后映射第二個,接著將數(shù)據(jù)循環(huán)兩次。
不良的編程習(xí)慣9:從循環(huán)中跳出
有些程序員在編程的時候,喜歡在每個循環(huán)中都使用一個變量,并且在該變量為真(true)的時候,就結(jié)束循環(huán)。雖然這是處置復(fù)雜循環(huán)的一種好方法,但是它會在某種程度上禁止我們在循環(huán)中使用return或break。
不良的編程習(xí)慣10:重新定義運算符和函數(shù)
對于某些初級程序員而言,由于知識與經(jīng)驗的不足,他們可能會重新定義運算符和函數(shù)。例如,在Python 2.7、及其之前的版本中,您可以指定TRUE=FALSE。這將導(dǎo)致的結(jié)果是:它會在您的代碼中將TRUE和FALSE的含義進(jìn)行互換。同時,在C語言預(yù)處理器、以及某些其他語言中,您也可以去重新定義加號之類的運算符。
當(dāng)然,此類重新定義也并非百無一用。面對巨大的既有庫,您可以在無需重新改寫代碼的情況下,臨時借用一下該“反轉(zhuǎn)”功能,來簡化大段的代碼。
綜上所述,我們在此羅列的所謂開發(fā)者常犯的十項惡習(xí),實際上并非一成不變的。關(guān)鍵就在于您是否能夠在恰當(dāng)?shù)膱鼍跋?,使用恰?dāng)?shù)木幊谭绞健?/p>
原文標(biāo)題:10 bad programming habits we secretly love,作者:Peter Wayner
【51CTO譯稿,合作站點轉(zhuǎn)載請注明原文譯者和出處為51CTO.com】






