Python編程基礎:程序員深愛而又不自知的 9 個不良編程習慣

咱們曾經都作過這樣的事情:當媽媽不注意的時候,偷偷地吃糖果零食,長此以往,咱們有了蛀牙。一樣的,咱們都違背過一些編程的基本規則,而且都會堅決地表示這種行爲是不可取的。但咱們就是偷偷愛着這些不良的編程習慣。程序員

咱們對所謂的編程規則嗤之以鼻,輸出的代碼也很糟糕——但咱們依然活着,持續也都運行着。編程上帝沒有下閃電劈咱們,咱們的電腦也沒有爆炸。事實上,只要咱們能編譯和發佈代碼,能夠正常運行,客戶彷佛就還算滿意了。編程

這是由於糟糕的編程不像安裝電路或者摸老虎屁股那樣有直接的危害性。大多數時間裏它也是能夠工做的。規則一般是做爲一種指導或格式上的建議,並無硬性規定必定要遵照,也不會致使代碼立刻死掉。固然,你的代碼可能會被人恥笑,甚至可能你們公開嘲笑你,不過,這種挑戰慣例的行爲可讓人增長一點顛覆傳統的快感,哪怕是在不經意間。數組

爲了讓問題變得更加複雜,有時候違反規則反而更好。(通常人我還不告訴他!)出來的代碼會更乾淨,甚至可能會更快和更簡單。規則一般顯得太過於寬泛,有技巧的程序員能夠經過打破這些規則來提升代碼質量。不要告訴你的老闆,這對你的編碼生涯會頗有意義。安全

Python編程基礎:程序員深愛而又不自知的 9 個不良編程習慣

下面這9個編碼習慣,雖然在編程規則中是被駁斥的,但咱們不少人就是會情不自禁地使用它們。bash

編程習慣No. 1:使用goto數據結構

關於禁止使用goto能夠追溯到許多結構化編程工具還未面世的時代。若是程序員想要建立一個循環或跳到另外一段程序中,那麼他們須要輸入goto後再跟一個行號。過了幾年以後,編譯器團隊讓程序員使用字符串標籤取代行號。這在當時被認爲是一個熱門的新功能。架構

有的人認爲這會致使「意大利麪條式代碼」。代碼會變得不可讀,而且很難理解代碼的執行路徑。線程混亂,纏纏綿綿到天涯。Edsger Dijkstra就三令五申地表示應該禁止這個命令,他有一份詼諧的手稿,題目爲《Goto語句貽害不淺》。編程語言

但絕對的分支是沒有問題的。這就讓人糾結了。一般,巧妙的 break 語句和return 語句可提供一個很是乾淨的關於代碼在那個時候執行什麼的聲明。有時候,添加 goto 到case語句會比更恰當的多級嵌套的if-then-else語句塊更易於理解。編輯器

也有反例。在蘋果的SSL堆棧中的「goto fail」安全漏洞就是最好的例子之一。可是,若是咱們可以仔細避免case語句和循環的一些尷尬問題,那麼咱們就能夠嵌入良好的絕對轉移,使閱讀代碼的人更容易明白這是怎麼回事。咱們能夠插入break和return 語句,讓每個人感受更清潔和更愉快——可能得除了goto的敵視者。函數

編程習慣No. 2:成功避開文檔

個人一個朋友有一個很是精明的老闆,這位老闆雖然歷來沒有寫過任何代碼,但卻秉持着每個功能都必須包含在文檔中的理念。哪一個程序員不提供註釋,那麼他就會受處處罰。因此,個人朋友在他的編輯器中聯入了一個有點像人工智能的玩意兒,因而乎,他的每個功能就都有幾行「文檔」了。由於這位精明的老闆還不夠聰明到能理解這些註釋其實啥意思也沒有,因此個人朋友逃過一劫。他的代碼經常被做爲正式文檔。我想,他應該快要升職了!哈哈哈!!!

許多函數方法,甚至一些類或多或少都能自文檔化。冠以insertReservation或cancelReservation或 deleteAll 等名稱的函數並不須要畫蛇添足來解釋它們的做用。爲函數取一個正確的名字每每就足夠了。事實上,這比寫一段長長的註釋要好,由於函數名能夠出如今代碼中的其餘地方。而文檔只能默默地呆在某個角落。自文檔化的函數名能夠改進它們出現的每一個文件。

