編程到底難在哪裡?

各種語言就好比文字,編程的過程就是用文筆書寫詩篇,假設對於語言的應用已經十分透徹了,那麼編程的難點在哪裡?

在使用的思路,還是各種演算法,還是以人腦卻用電腦的方式思考問題?


謝邀。

關於這個問題,這個人已經回答的很好了:


他在1986年的一次茶話會上發了一篇受邀論文(論文的開頭就是「謝邀」),題目就是《沒有銀彈-軟體工程中的根本和次要問題》。
這個人就是IBM大型機之父,Frederick Brooks.
整個論文不太長,有興趣的同學可以找來讀讀。在他的經典書《人月神話》中也有收錄。
在30多年後的今天,我們在知乎上討論這個問題,他卻早就回答了。他的答案,至今看來,都沒有一絲一毫需要修改的地方,毫無瑕疵。

布魯克斯把軟體開發中的困難分為兩類:
essence,可以譯為本質困難或者主要問題,指的是軟體開發中不可規避的問題,就是軟體本身在概念建構上存先天的困難,也就是如何從問題領域,發展出具體的解決方案。
Accident,可以譯為次要因素或次要問題,指的是把解決方案實施到電腦上,所遇到的困難。

他認為軟體開發中無法規避的四個特性是:
複雜度;
一致性;
可變性;
不可見性。

他還歸納了在次要問題上我們取得的進步:
高級語言;
分時系統;
統一開發環境。

次要問題我們就不展開了,相信大家都可以理解。
下面所有就都是摘錄了,分別描述了4個主要問題。


複雜度。

規模上,軟體實體可能比任何由人類創造的其他實體要複雜,因為沒有任何兩個軟體部分是相同的(至少是在語句的級別)。如果有相同的情況,我們會把它們合併成供調用的子函數。在這個方面,軟體系統與計算機、建築或者汽車大不相同,後者往往存在著大量重複的部分。
數字計算機本身就比人類建造的大多數東西複雜。計算機擁有大量的狀態,這使得構思、描述和測試都非常困難。軟體系統的狀態又比計算機系統狀態多若干個數量級。
同樣,軟體實體的擴展也不僅僅是相同元素重複添加,而必須是不同元素實體的添加。大多數情況下,這些元素以非線性遞增的方式交互,因此整個軟體的複雜度以更大的非線性級數增長。
軟體的複雜度是必要屬性,不是次要因素。因此,抽掉複雜度的軟體實體描述常常也去掉了一些本質屬性。數學和物理學在過去三個世紀取得了巨大的進步,數學家和物理學家們建立模型以簡化複雜的現象,從模型中抽取出各種特性,並通過試驗來驗證這些特性。這些方法之所以可行——是因為模型中忽略的複雜度不是被研究現象的必要屬性。當複雜度是本質特性時,這些方法就行不通了。
上述軟體特有的複雜度問題造成了很多經典的軟體產品開發問題。由於複雜度,團隊成員之間的溝通非常困難,導致了產品瑕疵、成本超支和進度延遲;由於複雜度,列舉和理解所有可能的狀態十分困難,影響了產品的可靠性;由於函數的複雜度,函數調用變得困難,導致程序難以使用;由於結構性複雜度,程序難以在不產生副作用的情況下用新函數擴充;由於結構性複雜度,造成很多安全機制狀態上的不可見性。
複雜度不僅僅導致技術上的困難,還引發了很多管理上的問題。它使全面理解問題變得困難,從而妨礙了概念上的完整性;它使所有離散出口難以尋找和控制;它引起了大量學習和理解上的負擔,使開發慢慢演變成了一場災難。


一致性。

並不是只有軟體工程師才面對複雜問題。物理學家甚至在非常「基礎」的級別上,面對異常複雜的事物。不過,物理學家堅信必定存在著某種通用原理,或者在夸克中,或者在統一場論中。愛因斯坦曾不斷地重申自然界一定存在著簡化的解釋,因為上帝不是專橫武斷或反覆無常的。
軟體工程師卻無法從類似的信念中獲得安慰,他必須控制的很多複雜度是隨心所欲、毫無規則可言的,來自若干必須遵循的人為慣例和系統。它們隨介面的不同而改變,隨時間的推移而變化,而且,這些變化不是必需的,僅僅由於它們是不同的人——而非上帝——設計的結果。
某些情況下,因為是開發最新的軟體,所以它必須遵循各種介面。另一些情況下,軟體的開發目標就是兼容性。在上述的所有情況中,很多複雜性來自保持與其他介面的一致,對軟體的任何再設計,都無法簡化這些複雜特性。


可變性。

軟體實體經常會遭受到持續的變更壓力。當然,建築、汽車、計算機也是如此。不過,工業製造的產品在出廠之後不會經常地發生修改,它們會被後續模型所取代,或者必要更改會被整合到具有相同基本設計的後續產品系列。汽車的更改十分罕見,計算機的現場調整時有發生。然而,它們和軟體的現場修改比起來,都要少很多。
其中部分的原因是因為系統中的軟體包含了很多功能,而功能是最容易感受變更壓力的部分。另外的原因是因為軟體可以很容易地進行修改——它是純粹思維活動的產物,可以無限擴展。日常生活中,建築有可能發生變化,但眾所周知,建築修改的成本很高,從而打消了那些想提出修改的人的念頭。
所有成功的軟體都會發生變更。現實工作中,經常發生兩種情況。當人們發現軟體很有用時,會在原有應用範圍的邊界,或者在超越邊界的情況下使用軟體。功能擴展的壓力主要來自那些喜歡基本功能,又對軟體提出了很多新用法的用戶們。
其次,軟體一定是在某種計算機硬體平台上開發,成功軟體的生命期通常比當初的計算機硬體平台要長。即使不是更換計算機,則有可能是換新型號的磁碟、顯示器或者印表機。軟體必須與各種新生事物保持一致。
簡言之,軟體產品紮根於文化的母體中,如各種應用、用戶、自然及社會規律、計算機硬體等等。後者持續不斷地變化著,這些變化無情地強迫著軟體隨之變化。


不可見性。

軟體是不可見的和無法可視化的。例如,幾何抽象是強大的工具。建築平面圖能幫助建築師和客戶一起評估空間布局、進出的運輸流量和各個角度的視覺效果。這樣,矛盾變得突出,忽略的地方變得明顯。同樣,機械製圖、化學分子模型儘管是抽象模型,但都起了相同的作用。總之,都可以通過幾何抽象來捕獲物理存在的幾何特性。
軟體的客觀存在不具有空間的形體特徵。因此,沒有已有的表達方式,就像陸地海洋有地圖、矽片有膜片圖、計算機有電路圖一樣。當我們試圖用圖形來描述軟體結構時,我們發現它不僅僅包含一個,而是很多相互關聯、重疊在一起的圖形。這些圖形可能描繪控制流程、數據流、依賴關係、時間序列、名字空間的相互關係等等。它們通常不是有較少層次的扁平結構。實際上,在上述結構上建立概念控制的一種方法是強制將關聯分割,直到可以層次化一個或多個圖形2。
除去軟體結構上的限制和簡化方面的進展,軟體仍然保持著無法可視化的固有特性,從而剝奪了一些具有強大功能的概念工具的構造思路。這種缺憾不僅限制了個人的設計過程,也嚴重地阻礙了相互之間的交流。

