最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

寫(xiě)好代碼,我的三個(gè) Code

2023-03-25 13:21 作者:木鳥(niǎo)雜記  | 我要投稿

本篇文章來(lái)自我的小報(bào)童專(zhuān)欄,初步規(guī)劃有以下幾個(gè)系列:

  • 圖數(shù)據(jù)庫(kù)101系列

  • 每天學(xué)點(diǎn)數(shù)據(jù)庫(kù)系列

  • 系統(tǒng)好文推薦系列

  • 讀書(shū)筆記系列

  • 數(shù)據(jù)密集型論文導(dǎo)讀系列

會(huì)保證每周不低于兩篇更新,訂閱方式見(jiàn)這里,歡迎喜歡我文章的朋友們的訂閱支持,激勵(lì)我產(chǎn)出更多優(yōu)質(zhì)文章。

國(guó)內(nèi)很多大學(xué)的計(jì)算機(jī)專(zhuān)業(yè),比較偏重基礎(chǔ)和理論的“灌輸”(就我當(dāng)年上學(xué)的體驗(yàn),現(xiàn)在可能會(huì)好一些),對(duì)于代碼能力,雖然也有一些課程實(shí)驗(yàn),但往往不太夠用。于是,在進(jìn)入正式工作前,很多同學(xué)就會(huì)對(duì)自己代碼水平不太自信。下面我就根據(jù)我自身的寫(xiě)代碼經(jīng)歷提供一些建議。

一些經(jīng)歷

我是 2010 年上的北郵,當(dāng)時(shí)也是很迷糊的就進(jìn)了計(jì)算機(jī)專(zhuān)業(yè)。自然的,在大學(xué)一開(kāi)始也談不上什么學(xué)習(xí)規(guī)劃。只能是沿用著高中的學(xué)習(xí)方法,懵懂地跟著老師走——上課就聽(tīng)課,課余就自習(xí)做作業(yè)。結(jié)果便是,學(xué)習(xí)效率很低,上課聽(tīng)不太懂、題目做不通透。但總歸,上完計(jì)算機(jī)導(dǎo)論后,編程作業(yè)都是自己啃出來(lái)的,跌跌撞撞的完成之后,慢慢地竟感受到了編程的樂(lè)趣。

我們當(dāng)時(shí)大作業(yè)最多的幾門(mén)課,C++ 程序設(shè)計(jì)、算法和數(shù)據(jù)結(jié)構(gòu)、操作系統(tǒng)、計(jì)算機(jī)網(wǎng)絡(luò)、微機(jī)原理等,現(xiàn)在想來(lái),大部分都都跟玩具一樣。后來(lái)做了國(guó)外一些知名大學(xué)公開(kāi)課的實(shí)驗(yàn)才知道,要打造好一個(gè)實(shí)驗(yàn)項(xiàng)目,是非常難的事情:

  1. 首先,得適配學(xué)生的水平,準(zhǔn)備詳盡的實(shí)驗(yàn)材料。

  2. 其次,得搭好代碼框架,在合適的地方“留白”,給學(xué)生“填空”。

  3. 最后,還得構(gòu)建足夠好的自動(dòng)化測(cè)試平臺(tái),進(jìn)行打分。

如果從頭開(kāi)發(fā),這里面涉及到的復(fù)雜度、需要花的心思,并不比發(fā)一篇頂會(huì)論文簡(jiǎn)單。那作為教授來(lái)說(shuō),有這些時(shí)間,我為什么不去發(fā)一篇論文呢?畢竟國(guó)內(nèi)高校都是科研第一、教學(xué)老末。

因此,我在本科課內(nèi),代碼水平也并沒(méi)有打下太好的基礎(chǔ)。在后面在讀研和工作中,不斷摸索,代碼水平才一點(diǎn)點(diǎn)提高?;仡^來(lái)看,對(duì)我代碼能力提升有比較大影響的可以總結(jié)為 “Code”:LeetCodeWriting/Review Code Loop、Clean Code

LeetCode

在說(shuō) LeetCode 前,想先說(shuō)說(shuō)工作后,見(jiàn)到的一類(lèi)神奇的人——打過(guò)算法比賽(通稱(chēng) ACM,其實(shí)是 ICPC 和 CCPC)的同學(xué)的印象。這類(lèi)同學(xué)的一大突出特點(diǎn),用最簡(jiǎn)單直接的語(yǔ)言來(lái)形容,就是:出活快。幾年的競(jìng)賽經(jīng)歷,讓他們只要在腦袋中對(duì)需求(題目)理解之后,就能在最短的時(shí)間內(nèi)轉(zhuǎn)化為代碼。