在有些狀況下,寫文檔甚至會致使狀況變糟。例如,當代碼瞬息萬變,團隊像瘋了似的重構的時候,文檔就會產生分歧。代碼是這樣寫的,但文檔解釋的仍是四五個版本之前的狀況。這類「過期」的文檔一般位於代碼頂部,有的人會在這裏對代碼應該發生什麼做一個美好總結。所以,儘管重構團隊已經仔細修改了相關的註釋,但仍是會遺漏文件頂部的這段「美好總結」。

當代碼和文本出現分歧的時候,註釋就變得毫無價值,甚至會產生誤導。在這樣的狀況下,良好的自文檔化的代碼顯然勝出了。

編程習慣No. 3:一行寫太多代碼

老闆忽然發神經地給團隊發了一封討厭的郵件:爲了執行很是嚴格的風格規定,咱們你們都必須重寫咱們的代碼。最神奇的要求是:每一個行爲或步驟或子句必須各自成行。你不能使用點語法連續調用函數。在一個分支語句中,你不能有兩個及以上返回布爾值的子句。若是要定義變量,那麼另起一行。若是你正在作一個複雜的計算,那麼不要使用括號。每一個片斷也自成一行。

他認爲他的這個法令將能使調試變得更加容易。就像你單步調試代碼同樣,調試器會一個動做一個動做地前進。這樣就不會卡在某一行。並且更容易執行。

可是這樣一來,鍵盤上的回車鍵煩不勝煩,由於我須要不斷地插入行。並且我敢確定,老闆所以還能夠處處吹噓他的團隊能寫多少行代碼。

唉,有時在同一行中聲明一堆變量反而更容易;有時把全部的布爾子句放在一塊兒反而更簡單——一切都能變得更加緊湊。那也意味着,咱們能夠在屏幕上看到更多的邏輯而無需滾動鼠標。更易於閱讀就意味着理解起來更快。這纔是簡單的精粹。

編程習慣No. 4:不聲明類型

那些熱愛類型化語言的人認爲,若是爲每一個變量添加明確的數據類型聲明,就能夠寫出更好的、沒有錯誤的代碼。花一點時間來拼寫類型,能幫助編譯器在代碼開始運行以前標誌愚蠢的錯誤。可能會讓人以爲痛苦,但頗有幫助。這是編程中中止bug的一種有備無患的方法。

可是時代變了。許多較新的編譯器徹底能夠智能地經過查看代碼來推斷類型。它們會向後和向前瀏覽代碼,直到能夠確定這個變量是string 仍是int,抑或其餘。若是這些被查看的類型不成隊列,那麼錯誤標誌就會點亮。所以不再須要咱們輸入變量的類型了。

這意味着咱們如今能夠在代碼中省略掉一些最簡單的聲明。代碼更清潔,並且閱讀代碼的人也猜得出for循環中命名爲 i 的變量表示一個整數型。

編程習慣No. 5:搖擺不定的代碼

有的程序員在代碼上特別優柔寡斷,猶豫不決。先是一開始將值存儲爲字符串,而後又解析成整數。接着又轉換回字符串。這是很是低效的,你甚至能夠感受到CPU在咆哮這種浪費負載的行爲。聰明的程序員之因此能快速地編碼,是由於他們事先會設計架構,以儘可能減小轉換。他們的代碼能更快地運行是由於他們有一個良好的規劃。

可是,無論你信不信,這種搖擺不定的代碼有時候也是有意義的。好比說,你有一個很是棒的庫,在它專有的黑盒子裏能作無數智能的事情。若是庫須要字符串的數據,那麼你就給它字符串,即便你剛將這個數據轉換成爲整數型。

固然,你能夠重寫全部的代碼,以儘可能減小轉換,可是這須要時間。並且,有時候讓代碼稍微多花點額外時間來運行也何嘗不可,由於重寫代碼須要耗費咱們更多的時間。有時,揹負這樣的技術債務比一開始就正確構建的成本要更低。

有的時候,庫不是專有的代碼,但那些你之前所有本身寫的代碼是你獨有的。有的時候,再次轉換數據比重寫庫中的全部代碼要快得多。因此,就讓它這樣吧,就讓代碼搖擺吧。

