日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

北京尚学堂|程序员的智慧

發布時間:2023/11/29 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 北京尚学堂|程序员的智慧 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

版權聲明:本文為北京尚學堂原創文章,未經允許不得轉載。

?

編程是一種創造性的工作,是一門藝術。精通任何一門藝術,都需要很多的練習和領悟,所以這里提出的“智慧”,并不是號稱一天瘦十斤的減肥藥,它并不能代替你自己的勤奮。然而由于軟件行業喜歡標新立異,喜歡把簡單的事情搞復雜,我希望這些文字能給迷惑中的人們指出一些正確的方向,讓他們少走一些彎路,基本做到一分耕耘一分收獲。

反復推敲代碼

既然“天才是百分之一的靈感,百分之九十九的汗水”,那我先來談談這汗水的部分吧。有人問我,提高編程水平最有效的辦法是什么?我想了很久,終于發現最有效的辦法,其實是反反復復地修改和推敲代碼。

在IU的時候,由于Dan Friedman的嚴格教導,我們以寫出冗長復雜的代碼為恥。如果你代碼多寫了幾行,這老頑童就會大笑,說:“當年我解決這個問題,只寫了5行代碼,你回去再想想吧……” 當然,有時候他只是夸張一下,故意刺激你的,其實沒有人能只用5行代碼完成。然而這種提煉代碼,減少冗余的習慣,卻由此深入了我的骨髓。

有些人喜歡炫耀自己寫了多少多少萬行的代碼,仿佛代碼的數量是衡量編程水平的標準。然而,如果你總是匆匆寫出代碼,卻從來不回頭去推敲,修改和提煉,其實是不可能提高編程水平的。你會制造出越來越多平庸甚至糟糕的代碼。在這種意義上,很多人所謂的“工作經驗”,跟他代碼的質量,其實不一定成正比。如果有幾十年的工作經驗,卻從來不回頭去提煉和反思自己的代碼,那么他也許還不如一個只有一兩年經驗,卻喜歡反復推敲,仔細領悟的人。

有位文豪說得好:“看一個作家的水平,不是看他發表了多少文字,而要看他的廢紙簍里扔掉了多少。” 我覺得同樣的理論適用于編程。好的程序員,他們刪掉的代碼,比留下來的還要多很多。如果你看見一個人寫了很多代碼,卻沒有刪掉多少,那他的代碼一定有很多垃圾。

就像文學作品一樣,代碼是不可能一蹴而就的。靈感似乎總是零零星星,陸陸續續到來的。任何人都不可能一筆呵成,就算再厲害的程序員,也需要經過一段時間,才能發現最簡單優雅的寫法。有時候你反復提煉一段代碼,覺得到了頂峰,沒法再改進了,可是過了幾個月再回頭來看,又發現好多可以改進和簡化的地方。這跟寫文章一模一樣,回頭看幾個月或者幾年前寫的東西,你總能發現一些改進。

所以如果反復提煉代碼已經不再有進展,那么你可以暫時把它放下。過幾個星期或者幾個月再回頭來看,也許就有煥然一新的靈感。這樣反反復復很多次之后,你就積累起了靈感和智慧,從而能夠在遇到新問題的時候直接朝正確,或者接近正確的方向前進。

寫優雅的代碼

人們都討厭“面條代碼”(spaghetti code),因為它就像面條一樣繞來繞去,沒法理清頭緒。那么優雅的代碼一般是什么形狀的呢?經過多年的觀察,我發現優雅的代碼,在形狀上有一些明顯的特征。

如果我們忽略具體的內容,從大體結構上來看,優雅的代碼看起來就像是一些整整齊齊,套在一起的盒子。如果跟整理房間做一個類比,就很容易理解。如果你把所有物品都丟在一個很大的抽屜里,那么它們就會全都混在一起。你就很難整理,很難迅速的找到需要的東西。但是如果你在抽屜里再放幾個小盒子,把物品分門別類放進去,那么它們就不會到處亂跑,你就可以比較容易的找到和管理它們。

優雅的代碼的另一個特征是,它的邏輯大體上看起來,是枝丫分明的樹狀結構(tree)。這是因為程序所做的幾乎一切事情,都是信息的傳遞和分支。你可以把代碼看成是一個電路,電流經過導線,分流或者匯合。如果你是這樣思考的,你的代碼里就會比較少出現只有一個分支的if語句,它看起來就會像這個樣子:

if (...) {

if (...) {

...

} else {

...

}

} else if (...) {

...

} else {

...

}