由于太過(guò)懵懂,我自然是沒(méi)有打過(guò)競(jìng)賽,等反應(yīng)過(guò)來(lái)競(jìng)賽的諸般好處時(shí),已經(jīng)大三下了。當(dāng)時(shí),校隊(duì)也不會(huì)招這么“大齡”的隊(duì)員了,就算招,門(mén)檻也非常高,也是大學(xué)諸多憾事中的一件了。

后來(lái)讀了研,在找工作前一年時(shí),LeetCode 已經(jīng)相當(dāng)流行了,便也和同學(xué)組隊(duì),互相激勵(lì)著刷了起來(lái)。當(dāng)時(shí)題目還不是特別多,到研二暑假找實(shí)習(xí)時(shí),大概把前兩百多道刷了兩遍。一開(kāi)始,會(huì)不斷思考題目是什么意思,該用什么算法解,有時(shí)半天想不出來(lái),便去看高票答案。很多高票解真的是精妙而簡(jiǎn)練,這大概也是當(dāng)時(shí) LeetCode 最吸引人的地方之一。慢慢的對(duì)各種類(lèi)型題目有些感覺(jué)之后,就開(kāi)始練速度和通過(guò)率。也就是上文說(shuō)的,在理解題目后,能夠迅速轉(zhuǎn)變?yōu)?bug free 的代碼。

因此,雖然沒(méi)有打過(guò)比賽,但是通過(guò) LeetCode 的訓(xùn)練,確實(shí)也有了類(lèi)似競(jìng)賽的收獲。但自然,在深度、廣度和速度上都遠(yuǎn)不及那些“身經(jīng)百賽”的同學(xué)。不過(guò)于我已經(jīng)是受益匪淺:

  1. 對(duì)常見(jiàn)數(shù)據(jù)結(jié)構(gòu)和算法掌握純熟。比如現(xiàn)在說(shuō)起六種排序,特點(diǎn)、使用場(chǎng)景、背后原理,可以做到如數(shù)家珍;比如說(shuō)起樹(shù)的各種遞歸非遞歸遍歷,腦動(dòng)模擬遞歸執(zhí)行過(guò)程,也是信手拈來(lái);再比如鏈表、隊(duì)列、圖等特點(diǎn),也能在腦中邊模擬,邊換成代碼。

  2. 學(xué)到了很多精巧的代碼片段“構(gòu)件”。比如如何二分、如何迭代、如何處理鏈表頭尾節(jié)點(diǎn)、如何設(shè)計(jì)基本數(shù)據(jù)結(jié)構(gòu)的接口等等。這些偏“原子”的構(gòu)件,是我后來(lái)工作中寫(xiě)代碼的血肉來(lái)源。

但只有這些,是遠(yuǎn)遠(yuǎn)不夠的,一到大項(xiàng)目里,寫(xiě)出的代碼就很容易——“有佳句無(wú)佳章”。

Writing/Review Code Loop

遇到上述窘境,往往是因?yàn)槿鄙僦写笮晚?xiàng)目的磨練。表現(xiàn)在空間上,不知道如何組織上萬(wàn)行的代碼,如何劃分功能模塊、構(gòu)建層次體系;體現(xiàn)在時(shí)間上,沒(méi)有經(jīng)過(guò)項(xiàng)目“起高樓、宴賓客、樓塌了”的構(gòu)建-腐爛-重構(gòu)循環(huán)。

工程中在理解代碼和組織代碼時(shí)有個(gè)矛盾:

  1. 可理解性。作為維護(hù)人員,我們學(xué)習(xí)代碼時(shí),多喜歡順著數(shù)據(jù)流控制流來(lái)理解,所謂根據(jù)某個(gè)頭,一路追查到底,是為縱向

  2. 可維護(hù)性。但作為架構(gòu)人員,我們組織代碼時(shí),為了容易維護(hù),多是按照圍繞模塊來(lái)組織代碼——把關(guān)聯(lián)緊密的代碼聚合到一塊,是為橫向。

所以我們?cè)谀玫揭粋€(gè)大工程時(shí),如果立即地毯式的看代碼,肯定會(huì)昏昏欲睡、事倍功半。不幸的是,由于多年讀書(shū)養(yǎng)成的強(qiáng)大習(xí)慣,這個(gè)毛病,跟了我很多年。正確的打開(kāi)方式是,要像對(duì)待團(tuán)在一起的多條線(xiàn)一樣,找到“線(xiàn)頭”,然后慢慢往外揪。在項(xiàng)目中,這些線(xiàn)頭是:service 的 main 函數(shù)、各種單測(cè)入口。

