對程式設計師來說,什麼才算是真正的程式設計能力?
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都是在說這個。而當把這套玩熟,如果喜歡,甚至可以做到正射必中:對於給定問題,產生絕對正確的程式碼。這不難理解,畢竟都說了是數學物件了,證明一下就好了。
如果有正在學java的程式設計師,可來我們的java技術學習扣qun哦:72340,3928,小編花了近一個月整理了一份非常適合18年學習的java乾貨,加入就免費送java的視訊教程噢!而且我每天晚上都會在裡面直播講Java知識,從零基礎學習到有基礎進階,歡迎初學和進階中的小夥伴。
1:能在0之上加上工程方法。
有時候這套方法不管用:比如說跟其他人在已有Code Base上協作,比如說需求變更了,比如說死活分解不出來,又比如說根本不知道具體的需求,得慢慢探索。其實這問題本質是,軟體實在太複雜了,一個數百萬行程式碼的專案已經超越了人類物理意義上的理解極限 - 看都看不完。
這也是為什麼重頭起編寫一個系統很難:Spec太複雜,各個元件的Assumption太多,並且持續進化,不可能一口氣搞定,就算給定各個預先寫好的元件,也會因為Assumption不Match而難以組合在一起,只能通過不停的Prototype,不停的重構,甚至不停的重寫來加深對系統的理解。
在這之上,SICP的‘一次性理解法’已經失效,這時候就需要不精確,比起邏輯學更像生物學的技巧 - 軟體工程了。
該怎麼設計?該怎麼重構?啥時候不重構而是頂著debt繼續往前(不然會無限重構做不出東西來)?該用啥技術?在各種tradeoff間如何選擇?再加上Debugger/Unit Test/CI/Git/Integration test這些Tool。
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)
如果要用一句話概況,猜程式設計能力是"對不同複雜度的問題(領域級/系統級/問題級),採用相對應工具降低複雜度,最後擊破"的能力吧。