注意到了嗎?在我的代碼里面,if語句幾乎總是有兩個分支。它們有可能嵌套,有多層的縮進,而且else分支里面有可能出現少量重復的代碼。然而這樣的結構,邏輯卻非常嚴密和清晰。在后面我會告訴你為什么if語句最好有兩個分支。

寫模塊化的代碼

有些人吵著鬧著要讓程序“模塊化”,結果他們的做法是把代碼分部到多個文件和目錄里面,然后把這些目錄或者文件叫做“module”。他們甚至把這些目錄分放在不同的VCS repo里面。結果這樣的作法并沒有帶來合作的流暢,而是帶來了許多的麻煩。這是因為他們其實并不理解什么叫做“模塊”,膚淺的把代碼切割開來,分放在不同的位置,其實非但不能達到模塊化的目的,而且制造了不必要的麻煩。

真正的模塊化,并不是文本意義上的,而是邏輯意義上的。一個模塊應該像一個電路芯片,它有定義良好的輸入和輸出。實際上一種很好的模塊化方法早已經存在,它的名字叫做“函數”。每一個函數都有明確的輸入(參數)和輸出(返回值),同一個文件里可以包含多個函數,所以你其實根本不需要把代碼分開在多個文件或者目錄里面,同樣可以完成代碼的模塊化。我可以把代碼全都寫在同一個文件里,卻仍然是非常模塊化的代碼。

想要達到很好的模塊化,你需要做到以下幾點:

- 避免寫太長的函數。如果發現函數太大了,就應該把它拆分成幾個更小的。通常我寫的函數長度都不超過40行。對比一下,一般筆記本電腦屏幕所能容納的代碼行數是50行。我可以一目了然的看見一個40行的函數,而不需要滾屏。只有40行而不是50行的原因是,我的眼球不轉的話,最大的視角只看得到40行代碼。

如果我看代碼不轉眼球的話,我就能把整片代碼完整的映射到我的視覺神經里,這樣就算忽然閉上眼睛,我也能看得見這段代碼。我發現閉上眼睛的時候,大腦能夠更加有效地處理代碼,你能想象這段代碼可以變成什么其它的形狀。40行并不是一個很大的限制,因為函數里面比較復雜的部分,往往早就被我提取出去,做成了更小的函數,然后從原來的函數里面調用。

- 制造小的工具函數。如果你仔細觀察代碼,就會發現其實里面有很多的重復。這些常用的代碼,不管它有多短,提取出去做成函數,都可能是會有好處的。有些幫助函數也許就只有兩行,然而它們卻能大大簡化主要函數里面的邏輯。

有些人不喜歡使用小的函數,因為他們想避免函數調用的開銷,結果他們寫出幾百行之大的函數。這是一種過時的觀念。現代的編譯器都能自動的把小的函數內聯(inline)到調用它的地方,所以根本不產生函數調用,也就不會產生任何多余的開銷。

寫可讀的代碼

有些人以為寫很多注釋就可以讓代碼更加可讀,然而卻發現事與愿違。注釋不但沒能讓代碼變得可讀,反而由于大量的注釋充斥在代碼中間,讓程序變得障眼難讀。而且代碼的邏輯一旦修改,就會有很多的注釋變得過時,需要更新。修改注釋是相當大的負擔,所以大量的注釋,反而成為了妨礙改進代碼的絆腳石。

實際上,真正優雅可讀的代碼,是幾乎不需要注釋的。如果你發現需要寫很多注釋,那么你的代碼肯定是含混晦澀,邏輯不清晰的。其實,程序語言相比自然語言,是更加強大而嚴謹的,它其實具有自然語言最主要的元素:主語,謂語,賓語,名詞,動詞,如果,那么,否則,是,不是,…… 所以如果你充分利用了程序語言的表達能力,你完全可以用程序本身來表達它到底在干什么,而不需要自然語言的輔助。

有少數的時候,你也許會為了繞過其他一些代碼的設計問題,采用一些違反直覺的作法。這時候你可以使用很短注釋,說明為什么要寫成那奇怪的樣子。這樣的情況應該少出現,否則這意味著整個代碼的設計都有問題。

寫簡單的代碼

程序語言都喜歡標新立異,提供這樣那樣的“特性”,然而有些特性其實并不是什么好東西。很多特性都經不起時間的考驗,最后帶來的麻煩,比解決的問題還多。很多人盲目的追求“短小”和“精悍”,或者為了顯示自己頭腦聰明,學得快,所以喜歡利用語言里的一些特殊構造,寫出過于“聰明”,難以理解的代碼。