我的公眾號dingshukai666,教編程,歡迎關注~

http://weixin.qq.com/r/yzhMVE3EShA1rQk3923Z (二維碼自動識別)


普通人:

我今天要買一斤蘋果。

程序員:

我今天要買一斤蘋果。

因為我只喜歡紅富士蘋果,所以我只買紅富士蘋果。

我能接受的最高價格是10元/斤。

正常情況下一斤蘋果用一個袋子能裝下,但是為防萬一,我會帶兩個袋子。

我知道附近的3家水果店,所以我會依次訪問這3家水果店。

根據上述條件,我設計出以下的買蘋果的流程:

買蘋果流程開始
對水果店0、水果店1、水果店2依次執行:
拜訪一家水果店流程開始
走到此水果店
如果此水果店沒有開門,則結束當前的「拜訪一家水果店流程」
如果此水果店沒有蘋果,則結束當前的「拜訪一家水果店流程」
如果此水果店的蘋果當中沒有紅富士蘋果,則結束當前的「拜訪一家水果店流程」
如果此水果店的紅富士蘋果剩餘不到一斤,則結束當前的「拜訪一家水果店流程」
如果此水果店的紅富士蘋果的價格高於10元/斤,則執行3次:
講價流程開始
詢問店主是否願意將價格降到10元/斤或更低
如果店主願意,則跳過剩餘的「講價流程」
講價流程結束
如果此水果店的紅富士蘋果的價格仍然高於10元/斤,則結束當前的「拜訪一家水果店流程」
打開一個袋子,將其作為當前的袋子
重複執行以下流程,直到總重量大於一斤:
裝袋一個蘋果流程開始
從所有的不在袋子中的紅富士蘋果中選出最好的一個
如果此蘋果能裝入當前的袋子,則將此蘋果裝入當前的袋子,否則執行:
換袋子流程開始
如果我有剩餘的袋子,則從中任意選出一個並作為當前的袋子,否則執行:
向店主要袋子流程開始
向店主索要一個袋子
如果店主拒絕給我袋子,則將我的所有袋子里的所有蘋果取出,然後結束當前的「拜訪一家水果店流程」
將店主給我的袋子作為當前的袋子
向店主要袋子流程結束
換袋子流程結束
測量我的所有袋子里的所有蘋果的總重量
裝袋一個蘋果流程結束
根據我的所有袋子里的所有蘋果的總重量和店主給出的價格,計算我應付的價格
向店主詢問我應付的價格
如果我不接受店主索要的價格,則執行3次:
校對流程開始
向店主解釋我計算出的價格,並詢問其是否同意
如果店主同意,則跳過剩餘的「校對流程」
校對流程結束
如果我仍然不接受店主索要的價格,則將我的所有袋子里的所有蘋果取出,然後結束當前的「拜訪一家水果店流程」
如果我沒帶錢,則將我的所有袋子里的所有蘋果取出,然後結束當前的「拜訪一家水果店流程」
付錢拿走蘋果
跳過剩餘的「拜訪一家水果店流程」
拜訪一家水果店流程結束
買蘋果流程結束

這個流程怎麼樣?我來設計一些測試樣例,測試一下這個流程。

測試發現一個問題:如果水果店0和水果店1都有紅富士蘋果並且價格都低於10元/斤,而且水果店1的價格比水果店0更低,那麼我希望買水果店1的蘋果,但我設計的流程會讓我買水果店0的蘋果。

為了解決這個問題,我應該先詢問所有水果店的價格,然後去價格最低的那一家買蘋果。

經過修改,我重新設計出以下的買蘋果的流程:

買蘋果流程開始
對水果店0、水果店1、水果店2依次執行:
詢問一家水果店的紅富士價格流程開始
走到此水果店
如果此水果店沒有開門,則視此水果店的紅富士價格為無窮大元/斤,並結束當前的「詢問一家水果店的紅富士價格流程」
如果此水果店沒有蘋果,則視此水果店的紅富士價格為無窮大元/斤,並結束當前的「詢問一家水果店的紅富士價格流程」
如果此水果店的蘋果當中沒有紅富士蘋果,則視此水果店的紅富士價格為無窮大元/斤,並結束當前的「詢問一家水果店的紅富士價格流程」
如果此水果店的紅富士蘋果剩餘不到一斤,則視此水果店的紅富士價格為無窮大元/斤,並結束當前的「詢問一家水果店的紅富士價格流程」
向店主詢問此水果店的紅富士蘋果價格並記錄
詢問一家水果店的紅富士價格流程結束
從3家水果店中選出紅富士價格最低的一家(如果有並列則隨機選擇),將其作為目標水果店
如果目標水果店的紅富士蘋果價格為無窮大元/斤,則結束當前的「買蘋果流程」
走到目標水果店
如果此水果店的紅富士蘋果的價格高於10元/斤,則執行3次:
講價流程開始
詢問店主是否願意將價格降到10元/斤或更低
如果店主願意,則跳過剩餘的「講價流程」
講價流程結束
如果此水果店的紅富士蘋果的價格仍然高於10元/斤,則結束當前的「買蘋果流程」
打開一個袋子,將其作為當前的袋子
重複執行以下流程,直到總重量大於一斤:
裝袋一個蘋果流程開始
從所有的不在袋子中的紅富士蘋果中選出最好的一個
如果此蘋果能裝入當前的袋子,則將此蘋果裝入當前的袋子,否則執行:
換袋子流程開始
如果我有剩餘的袋子,則從中任意選出一個並作為當前的袋子,否則執行:
向店主要袋子流程開始
向店主索要一個袋子
如果店主拒絕給我袋子,則將我的所有袋子里的所有蘋果取出,然後結束當前的「買蘋果流程」
將店主給我的袋子作為當前的袋子
向店主要袋子流程結束
換袋子流程結束
測量我的所有袋子里的所有蘋果的總重量
裝袋一個蘋果流程結束
根據我的所有袋子里的所有蘋果的總重量和店主給出的價格,計算我應付的價格
向店主詢問我應付的價格
如果我不接受店主索要的價格,則執行3次:
校對流程開始
向店主解釋我計算出的價格,並詢問其是否同意
如果店主同意,則跳過剩餘的「校對流程」
校對流程結束
如果我仍然不接受店主索要的價格,則將我的所有袋子里的所有蘋果取出,然後結束當前的「買蘋果流程」
如果我沒帶錢,則將我的所有袋子里的所有蘋果取出,然後結束當前的「買蘋果流程」
付錢拿走蘋果
買蘋果流程結束

現在這個流程是不是完美了呢?不是,我還能發現很多問題。
如果3家水果店都有紅富士蘋果但都不到一斤,但是三家店加起來能達到一斤,那麼我不應該結束流程回家,而是應該把三家店的紅富士蘋果都買下來。
如果我向水果店詢問價格的時候這家店還有紅富士蘋果,但我詢問完所有水果店的價格後這家店的紅富士蘋果賣完了,那麼我的流程會讓我試圖處理不存在的紅富士蘋果。
我走路的過程中可能會遇到突發事件,比如發現了新的水果店,比如袋子破掉了蘋果掉一地,對於這些情況我的流程都無法進行處理。

