我高效學(xué)習(xí)編程的心得
咱們干程序員的,經(jīng)常需要應(yīng)用、研究一些開源組件。研究開源組件,就少不了去看資料、看源代碼。在看代碼、學(xué)習(xí)的過程中,咱們可不能像那些眼瞎的裁判,咱們需要高效的學(xué)習(xí):看清全局、主要脈絡(luò)、關(guān)鍵細(xì)節(jié)。
這篇文章就和大家說說我自己高效學(xué)習(xí)的方法。
對(duì)我而言,做好這件事的關(guān)鍵就在于問自己七個(gè)問題。
問題1. 組件解決了什么問題
問這個(gè)問題的目的是明確組件的問題域,任何組件的出現(xiàn)都是為了解決某類問題的。
我們?cè)诼殬I(yè)生涯里,遇到的技術(shù)問題其實(shí)是有限的。面對(duì)這些有限的問題,我們熟悉的組件越多,解決問題的思路和辦法就越多。當(dāng)你對(duì)某種技術(shù)問題,有著比別人更多的思路和辦法,那自然而然,你的技術(shù)話語權(quán)就會(huì)越大。
以我曾經(jīng)深入研究過的 druid(阿里的開源數(shù)據(jù)庫(kù)連接池)組件為例:
druid 要解決的問題本質(zhì)其實(shí)是如何降低應(yīng)用和中間件交互所消耗的時(shí)間成本。
知道了 druid 要解決的問題,我們就等于知道了它的核心主題。druid 的主要技術(shù)思路,全部都是圍繞著這個(gè)核心主題來實(shí)現(xiàn)的。
比如,druid 本身的 LRU 策略、對(duì)一些關(guān)鍵對(duì)象的緩存、競(jìng)爭(zhēng)資源的高效率利用……都是圍繞著這個(gè)核心問題來設(shè)計(jì)和落地的。
同時(shí),我們明確了 druid 要解決的問題后,如果我們對(duì)現(xiàn)在 jedis 這套東西不滿意,是不是就可以利用 druid 的技術(shù)思路,重新設(shè)計(jì)和實(shí)現(xiàn)一套新組件,去替代 jedis,以便降低和 redis 交互的時(shí)間成本呢?
問題2. 組件有什么優(yōu)點(diǎn)
確認(rèn)了組件需要解決的問題,只是第一步。一套開源組件,往往項(xiàng)目都比較龐大。所以,就得想個(gè)辦法分而克之,分出各個(gè)具體的知識(shí)點(diǎn)去學(xué)習(xí)。
而這些知識(shí)點(diǎn),往往和官方文檔宣傳的組件優(yōu)點(diǎn)可以對(duì)上。
比如,druid 的官方文檔是這么說的:
從上面這幅圖,就可以看出來,druid 有如下幾個(gè)特點(diǎn):
能被監(jiān)控 容易擴(kuò)展 性能優(yōu)秀 穩(wěn)定性好 安全 運(yùn)行期問題容易排查
這些就是我們要去學(xué)習(xí)的各個(gè)知識(shí)點(diǎn)。
問題3. 組件的主干和分支都是哪些
知道了組件的優(yōu)點(diǎn),就等同于知道了需要學(xué)習(xí)的知識(shí)點(diǎn)。可是,知識(shí)點(diǎn)如果多而雜,就需要確認(rèn)好哪些學(xué)哪些不學(xué)?哪些先學(xué)哪些后學(xué)?
那么,組件的主干和分支就需要分解出來,以便定出學(xué)習(xí)計(jì)劃。而劃分出主干和分支,就需要綜合我們前面說的組件要解決的問題。
通過前面的學(xué)習(xí),我們知道 druid 解決的是降低中間件的時(shí)間成本,也知道了它的特點(diǎn):
能被監(jiān)控 容易擴(kuò)展 性能優(yōu)秀 穩(wěn)定性好 安全 運(yùn)行期問題容易排查
此時(shí),我們的學(xué)習(xí)計(jì)劃就是:先學(xué)習(xí) druid 是如何實(shí)現(xiàn)高性能的;高性能后,如果我們研究 druid 是為了后續(xù)在工作中應(yīng)用,那么,能被監(jiān)控這個(gè)特點(diǎn)就是下一個(gè)要學(xué)習(xí)的知識(shí)點(diǎn)。
所以,這一問,是為了擬定學(xué)習(xí)計(jì)劃而問。
問題4. 組件的這些優(yōu)點(diǎn)是如何實(shí)現(xiàn)的
在上個(gè)問題之后,我們就可以分步驟的進(jìn)行學(xué)習(xí)了。學(xué)的怎么樣,就需要通過這個(gè)問題,來考察自己是否真的學(xué)懂了這些知識(shí)點(diǎn)。
回到 druid 上,讓人滿意的答案就是,我們能用自己的話去總結(jié)出每個(gè)知識(shí)點(diǎn)的技術(shù)實(shí)現(xiàn)。比如:
“問:druid 的監(jiān)控是如何實(shí)現(xiàn)的?
”
答:druid 通過自己實(shí)現(xiàn) JDBC API 自身提供的 PooledConnection、Connection、Statement、ResultSet接口,獲得了可以在這些接口的關(guān)鍵方法中植入統(tǒng)計(jì)的能力。統(tǒng)計(jì)的數(shù)據(jù)會(huì)定期采樣后存儲(chǔ)在某些命名叫做 xxxStat 的對(duì)象里,供后面展示使用。
“問:druid 是如何實(shí)現(xiàn)擴(kuò)展的?
”
答:能擴(kuò)展的實(shí)現(xiàn)方式是第三方實(shí)現(xiàn) druid 提供的一個(gè) Filter 接口后,再被配置到 druid 的配置文件里。這樣就會(huì)在 DruidDataSource 初始化的時(shí)候,去讀取并初始化這些實(shí)現(xiàn)了 Filter 接口的實(shí)例。初始化后的 Filter 會(huì)在后面 druid 從創(chuàng)建數(shù)據(jù)庫(kù)連接到執(zhí)行 SQL 語句再到釋放連接這一系列步驟后,被不斷的鏈?zhǔn)綀?zhí)行。
就這樣,分知識(shí)點(diǎn)回答出讓自己滿意的答案,就等同于考核了自己對(duì)每個(gè)知識(shí)點(diǎn)學(xué)習(xí)的質(zhì)量,如果回答不滿意,就再去查漏補(bǔ)缺即可。
問題5. 組件的系統(tǒng)設(shè)計(jì)思路是什么
我們學(xué)習(xí)了各個(gè)零散的知識(shí)點(diǎn)之后并不夠,因?yàn)閷W(xué)習(xí)一套開源組件,原理是基礎(chǔ),系統(tǒng)設(shè)計(jì)則是骨架。
明白了技術(shù)點(diǎn),只是對(duì)當(dāng)編碼高手有用,但是當(dāng)你自己設(shè)計(jì)組件的時(shí)候,你的底氣在哪里呢?答案就在這些你看過的開源組件的系統(tǒng)設(shè)計(jì)思路上。
所以,把知識(shí)點(diǎn)融合起來形成一個(gè)整體,再去推斷出系統(tǒng)的設(shè)計(jì)思路,對(duì)我們成為一名優(yōu)秀的架構(gòu)師,是有非常大的幫助的。
比如,通過各個(gè)知識(shí)點(diǎn)的深入學(xué)習(xí),融會(huì)貫通后,我認(rèn)為 druid 的設(shè)計(jì)思路如下:
如果以后遇到為公司底層構(gòu)造一套池化中間件對(duì)象的需求時(shí),這種設(shè)計(jì)思路自然就成了我設(shè)計(jì)的重要模板之一。
問題6. 組件的缺點(diǎn)是什么
為什么會(huì)問組件的缺點(diǎn)?因?yàn)樵谖胰绱肆私饬艘惶捉M件之后,卻還是免不了誤用和踩坑,這其中最嚴(yán)重的就是,生產(chǎn)環(huán)境在組件出現(xiàn)問題之后,我們卻沒有緊急預(yù)案。
這種現(xiàn)象的原因就是沒有去深入思考過一套技術(shù)的利弊。問組件的缺點(diǎn),就會(huì)迫使我們?nèi)ド钊胨伎祭?,從而在以后不管是?yīng)用組件,又或者是去根據(jù)學(xué)習(xí)到的知識(shí)自己實(shí)踐,都能成竹在胸,從容以對(duì)。
回到 druid 身上,當(dāng)我們?nèi)プx它源碼的時(shí)候,思考一下:
durid 的這些實(shí)現(xiàn)真的就是完美的嗎?
那肯定不是, 比如:
druid 的采樣功能很多時(shí)候我們并不需要,但是由于 druid 的實(shí)現(xiàn)是寫死在實(shí)現(xiàn)的關(guān)鍵代碼里的,所以無法自由的對(duì)其進(jìn)行插拔。這時(shí)候,就要注意,采樣可能造成的內(nèi)存占用問題。
druid 是對(duì) JDBC API 做了層層封裝的,在這些封裝中 druid 又添加了很多自己的實(shí)現(xiàn)。但是,這些實(shí)現(xiàn)很難避免bug,然而由于有這些封裝,就會(huì)導(dǎo)致 Bug 很難查,又或者很難自己改。這時(shí)候,就需要在測(cè)試環(huán)境,把 druid 的日志級(jí)別調(diào)成 DEBUG 級(jí)別,然后仔細(xì)觀察日志,看看是否有什么不可知的風(fēng)險(xiǎn)。
所以,這一問,是為了深度思考,讓我們?cè)谌魏涡录夹g(shù)的學(xué)習(xí)和實(shí)戰(zhàn)時(shí),都能成為最穩(wěn)定的那個(gè)仔。
不管以后我們模仿還是應(yīng)用 druid,就能提前預(yù)測(cè)到風(fēng)險(xiǎn),從而重點(diǎn)監(jiān)控,提前準(zhǔn)備預(yù)案。
問題7. 和同類別的組件之間有什么區(qū)別
當(dāng)學(xué)習(xí)完了組件,知道了組件的優(yōu)缺點(diǎn),理解了組件的運(yùn)行原理,明白了組件的設(shè)計(jì)思路之后,一切就完整了嗎?
對(duì)不起,還不夠。
因?yàn)槲覀冞€缺乏一種東西,就是學(xué)習(xí)的拓展,即學(xué)習(xí)的廣度。
學(xué)習(xí)組件,我們除了知道它要解決的問題域外,還需要知道它在同類組件中的地位。
為什么?因?yàn)橐院笪覀內(nèi)ト魏我粋€(gè)稍微成規(guī)模的公司后,需要面臨一個(gè)問題,內(nèi)部的競(jìng)爭(zhēng)。
比如,我們寫了一套消息治理中間件。如果想提升自己的技術(shù)話語權(quán),就需要在全公司,和同類產(chǎn)品競(jìng)爭(zhēng)。競(jìng)爭(zhēng)勝出了,自己的職業(yè)生涯就有了巨大發(fā)展的可能。
回到 druid 上,在SpringBoot2.0時(shí)代,druid 出現(xiàn)了巨大的競(jìng)爭(zhēng)對(duì)手——HiKariCP。
而 HiKariCP 之所以能勝出,是因?yàn)樗懦?druid 使用的公平鎖,使得性能提升了大約 70%。
通過 druid 和 HiKariCP 的比較和學(xué)習(xí),我們就能更加深入的理解高并發(fā),能更有效率的去壓榨出系統(tǒng)的性能。
通過 druid 和 HiKariCP 作者之間的互相較量,我們還能明白如何去更好的對(duì)比競(jìng)品,去展現(xiàn)最為關(guān)鍵的數(shù)據(jù)指標(biāo),一舉贏得勝利。
以上列舉的七個(gè)問題,是我為了解決高效高質(zhì)研究開源組件,得到的最佳實(shí)踐。
總結(jié)一下:
先通過問組件解決了什么問題,去確定自己的學(xué)習(xí)目的和思考邊界。 再問組件有什么優(yōu)點(diǎn),以及主干和分支是哪些,去擬定出學(xué)習(xí)計(jì)劃。 再后,通過問組件的優(yōu)點(diǎn)是如何實(shí)現(xiàn)的,去考察自己的學(xué)習(xí)質(zhì)量。 然后,通過問組件的系統(tǒng)設(shè)計(jì)思路是什么,讓自己講學(xué)到的各種獨(dú)立的知識(shí)融匯貫通,打造成體系。 最后,通過問組件的缺點(diǎn)是什么以及和競(jìng)品的區(qū)別去迫使自己在學(xué)習(xí)之外,再行深度思考和廣度思考,對(duì)學(xué)習(xí)進(jìn)行查漏補(bǔ)缺以及進(jìn)一步提升學(xué)習(xí)質(zhì)量,打造出更為突出的知識(shí)體系。
IT這行業(yè)是需要不斷學(xué)習(xí)的,而高效高質(zhì)量學(xué)習(xí),是讓我們的職業(yè)生涯走的更穩(wěn)更順的關(guān)鍵所在。
希望這篇文章對(duì)大家有幫助,看完如果覺得有收獲,請(qǐng)幫忙轉(zhuǎn)發(fā)、隨手點(diǎn)個(gè)在看,你的支持對(duì)我很重要。
我是 Guide哥,一個(gè)工作2年有余,接觸編程已經(jīng)6年有余的程序員。大三開源 JavaGuide,目前已經(jīng) 100k+ Star。未來幾年,希望持續(xù)完善 JavaGuide,爭(zhēng)取能夠幫助更多學(xué)習(xí) Java 的小伙伴!共勉!凎!點(diǎn)擊即可了解我的個(gè)人經(jīng)歷。
歡迎點(diǎn)贊分享。咱們下期再會(huì)!
