编程究竟难在哪?
hi,大家周末好,很多人覺得編程很難,尤其是做算法題,很多時候無從下手,明明知道怎么做,就是很難實現出來,今天分享一篇文章,希望讓你明白人類編程背后的思維模式,只有看清問題的本質,才能快速解決問題!
編程的難分為兩類,一種是工程上的難,一種是算法上的難。
工程
我先回答一下工程上的難:
我們做一個比較, 就是開發一個大型軟件, 和設計并建造一棟摩天大樓, 究竟哪個更難, 為什么?
實際上這個比較一旦拋出, 軟件開發的"難"就立馬顯現出來了。
摩天大樓一旦蓋起,將不再,也不可能“更新版本”,更不可能在建筑結構上進行“重構”,比如一個一百層的摩天大樓,不可能說過兩個月發現地方不夠住,然后再加五層,又過了兩個月發現某個房間的設計滿足不了人們日益增長的需求,將整個房間擴大兩倍,究其原因,就是因為“建筑”這個東西太不靈活了,你如果想“重構”這個摩天大樓,幾乎只有一個辦法:炸毀,推倒重來。
而對于軟件來講,它本身的一個靈活性,導致了它可能在不破壞原有的大部分功能的前提下進行一定的功能性改造,在改造的過程中,原有的一些功能模塊的更改,可能導致之前的一些文件或環境, 或應用程序在這個新的版本下出現不兼容的現象,所以它要保證舊的東西在新的東西下能成功運行。
一個東西越是牽扯的東西多,越和環境耦合,和“用戶”耦合越深,和“自身”耦合,和“歷史”耦合越深,它的“更新”就越難,而“重構”是多次更新之后的“必然結果”。
這就是為什么摩天大樓幾乎無法進行功能性更新,因為建筑這個東西本來就是一個“超級耦合體”,你改變墻壁的厚度,會減輕它的重量,但于此同時因為墻厚度降低,它本身的抗壓剛度和抗扭剛度也發生了降低,所以后果可能還需要重新計算,墻里面的電線會不會因為墻的厚度改變而需要重新布線?而且不僅如此,墻的厚度還會改變房間的大小,這是它和其自身的高度耦合。
它和用戶的耦合性也很深,因為這個房間的一些地方有可能早已住了人,原有的位置放置了很多用戶的東西,比如一些很重的家具等,你對墻重新施工,就意味著你要強迫用戶更改它們原有的使用習慣,甚至可能讓用戶原有的一些家具無法在新的版本中放進去,這是用戶的耦合性。那么類比軟件,比如我們都知道的excel,這個軟件開發了二十多年,你在2003版的excel里編輯的,十幾年歷史的excel文件,你覺得可以在2018版的excel中打開嗎?這聽起來很不容易,但是微軟做到了,這就是為什么說現在除了微軟幾乎沒有公司有能力開發出這樣的軟件,原因之一就是它變態的兼容性,長達十幾年的時間跨度,版本跨度,保證文件的兼容性,這本就很了不起。
所以向前兼容是軟件開發的主要難點之一。
有時候不僅是某個功能模塊的更新,隨著一個”服務型“的應用不斷發展,它要提供服務的用戶量就會不斷提升,一個典型的例子是淘寶,學過數據結構的我們知道,這世界上很多東西的復雜性并不是線性增長的,簡單的例子就是排序,最優的時間復雜度也是nlog(n),理想世界如此,現實世界怎么可能更簡單!
十年前php可以撐起淘寶的流量,而今天呢?php的性能問題恐怕讓其無法再承擔淘寶的億級流量,所以只能用java重寫,而這就是重構,重構其實就可以認為是推倒重來,代價很大,需要更換技術棧,但必要時不得不做。
有人說服務一萬人用一臺服務器,那么服務一億人用一萬臺服務器就解決了,哪來那么多事,而這也正是我剛才說的,陷入了”線性增長思維陷阱“。
一萬人的時候,可能有時候可以讓系統停掉,進行一到兩小時的服務器維護,這一萬人也不會因為你停了服務器就有多大的損失,那一億人呢?你的服務器集群敢斷電嗎?敢讓網站掛掉進行網站維護嗎?
所以既然要讓網站每時每刻不斷運行,就首先要做到持續集成,持續部署,對應用進行完善的版本控制,為了降低系統bug風險要進行完善的發布前測試,而測試又分單元測試和集成測試,缺一不可。為了防止某個地區的服務器因為突發事故,比如地震,火災,大面積停電等事故發生宕機甚至損毀,我們需要進行服務器的異地容災,那么另一個地區馬上就能無縫根據原有服務器的中斷鏡像進行服務重建,做到服務端這邊“山崩海嘯”,用戶端那邊還能一如既往的從容淡定,感覺什么事都沒發生一樣。
所以,扯了這么多,我用一句話總結編程的”工程性難點”就是,你如何在這錯綜復雜的耦合中,在復雜性不斷增加的過程中,如何讓軟件有序,規范地”進化“,而不是讓其肆意瘋長,最后成為一坨無人能懂,無人敢碰的”屎山“。
算法
算法的難主要集中在兩點, 一種是算法的構思和提出, 一種是提出算法之后, 用code實現出來。
個人認為算法的構思和提出最為困難,因為這部分經常要求我們將我們眼中“顯然”的東西,轉換成計算機語言。
比如我們現在要實現一個算法,這個算法能夠識別一張圖片,判斷圖片中是否有人臉,對于人類來講,這是不經思索的,一眼就能看出來的,但是問題是,你自己也不知道你自己是怎么看出來的,這個判斷過程,其實我們的大腦內部發生了很復雜的化學反應,但是我們卻說不清,我們到底是怎么判斷的,還比如判斷人臉的情緒等等。
但有人說,這說明計算機比人笨,事實上完全不是這樣,計算機從來就不比人笨,事實上比起人類能做到的事計算機做不到,計算機能做到人類做不到的事反而更多。
計算機的特點就是容錯率低,但是可預測性強,確定的代碼和輸入就能得到確定的結果和輸出。
人類的特點是容錯率高,但是可預測性差,對一個東西的執行結果經常受情緒,身體狀況,心態等的影響,結果常常是不確定的。
所以其實,一個系統的”容錯率“和”可預測性”是個永遠不可調和的矛盾,一個編程語言如果具有一定的容錯率,看起來好像編程更為容易,實際上反而是災難,bug更難發現,問題更難復現,一個運行正常的系統很有可能有一天腦子一抽輸出一個錯誤結果, 這就是為什么幾乎所有語言都有異常拋出機制, 就是為了降低容錯率。
所以我們要注意一點就是,編程困難,并不是因為計算機不夠先進,不夠智能,而是我們為了“可預測性”,心甘情愿地接受了這種極低的“容錯率”,這直接導致你寫程序,少打一個分號,編譯錯誤,打錯一個變量名,編譯錯誤,數組越界,編譯錯誤。
容錯性這么低,你還指望它能接受人類這種模糊的自然語言?當然不可能了,所以它一定有自己的,語義清晰的語言。
一個語言一旦語義清晰了,語言灰度底了,它一定是邏輯性很強的,或者說,我們其實是用邏輯寫代碼,而不是用“感覺”或是“情感”寫代碼,這和我們人類理解世界的方式本來就是有區別的。
人類雖然有邏輯思維的能力,但是邏輯思維從來就不是人腦的強項,人腦的強項其實是整體感知,和一些“系統預設”的功能,比如你眼睛睜開了,投入你視網膜的光就會自動的轉換成圖像信息被你感知,這個過程你調用了任何邏輯思維了嗎?你幾乎什么感覺都沒有就完成了一個極其復雜的過程。
所以我們的大腦絕大多數復雜的進程,或者說運行過程,都不能被我們邏輯性地去感知,比如你聽到一首歌,這首歌給你一種很舒緩的感覺,你說你聽著這首歌仿佛進入了一片天靈之地,但是這個過程,請問你進行了任何邏輯思維沒有?
你就是感覺了一下而已,但是我們想讓機器去做這樣的“感知”,因為計算機體系的極低容錯性,我們必須用我們的邏輯思維搞明白,這首歌,究竟是因為什么,它有什么樣的特質,才導致了它給你這樣的舒緩感覺,這樣你才可能把這個過程轉換成計算機語言輸入到計算機中,讓計算機去判斷這首歌是“舒緩的“還是”狂野的“。
所以我總結一下編程在算法上的難,就是:
人類這種容錯率高,可預測性差的生命,非要逼著自己去和一個容錯率低的,可預測性強的這樣一種”硅基生命“交流,不得不逼著自己用邏輯性很強的語言去和他交流, 在這個過程中我們不得不打破我們原有的感覺和感知, 對其進行邏輯解構, 這樣才能讓跨物種交流得以實現.
看到這里,你一明白了,要想讓兩種不同的生物更好的交流,要不就是讓人類變得更像計算機,要不就是讓計算機變得更像人。
你想一下siri,cortana這種語音助手,它是不是具有一定的不可預測性?你和它說一句話,你知道他要回復你什么嗎?不知道,但也正因為如此,我們讓計算機變得更像人類,從而讓人類這一端,可以更輕松地和計算機交流,這其實就是人工智能。
一個AI的算法模型種,往往要引入大量的參數,然后不斷地輸入樣本,根據預測值和真值是否匹配而動態地改進這些參數,這樣一個系統,容錯率是低了,可預測性呢?確定的AI算法模型能得到確定的預測結果嗎?
所以與此同時,你也要注意。
容錯率低的,重要的事不要交給siri去做,因為它和人一樣,不可預測。
本文素材由牛岱授權
來源:https://www.zhihu.com/question/311432227
更新整理:極客重生
- END -
看完一鍵三連在看,轉發,點贊
是對文章最大的贊賞,極客重生感謝你
推薦閱讀
深入理解程序的本質
硬核致敬Linux !30歲生日快樂!
深入理解瀏覽器原理和架構|硬核
總結
- 上一篇: 赠送 12 本 《C++ 服务器开发精髓
- 下一篇: 使用 ebpf 深入分析容器网络 dup