并不是語言提供什么,你就一定要把它用上的。實際上你只需要其中很小的一部分功能,就能寫出優秀的代碼。我一向反對“充分利用”程序語言里的所有特性。實際上,我心目中有一套最好的構造。不管語言提供了多么“神奇”的,“新”的特性,我基本都只用經過千錘百煉,我覺得值得信奈的那一套。

現在針對一些有問題的語言特性,我介紹一些我自己使用的代碼規范,并且講解一下為什么它們能讓代碼更簡單。

- 避免使用自增減表達式(i++,++i,i--,--i)。這種自增減操作表達式其實是歷史遺留的設計失誤。它們含義蹊蹺,非常容易弄錯。它們把讀和寫這兩種完全不同的操作,混淆纏繞在一起,把語義搞得烏七八糟。含有它們的表達式,結果可能取決于求值順序,所以它可能在某種編譯器下能正確運行,換一個編譯器就出現離奇的錯誤。

其實這兩個表達式完全可以分解成兩步,把讀和寫分開:一步更新i的值,另外一步使用i的值。比如,如果你想寫foo(i++),你完全可以把它拆成int t = i; i += 1; foo(t);。如果你想寫foo(++i),可以拆成i += 1; foo(i); 拆開之后的代碼,含義完全一致,卻清晰很多。到底更新是在取值之前還是之后,一目了然。

- 有人也許以為i++或者++i的效率比拆開之后要高,這只是一種錯覺。這些代碼經過基本的編譯器優化之后,生成的機器代碼是完全沒有區別的。自增減表達式只有在兩種情況下才可以安全的使用。一種是在for循環的update部分,比如for(int i = 0; i < 5; i++)。另一種情況是寫成單獨的一行,比如i++;。這兩種情況是完全沒有歧義的。你需要避免其它的情況,比如用在復雜的表達式里面,比如foo(i++),foo(++i) + foo(i),…… 沒有人應該知道,或者去追究這些是什么意思。

- 永遠不要省略花括號。很多語言允許你在某種情況下省略掉花括號,比如C,Java都允許你在if語句里面只有一句話的時候省略掉花括號:

if (...)

action1();

- 避免使用continue和break。循環語句(for,while)里面出現return是沒問題的,然而如果你使用了continue或者break,就會讓循環的邏輯和終止條件變得復雜,難以確保正確。

出現continue或者break的原因,往往是對循環的邏輯沒有想清楚。如果你考慮周全了,應該是幾乎不需要continue或者break的。如果你的循環里出現了continue或者break,你就應該考慮改寫這個循環。

另外一種過度工程的來源,是過度的關心“代碼重用”。很多人“可用”的代碼還沒寫出來呢,就在關心“重用”。為了讓代碼可以重用,最后被自己搞出來的各種框架捆住手腳,最后連可用的代碼就沒寫好。如果可用的代碼都寫不好,又何談重用呢?很多一開頭就考慮太多重用的工程,到后來被人完全拋棄,沒人用了,因為別人發現這些代碼太難懂了,自己從頭開始寫一個,反而省好多事。

過度地關心“測試”,也會引起過度工程。有些人為了測試,把本來很簡單的代碼改成“方便測試”的形式,結果引入很多復雜性,以至于本來一下就能寫對的代碼,最后復雜不堪,出現很多bug。

世界上有兩種“沒有bug”的代碼。一種是“沒有明顯的bug的代碼”,另一種是“明顯沒有bug的代碼”。第一種情況,由于代碼復雜不堪,加上很多測試,各種coverage,貌似測試都通過了,所以就認為代碼是正確的。第二種情況,由于代碼簡單直接,就算沒寫很多測試,你一眼看去就知道它不可能有bug。你喜歡哪一種“沒有bug”的代碼呢?

根據這些,我總結出來的防止過度工程的原則如下:

- 先把眼前的問題解決掉,解決好,再考慮將來的擴展問題。

- 先寫出可用的代碼,反復推敲,再考慮是否需要重用的問題。

- 先寫出可用,簡單,明顯沒有bug的代碼,再考慮測試的問題。?

更多Java培訓,Java視頻,Java教程盡在北京尚學堂,關注北京尚學堂官方微信,獲得一手Java最新知識。

更多猛料!歡迎掃描上方二維碼關注北京尚學堂官方微信公眾號(資料領取驗證消息:156)

本文作者北京尚學堂原創。如需轉載請聯系作者授權,未經授權,轉載必究。

?

轉載于:https://my.oschina.net/u/2947706/blog/790346

總結

以上是生活随笔為你收集整理的北京尚学堂|程序员的智慧的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。