標籤:

為什麼說讀代碼比寫代碼難?


很多人不明白代碼意味著什麼,代碼意味著要隨時理清這一坨:

讀代碼:
找到圖中兩個節點之間的可能路徑

改代碼:
替換一個節點,完整地保證那個節點和每個節點之間的連通性,正確性

寫代碼:
新增一個節點,然後(其實不管你怎麼)連到原圖中

產品經理:
我其實根本就不關心這些線是怎麼連起來的


以上,讀代碼是NP難度,寫代碼,不好意思,對很多人是P級別的。


好的代碼,讀起來容易,但這是有前提的——就是你得跟作者有相同的知識背景。當然這一般是達不到的。就算人家有注釋,說不定你得把注釋當成關鍵字,好好地Bing一把,學他個三五個月,你才能理解作者的意圖。


首先,就不說寫的爛的代碼了。只說寫的好的代碼。寫的好的代碼,依然是很難閱讀的。

寫的好的代碼,一般是遵循一些原則。而這些原則,很難從最後的代碼中反推出來。這些原則一般都是 declarative knowledge。而我們看到的代碼大多是 imperative code。即使是 functional program 或者 declarative language 的 code,一般也是用低級的抽象來描述高級的原則。

舉一個類比。目前體育比賽中很多規則的修改,都是借鑒以往比賽中,一些舊規則導致比賽比較沉悶,或者被運動員鑽空子的經驗教訓。但是單單去看這些規則,你無法反推出來它們是為了避免什麼情況。

所謂的「讀懂寫的比較好的代碼」,一般是從代碼以外的途徑了解作者的意圖。然後再掌握作者貫徹這些意圖的一些基本習慣。

遵循原則的代碼已經如此難以閱讀,事實比這個還糟糕。任何原則應用於具體問題,都有例外。所以在任何代碼中,都有遵循原則的代碼和例外的代碼。好的代碼只是減少後者的比例,而無法完全杜絕。


https://jysperm.me/2015/02/reading-code/


自我開始編程以來,我一直覺得讀別人的代碼的難度,要幾倍於自己寫代碼。一直以來我都很困惑,難道是我技藝不精,所以讀別人的代碼很困難么。

其實不是,我能看懂代碼中的每一句話,並沒有我不認識的語法,但連在一起就不懂為什麼作者要這麼安排代碼了。


後來我漸漸有了一些想法,代碼是程序員給計算機的命令,是作者思考過後的產物,但思考的過程卻沒有體現在代碼上,這就好比一道數學題,只有一個最終答案,所有的計算過程都被省略掉了,自然難以理解作者的意圖。一段代碼一開始寫出來,後來發現存在問題,陸陸續續地改過好幾版是很常見的事情。最終版本中可能每個小的細節,都是作者花了很多時間試錯的結果,但這個試錯的過程並沒有直接地體現在代碼上。


另一方面,代碼中往往存在一些「隱含前提」,例如假定函數的參數已經在傳入之前被以某種方式處理過了,這個假定很可能於另一個文件的某行代碼有關,這種聯繫很難引起閱讀者的注意。當然,好的設計可以緩解這個問題,但很難被徹底地解決。


代碼的歷史會被保存在版本控制系統里,但說實話,按我的經驗,很少真的有人去翻版本歷史,因為正確地使用版本控制工具相比起寫代碼是一項比較不受重視的技能,在這種情況下翻歷史是非常耗時的。當然,有些人會將一些細節以注釋的形式添加到代碼中,但注釋也只能承載很小的一部分信息,因為維護注釋也是一項很高的成本,我個人一向是反對添加註釋來解釋代碼的。


所以閱讀代碼實際上並沒有看上去那麼輕鬆,為了徹底理解一段代碼,很有可能你需要付出和編寫這段代碼差不多的努力,來了解這段代碼的歷史和前提。