但我們?cè)跇?gòu)建一個(gè)大工程時(shí),又得反著來(lái):先搭建一個(gè)揉在一起的主流程,然后逐漸迭代。就像盤(pán)古開(kāi)天辟地一樣,隨著時(shí)間而演化,讓天慢慢地升高、地慢慢下降,讓整體化為地上四極、山川河流、太陽(yáng)月亮。如是迭代,將一個(gè)混沌的流程,慢慢地模塊化。比如常用的工具模塊(utils)、業(yè)務(wù)相關(guān)基礎(chǔ)模塊(common)、控制模塊(controller、manager)、RPC HTTP 等回調(diào)處理模塊(processor)等等。

但當(dāng)然,如果你已經(jīng)有了構(gòu)建某種類(lèi)型系統(tǒng)的經(jīng)驗(yàn),則并不需要在構(gòu)建初期經(jīng)歷這個(gè)漫長(zhǎng)過(guò)程,可以直接按經(jīng)驗(yàn)分出一些模塊。更進(jìn)一步,你已經(jīng)形成了自己的一個(gè)代碼庫(kù),比如時(shí)鐘、網(wǎng)絡(luò)、多線(xiàn)程、流控等等,可以直接拿來(lái)就用。

那剩下的問(wèn)題就是細(xì)節(jié)的微調(diào),我們?cè)谶M(jìn)行分層時(shí),邊界處的功能,是往上升,還是往下沉;某個(gè)較完整的結(jié)構(gòu),是拍平到使用類(lèi)里,還是單獨(dú)拎出來(lái);這些形形色色的決策,都沒(méi)有一個(gè)定則,更多的還是根據(jù)場(chǎng)景的需求、工期的長(zhǎng)短等諸多實(shí)際情況,便宜行事。而這種背后的決策,則是在長(zhǎng)時(shí)間對(duì)中大型項(xiàng)目的學(xué)習(xí)、對(duì)別人修改的 Review、自己上手搭架子和修修補(bǔ)補(bǔ)中,一點(diǎn)點(diǎn)形成的直覺(jué)。

就像股票市場(chǎng)有周期一樣,工程代碼也是有其周期。不經(jīng)歷一個(gè)股市牛熊周期,我們不敢輕言空多;不經(jīng)歷過(guò)一個(gè)工程構(gòu)建-成熟-腐爛的周期,我們也不敢輕言取舍。即,沒(méi)辦法在工程構(gòu)建初期,預(yù)見(jiàn)到其最常用的打開(kāi)方式,進(jìn)而面向主要場(chǎng)景設(shè)計(jì),犧牲次要場(chǎng)景的便利性。

單元測(cè)試的重要性,怎么強(qiáng)調(diào)都不為過(guò)。一方面,能不能寫(xiě)出的單元測(cè)試,意味著你代碼的模塊邊界是否清楚;另一方面,通過(guò)設(shè)計(jì)好的輸入和輸出,測(cè)試能夠保證某種“不變性”,之后無(wú)論你怎么微調(diào)、重構(gòu),只要能跑過(guò)之前的測(cè)試,那就可以放心一半。另一半,就要靠自己和別人不斷 Review 、測(cè)試集群線(xiàn)上集群不斷地迭代了。

所以,這個(gè)過(guò)程是一個(gè)無(wú)休止的 loop,不斷的磨,爾后不斷地提升。

Clean Code

最后說(shuō)說(shuō)對(duì)代碼的品味。小節(jié)標(biāo)題是:Clean Code,是因?yàn)槲覍?duì)代碼的品味,最初是從 Clean Code: A Handbook of Agile Software Craftsmanship[1] 這本書(shū)建立起來(lái)的。其第二章對(duì)命名——這個(gè)工程中“最難”的事情——的闡述,給我印象很深。

舉幾個(gè)例子:

  1. 單一職責(zé)。如果你不能清晰的對(duì)你的類(lèi)或者函數(shù)命名,說(shuō)明你的類(lèi)或者函數(shù)干的事情太多了。

  2. 命名代替注釋。比如不要直接使用字面值常量,最好給其一個(gè)名字;比如最好不要使用匿名函數(shù),也要給其一個(gè)能看出含義的名字。

