程式設計到底難在哪裡?

程式設計師之家v發表於2018-01-13

寫在前面:我用自己不純熟的英翻中把原文中程式設計師交流時經常使用的英文都換成了中文,翻譯不好請諒解 -_-)


記得之前組裡來了一個美國實習生小夥子,很極客的那種,幹活快,一天能給你寫2000行程式碼(我複查的速度跟不上他寫的速度),讓做什麼東西,上午告訴做個這個功能,下午就能在測試環境跑起來演示了。跟他單獨開會的時候,他說覺的普通的程式設計沒什麼意思,太簡單了,寫程式這方面已經沒什麼追求了,他比較想跟我研究大資料的框架,資料庫,或者機器學習之類的工作,做設計,早日脫離程式碼這種無腦工作。


我足足花了1周時間,每天讀他的程式碼到凌晨。給他寫的評語反饋快趕上我在知乎寫的答案文章之和了。。。期間幾小時幾小時的開會論戰,孩子狂,語速快,腦力靈,辯論角度刁鑽。他天天要與我論戰,看我的評語,速度還算慢下來了。


沒來得及討論完,隔週我要休假了,2周。交代了些他要做的工作。


2週迴來,讓他改的那個java包爆炸了,本來我們一個支援了7個功能的框架包,總程式碼量也就5k吧,等我回來這包程式碼量1w5+。也就是說他為了一個小功能加了1w行程式碼。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


這沒法複審,只能跟他坐一塊,先讓他給我講講這程式碼都幹什麼的,然後他說:


“en。。。這塊我現在也看不太懂當時為什麼這麼寫了。。。”


“en。。。這邊寫的比較複雜是因為當初那邊是那樣寫的,所以這邊沒辦法才只能這麼寫。”


“en。。。把當初那邊改好很麻煩,影響也很大,不如就這樣吧。”


“en。。。這裡這麼寫是因為你看著裡是這樣的, 然後這裡有這個邏輯,然後這裡。。。(來回來去翻n個類之後)。。。 所以你看我這裡雖然寫的比較詭異,但是完全沒問題的!(得意ing)”


“en。。。這邊做的這麼奇怪是因為有個bug,通過這麼寫,這個就bug沒了,我也不知道怎麼回事。。。所以你看我在這邊註釋,這行不能刪了。。。”


“en。。。我覺得這個功能很酷,你們雖然現在不需要,不過有總比沒有好吧,將來如果……%¥……&%&……%*7&%……*%…(我沒聽懂)的話,這個就很有用!!”

...


一次次被我打回去重寫,後來總算簡化成大概5k行了;臨走時候跟我說:你這樣程式設計也太難了。。。


再後來由於一些額外複雜的程式碼造成我們實現新東西會很複雜,我又重寫了一遍,總共大概不到1k行程式碼。


640?wx_fmt=png



這裡邊有幾件事情我想說

  • 做出來容易, 做正確難,這裡做出來指沒bug且完成需要的功能,這是最基本要求,不多加討論。這裡正確,不是指功能正確,而是指程式可以很容易推理理解,理解意圖, 理解如何做到的,理解為什麼系統不會出錯。理解為什麼要這麼做。正確是現在怎麼寫不會挖坑害將來的人,現在怎麼寫能讓別人1年後看你程式碼時候不可能理解錯你現在的意圖,現在怎麼寫能在別人將來犯錯的時候提示他你錯了。


  • 程式設計是給未來的未知人講故事,你無法知道將來這個人是誰,他都懂什麼,他經歷過什麼,這個系統將來已經是什麼樣子了。我們需要在這種無知,缺乏資訊的情況下做決定,從千萬種把這件事做出來的方法裡,選出你覺得最能把這個故事給講好的那種方式,把故事寫下來。程式設計是一種溝通,溝通是一種藝術,用程式跨越時空之溝通則是一門屬於程式設計師的特有的藝術(就好比數學家用數學公式來溝通) coding is all about the art of communication(引用)。


  • 壞的決定會導致壞的決定,甚至導致人們去扭曲一個好的決定去迎合壞的決定。垃圾會製造垃圾,一個放在系統裡不經清理的額外複雜度,會導致更多的額外複雜度的生成。


每個人甚至同一個人的不同時刻都有自己的不同的製造額外複雜度的缺陷,比如我每年去看去年自己寫的程式碼,覺得都是垃圾。



然後我又想問幾個問題

我們所在的部門,所在的組,公司,它們的文化,到底是關心做出了一個東西,還是關心做好了一個東西。一個總是給系統新增垃圾,留坑給後人,但是能很快做出能跑起來的系統的程式猿,我們到底認為他是做了好事還是做了壞事?我們到底認為他很強,還是他很弱?用超過必要而為了突顯技術實力的複雜工具,技術框架搭建系統,做完跑路,在一個組,一個部門,一個公司,那裡的文化,到底應該是鼓勵還是抑制這種行為?我們又應該如何在一個環境中,去倡導推崇什麼樣的文化,相遇什麼樣的人?


人與文化,決定了什麼人留在這裡,什麼人離開,什麼人吸引什麼人,什麼人成長成什麼樣子。而設計/技術這些枝末細節則必順應此中的人與文化而自然變化,或自愈,或走向毀滅;哪怕在惡劣的環境中,向下引導,向上規諫,潛移默化,最終改天換日,此為程式設計之大道也!



