編程能力如何突飛猛進?
點擊左上方藍字關注我們

轉載自 | 深度學習與計算機視覺
作者:MutexLock
https://www.zhihu.com/question/356351510/answer/1148885728
疫情原因回不去學校,作為一個馬上畢業(yè),即將入職騰訊的大四生,分享一下自己的學習歷程吧。
本人在大學之前從未接觸過編程,最開始的編程學習還是在高考完后,從書店買了本C Primer Plus,然后暑假開始啃,前前后后也就看了幾十頁。
大一上的時候,來到了華中師范大學,還沒有轉專業(yè)到計算機,一直在自學C語言和看一些計算機入門書籍(編碼、計算機科學概論)。當時也很迷茫,不知道以后道路如何,所以也學了一些雜七雜八的東西(前端 python啥的),所幸的是,當時堅持把C Primer Plus結結實實地精讀了一遍,而且?guī)缀蹙毩曨}都做了,算是比較好的開端。
大一下,轉專業(yè)到計算機了,開始自學數(shù)據(jù)結構,算法和C++,部分看完了 數(shù)據(jù)結構與算法分析,并且把書上的數(shù)據(jù)結構實現(xiàn)了一遍,記得當時五月份給自己的flag是看完C++ Primer,然后每天上課看,晚飯吃完后也跑去七號樓刷書,最后囫圇吞棗似的看完了大部分。
大一暑假,txr大佬 @杏仁糖給我說他面試通過了華科的聯(lián)創(chuàng)團隊Unique Studio,而且給我說他們團隊都特別厲害,有些人在軍訓的時候就把C++ Primer給蹲著看完了,當時十分欽佩,幻想也能夠進入貴團隊。于是打算在大二上的時候,去報名他們的秋招。所以,那個暑假在學校自學,呆了五十多天。最初,拿起一本APUE,看了一章后感覺看不懂又放下了。然后,又拿起一本紅色封面的算法第四版,這本書看完了,并且用C++把上面的算法都實現(xiàn)了一遍。另外,聽知乎大佬說CSAPP是必看的神書,當時也懵懵懂懂地看了前面三章,做了lab。為了學習linux,還看了一本叫l(wèi)inux命令行大全的書。武漢的夏天很熱,只能寂寞待在宿舍的我,打開了LeetCode的世界,寫了一百多道題。
大二上,十月,忐忑迎來了聯(lián)創(chuàng)的面試,前面兩輪都過了,直到其特色的“熬夜測試”環(huán)節(jié),因為實力不足+精力不足,測試敗北,沒有通過。清晨七點,在回學校的公交車上思考自己不足,總結是知識體系仍然不夠完全,而且深度也不夠。后來這個學期有點“誤入歧途”的意思,入了Machine Learning的坑,記得當時花了好幾個月刷完西瓜書和吳恩達機器學習課程的講義(真佩服當時的毅力,都是英文和公式推導),后來想了想,ML/DL這個東西有點玄學,于是毅然決定成為一名做工程的程序員。總的來說,雖然這個學期的時間都投入到ML的學習中,沒有學習工程方面的東西,只有用python寫了一點好玩的爬蟲,但是給了我以后堅定走工程方向的決心吧。
大二下,這個學期是打下計算機知識基礎的關鍵時期。從知乎找了一系列書單,看完了CSAPP(做了lab,為了bomb lab還通宵了,強迫癥想讓自己把炸彈都拆了)、半本算法導論、effective C++、計算機網(wǎng)絡系統(tǒng)方法(前三章)、部分TCP/IP詳解等,做了一些項目,比如正則引擎(這個是參考了輪子哥的教程)等等,嘗試寫JSON庫(未遂)。其實,因為學校只是一個普通211,找到好工作的學長學姐先例很少,一直是沒有信心自己能去大廠,直到當時了解到myk @孟永康學長在春招收割了一系列offer后,才有了些許信心,相信自己如果能夠像他那樣努力,那么也能夠找到好工作(感謝myk學長那時的鼓勵和指導)。所以,定下了一年把自己水平提升到能夠在大三下春招的時候拿下大廠offer的目標。
大二暑假和大三上也一直為這個目標奮斗,補上了APUE、部分UNP、深度探索C++對象模型、STL源碼剖析、操作系統(tǒng)概念、操作系統(tǒng)真象還原、Linux多線程服務端編程、部分C++ template、部分C++ Concurrency in Action等書籍。然后,也一直沒有放棄刷題,LeetCode寫到了三百多道。同時也做了一些項目,跟著操作系統(tǒng)真象還原寫的操作系統(tǒng)、簡單的協(xié)程庫,閱讀了一些優(yōu)秀的開源項目,SGI STL、muduo、libgo、libco等。中途還對haskell產生過興趣,打印了一本Learn Yourself Haskell For Great Good,看完后感覺坑太深,還是專注找工作吧,haskell對我一直都有很強的吸引力,但是這種也只能作為愛好吧。另外,編譯器也是有這種魔力,看了部分編譯原理(龍書)、部分現(xiàn)代編譯原理(虎書)和部分Engineering a Compiler,多次嘗試寫自己的編譯器,多次未遂(不過現(xiàn)在有空了,在補上之前的爛尾項目)。
時間到了12月份,9號樓某個自習室內,txr大佬一直鼓勵我去投簡歷找實習,本來我一直畏畏縮縮,對自己不太有信心,被鼓勵后想著投就投吧。當時投了字節(jié)跳動和momenta的實習,面試都比較順利,于是在大三上就在字節(jié)跳動開始了愉快的實習,比自己的計劃早了大半年。當時為了準備面試,看了好多牛客網(wǎng)的面經,查漏補缺式地補齊自己的知識盲區(qū)。
大三下,基本都是在實習,學習了很多工程實踐上的東西,接觸了go的技術棧,并且對devops和軟件工程方面有了認知,包括代碼管理、發(fā)布流程、微服務啥的。然后實習的時候騎驢找馬,找到了騰訊的暑期實習。因為這個時候沒有了找工作的壓力,所以開始學一些自己感興趣的東西,包括Rust(至今水平還是不太行)、分布式系統(tǒng)(DDIA、MIT6.824等),零零散散學了點東西。
大三暑假,騰訊實習了兩個月,開始學習kubernetes、各種中間件等實際業(yè)務用到的東西,這個時候就感覺擁有到扎實的計算機基礎是最重要的東西。
最后,順利拿到了騰訊轉正和字節(jié)跳動的秋招offer,兩家都給的比較高,選擇了工作體驗更喜歡的騰訊哈哈。
總的來說,學習計算機是需要積累的,花一兩年時間啃下那些厚厚的經典書籍后,才能構建自己的知識體系,然后閱讀大量優(yōu)秀源碼,做一些有趣的項目,編程能力就能突飛猛進啦。
現(xiàn)在回頭來看,大學時光真是如此寶貴,這是人生中為數(shù)不多可以靜心學習的一段時間,可以不用考慮任何其他事情,每天學習十多個小時。
這個是當年狼廠網(wǎng)頁搜索部門的傳統(tǒng),不知道現(xiàn)在還有沒有,入職第一個任務是完成兩道練習題。一題是在Linux上用純C(不許用C++,沒有stl可用)完成一個多線程的網(wǎng)頁抓取器,另一題是同樣的環(huán)境語言完成2G大小的query(搜索查詢詞)的top100提取,有時間要求。
入廠之前我在Linux上沒有寫過代碼。
兩天時間從Linux基本命令的熟悉,vim gcc gdb的使用學習,從malloc和free開始搞內存管理,從0開始碼hashtable(還得自己寫hash函數(shù)),從socket開始實現(xiàn)http client和各種協(xié)議碼解析,使用pthread多線程和信號量互斥同步,基本把操作系統(tǒng)計算機網(wǎng)絡復習了一遍。
搞完入門練習,leader過來跟我說:小胡,現(xiàn)在有一個重要的模塊交給你,趕緊熟悉一下,然后完成如下功能升級。
這個模塊是前廠存儲網(wǎng)頁的核心模塊,在當年內存4g的奔騰主機上單機存儲幾千萬網(wǎng)頁,幾臺機器存下了當時整個中文互聯(lián)網(wǎng)。支持高性能的隨機存取和順序讀,可以說把機器性能壓榨到了極致。3w行,純C。
啃了幾天終于搞明白了結構,(多年以后我還得感謝source insight),同時也對寫這個模塊的大牛佩服的五體投地,為了壓榨內存把每一個bit都物盡其用,各子模塊之間的分工又是那么的優(yōu)雅。
然后是上手改,看懂了之后功能升級很簡單,只改了十幾行代碼,但上線的時候真是手發(fā)抖!
后來才知道這個模塊好幾個前任都沒成功接下來就被fire了....
后來又經歷了若干次升級,解決各種詭異bug(搞過高并發(fā)存儲系統(tǒng)的應該知道坑有多深),編碼和解決問題的能力突飛猛進。
結論: 學習系統(tǒng)設計的最佳途徑是看一個優(yōu)秀設計的源碼,檢驗成果的方式是改造它應用于你的實際場景。
搞定存儲模塊之后,我的下一個任務是升級喝擴展一個完整的抓取系統(tǒng)。
和入門練習做的抓取器不同,這個完整的抓取系統(tǒng)(又稱spider)是工業(yè)級的,需要每天完成千萬級的抓取量,還需要考慮并發(fā)壓力控制,網(wǎng)頁更新調度,垃圾網(wǎng)頁處理,去重等等諸多現(xiàn)實的工程問題。
大大小小十來個模塊,十來萬行代碼,大部分是C,還有接近一萬行的bash腳本(用bash實現(xiàn)分布式的網(wǎng)頁去重處理你信?)
這時會發(fā)現(xiàn)很多模塊內部都有不少實現(xiàn)不盡如人意的地方,但是由于借口定義的好,模塊直接容錯性強,整個系統(tǒng)還是work的。
這促使我思考系統(tǒng)級的架構,最需要關注的重點是什么,良好的結構遠勝于細節(jié)的雕琢。
大約小半年后,我對這個系統(tǒng)基本做到出任何問題能立刻反映到是那個模塊出的問題,對問題的分析定位能力又上了一個臺階。
結論: 理解了接口定義和系統(tǒng)結構重于實現(xiàn)細節(jié),就邁出了架構師的第一步
此時大概工作快兩年了,原來的抓取系統(tǒng)有一個很大的問題,就是積累的網(wǎng)頁數(shù)太多,更新資源分配不過來,導致系統(tǒng)中大量網(wǎng)頁在互聯(lián)網(wǎng)上已經404但仍然會進到線上被檢索出來。我們稱之為死鏈接問題
通過對死鏈的規(guī)律分析,我發(fā)現(xiàn)互聯(lián)網(wǎng)上大部分死鏈存在站點或目錄級聚集的現(xiàn)象,這個其實很好理解,一個網(wǎng)站無力維護了,自然就全部掛掉,目錄級很可能是網(wǎng)站改版了,或者一個子頻道關閉了。利用這個規(guī)律,我們可以大幅度降低死鏈檢測的資源耗費。
在這個認識的基礎上,我設計了一個獨立的死鏈檢測系統(tǒng)。上線效果很不錯,檢查死鏈的流量開銷降低到原來10%,網(wǎng)頁庫中死鏈還下降了。
結論: 架構師首選要解決的是待解決問題的精確描述,和對問題域的分布規(guī)律的挖掘,然后才是結構設計。
工作第四,五年間,hadoop在業(yè)界逐漸流行起來,基于Google三件套的設計,當年的hadoop最上層的table還很不完善,但是mapreduce和hdfs已經很可以用了。 如何利用分布式基礎框架改造系統(tǒng),讓系統(tǒng)更健壯(以及永更廉價的硬件給公司省錢),成了當時的一個重要問題。
整個抓取系統(tǒng)和建庫系統(tǒng)的分布式改造,相當于重新設計一個新的大系統(tǒng)。需要考慮方方面面,如何逐步升級兼容原有系統(tǒng)?如何保證功能的完整性?原有設計中有一些不合理的地方,如何利用這次遷移同步改造?
主導完這些工作后,系統(tǒng)架構方面再也沒有遇到搞不定的問題。
結論: 好的架構師需要在合適的時機解決重要的問題,業(yè)務發(fā)展才能給你這樣的機會。
包括購買了梯子,獨自啃下兩套純英文官方文檔,在GitHub上友好親切的交流,刷題,看最新的軟件工程實踐書,等等
1、提高知識最好的途徑是讀書,包括但不限于計算機四大名著《操作系統(tǒng)》《計算機網(wǎng)絡》《數(shù)據(jù)結構》《計算機組成原理》。經典書籍不僅僅有完善有效的知識,更重要的是這些書里的計算機經典思想,一直到現(xiàn)在都沒有過時,十分的有用。
2、Github是個好網(wǎng)站,值得習慣性的到上面搜索需要的東西。比如awesome系列和一些質量很高的資料整理項目(整理常見的面試、刷題、常見工具鏈的git repo)
3、v2ex和知乎都是很好的網(wǎng)站(盡管審核方面被吐槽很多),論壇上有很多很厲害的大佬,關注認真答題大佬的動態(tài)對開拓知識領域是有一些幫助的。
4、善用搜索引擎(專指Google),最好能把自己最常用的工具的官方文檔啃一遍。主要是習慣英文文檔的表達方式+系統(tǒng)的認識自己所用的工具,對自己寫文檔也是有很多幫助的。
5、因個人有長期的抑郁經歷,所以對心理方面關注得也比較多,十分推薦學習《哈弗大學幸福課》,觀看地址https://www.bilibili.com/video/BV1Gs411o71d?p=1。這門課的綜合內容十分豐富,實踐性很強,能夠有效的提高生活、職場中的軟技能(溝通能力、抗壓能力等)(這門課另外一個很厲害的地方在于,僅僅是上課的方式,也能提高你的邏輯思維能力,畢竟據(jù)說是哈弗學生選修最多的課,課程質量極其的高)。
6、有一個我自己打算做但實踐得還不太好得地方:看經典開源項目得源碼和架構。只看過一些小的玩票性質的開源項目,也學到了不少東西,大型的經典的開源項目還沒能看(STL、Git等),這些項目對我來說主要是太龐大,時間上有些不夠用。
7、最近在堅持做Leetcode每日一題,也推薦大家一起刷呀。保持手感,很多題看起來簡單,但評論區(qū)也能看到有趣的知識。
8、關于職業(yè)規(guī)劃這種事情,我以前是沒有的(主要還是抑郁+低自尊影響的吧)。現(xiàn)在獲取的信息太多太多,沒有職業(yè)規(guī)劃很容易被帶偏。我是在做了長期的心理咨詢+《哈弗大學幸福課》,工作、生活上都有一些經歷了之后才慢慢想清楚自己將來的生活與工作要怎么打算。這種事情想清楚過后,做自己想做的事情目標會比較清晰,不會得過且過。
也就是說,作為一名程序員,不思考,不總結,寫再多的程序,吃再多的虧,你可也無法成長為一名高水平的程序員。
編程不是體力勞動,而恰恰是少有的,一種近乎純粹的腦力勞動。所以,也并不存在所謂的肌肉記憶。
例如,相對于具體的編程語言,設計模式是一個更高層次的東西,重要性不言而喻。
但是,這并不意味著,人一開始就應該去閱讀那些經典的教程(例如GOF的《設計模式》,《Head First設計模式》),從而掌握設計模式。
因此,學習設計模式的正確之道,就是在大量實踐之后,遭遇了現(xiàn)實的困境,有了自己的朦朧思考之后,再來閱讀經典教材,然后才會有“原來如此”的感悟。
而且這個過程還是反復的。是一個不斷實踐,不斷思索,不斷領悟的過程,也根本不存在一個所謂的“頓悟”點。
而應對本問題,對編程來說,也根本不存在一個清晰的時間點,人就突然領悟了某個“絕世秘籍”,從而水平大增。
而且,不僅設計模式如此,再往上的架構設計等依然如此。
我學習的路子更像學院派,從linux和C語言學起,看操作系統(tǒng)原理、數(shù)據(jù)結構、算法導論。確實感覺自己有這么幾個質變的飛躍點。
1. 當我在linux的終端第一次成功編譯和運行C語言版的hello world時。為了做到這一步,我克服了很多困難,首先是理解linux下命令的運行原理,了解什么是path,然后理解了linux上的那些命令和我寫的hello world從本質上講并沒有區(qū)別。為了編譯,我安裝gcc,明白了包管理相關的概念。之后這個經歷很快幫我理解了第三方庫的概念、版本管理等問題,讓我在之后快速擴展打下了堅實的基礎。從0到1是最難的,為了實現(xiàn)這一步,我實際花費了將近一個月的時間。
2. 在《程序員的自我修養(yǎng)》里看到這么一句話時:抽象級別再高的編程語言,最終都要轉化為二進制洪流,運行在電路板上。可以說是醍醐灌頂,讓我在之后寫代碼的過程中,總是忍不住去追問這些代碼最終可能轉化為什么樣的二進制流,怎么運行在電路板上。這之后促進我初步了解了計算機的硬件結構,了解了一行代碼從寫出來、編譯后、運行起來,又怎樣透過網(wǎng)絡傳輸,以及最后顯示在屏幕上經歷的全過程,對我之后的幫助很大。這之后我又有機會研究了無線網(wǎng)的各種傳輸協(xié)議,
那時候就似乎看到自己寫的代碼從文本轉化為二進制,從二進制轉化為電磁波,突破了那個機箱和屏幕,彌漫于我們所在的空間之中,成了可感受的實物。對于理工男來說,沒有比這個更浪漫的事情了。感受寫代碼的浪漫,是促進我不斷前行的重要原因。
3. 自學結束,開始步入工作時。第一次接觸一個實際的項目時,才發(fā)現(xiàn)書中的東西過于基礎(基礎很美也很重要,我仍然喜歡不斷探究基礎的東西),而現(xiàn)在各種基礎工作其實有大量的框架和第三方庫做了,我們不需要處理,這樣從一些基礎的東西脫離出來,快速搭建項目,一些對工作更重要的技能開始凸顯,比如說數(shù)據(jù)庫、緩存、測試等等。這時候從掌握大量基礎概念,到快速完成一個項目,并產生實際的價值,這又是一次質的飛躍。
當然,學習很難一帆風順,我和初入程序員屆的師弟師妹聊天,和已經大廠P7T3聊天,發(fā)現(xiàn)編程的路就像人生,每個階段都有自己的追求,也有自己的茫然,然而更多的時候,沒有做不到,只有不愿意去做,只要你有堅定的目標,持之以恒地去做,終究沒有什么能攔住你的腳步,即使某一段時間再痛苦,也總能柳暗花明,到達新的一個階段,那一瞬間的美好,就是對自己最大的肯定和獎賞。
那個轉折點就是,我本來在一個十多個人的大組里面當個小透明,突然一兩個月內組里面所有比我資深的人都走光了,只剩我和另外兩個新來的。瞬間,我半路接手了十來個項目。
那個時候我還很年輕,不太能接受失敗。于是我就硬抗下所有項目。本來,我只用寫寫文檔寫寫代碼。那段時間我得搞清楚那一大堆項目的前因后果,為什么要做這些項目,已經做了哪些,項目還有哪些stakeholder,為什么當時要這么設計,我如果看不慣還有沒有改的余地,我要和哪些人溝通這些項目,我需要什么樣的資源來做這些項目,我如何培訓那兩個新來的一起把這些項目做完,等等等等,做了很多“基本程序猿”以外的事情。
總之,我被趕鴨子上架當了一回“l(fā)eader”,而且是一次性十來個項目。雖然我寫代碼的功夫沒啥變化(一直不算差),但是那段時間軟技能得到了極大提高,對整個行業(yè)的認識也有不少提升。
PS. 當時我也思考過要不要跟隨組的大部隊一起跑路,后來覺得一次性拿到這么多項目更能鍛煉自己,真要跑路做完了再跑。(本文轉載自知乎,僅做學術分享,侵刪)
END
整理不易,點贊三連↓
