當前位置: 華文問答 > 數碼

什麽才算是真正的編程能力?

2016-10-28數碼

0:可以完全理解一問題,並且給出對應的程式碼。

往窄了點說,這就是acm在培養的東西。

並且這不能靠調api完全解決:

有的時候,你的問題需要你把多個標準演算法串一起。

比如說最近有個把STLC AST從implicit sharing變成explicit sharing的任務,這靠LCA+reverse topo dependency calculation(沒這步LCA的時候scope跟著term一起被reorder了,根本做不出),最後接上metaocaml style letlist,搞定。

有的時候,根本沒有任何API,需求是從一個演算法改成另一個。比如說D*演算法復雜度是O(nv^3)的,很不好,我們想最佳化下,把復雜度往下降點,這一樣沒有任何包可以調。

往廣了說,大一點的需求也能用這種能力。既然有‘組合性’這個概念,我們就能倒過來,給出一個大型問題,分解成多個子問題,各個被單獨解決後再組合一起。

名書SICP裏面就很推崇這種‘理解,分解,破解’的套路,而圖靈獎得主Edward Dijkstra甚至更極端,認為這方法是唯一一種編程的方法。無論這是不是唯一法,這能力都是很不可或缺的基本功。

當你掌握這方法以後,你會發現你做的很多是在腦袋中去推敲這問題的性質,試圖分解這個問題,如果可以的話呼叫/組合已有API/演算法。。是不是很像數學?因為電腦程式在某種意義上就是Mathematical Object - Curry Howard Isomorphism/Stepwise Refinement/Program Calculation都是在說這個。而當你把這套玩熟,如果你喜歡,甚至可以做到 正射必中 :對於給定問題,產生絕對正確的程式碼。這不難理解嘛,畢竟都說了是數學物件了,證明一下就好了。

1:能在0之上加上工程方法。

有時候這套方法不管用:比如說你跟其他人在已有code base上協作,比如說需求變更了,比如說你死活分解不出來,又比如說你根本不知道具體的需求,得慢慢探索。。其實這問題本質是,軟件實在太復雜了,一個數百萬行程式碼的專案已經超越了人類物理意義上的理解極限 - 看都看不完。

這也是為什麽重頭起編寫一個系統很難:spec太復雜,各個元件的assumption太多,並且持續前進演化,不可能一口氣搞定,就算給定各個預先寫好的元件,也會因為assumption不match而難以組合在一起,只能透過不停的prototype,不停的重構,甚至不停的重寫來加深對系統的理解。

在這之上,SICP的‘一次性理解法’已經失效,這時候就需要不精確,比起邏輯學更像生物學的技巧 - 軟件工程了。

該怎麽設計?

該怎麽重構?

啥時候不重構而是頂著debt繼續往前(不然會無限重構做不出東西來)?

該用啥技術?在各種tradeoff間如何選擇?

再加上debugger/unit test/ci/git/integration test這些tool。。

這些(系統編程) @h8liu 說得很好了,就不多說了。

2:對整個電腦stack有認識,能把各種技能混著耍

比如說,學過電腦體系結構,明白dennard scaling死掉後單執行緒已經上不去,GPU等massively parallel architecture是未來,然後給neural network遷移上GPU(deep learning)。

然後,會deep learning,發現這貨給出的答案不一定是對的,但是可以當heuristic/hint,給傳統方法加速(Alphago的MCTS(AI),Learn Indexed Structure中預測結果存在那(數據庫),AutoTVM的快速評分(編譯器),DeepCoder的降低搜尋空間(Program Synthesis),Peloton的給數據庫預測負載(數據庫))

又或者,會FPGA,知道GPU之上還有很多最佳化空間,於是直接把整個matrix multiply fuse成電路(TPU),又或者會quantization,去研究怎麽給quantized NN做ASIC(Bit Fusion)。

還有,會PL,發現Deep Learning的computation graph其實就是個first order PL,為了加入控制流(RNN/LSTM/TreeLSTM。。)以Lambda Cube為基礎設計一個IR,再想辦法在上面做反向傳播,來做program optimization(TVM上的Relay)。

除了理解力到位,試圖把未知的新工具用上已知領域,還有個更簡單粗暴的用法:降低/消除低效介面帶來的額外開銷。

學了Memory Hierarchy以後,在用一個記憶體以前可以提前fetch,降低軟件的memory access latency(prefetching)

如果有FPGA,可以把一部份任務schedule並offload上硬件,提高效能(Hardware/Software codesign)

有task要在docker裏面跑?既然docker都有保護了,那還憑啥要跑一個有保護模式的OS,要多個address space並且不停在kernel/user上跑?Unikernel走起!

把這套玩到爐火純青,還能像Midori這樣,大手一揮,重新設計整個Software Stack,把裏面的各種多余的抽象(protection類別系統給了,就不需要OS上搞)整合掉,爽不?

3:對不理解的CS&數學知識能在遇到的時候快速的補起來。

電腦科學實在太廣太深,學習中碰到不會的東西已經是很正常了,所以說能力中還有一部份是:在程式碼/paper中發現完全不會的定義,如何在最短時間內學習/跳過,並不影響後續理解/debug?

而這些概念不一定只有CS的,有時候還有數學,所以還要打好最低限度的數學基礎,達到‘看到不認識的數學定義不會去手足失措而是能慢慢啃/推敲’。不過還好,用到的數學跟數學系的雙比不深,挺喜歡的一篇paper,Partially-Static Data as Free Extension of Algebras 也就用到了Free Algebra,屬於很基礎的抽象代數,並沒深到那去,老板給我的paper,Sampling Can Be Faster Than Optimization ,能抓出重點,搞懂Metropolis–Hastings跟MALA(Intro to Stats就會教了,很淺),然後明白主Theorem是啥,也就差不多了,畢竟CS水這麽深,主次要分清,數學能抓多少就抓多少吧。。

這些就是我所認為的不會隨著時間而失效,也不能被體力勞動+調包取代的,真正的編程能力:

不停擴充自己的toolbox,並對自己的tool或多或少有本質上的理解。(Machine Learning/GPU Programming)

根據自己對這些工具的理解,想出新的組合法。(Deep Learning)

把自己的idea構建成一個復雜,大而全的系統,而不僅僅是一個玩具。(Pytorch)

落實到一個小功能的時候,能透過計算力,透過品味,設計出一個好用的API,編寫一個正確高效的實作。(Reverse Mode Automatic Differentiation)

如果要用一句話概況,我猜編程能力是"對不同復雜度的問題(領域級/系統級/問題級),采用相對應工具降低復雜度,最後擊破"的能力吧。