啊問題太多了我懶得再改流程了。我還是去X寶買吧。
那麼接下來我要設計一個在X寶買紅富士蘋果的流程……

==========================================================

這篇沉寂了5天只得到1個贊的回答竟然一夜之間收穫2000+贊,一舉成為個人最多贊的回答。感謝大家的支持,以及精彩的評論。

這篇回答並不是講述在生活中程序員如何買蘋果,而是以買蘋果為例說明程序員如何解決問題。程序員需要對問題進行透徹的分析,理清其涉及的所有細節,預測可能發生的所有意外與非意外的情況,列出解決方案的所有步驟,以及對解決方案進行盡量全面的測試。

而這些正是我認為編程難的地方。任何一點遺漏都會成為bug,輕則導致挨罵,重則導致經濟損失甚至危害安全。

注意這些難點全部和語言無關。和編程所需要的絕對嚴密的邏輯相比,語言實在是太簡單了。(某些自帶代碼混淆效果的語言除外)

==========================================================

我勒個去4000+贊了!媽媽!我火了!

好多評論說這代碼像python。然而我根本不會講python。

==========================================================

本回答可以隨意轉載,只需附帶原文鏈接即可。


最近項目逼緊,老同事有一個bug始終解決不了,拖了半個月了,老大就把我給派過去協助。

我們做的是用C語言生成硬體代碼(更低層的verilog,verilog是一門硬體編程語言),懂這個的知道這個叫做HLS開發(高層次綜合)。

HLS算得上是比較新的東西,因為傳統上設計硬體,都是直接coding 硬體設計代碼。幾十年都是如此,直到最近幾年HLS開始慢慢有了應用。

他那段代碼並不是很複雜,總共30多行,我反覆閱讀了代碼,邏輯功能沒有問題,模擬也沒有問題。純C語言模擬可以實現想要的功能。

綜合成底層的verilog代碼的過程中也沒有報錯。

但是綜合得到的verilog代碼,跟C代碼的功能卻不一致。

也就是說工具並沒有成功的從C語言轉換到我們需要的verilog語言。

我們初步斷定是coding style的問題,因為HLS對C語言的寫法有要求,如果寫的不好,要不綜合得到的硬體性能不好面積太大,還有可能綜合的不對。

因為肉眼看不出來,所以暴力的方法,就是重新寫一個。換一種寫法,說不定運氣好能過。

所以我試了另外一種寫法,用了一種高級的數據類型,代碼只有10行。

綜合結果也不對。

我把其中的部分代碼一行一行刪掉,最後只剩下4行,終於對了。

所以我判定另外6行有問題。

我對另外6行再次改寫,把一些常變數換成固定數值,發現固定數值就沒有問題。

看到了一點曙光。

於是我開始懷疑是一個常量的數據類型錯了。

原代碼裡面常量採用了constant int的類型,當我將其改成ac_int&<32,true&>的時候,終於對了。

所以你看,我們搞了一個星期,到最後發現就是一個變數類型定義不對。

總代碼數非常少,也就是十幾行,修改的地方也就幾個字元。

但是為了得到這個結果,我們試了十幾種方法,換了各種各樣的coding style。

編程難的地方的就是這裡。寫的時候很爽,覺得自己思路清晰,寫完了,全是bug。

bug多了,就覺得沒意思了。

現在的編程,說是高級語言,其實還是人在理解機器。

為什麼Class複製之後只是指針複製了?別的變數複製之後整體都被複制了?

這些都是為了機器的方便,為了少點開銷,對人只會造成混淆。

機器不具有容錯能力,機器一遇到bug只會撒手,說白了還是我們的機器不行。

我們仍然處於編程歷史的初級階段。


難在複雜性的持續增加。

如果編寫一段寫完就扔的代碼(如運維修復),那其實是可以很快做好的,想不通的地方繞一繞總也能搞得定。

但當你編寫的是一段大規模使用,需要持續改進,並且不斷有新功能需要添加的代碼。那麼難度就急劇增加了(這也是我認為的編程的主要難處)。

一方面,最開始編寫代碼的時候就要考慮到以後的擴展性,而這個考慮又永遠不可能是完備的,也不應該是完備的(不要過早優化)。只有一些基本的原則,比如保持單模塊的獨立性,避免模塊間的耦合,這些原則的運用需要豐富的經驗,並且不一定總是用好了。

另一方面,在代碼的持續演進過程中,需要對抗代碼的腐化。當原來拍著胸脯保證的確定因素突然變成不確定因素;當代碼引入了不合理的功能(如需要理解上層邏輯);當有新的人來維護代碼。代碼腐化的結果是大大增加了工作量和減少了代碼的穩定性。(代碼腐化只有一個好處,天天加班,顯得事情很多,搞不好能把領導唬住)