工作中,我們常說(shuō),某某對(duì)代碼有“潔癖”。我也多少有一些,但我并不以為這是潔癖,而是一種對(duì)美的欣賞和追求。代碼的美體現(xiàn)在哪里呢?我這里稍微拋個(gè)磚(當(dāng)然,我之前也寫(xiě)文章就代碼命名問(wèn)題啰嗦過(guò),感興趣的可以點(diǎn)這里[2]可以去看看):

  1. 一致性。比如具有相同含義的實(shí)體,使用相同的命名;而需要區(qū)分的實(shí)體,則要通過(guò)命名閾、前綴來(lái)進(jìn)行甄別。從而給讀者造成最小的心智負(fù)擔(dān)。

  2. 體系性。是指我們?cè)谧鲆唤M相關(guān)接口時(shí),要考慮其體體系性。比如增刪改查,比如生產(chǎn)消費(fèi),比如預(yù)處理、處理、處理后,比如讀取寫(xiě)入等等。體系性又包括對(duì)稱(chēng)性和邏輯性,讓人在拿到一組接口時(shí),就能最小成本地理解其是如何相互聯(lián)系、又是如何具有區(qū)別的。

  3. 沒(méi)有贅肉。寫(xiě)代碼,不要啰嗦,不要啰嗦,不要啰嗦。如果不小心啰嗦了,說(shuō)明你可能沒(méi)有想清楚所解決問(wèn)題的本質(zhì)。復(fù)雜的表象,在不斷地剝離雜質(zhì)后,往往有很簡(jiǎn)單的關(guān)竅。抓住這些關(guān)竅,再往其上附著骨肉,同時(shí)理清楚一對(duì)一、一對(duì)多、多堆多等依賴(lài)關(guān)系,往往能化簡(jiǎn)為繁。

不同概念(對(duì)應(yīng)代碼中的類(lèi))間的關(guān)系,在理解代碼組織的時(shí)候至關(guān)重要,最好在名字上有所體現(xiàn),比如一對(duì)一,一對(duì)多還是多對(duì)多。每個(gè)概念的內(nèi)涵,以及多個(gè)概念之間的包含、連接關(guān)系,是在做模塊設(shè)計(jì)的時(shí)候最需要考慮的事情之一。

在審美之外,還要說(shuō)說(shuō)建模(在某種程度上和隱喻是相通的)。畢竟,我們?cè)谡f(shuō)構(gòu)建時(shí),本身就是借助的建筑學(xué)中的隱喻。軟件工程中,類(lèi)似的隱喻隨處可見(jiàn)。

我們大腦在認(rèn)知新事物時(shí),多建立在基于舊的模型推演上。因此,如果在處理模塊時(shí),如果能從經(jīng)典的模型庫(kù)中,找到一個(gè)相對(duì)合適的抽象,往往能夠極大降低用戶(hù)理解門(mén)檻。比如經(jīng)典的生產(chǎn)者消費(fèi)者模型、樹(shù)形組織模型、路由器模型、線(xiàn)程調(diào)度模型、內(nèi)存模型等等。此外,也可以使用某種常見(jiàn)意象、隱喻來(lái)命名項(xiàng)目,往往也能在易理解性上收獲奇效。比如監(jiān)控系統(tǒng),可以叫“鷹眼”;比如各種流水線(xiàn)管控,可以叫“富士康”(手動(dòng)斜眼);再比如更常見(jiàn)一些的數(shù)據(jù)采集,我們都知道他叫——“爬蟲(chóng)”。

The last Thing

世間的事情往往是多方印證、互相補(bǔ)足的——如果你想寫(xiě)好代碼,就不能只是低頭寫(xiě)代碼,你得去讀讀歷史、學(xué)學(xué)美術(shù)、寫(xiě)寫(xiě)文字、見(jiàn)見(jiàn)河山,建立一套你自己的審美偏好,然后將其理念平移到寫(xiě)代碼里來(lái),才能寫(xiě)出符合直覺(jué)、具有美感的好代碼。

參考資料

[1]

Clean Code: A Handbook of Agile Software Craftsmanship: https://book.douban.com/subject/4199741/

[2]

好好寫(xiě)代碼之命名篇——推敲: https://www.qtmuniao.com/2021/12/12/how-to-write-code-scrutinize-names/


題圖故事

最近回北郵西土城校區(qū)轉(zhuǎn)了一圈,從教三看主樓和新科研樓



寫(xiě)好代碼,我的三個(gè) Code的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
双流县| 霍山县| 托克托县| 南召县| 裕民县| 迁西县| 遂昌县| 海宁市| 鹤壁市| 金沙县| 贵港市| 衡阳市| 巢湖市| 安岳县| 长寿区| 修水县| 突泉县| 云林县| 辽阳市| 台中县| 东源县| 宁安市| 克拉玛依市| 姚安县| 小金县| 府谷县| 定南县| 皮山县| 平泉县| 吉首市| 太谷县| 蒲江县| 东光县| 韶山市| 仁寿县| 余姚市| 綦江县| 甘德县| 凌海市| 高青县| 攀枝花市|