下邊是定理證明

最小垃圾存在定律:定義垃圾為系統的總複雜度減去系統的本質複雜度;那麼得到:如存在多種方法可以設計與實現一個系統或功能,存在且只存在一種實現會引入最少的垃圾;


垃圾與複雜度正比定律:根據定義可得,系統存在的垃圾越多,系統越複雜;


垃圾倍增定律:基於已有垃圾量a的現狀來演化,進化此係統,增加的新垃圾量與已有垃圾量a成正比;


系統腐敗定律:當基於垃圾量a來實現新功能的cost大於新功能本身的價值時,系統腐敗,需要重構;

戰鬥人員負戰力定律:如果程式設計師a引入的垃圾,在n次迭代中經過倍增所造成的成本,大於其所清掃的垃圾經過倍增所獲得的機會成本,和其實現的新功能價值之和。此時,我們稱此程式設計師戰力為負值,其戰力絕對值與其引入垃圾的能力和其清掃垃圾的能力的差值成正比


以一敵百存在定律:由負戰力定律可知,對所有的自然數n,一個正戰力的戰鬥人員的戰力 > (負戰力戰鬥員1+負戰力戰鬥員2+ … 負戰力戰鬥員n)的戰力和


系統本質複雜度不可知定律系統表徵複雜度無限接近本質定律:取決於戰鬥人員的知識量,經驗,天賦等,對於任何戰鬥人員n,都必定存在一個戰鬥人員m(考慮歷史長河)使得戰鬥人員n觀察系中的純淨無垃圾系統(複雜度總為1)是戰鬥人員m觀察系中的含垃圾系統(複雜度為1+x),這使得在所有觀察系中(包含外星生物),系統的表徵複雜度(或者說觀察複雜度)無限趨近與本質複雜度。然而我們只能通過觀察來感知事物的本質複雜度,卻永遠無法得知我們離本質複雜度還有多遠。


以有限的生命去追求可以無限的提升的淨化方法與視野,我們稱之程式藝術家,也就是SDA(Software Development Artist)


… it's extraordinarily important that we in computer science keep fun in computing…

——— Alan J. Perlis (April 1, 1922-February 7, 1990) 《SICP》

打星際… 哦,不, 錯了重來…  寫程式,你快樂嘛?


0?wx_fmt=gif


寫在最後,看到大家最關心的是他拿到正式錄取資格了麼?還有也許通過我的描述關於他的這個側面,你會覺得他很不稱職。其實不是的,他程式碼寫的絕對是平均值往上的水平,他的問題在於:


1、是他根本沒有想過去簡化業務邏輯,所以很多符合最初需求的程式碼在簡單優化業務邏輯之後完全不需要;


2、是自己加了很多功能;


3、是自己加了很多自以為是的優化,比如用一個演算法估算某個函式的輸入陣列的最大可能值,然後用那個值來初始化一個陣列,因為這樣就不會重新分配記憶體了(他原話)


4、抽象能力有限,這個畢竟經驗少, 年輕;


5、濫用設計模式(關於設計模式,最多程式設計師被絆住的一關:設計模式是物件導向程式設計模型中,應對經典問題的經典解決方案。



這裡有兩個問題

第一,設計模式的場景用對了麼

第二,為什麼要用物件導向正規化,選擇程式語言正規化時,要從表達力最弱最簡單的語言正規化開始選擇。


這叫做最弱表達力原則,而物件導向正規化作為最複雜,表達力最強的語言正規化,在大多數時候都可以避免使用。關於第二點的論述證明,你可以看concept techniques and models of computer programming這本書。注意,這裡說的是語言正規化,而不是語言。即使你用java,如果你從來不使用mutable(專業詞彙)的功能,和繼承。那麼你就沒有使用物件導向正規化)


他其實有非常強的解決問題的能力,想法天馬行空,通過自己設計演算法來猜函式可能需要的陣列大小就可見一斑,還有一個從s3(專業詞彙)讀資料的需求,他不是簡單調api完了,而是寫了一個環狀buffer(專業詞彙),使得網路,硬碟,app可以在理論上最大效率的適應程式當時的場景(為了協調非同步,他自己發明了一個很笨拙的promise(專業詞彙))


這非常厲害,一般的實習生哪怕sde1可能都寫不出來(可惜的是場景會隨業務邏輯激烈變化,今天的優化可以是明日的累贅,這就叫做過度優化,過度優化是一種強耦合,會把你的系統死死的釘死在當前版本)。他只是不明白簡單是美這件事情而已。如果能有人幫他斧正,日後必成大器。


他最終拿到了正式錄取資格,這其中還有個小波折,終審的bar raiser(amazon內部的一個可以一票否決招聘結果的角色)看到他在程式碼複查系統裡跟我的各種激辯,覺得這人不能留。好說歹說才給了正式錄取資格。不過最後人家沒接,去讀博啦。


最最後,在一個相對乾淨的環境寫程式,不斷找出新的本來以為不是垃圾的垃圾,對我來說,是一件非常愉快的事情。然而幫別人打掃他本就不該製造的垃圾則是非常痛苦的一件事。


公眾號內回覆“1”帶你進粉絲群!

0?wx_fmt=gif

相關文章