前面提到的是閱讀「好的代碼」的情況,比如大多數活躍的開源項目,如果是面對質量較差的代碼情況就更為糟糕了。


所以我的觀點是,讀代碼絕對不是一種好的學習方式,我認為學習一項技術應當先閱讀書籍,然後嘗試自己實踐,最後再參考代碼質量較高開源項目。


對於大多數項目而言,可能從未把「供他人學習」當作目標,只有當你自己實踐過,積累了一些經驗並且也遇到過一些困難的時候,你才能讀懂代碼並且從中學到解決問題的技巧。而在開始實踐之前,最好的知識來源是書籍,因為書籍的內容是經過精心的安排的,最高目標就是供他人閱讀。


舉個極端一點的例子,比如有個小學數學題是這樣的:

問:小明今年17歲,老王比小明年長11歲,老江比老王年長100歲,請問老江多少歲?
解:17+11+100=128(歲)

感覺特別簡單,只要上過小學就會算。
↑這基本上是自己寫代碼的時候的情況。

—————————————————————————————————————————
——————————————————難度之壁———————————————————
—————————————————————————————————————————

那麼現在反過來:你在教室外面走著,然後飄過來一個紙片,上面寫著:


『解:(7+1)*4=32(分) 』


——請問這個式子是用來算什麼的?

解:
卧槽尼瑪剛離職的混蛋沒寫注釋!
這個變數被命名成分,我猜應該是一個評價的標準,不對,也有可能是人民幣的基本單位,不對,也有可能是美分……暫且按照它是某種評價標準來看好了。不對啊,評價標準為什麼要乘以4呢?評價標準不應該能乘4啊,乘4算個什麼評價標準啊跟不乘不是一樣的嗎,所以不是評價標準。還是應該是分。人民幣分現在基本上沒人用了,別的小幣種出題的老師應該不知道,所以這裡應該是美分。如果這是一個金額單位,那麼前面應該也都是金額單位,乘4之前應該是單價,那麼為什麼要加1呢?可能是把稅分開算了?有可能,寫幾個測試加斷點試一下…
……
~2 hours after~
我擦原來分是分鐘的意思,這玩意是用來計算時間的!
它這個式子還寫錯了!應該是+1秒不是+1分鐘!

↑這個是閱讀別人代碼的時候可能發生的事情。


寫代碼是在表達自己,讀代碼是在理解別人.


假如你讀到這樣一篇文章:
「張三把一個不明物體A、一個不明物體B、兩個不明物體C交給了傑克,傑克拿起A,把A的一部分出示給皮爾杜,皮爾杜開始在從一個本本里掏出一個東西,連同收到的東西一起交給門捷洛夫,門捷洛夫鼓搗了半天...然後告訴皮爾杜不對,皮爾杜又掏出一個東西...門捷洛夫告訴皮爾杜對,皮爾杜告訴了田中...」
提問:張三在幹嘛呢?
你會不會頭疼上面都在胡說什麼呢?如果做一個替換:
張三 —— 顧客; 傑克 —— 收銀員; 皮爾杜 + 門捷洛夫 + 田中 —— 收銀台(掃描 + 查詢 + 顯示)。
讀代碼的困難之處同上,就是你沒法知道作者設置的x, y, count, option, timeline等變數究竟代表了什麼東西。


讀代碼包括:讀懂代碼上下文 --&> 基於上下文分析代碼邏輯 --&> 整合思路理清代碼邏輯關係。

寫代碼是在給了這些上下文和思路後通過代碼表達出這些邏輯。
有篇文章分析說:程序員70%-78%的時間是在理解已存在的代碼。在程序員掌握了編程方法和編程語言後,絕大部分時間都是在做「讀代碼」的工作,而這個工作往往會因為功能複雜性、代碼結構等(上面已經列了很多)更加困難。
之所以很多人還覺著「寫代碼」難,是因為還沒有深入掌握編程方法和編程語言。


拉屎當然比吃屎容易。