編程習慣No. 6:編寫你本身的數據結構

有一個標準規則是,程序員在完成數據結構課程的第二年,不該該寫用於存儲數據的代碼。基本上咱們須要的全部的數據結構,已經有人寫好了,並且其代碼已歷經多年的測試和再測試。它和語言捆綁在一塊兒,並且經常是免費的。你的代碼只能造就bug。

但有時你會發現數據結構庫有點慢。有時它們會迫使咱們使用標準的,但於咱們的代碼倒是錯誤的結構。有時庫會把咱們推向在使用結構以前從新配置數據的地步。有時庫會包含一些所謂有備無患的保護功能,如線程鎖,但其實咱們的代碼並不須要。

若是遇到這種狀況,那麼就應該着手寫咱們本身的數據結構。這或許能讓你作得更快,作得更多。並且代碼會變得更清潔,由於咱們不會包括那些多餘的用於格式化數據來完成一些功能的代碼。

編程習慣No. 7:在中間打破循環

有一個規則制定小組宣稱,每一個循環都應該有一個「常量」,也就是說當這個邏輯語句爲true的時候,循環一直執行。當常量必定不會是true的時候,循環纔會結束。這是考慮複雜循環的好方法,但它會致使愚蠢的禁令——例如禁止咱們在循環中間使用return 和break 語句。這一條也包含在禁止goto語句的規則中。

這個理論是好的,但它一般會致使更復雜的代碼。請看下面這個簡單的案例,遍歷數組,將找到的元素傳遞給test函數,並將該元素返回:

while (i<a.length){
 ...
 if (test(a[i]) then return a[i];
 ...
}
複製代碼

「循環常量」愛好者會要求咱們增長一個布爾變量,命名爲notFound,而後這樣使用:

while ((notFound) && (i<a.length){
...
if (test(a[i])) then notFound=false;
...
}
複製代碼

若是這個布爾值可以合理地命名,那麼這就是一段很棒的自文檔化的代碼,更易於你們理解。但這也增長了複雜性。這意味着你須要分配另外一個局部變量,並堵塞寄存器,由於編譯器也許還不能足夠智能到解決這個問題。

有時候,一個goto 語句或一個跳轉會更乾淨利索。

編程習慣No. 8:使用短變量名(i和x和and也是有意義的)

Edgar Allan Poe這位詩人和小說家曾經說過,在一個故事中的每個詞都應該是有內涵的。編碼規則也強調如此。變量名應該說明這個變量的所做所爲。那些使用駝峯式大小寫的方法來寫變量名,以表達關於變量細節的Java程序員深覺得然,因而一個又一個瘋狂長度的變量名出爐了。有些程序員寫的變量名,會組合五六個甚至更多的詞語。

但有的時候,使用單個字母做爲變量名反而會更方便。有時在循環迭代中只使用i或j會更簡單。有時使用字母a表明array ,l表明list會更便捷,即便是字母l和數字1看上去很難辨別。

正如這篇文章前面鼓勵的是自文檔化的代碼,而非長長的註釋。在上述狀況下,單個字母的變量名也是自文檔化的。字母 i 是通用的迭代器。只要是程序員馬上就會懂。

編程習慣No. 9:從新定義運算符和函數

一些最有趣的編程語言容許你去作一些特別詭異的事情,例如從新定義元素的值,就如同常量通常。例如Python,你能夠輸入TRUE=FALSE(在Version2.7及以前的版本)。這並不會產生某種邏輯崩潰,或致使宇宙終結——僅僅只是互換了TRUE和FALSE的含義。你也能夠在C預處理器和一些其餘語言中玩玩相似於這樣的危險遊戲。還有一些語言容許你從新定義運算符,如加號。

固然這是延伸了,不過有一個觀點是,在一個大的代碼塊內,當從新定義一個或多個所謂的常量時,速度會更快。有時老闆會要求代碼作一些大相徑庭的事情。固然,你能夠修改代碼的每一個事件,或者,你能夠從新定義。這讓你看上去像一個天才。沒必要重寫一個龐大的庫,只需翻轉一下,就能夠作相反的事情了。

這9個習慣就都在這兒了。千萬不要輕易嘗試,無論它看上去有多牛掰。太危險了,這是實話。

相關文章
相關標籤/搜索