一個測試工程師走進一家酒吧,要了一杯啤酒;
一個測試工程師走進一家酒吧,要了一杯咖啡;
一個測試工程師走進一家酒吧,要了0.7杯啤酒;
一個測試工程師走進一家酒吧,要了-1杯啤酒;
一個測試工程師走進一家酒吧,要了2^32杯啤酒;
一個測試工程師走進一家酒吧,要了一杯洗腳水;
一個測試工程師走進一家酒吧,要了一杯蜥蜴;
一個測試工程師走進一家酒吧,要了一份asdfQwer@24dg!*(@;
一個測試工程師走進一家酒吧,什麼也沒要;
一個測試工程師走進一家酒吧,又走出去又從窗戶進來又從後門出去從下水道鑽進來;
一個測試工程師走進一家酒吧,又走出去又進來又出去又進來又出去,最後在外面把老闆打了一頓;
一個測試工程師走進一家酒吧,要了一杯燙燙燙的錕斤拷;
一個測試工程師走進一家酒吧,要了NaN杯Null;
一個測試工程師衝進一家酒吧,要了500T啤酒咖啡洗腳水野貓狼牙棒奶茶;
一個測試工程師把酒吧拆了;
一個測試工程師化裝成老闆走進一家酒吧,要了500杯啤酒並且不付錢;
一萬個測試工程師在酒吧門外呼嘯而過;
一個測試工程師走進一家酒吧,要了一杯啤酒";DROP TABLE 酒吧;

測試工程師們滿意地離開了酒吧。
然後一名顧客點了一份炒飯,酒吧炸了。

——轉載自朋友圈


這是一個大坑。
準備花一個春節的時間填完。
首先安利一個收藏夾:野生程序員 - 收藏夾 - 知乎。
所有關心「如何轉行程序員」的同學,請關注這個收藏夾就可以了。你們的評論/私信我都看了,有代表性的問題我都會想辦法弄到這個文件夾中,恕不能一一回答。

泡杯茶,我們慢慢聊。

編程難,首先入門就難。

「Hello,world」,其實並不像你想像的那麼簡單。

某雖不才,小學稀里糊塗的拿過縣裡奧數三等獎,95年就能用小霸王學習機(Basic)打出楊輝三角形,高中理科,98年能考進重點大學(專業悲催的國際貿易),大學期間還過了計算機二級(FoxBase),另外還參加自考拿到了法學學位和司法資格證書……說這些不是為了吹牛逼,而是為了讓你知道我真正正兒八經的學開發的時候有多慘啊有多慘!!!

/(ㄒoㄒ)/~~

然後,我關了公司,賣掉了汽車,背起了書包,和一大幫毛頭小子坐在一起,開始了我的編程之路。
真 心坑爹啊!說起來都是淚……我一個文科生,從中間開始學編程,這是一種神馬體驗?是「坐飛機」的體驗呀!我26年的人生中,第一次體會到什麼叫「上課坐飛 機」:老師講的每一個字我都聽得懂,但連在一起我就什麼都不懂,完全不懂他在說什麼。上機好一點,我TM至少知道開機。當然,除了開機我其他什麼都不會 了。

你可能會奇怪,那我之前學過的 if...else 呢,我之前學過的select呢?
我TM的怎麼知道?!誰讓老師一來就給我講什麼「面向對象」——面向,面向是個什麼鬼;對象,你說娟兒,我們馬上就要結婚了……
印象最深的就是開頭那幾課,講什麼貓啊狗啊四條腿之類的

你以為挺過了這個階段,能做出一個什麼「圖書管理系統」之類的玩意就OK了么?

培訓班是從非常實用的角度出發的,有點像速成雞,個頭看起來好像不錯,其實生存能力還完全不行。

在實際的學習工作中也發現了自己的不足,……,所以我要想提高的話,最好能去參加一次軟考,過了軟考怎麼怎麼牛B之類的。

和司法考試一樣,軟考也是有指定教材的;和司法資格考試不一樣的是,這個教材是根本看不懂的!我又在網上下載了視頻,沒用,吧啦吧啦講的些什麼東西啊?本來熱情高漲的信心被嘩的潑了一瓢冷水,看著那些什麼樹啊、圖啊、狀態機之類的東西,一種無力感悄悄的從心裡升起,隨之而來的就是困頓彷徨。

……
我慢慢的明白,我之所以看不懂軟考教材,是因為這教材里的每一個章節,都是大學計算機專業里的一門課程。這個教材,更像是一個大綱一個提煉總結,是給那些已經學過了《計算機基礎和原理》、《編譯原理》、《數據結構和演算法》……的大學畢業生作為考前複習資料看的。所以,我要做的,就是先把這些所有的課程學一遍。

所以就有這個高潮部分了。

我來到圖書館,因為這裡的書夠多。比如數據結構,這本書我看不懂, 我就再找一本,還看不懂,我就再找一本……總有一本書,能用我懂的語言,告訴我這究竟是怎麼一回事!一本不行就兩本,兩本不行就三本……空蕩蕩的圖書館裡,我有一種進入了金庸武俠世界,博採眾長,修鍊高深武學的感覺。這種感覺不斷的刺激著我的腎上腺素分泌,那種日夜不止的亢奮,直到今日,我都再也沒有能體驗到過。
……
在沒有任何基礎的情況下,我用4個月的時間,完成了大學四年的教程,一次性的通過了據說很多計算機專業畢業生都通不過的軟考!我像狼一樣的嚎叫,我淚流滿面咬牙切齒的叫囂,「就算我以後一輩子都是個笑話,我有這一次證明就夠了!就夠了!」

有了實戰經驗,夯實了軟體基礎,從此就走上了人生巔峰?

NO, NO, NO! too young too simple,

接著花式虐狗:

注意:不是裝孫子。我就真是一個孫子!

正式上班的第一天,老大就甩給我一個100多頁的文檔,純英文的,讓我「先看看」。「先看看」是什麼意思?不懂啊,更不敢問……
於是我就從第一頁開始看吧。真心看不懂,不是英文看不懂,是裡面的邏輯搞不懂……反正我就是不停的打瞌睡。睡又不敢睡,看又看不懂,問又不敢問,每天真的是如坐針氈如履薄冰。

……
老大的第二句話砸得我眼冒金星,「你先寫個設計文檔,給我看一下,然後我們就開工吧」!
如果可以自由表情的話,我的眼裡一定滿是淚水。設計文檔?傳說中的設計文檔?長什麼樣的?但現實是,我的眼神柔和而平靜,輕輕點頭,「好的」。

但接下來寫代碼就慘了。因為多人合作,所以公司用的是源代碼控制工具TFS,這東西我根本就沒聽說過,更不知道怎麼用。小心翼翼的問了下同事,聽得迷迷糊糊似懂非懂就只好硬著頭皮上了。

然後就闖禍了,一天下午,聽到同事叫了一聲,「咦?(代碼)怎麼跑不過了?編譯都不行啊?」我的心裡一緊。然後很快,就聽到諾大的辦公室此起彼伏的驚叫應和,一會兒就像一鍋粥一樣。

「老葉,是你提交的代碼出了問題?」
「啊?應該不會吧?」我後背開始冒汗。
「怎麼不是?你看你看……」暈死!這MB的源代碼一條條記錄清清楚楚,捉賊捉贓,被抓現行了!
「快點把它fix掉,別人(的代碼)都不能跑了」,見我還傻愣著,我們同事提醒我。
「fix掉?怎麼fix掉?」我在心裡悲鳴。裝不下去了,只好硬著頭皮承認原來自己不會。
「啊?」同事看了我一眼,還是過來幫忙吧。結果他也搞不定,「老葉,你究竟幹了些什麼呀?」
「啊,嗯,那個……」我支支吾吾,我哪知道我幹了些什麼?我要知道,會是現在這個樣子么?

……
日復一日,我悲慘的境遇沒有任何改變,不知道這種日子什麼時候是個頭。

以上引用全部都在《折騰》三卷:孕育 (初稿)哪裡可以看到?有興趣的同學可以自己去看。很多人覺得很熱血很勵志,但只是因為這是「事後吹牛逼」。
其實每一步都是一個坎。
很多人想學開發,買了一兩本書,聽了一兩節課,天書一樣,望而生畏,也就算了。這種人「連廟門都摸不到」,估計要佔到一半?
剩下的下了狠心,死活硬撐著把培訓班之類讀完了(或者自學到一定階段吧),但沒有文憑沒有工作經驗,找不到對口的工作,只好先將就著找一份「相關的」工作,慢慢的漸行漸遠,也再也回不了頭了。
就算好不容易找到了工作,開頭那段苦日子,也不是人過的。說句不好聽的話,現在大多數90後,從小嬌生慣養,受不得氣,前幾份工作換得走馬燈似的……換著換著很多人就放棄了。
我上的培訓班,二十多個同學,畢業的時候只有十來個了,畢業後做開發的五六個,一直到現在還做開發的……我知道的就兩個。

好了,講到這裡,其實我還是在說「很難」,「萬事開頭難」,本來如此。但具體到編程,到底哪裡難?還是不能迴避這個問題啊,我總結一下吧:

1、理解難。
不知道是不是因為計算機還剛剛發展的原因,軟體開發相關的書籍本身總量就很少,而且更麻煩的事,能稱之為「精品」的就更少。這裡所謂的「精品」,是指能深入淺出、通俗易懂的把道理說明白,說白了,面向初學者的書。
說都說到這裡來了,多說幾句吧。我發現很多人喜歡推崇「經典」(≈陳舊)的、「大部頭」(≈學究式)的書籍,感覺好像要「一般人都看不懂」的書才是好書。我始終覺得這很荒謬,當然,也可能是我境界還達不到。我對於這一類知識性的教科書,就一個要求,讓我以最快的時間獲取到正確的知識。不要和我繞彎子,又不是看《紅樓夢》;甚至不需要太精確,先給我一個大致的輪廓和印象都行。這樣的書屈指可數!
所以,確實沒辦法,我只有硬啃啊。「這本書我看不懂, 我就再找一本,還看不懂,我就再找一本」,這其實是挺無奈的。
而且計算機的很多底層的東西,非常複雜。什麼編譯原理,數據結構和演算法,我當時學這些東西的時候,就一個感覺:是不是世界上最聰明的人都來搞計算機了?他們的腦袋是怎麼把這些東西想出來的?
以我涉獵的些許學科來說,其中的很多知識理解起來,需要的其實都是「常識」。比如法律,公平正義;比如經濟學,需求供給理智人;比如建築,構造力學……唯獨這個計算機底層相關的東西,究竟是些什麼鬼?!
燒腦啊!
就最簡單的排序為例。我能完全理解的就一個冒泡,勉強能理解的有一個好像叫「二分排序」,然後其他的各式各樣的排序演算法,完全是……算了,都是淚,壞名頭,不說了。

2、實踐難。
有一些同學非常具有挑戰精神。難是吧?越難我越有勁!
於是抱著書本就開始硬啃。
結果大家當然能想得到了,然並卵。
計算機本質上是一個「實踐科學」。僅僅有理解,那是絕對不夠的。是騾子是馬,得牽出來遛遛。
這就是很多計算機專業的同學畢業後找工作很難的原因。
所謂「上不了手」啊。最簡單的,連一個開發環境都搭建不起來,代碼一報錯就傻眼,斷點調試全不會……實際開發中出現的問題是千奇百怪的,絕對不是你在學校機房,按照書本一點一點敲出來就OK的。
同樣的,這方面的教材也非常非常的少。基本上只能靠大家自己摸索,或者運氣好的,單位上有老鳥帶一帶。所以才有這種說法:「上一個月的班,比你自己看一年的書都強」。這種實踐能力,確實是看書很難獲得的。

+++++++++++++++++

呵呵,得順便安利一下這個東東:倡議:我們「一起幫」 - 自由飛 - 博客園。
希望能或多或少的解決一點這方面的問題。

+++++++++++++++++

好的,說完了入門,我們接著說:編程難,提高更難

其實想想這話像白說的一樣,因為任何一個行業做到一定程度再想要提高都很難。

一般來說,在這個行業待上兩年,再多也就三五年,就應該能入門了。(我個人覺得,入門的標準就是能獨立實現,自己崗位範圍內的,大部分的功能)

以我有限的閱歷來看(加這麼一句定語,不是謙虛,是心虛了),編程其實是一個很大的概念,但我喜歡把它分成兩種(簡單重申,以前回答/文章都反覆說過):

1、基礎類的計算機科學。大概就是編譯、演算法,數據結構之類的,個人覺得確實是拼智商的。我承認,我一直沒怎麼搞明白這些人是怎麼想出這些鬼主意的,我連弱爆了的排序都要掰著手指頭算,他們搞什麼樹啊圖啊之類的……沒辦法,只有膜拜!AlphaGo大戰李世石現場直播我一集沒拉下,心情一直不好了好幾天——總感覺自己就是或者很快就會是一個廢物一樣。

2、應用類的軟體工程。首先感謝主,讚美主,還是給了我這種傻子一條活路。在智商被碾壓之後還能看到一些不那麼需要智商的工作:IT民工——這不就是給我這個「包工頭」量身打造的么?你看,連名字都這麼像。我以前乾的是建築工程裝飾工程,現在叫軟體工程。

這一類型的開發工作,對於已經入門的開發人員而言,看上去非常簡單:後台「無非就是資料庫增刪改查」,前台就更簡單了,數據的顯示和傳遞而已……就算要點什麼新技術,「google+英語」就可以「卓越」,「百度+中文」就可以「應付」,一天到晚複製粘貼,修修補補,所以都說自己是個「搬磚的」。

怎麼突破這種日常的、平庸的、瑣碎的、繁雜的工作?

  1. 有的同學說,「往上爬,做管理吧」;
  2. 有的同學覺得管理玩不轉,「還是做技術吧,爭取做架構師」;
  3. 有的同學回頭啃以前懶得啃沒啃透的數據結構和演算法,「不要在做碼農了,我要做程序員」;
  4. 有的同學覺得樓下貼膜小哥的生意不錯,準備轉行了……

我個人覺得:1和4都轉行了,不在我們的討論範圍之類;3其實一開始就沒搞懂我之前說的「計算機科學」和「軟體工程」的區別;我們著重說一下2,「繼續做技術,做架構師」這條路。

其實寫代碼寫到一定的時候,你就會發覺:寫代碼就像寫文章。本質上,編程無非就是告訴計算機要怎麼怎麼的做,就像一個說明書或者命令集,給計算機下一道一道的命令,如果怎麼怎麼,就怎麼怎麼……

這裡有一道分水嶺:「會」和「好」的分水嶺。之前,是要「會」,比如語法正確、邏輯嚴密,要能和計算機正確溝通;但之後,是要「好」,這些命令要組織得「好」……

但首先怎麼個好法,這就很難講;接著,我要怎麼樣才能寫得這樣好,簡直沒法教。

最重要的是,選擇A還是選擇B,靠的是一種「權衡」。幾條路擺在面前,怎麼選?這就非常頭痛。

尤其是做著ABCD單選題長大的孩子來說,這簡直就是一場災難。因為是這樣也可以,那樣也可以,都可以,都對!你怎麼選?

你說既然都可以那我隨便選,天馬行空,想怎麼來就怎麼來!

但恰恰是你還不能這樣亂來,因為後面會出問題。不是電腦出問題,是人腦出問題。隨著項目代碼體量的加大,複雜度的加深,之前不是問題的問題都會一個接一個的冒出來,各個問題之間盤根錯節,牽一髮而動全身,讓你顧此失彼疲於奔命……

寫不下去了,呵呵。

因為這些東西,你經歷了才會懂,沒經歷我說了也是白說,你很難理解。

對於目前絕大多數的軟體工程而言,最難的其實就是「駕馭複雜度」,因為現在的軟體太複雜了!

+++++++++++++++++++

2017年9月11日

說實際的,歡迎大家 註冊·一起幫,這是我一個人從頭到尾開發的一個網站項目,開發過程全程直播並有錄像。

設立的初衷就是為了降低自學編程的難度,尤其是一些對新人來說「莫名其妙的」問題(比如配置不對、連不上資料庫之類的),問題本身沒多少技術含量,但確實新人自學過程中的攔路虎,自己瞎折騰不知道要花多少時間,但如果有人遠程桌面幫忙看看,很快就可以解決。

有興趣的同學註冊看看吧?


不是大牛,但從初中開始接觸編程時間也挺長了,也來談談對編程的想法

不同的人對編程難的理解是不同的,因為編程本身的維度是不一樣的,但最根本的,難在複雜性的控制,而不是一個個獨立的概念. 普通的像office上寫個vba,此時需要的只是永遠不會變的業務邏輯,並且這種代碼一般都是一個人寫的1000行以內,因此你不需要軟體工程的知識,時間長了也許會有編程很簡單的錯覺.這種編程最難的難在邏輯.

邏輯的難再上升一點便是演算法,數據結構,這時候你會學到時空複雜度,學會用三種方法證明快排的時間複雜度,知道了現代計算機在面對非P類問題的無力,知道圖靈機對於undecidable的問題的局限性,知道了用泵引理證明標準正則表達式永遠也找不到匹配的括弧,這時候你覺得很難,難在發現計算機其實幹不了很多事.

接下來你或許回去刷各路oj,面對題目,第一步難在問題的抽象\建模上,第二步難在抽象出中正確模型後演算法的選擇上.也許一個非常像貪心的題結果是網路流,也許一個非常像DP的題,結果是最短路,矩陣快速冪....抽像出模型後,根據實際問題的各種條件選出最優方案,例如這種形式的dp 可以單調棧,斜率,平行四邊形優化,選擇在線or離線演算法?稀疏圖還是稠密圖?這時候你會覺得很難,難在最基礎的演算法

接下來你會細分到具體的領域,此時的難就難在領域知識,這也是見仁見智.圖形學各種立體角的積分也許對你很難,數學系轉過來的小張也許就覺得公式比代碼來得親切.當然你也可以不管的,將系統看成一個黑盒,無腦調用現成的api,你不必關注神經網路是如何backpropagation的tensorflow,caffe等成熟的庫已經把所有東西封裝的很好了,你不必關注C++ RTTI的特性是如何實現的,現實生活中存在著大量這樣的"程序員",當發生問題時,梯度消失?爆炸?即使沒有太難的專業知識只是業務邏輯,為啥我把循環展開速度會快那麼多(gcc O2默認不進行循環展開優化)?為啥我只是把數組長度變一下速度立馬變了?他們也可以試出很多經驗規律,可以工作的很出色,但他們會覺得很難,這樣的難,難在編程所在平台,領域專業本身的複雜度,如同上面循環展開等,是由於目前CPU採用的分支預測策略以及pipeline被打斷,因此也算作領域的知識

最後,你終於開始寫real world的代碼了,你會發現代碼有10個G!用vs2017載入所有代碼便是一個晚上,你這輩子都無法全部讀完所有代碼,此時你發現,控制代碼複雜度非常難.當新增一個需求,壞味的代碼要在密密麻麻的代碼和文件中修改一兩個參數,代碼之間耦合非常大,A功能調好B功能不能用,AB都調好C又不能用,等C再調好,少年,晚上3點了,不要再加班了.一群人同時編譯一個函數,一個類,一個文件,你剛準備提交,別人又在這個文件里做了改動conflict了,你又只能花半小時把代碼合回去,又要看別人的合代碼防止衝突,合完剛想提交又有一個人提交,又conflict了.如果之前的東西偏計科,那這裡便是偏軟工的難度了.你會學著讓代碼分層,使用單例讓其只有一個訪問入口點,減少全局變數.體會到了don"t repeat urself的用處,看到一長段if else的邏輯,會想到用策略模式讓其變成一個個分散的類了,不再用全局變數了,識別清楚了哪些地方可能會有改動,日後業務可能會有擴展,提前調整架構.例如日後項目要增加支持中英雙語了,別人還在忙著將string改成wstring,彷彿重新寫一個系統,而你由於代碼架構靈活只要將新加的語言翻譯好即可.

這才明白所謂架構,不如接地氣的說下是整理代碼,就好像面對一個巨大的房子,裡面各種凌亂的衣服,電器,傢具,你要做的是把襪子分們別類的放到一堆,並且整個房子只有這個柜子能找到襪子,用完也只能放到這個柜子里,這樣就不至於東一隻襪子,西一隻襪子,遙控器的按鈕不能串,不能想打開電視機,空調也打開了;當一個柜子塞滿了衣服,並且有很多不同的人來取這些衣服,不如分出一些小柜子,按取的人分門別類,如果有若干人自己的衣服太多,則分出來春裝夏裝秋裝繼續分小柜子;房子的某些位置識別出可能日後會搬進新家電,那一開始走線的時候就要在那兒裝接線板,插座,架構這個詞太高高在上了,整理才適合

接著你會發現OO的思想本來就有著非比尋常的複雜度,每一個instance都是帶狀態的,這一次調這個介面的狀態和下一次可能是不一樣的,它是不純的.當遇到並發的情況時,這個缺點尤為明顯.你也許會接觸FP那套純函數的想法來消除副作用,然後打開了一扇嶄新的大門.

編程難在哪裡,不同的人,時期都會有不同維度的回答,但在我看來,編程的難在於世界本來就是複雜的,而編程只是用邏輯去模擬整個世界,編程的難在於邏輯的難,世界的難

這時候你剛接觸TMP的學弟對著動轍上百個編譯錯誤的甚至把編譯器搞掛的代碼,說編程好難啊          ----是啊,編程好難啊


編程不怎麼像是寫詩歌或者文章,因為對於詩歌和文章來說,基本元素粒度和作品的容錯度都相當大。

編程更像是繪畫或者雕塑,往畫布上塗一筆或者往石頭上鑿一下都很容易,但是要做出好的作品,需要做很多步,每一步都要很精確,而且往往會在做到最後的時候發現雖然細節還都不錯,但是整體看來總是看著不對勁。


難在偶發複雜性和固有複雜性: http://web.archive.org/web/20070329052658/http://www-inst.eecs.berkeley.edu/~maratb/readings/NoSilverBullet.html


編程就是老天給飯吃。


從專業性的角度出發,我們尊敬建築師遠遠高於尊敬程序員,畢竟軟體每天都在崩潰,而橋樑鮮有坍塌。

然而建築師修一座橋時,不會在修到一半時被告知河比預期的寬了兩百米;不會在修到四分之三時被告知河岸不是泥土而是花崗岩;不會在修到百分之九十九時被告知這座橋不應該是公路橋而是人行橋。而這一切在軟體開發行業里似乎是司空見慣的。

編程,或者說軟體開發更像是一個在瞬息萬變的大環境下保持一個小系統穩定發展並具有更新能力的事。這有點像城市規劃,其難度來自於人類社會本身的複雜度。人人都想去解決類型理論或超越馮諾伊曼模型之類的問題,但我認為這些問題屬於數學或狹義上的計算機科學,而不是編程。


2016年9月17日補充:

編程是一個靈活的工藝產品,是沒有定數的。代碼產品是無形的,猶如每個人心中有不同的漢姆雷特,不像 1+1 = 2 一樣結果明確。同樣的需求條件下,不同的人,不同的自我要求,有不同的產出。

同樣的功能,寫出代碼來,對質量有要求時,就如同海綿里的水,只要你願意擠,可以讓代碼寫的更完善,更周到,更穩妥,質量更好。而這些都是代碼的內在,不示與人的。所以,當你對代碼質量要求越高,對你的思維把控,對代碼的要求也會提升,與此同時,編程的成本和難度也會增加。

當你對代碼的要求降低,進度速度會提升,編程成本,難度和代碼質量也會隨之降低。

--

2016年8月18日再補充:

編程的難度,和你對自己代碼質量的要求也是正相關的。隨著你的經驗的增加,你會對代碼質量的要求也越來越高,你希望你的代碼可以更加通用和規範,穩定,具有好的可維護性,而不是僅僅某個具體項目中的具體需求中使用一次而已,因此,你會寫更通用,更抽象的代碼,你會考慮更多情況,在更多環境中可以使用,使得編程難度增加。

--

2016年8月8日補充:
這個問題是幾乎無法有一個統一簡潔的答案,只能從個人主觀感受的膚淺的談一點點感受,必然是片面的,不全面的,也不夠完整的。

----
編程的困難之處在於:

(1)思維模式的切換。你需要有技術思維。能夠成功建模。這可能是大多數人,沒有信心,或者不適合從事編程的原因之一。說到底,程序員就是在兩種思維模型之間轉換的人。一種是人類看到的感受到的外行人視角,一種是技術思維,即如何通過編程,來完成前者。

(2)語言上的難度,例如 C++ 語言本身。它包含了讀寫兩方面的基本要求,達到你可以面對越來越複雜,越來越難於理解的代碼,而不會感到困難和退縮的程度。很多人看到複雜的代碼時,自信心就已經被擊潰了。C++ 和 彙編,大概是目前難度最大的兩門語言。彙編難度主要是代碼可讀性是最低的,代碼量和跳轉數量是最大的。

(3)超強的對耐心的挑戰,編程中遇到的困難的挫敗感極強,大部分人會對此感到崩潰。編程需要付出和投入極大精力和耐心,對人的能力是很大挑戰,例如,無法完成任務,無法解決某個問題,無法找到問題所在。編程領域,有很多水平體現在穩定可靠性上,當你寫出一個東西,實驗是成功,然而在部署後實際運行時,總是出現隔三差五齣現很難解釋的問題的時候,說明你的水平有限。你的水平,和你的成果的可維護性,穩定性,可靠性是成正比的,而很多人可能會比較忽視這種「不夠直觀和直接,難以量化」的能力。它們需要程序員的責任心和經驗的積累,比如說,多線程編程方面的經驗等。

(4)當你掌握了基本編程技術和技巧,可以開始工作時,還有一項潛在的能力在考研你,你的大腦必須能夠完成在比較複雜場景下的調度,和場面掌控能力。比如說,你能夠一個人編寫需要配合的多個應用程序,它們可能來自服務端和客戶端,可能來自不同的功能程序。通過多個應用程序相互協調協作,通過溝通來有條不紊的完成一項任務。你的大腦必須足夠應付這樣的局面。在複雜的環境中,掌控大局,熟練的掌控整體和局部,有條不紊。

(5)需要鋪墊大量基礎知識,才能開始進入實踐。比如說,你要編寫「俄羅斯方塊」這樣一個簡單的遊戲,你需要有數據結構,和簡單演算法的基礎知識的積累,而不僅僅是學會了編程語言就可以的。


我畫過一張程序員工作的圖,可以很好的回答這個問題:


任何事物的創造,都會經歷兩個階段:

  1. 先在頭腦中創造
  2. 然後在現實中創造出來

編程的難點,就在第一個階段:如何在頭腦中設計、創造出產品。這需要你有邏輯思考、分析、想像、設計、整合、創造等各種能力。

一旦你把要做的東西事先在頭腦中想明白了,那接下來的編碼過程,反倒是輕鬆容易的。


軟體工程一般來說,難點僅僅在於不同級別的經理瞎指揮。

比爾蓋子20年前就意識到這個問題,所謂得到一個稍微靠譜一點的管理人員,是多麼難。


編程最難的地方其實不在於技術,而是在於「行動」,有一句名言,可以概括這一點:偉大的思想只有付諸行動才能成為壯舉。


編程本身不難。即使是書寫機器碼,也不是難事。

難的是:
1、如何將問題抽象。抽象問題才是編程的本質,你的程序如何編寫,如何設計,如何架構,都取決於你對問題看待是否全面,是否找到了問題的本質。

2、對軟體開發這件事情的認知。人類對軟體開發這件事情的認知遠沒有達到傳統製造業那樣的高度和成熟度。所以如何對軟體開發這件事情進行組織、管理變成一件需要探索的事情。

3、變化快。行業發展速度快。發展快意味著需要更快的學習新事物、使用新的視角來看待世界,這中高速變化在傳統製造業中是不曾有過的


人類世界,不管是「生產」什麼,「按章辦事」是最簡單的事情。讓自己符合「固定的標準」最容易——按圖紙,按流程,按標準做出來就好。
這個世界最難的是「創新」,其次難在「靠思維本身」挑戰「不可控的邏輯」去解決問題,再次難在「今天的自己把昨天的自己推翻」。程序員哥哥統統中槍。

編程之難,不在寫代碼本身——坐下去敲鍵盤而已。
編程之難,難在這是一條不歸路。難在邏輯複雜,難在太可變,難在不可見。你根本沒有喘氣的時候。從「入門」就開始難。一直難到你退休。

我來舉一個例子:
你認為走路簡單,在你看來是人類本能,但人類進化了200萬年,大腦才學會了走路——在人類進化過程中,人的大腦容量不斷增加,在200萬年的演變過程中,人類大腦體積增加了三倍,負責計劃和決策的大腦新皮層明顯增加,正因為如此,人類創建了各種文明以及複雜的社會行為。

我們走路,遇到台階的時候,正常反應是這樣的:眼睛看到台階高度,指揮大腦抬腿到合適的高度,條件反射的控制平衡,一隻腳落地,然後繼續抬另外的一隻腿,這個過程中如果台階出現過低的情況,人會產生一個踉蹌,你的大腦會立刻自動調整平衡。
但讓機器人走台階就十分難。因為受計算機思維方式限制。也和它的腦容量有關。如果說人類取得如此大的進步和腦容量增加有關。機器同理。

我是說,我們習以為常的事情,我們的祖先經過了200萬年的進化,你當然不覺得難,但是形成的過程是很複雜的。
而計算機出現才50年,目前還是基礎階段,機器的各種思考模式還有著很大的局限性,也是人類駕馭它最難的時候。

計算機難主要難在3個點上
1計算機由於電氣的特性。很多特質和人類思考的習慣不一樣,程序員哥哥需要經過反覆訓練才能習慣計算機的思考方式。

2業務邏輯的複雜性。一個行業的複雜性,任何一個人都說不清楚或完全掌握(包括業內頂級專家),現在要靠一堆程序員哥哥,一點點把他們架構起來,通過計算機的思考方式來實現。你說難不難?

3環境的複雜性,各種異常條件,各種衝突。這個不展開說。

當然了,目前的大環境,技術已經很進步了,帶來的解決問題的基礎設施已經越來越完善,10年以前看起來複雜的問題,現在都是小問題。現在複雜的問題,5年以後也是不值一提。
儘管業務層面的問題,在目前已經不是太難的問題,但新的問題——比如人工智慧相關,大數據相關,虛擬現實相關,自動計算等等吧,新的問題每一天都在出現,你無法想像也無法預測。為了解決這些「問題」,就會出現新的語言。你無法知道新的語言有多少,你無法知道需要學到哪一天才是盡頭。

你要問什麼是程序員哥哥的最高水平?我告訴你,沒有,因為這個世界變化太快了,新技術新科技日新月異。

所以程序是很難的。(我沒有說寫代碼)

最後:我在知乎答題都是看到喜歡的問題隨手念念一下,我認為我整體邏輯沒有錯即可,不要摳我字眼。手機碼字而已。


其實編程這個事情,一樣隔行如隔山,excel裡面寫個宏也是編程,寫個windows也是編程,不能一概而論。

比較簡單的程序其難度主要在於編程人員的技能,比如你是學生,你覺得你課程里的編程題有難度,主要是你對所使用的語言技能還不足夠。

跨過了這個點,在商業公司或者社區軟體裡面,難度主要是工程難度,複雜度的上升,參與人數的增加導致了工程難度,個體就算能完成,整合起來不一定能完成。

再跨過了這個點,所謂編程,就已經不是簡單地寫代碼了,其中還包括了選型的難度,使用什麼語言,使用什麼部件,都是難點。

再跨過這個點,編程的難度在於時間,成本和風險的控制,這就不單單是技術層面的問題,還有管理的問題。


題主這個問題我也從另外一個角度考慮過:程序員作為一種職業,它的核心技能是什麼?
我的看法:程序員的核心技能是短期記憶力 (short term memory [wikipedia] - Short-term memory is the capacity for holding a small amount of information in mind in an active, readily available state for a short period of time.),這也是區別一個優秀程序員和普通程序員的重要指標。
程序員需要學習很多新東西:程序語言的原理、語法、基本庫和框架的了解,以及領域知識等等;還要在工作中積累包括程序架構上、工程上、工作方法上的各種經驗。但是我覺得這些都不是核心,如果把一個程序員比作一台計算機,上面提到的東西都是數據,都是可以錄入的(或許錄入速度有快慢之分);而衡量一台計算機的優劣,真正關鍵的是處理能力的參數,例如處理器的主頻和內存的大小等等,這些硬體指標映射到程序員身上代表著什麼呢?對於程序員來說,一定有一些核心的思維能力起到決定性作用,換句話說,如果把智商看作一個多維向量,其中一定有某一個或一些維度是對程序員是至關重要的。
程序員在編寫代碼的時候,要在頭腦中構建好一個程序的模型,包括數據結構和演算法,再把這個模型轉化成代碼。在此過程中,這個模型一直存於頭腦的短期記憶中,並且可能需要不時地刷新。一旦受到外界干擾,這個模型就可能消失,必須花很大力氣重新載入,有人把這個模型比作紙牌屋,因為它實在太容易坍塌。所以程序員編程的時候都很怕干擾,因為一旦受到中斷,再次恢復原來的工作效率需要一段預熱的時間。更加困難的地方在於,這個模型並不是靜態的,它是會隨時間演變的,程序員要經常思考程序執行的過程(用自己的大腦扮演CPU的角色),根據不同的條件對模型作出變更。編程序這個腦力勞動,其實就是在大腦的易失存儲中,維護和完善一個具有時間和空間維度的模型的過程。
所以我猜想,一個合格的程序員和其他腦力勞動者的一個主要區別可能就在短期記憶這一塊:或者程序員的短期記憶空間較大(一般人是 7+2/-2樣東西,但程序員有時需要把一個龐大的系統放在腦子裡),或者短期記憶維持時間較長(寫代碼常常是連續多個小時的工作,在這樣長的時間裡在腦中維持一個模型是很耗費能量的),或者這塊記憶體的讀寫速率高(優秀的程序員想到一個問題時,能很快定位到程序模型中的具體位置)。當然,這些純屬猜測,需要心理學的實驗來證明。
我最近讀了Coders At Work,這是一本國際上最頂尖的15位程序員(或者叫大師)的訪談錄,看完以後,我發現這些人有一個特點,就是都對軟體工程的某些方法(比如設計模式等)嗤之以鼻。我覺得這不是巧合,軟體工程的一些方法就是為了讓各種水平參差不齊的的程序員都能理解複雜的代碼,以便他們能在一個軟體項目中合作。我們採用各種抽象方法(面向對象、設計模式等等)來降低每個代碼單位的複雜性,就是為了讓每一個這樣的單位(類,對象等)都能裝載到我們的短期記憶中而不溢出。而對於那些大師,這些抽象毫無必要,他們能把一大塊程序載入大腦,理解得清清楚楚,擺弄地遊刃有餘。在我看來,他們和普通人的差異就在這裡。
當然,也有人說過腦子笨的程序員才能成為好程序員,因為他們短期記憶小,所以不會寫那種上百行的函數(spaggetti code),代碼的模塊性自然都比較好。這裡的「好程序員」,應該指的是軟體項目里的模範代碼工人,而不是Coders At Work中那些天賦異秉的大神們,而軟體業要發展,可能還是要靠這些有著超強存儲能力的大腦吧。

-----------------------------------------------
歡迎程序員關注我的微信公眾賬號:codergroup
針對程序員群體,每周推送一次,都是你最關心的業界資訊、技術動向,還有那些只有我們才懂的梗~。組織在呼喚你,還不加入?

http://weixin.qq.com/r/njq-p8vEHZZirY-E92_M (二維碼自動識別)


命名是一門藝術,函數與變數的命名也是編程中的一個重點、難點。

命名為什麼會這麼難,因為它太重要了。準確的命名可以提高代碼的可讀性,讓人容易理解,方便調試,也給以後修改和維護你的代碼的人帶來方便。

假如你維護一個代碼,那個變數名稱充斥著,aa,ab,ac,i,j,,,,,沒有一個清晰的注釋說明這些是幹什麼的。然後,你要讀不懂,人家還懷疑你的水平不行,我了個去,砸電腦!!!

就像Jeff Atwood 所寫的:

「想出好的命名的確很難,但是有難的道理,因為好的命名需要只用一兩個單詞出表達你的根本意思。通常,如果你無法想出一個合適的名字,意味著你的設計可能有問題。你的一個方法里是不是實現了太多的功能?或者你的類的封裝,凝聚性不夠強?」

「我的經驗是如果無法給你的類想出一個合適的名字,大多數情況都是你的類有問題:你可能不需要這個類,它有點多餘了」

所以說,如果不能為一個變數或者函數想出一個清晰又簡潔的名字,那可能是你的代碼有問題,你得考慮重寫或者進行代碼重構了。

名不正則言不順, 言不順則事不成。


推薦閱讀:

TAG:軟體 | 程序員 | 編程語言 | 編程 | 計算機 |