是的,我知道你在想什麼——我看過的所謂程序員的代碼,80%以上都寫得屎一樣


寫代碼是理解問題,讀代碼是理解人。


Context is king。
讀代碼最難的是不能了解當初作者寫這個代碼時所處的Context。
這個Context包括,作者當時的水平、開發環境、精神狀態等等都有關。
比如或許他有段時間正和女友吵架,導致那幾天的代碼寫的比較隨意一點。


寫代碼如拉屎,時而一瀉千里,時而靠擠。
讀代碼就是清理複雜繁亂的排泄物,令人頭疼又作嘔。
比這更噁心的是啥——讀別人的代碼。


becausetheydontcasesensitiveanddontknowanythingaboutminusorunderline();


因為程序代碼往往有複雜的邏輯,而且是別人寫的,自己很難在短時間內理清邏輯關係;況且在理解該邏輯關係之前,甚至要先推斷代碼的功能、輸入和輸出。而在自己寫代碼的時候,功能往往是明確的,自己整理的思路自己自然明了,一旦思路明確,寫出正確的代碼就比較容易了——對合格的有一定水平的程序員而言。


逆向工程當然難


  1. 讀比你水平高的代碼,自然難。難在跟上人家的想法。
  2. 讀水平相當的代碼,難。難在了解代碼後面來龍去脈,推測作者的意圖。
  3. 讀低水平代碼。難在把爛東西看完還要一針見血總結出道道,避免自己犯同樣錯誤。

讀代碼難,其實難在對自己的認識和對對象的把握。

最後再扯一下,其實題目也不準確,並不是所有讀代碼都難。例如開車狹路遇高手,對方會清楚地表達他的駕駛意圖,讓你輕鬆決定如何處理。或是人家油門一踩,你還沒反應過來車已經過去了。有而最怕的是前方本側有障礙,你特地給對方留出一大塊車道先行。結果對方遠光不關,一腳剎車等你來闖關。


情況有很多:
1:知識背景不同。比如你對資料庫的實現了解很少,你就完全不知道整個代碼到底是要實現什麼演算法,什麼數據結構
2:思考方式不同。有人喜歡 a*(b+c),有人喜歡 a*c+a*c ,右撇子總是很難理解左撇子左手比較有力的那種感覺
3:無關干擾很多。「門前有兩棵樹,一棵是棗樹,另一棵也是棗樹」,表達了作者當時什麼樣的意境?其實作者就是隨便這麼一寫,但是別人看了,總覺得有深意,被繞進去了。
4:寫代碼時臨時起意的情況很多。建房子,你知道標準流程就那樣了,所以一看就知道怎麼建的。但是代碼呢,比如我要寫一個類,這個類專門用於建房子,我最初設想有幾個方法:拿錢,設計,找建築隊,建設,裝修。 然後寫著寫著,我發現,拿錢這事吧,該有個方法來處理怎麼拿。然後設計這事吧,我得寫個方法,找出我最滿意的設計方案。。。。等等,在寫代碼的過程中,總體流程算是線性的,但是詳細的代碼過程中,會有很多突然蹦出來的東西。而我們讀代碼,模擬不了作者腦子不停蹦創意的過程,所以,就總覺得這代碼怎麼感覺在迷宮裡轉悠呀。


同樣是代碼,讀別人的SQL、HTML、CSS比讀別人寫的C++、JavaScript要容易,為什麼?

原因在於非聲明式的語言會引入Personal Style這個問題,而別人的Personal Style不像一個編程語言有教程有指南有參考手冊,而且作者本人也不一定前後一致,很多情況下你只能「痛苦地」揣測他為什麼這麼寫,因此你的大腦自動就排斥做這種事


寫的時候你腦海中已經有一順溜的思路、邏輯,而讀代碼時要去理解寫代碼者的思路和邏輯。


據說讀別人代碼和司機開車對路上其他車輛的感受一樣


推薦閱讀:

TAG:編程 |