任何一位工程師都不可能了解所有領(lǐng)域的技術(shù)知識懂扼;任何一個(gè)團(tuán)隊(duì)也不可能包含所有類型的專業(yè)人才蛤袒。而一個(gè)完整的產(chǎn)品被開發(fā)出來乘粒,或者一個(gè)系統(tǒng)被構(gòu)建出來,這個(gè)過程都會用到種類繁多的技術(shù)挺邀,一般來說總會有一部分超出當(dāng)前團(tuán)隊(duì)所能掌握的現(xiàn)有經(jīng)驗(yàn)揉忘。這個(gè)矛盾怎么解決呢?這就需要工程師來進(jìn)行技術(shù)攻關(guān)了端铛。
沒錯(cuò)泣矛,工程師的真正價(jià)值就是把未知變成已知的能力。
現(xiàn)在假設(shè)你的leader交給你一件你從來沒接觸過的任務(wù)禾蚕,比如您朽,它可能涉及到研究若干框架以及系統(tǒng)架構(gòu),優(yōu)化某些算法,設(shè)計(jì)和實(shí)現(xiàn)某一類型的網(wǎng)絡(luò)協(xié)議哗总,對音視頻進(jìn)行處理几颜,研究系統(tǒng)底層,甚至這個(gè)過程可能會涉及到一些復(fù)雜的數(shù)學(xué)知識讯屈〉翱蓿總之,這項(xiàng)任務(wù)對你來說有點(diǎn)復(fù)雜涮母,你從來沒有接觸過谆趾,所以完全沒有概念。
你之所以領(lǐng)到這樣一項(xiàng)任務(wù)叛本,首先沪蓬,是因?yàn)轫?xiàng)目在當(dāng)前或者未來需要解決這樣的技術(shù)問題,而團(tuán)隊(duì)中沒有人有現(xiàn)成的經(jīng)驗(yàn)?zāi)軌驊?yīng)付来候。另一方面怜跑,你肯定是在以前的工作中表現(xiàn)出了過人的學(xué)習(xí)和研究能力,你的leader才敢把這個(gè)工作交給你吠勘。
我在上篇文章《馬拉松式學(xué)習(xí)與技術(shù)人員的成長性》中提到過性芬,按技術(shù)領(lǐng)域來劃分,編程可以分為「一般性」和「專業(yè)性」兩大類剧防。作為一件需要進(jìn)行技術(shù)攻關(guān)的任務(wù)來說植锉,它有可能會涉及到一些「專業(yè)性」的領(lǐng)域了。我相信峭拘,每一位執(zhí)著于技術(shù)的工程師俊庇,在他成長的過程中,總會碰到類似的經(jīng)歷鸡挠,去挑戰(zhàn)一些自己未知的東西辉饱。在這個(gè)過程中,既為團(tuán)隊(duì)解決了眼前的問題拣展,也為自己打開了一片新的技術(shù)天地彭沼。這也是技術(shù)小白進(jìn)階到專業(yè)人才的必經(jīng)之路。
今天备埃,我就根據(jù)自己的經(jīng)歷和體驗(yàn)姓惑,說一說從零開始進(jìn)行技術(shù)攻關(guān)的一系列過程,以及可能碰到怎樣的一些問題按脚。希望你看完能有共同的感受于毙。
研究問題本身
有些情況下,你的leader沒法告訴你具體應(yīng)該做什么辅搬,他只是告訴你問題是怎樣的唯沮,比如,視頻播放總是卡頓,或者介蛉,用戶總是說丟消息夯缺,再比如,用戶反饋說搜東西的時(shí)候結(jié)果給的不準(zhǔn)甘耿,打語音或視頻電話總是接不通踊兜,總是有些圖片訪問不到,諸如此類佳恬。
我們第一步應(yīng)該做的捏境,就是先研究問題本身是怎么產(chǎn)生的。首先試圖從用戶的角度去理解問題毁葱,然后從技術(shù)的角度去了解現(xiàn)有的實(shí)現(xiàn)垫言,包括細(xì)節(jié)。這時(shí)候倾剿,全局的視角變得非常重要筷频,你如果既能理解服務(wù)器的邏輯,也能理解客戶端的邏輯前痘,那么解決問題的思路會大大開闊凛捏。有些“系統(tǒng)性”的問題,屬于設(shè)計(jì)缺陷芹缔,并不是做局部改動(dòng)就能解決的坯癣。這種問題,對于只接觸客戶端編程或只接觸服務(wù)器開發(fā)的工程師最欠,解決起來就有難度示罗,他們考慮問題的思路容易被見到的東西限制住。所以芝硬,適時(shí)擴(kuò)大自己的知識域蚜点,永遠(yuǎn)都有好處。
如果問題足夠復(fù)雜拌阴,我們可能還需要增加跟蹤日志绍绘,便于在出現(xiàn)特殊的問題時(shí)能夠分析它發(fā)生的過程;并定義性能指標(biāo)皮官,對現(xiàn)有系統(tǒng)的總體狀況有一個(gè)量化的度量脯倒。它們一方面有助于我們更深入地理解當(dāng)前系統(tǒng)实辑,另一方面也為后面的優(yōu)化和重構(gòu)過程提供了方向捺氢。
通過對問題本身的研究,我們知道了系統(tǒng)的瓶頸或問題癥結(jié)在哪里剪撬。如果我們發(fā)現(xiàn)只有推翻現(xiàn)有系統(tǒng)完全重構(gòu)才能根治問題摄乒,那么接下來就跟從頭開始設(shè)計(jì)一個(gè)全新系統(tǒng)的過程一樣了。
對專業(yè)領(lǐng)域的Overview
在接觸一個(gè)新領(lǐng)域之前,對它進(jìn)行一個(gè)總體的概覽是很有必要的馍佑,這讓我們對后面整個(gè)的精力投入做到心中有數(shù)斋否。
這個(gè)階段的目標(biāo)是,花最短的時(shí)間快速了解相關(guān)的各個(gè)概念拭荤,不求深入理解茵臭,只求了解技術(shù)概況。所以舅世,這個(gè)過程怎么快就怎么來旦委,選擇自己熟悉的方式〕牵可以去你自己喜歡的技術(shù)社區(qū)搜索相關(guān)的文章缨硝,或者通過百度搜索一些概念。很多人不建議用百度來搜索技術(shù)問題罢低,但了解一些概況還是沒有問題的查辩,不過要適可而止。等到真正需要系統(tǒng)地研究技術(shù)細(xì)節(jié)的時(shí)候网持,還是應(yīng)該直接閱讀更規(guī)范的資料(后面我們還會提到)宜岛。
Run起來,獲得感性認(rèn)識
在當(dāng)今的技術(shù)條件下功舀,幾乎什么技術(shù)領(lǐng)域的問題都有開源的軟件可以借鑒谬返。如果針對我們要解決的問題能找到開源項(xiàng)目,那么非常幸運(yùn)日杈,我們探索的過程會大大縮短遣铝。
很多技術(shù)領(lǐng)域都存在眾多抽象的概念,通過前面Overview的階段莉擒,我們一般只能了解到這一層酿炸。而開源項(xiàng)目能幫助我們快速地將抽象的概念具體化,獲得感性的認(rèn)識涨冀。下載一份代碼填硕,編譯通過,然后運(yùn)行起一個(gè)簡單的Demo鹿鳖,從API層面去理解它(內(nèi)部的實(shí)現(xiàn)尚不是重點(diǎn))扁眯。
很多情況下,開源的實(shí)現(xiàn)不止一個(gè)翅帜,這就面臨一個(gè)選擇的問題姻檀。人們對于開源項(xiàng)目的第一印象一般來源于項(xiàng)目的入門教程(tutorial),可見一份好的文檔對于一個(gè)開源項(xiàng)目來說多么重要涝滴。根據(jù)我個(gè)人的經(jīng)驗(yàn)绣版,文檔是否健全胶台,也是選擇開源項(xiàng)目的重要依據(jù)。
當(dāng)然杂抽,在這個(gè)階段诈唬,我們要解決的主要還不是選擇開源項(xiàng)目的問題,而是要通過快速Run起一個(gè)相關(guān)的實(shí)例來達(dá)到對技術(shù)獲得感性認(rèn)識的目的缩麸。注意這種感性認(rèn)識是技術(shù)層面的铸磅,是至少基于API層面的。我們經(jīng)澈贾欤看到愚屁,對于一些熱門的技術(shù)領(lǐng)域,很多非技術(shù)人員也能略知一二痕檬,甚至對一些技術(shù)概念有所了解霎槐,但是,技術(shù)人員與非技術(shù)人員的區(qū)別梦谜,應(yīng)該說丘跌,從這個(gè)階段開始就有所不同了。
同行交流
能夠Run起一個(gè)實(shí)現(xiàn)唁桩,并從API層面粗略地了解一項(xiàng)技術(shù)之后闭树,在這個(gè)認(rèn)識的基礎(chǔ)上,我們就差不多可以找同行交流一下了荒澡。如果在我們正要涉足去研究的領(lǐng)域里报辱,我們恰好認(rèn)識一些這方面的專家,那么無疑是非常幸運(yùn)的单山。邏輯清晰的技術(shù)高手碍现,一般用不了幾句話就能把某項(xiàng)技術(shù)的關(guān)鍵問題描述清楚了。從這種交流中米奸,我們受益匪淺昼接。
但要注意,我們一定要在對該項(xiàng)技術(shù)有所了解之后悴晰,再去找專業(yè)人士交流慢睡。否則這種交流建立在信息嚴(yán)重不對稱的基礎(chǔ)上,就是極其低效的铡溪。對該項(xiàng)技術(shù)的初步了解漂辐,也是讓我們能問出真正有效的問題的基礎(chǔ)條件。
研究Spec
我曾經(jīng)寫過一篇關(guān)于如何學(xué)習(xí)新技術(shù)的文章《技術(shù)的正宗與野路子》棕硫,在文中提到的一個(gè)重要的觀點(diǎn)髓涯,就是一定要找到能稱得上Spec的文檔去閱讀。所謂Spec饲帅,是集中體現(xiàn)該項(xiàng)技術(shù)的設(shè)計(jì)思想的東西复凳,是高度抽象的描述瘤泪,一般也是一份完備的灶泵、系統(tǒng)性的描述育八。它的存在形式有很多種,可能是一份官方文檔赦邻,也可能是一份公開的技術(shù)標(biāo)準(zhǔn)髓棋,比如RFC或者W3C的規(guī)范,還可能是以論文的形式惶洲,甚至與其它技術(shù)資料混雜在一起按声。
總之,你應(yīng)該設(shè)法識別出哪些文檔是Spec恬吕,然后在需要的時(shí)候通讀它們签则。有些涉及到抽象概念的技術(shù),你不讀通這么一份Spec铐料,有可能后面是看不懂代碼的渐裂。這確實(shí)是比較費(fèi)力的一個(gè)過程,但也正是這個(gè)過程钠惩,才真正開啟了從門外漢向技術(shù)專家邁進(jìn)的征程柒凉。
研究和選擇具體實(shí)現(xiàn)
假設(shè)我們找到了開源代碼可供參考。前面我們已經(jīng)能Run起來一些小的Demo了篓跛,并且基本通讀了一份大而全的Spec膝捞,現(xiàn)在需要研究的就是再深入一層,看看這份Spec中的關(guān)鍵點(diǎn)是如何實(shí)現(xiàn)出來的愧沟。你前面已經(jīng)花了很多時(shí)間來調(diào)研蔬咬,這中間肯定產(chǎn)生了很多疑問,比如有些抽象的概念以及相似概念之間的聯(lián)系還是難以理解沐寺,有些過程的實(shí)現(xiàn)初看起來并不是那么地顯而易見计盒,而現(xiàn)在就到了該解決它們的時(shí)候了。頭腦中的疑問和關(guān)鍵點(diǎn)芽丹,要自己總結(jié)出來北启,然后在代碼中去找到答案,這是把抽象概念最終落地的一個(gè)過程拔第。
如果有多個(gè)開源的實(shí)現(xiàn)咕村,那么就涉及到如何選擇的問題。有很多因素需要考慮:
API層面邏輯是否清晰。很多代碼在你初步接觸了API這一層之后就大概知道自己是不是喜歡它了泳猬。
模塊化和抽象層次是否足夠好批钠。這決定了你把這份開源代碼集成到自己項(xiàng)目中的難易程度宇植。
是否仍然有人維護(hù)。你當(dāng)然希望在提issue和pull request的時(shí)候有人能夠響應(yīng)埋心。
研究相似產(chǎn)品的實(shí)現(xiàn)
有可能我們要實(shí)現(xiàn)的東西其他家的線上產(chǎn)品已經(jīng)提供類似的功能了指郁。我們有必要在實(shí)現(xiàn)自己的方案之前研究一下他們的做法(逆向工程),對比之后從而做出一個(gè)更優(yōu)的實(shí)現(xiàn)拷呆。
具體怎么研究呢闲坎?兩種常見的方式:一種是反解客戶端的包,看看里面引用了什么茬斧,是不是在我們調(diào)研過的那些技術(shù)范圍之內(nèi)腰懂;另一種當(dāng)然就是抓包,從網(wǎng)絡(luò)通訊上猜測他們用了哪一類技術(shù)项秉。
網(wǎng)上瀏覽最佳實(shí)踐
經(jīng)過前面的調(diào)研绣溜,我們基本上已經(jīng)在頭腦中產(chǎn)生了自己的方案了。但在真正實(shí)現(xiàn)它之前 娄蔼,我們一般還想做一件事怖喻,就是「循證」。
記得胡峰同學(xué)在他的微信公眾號「瞬息之間」上贷屎,發(fā)過一篇文章《技術(shù)干貨的選擇性問題》罢防,里面就提到了通過閱讀技術(shù)文章來「循證」的做法。很多個(gè)人博主和團(tuán)隊(duì)博客會在網(wǎng)上發(fā)表他們自己系統(tǒng)的實(shí)現(xiàn)過程唉侄,以及系統(tǒng)前后版本的演進(jìn)過程咒吐。如果我們恰好找到相關(guān)的類似這樣的文章,那么它們就有很大的參考價(jià)值属划。我們從別人分享的技術(shù)方案中獲得一個(gè)印證恬叹,確保自己的想法沒有走向極端,或者漏掉了什么重要的東西同眯。
結(jié)合自己的系統(tǒng)設(shè)計(jì)方案
對于復(fù)雜的系統(tǒng)绽昼,即使有開源的代碼,通常也不能直接拿來就用⌒胛希現(xiàn)有系統(tǒng)總有一些特殊性硅确。這涉及到多種選擇的可能性:
找到了一份代碼擴(kuò)展性很好的開源實(shí)現(xiàn)。這份代碼有清晰的模塊化和分層結(jié)構(gòu)明肮,我們不需要改動(dòng)原來的代碼菱农,只需要補(bǔ)充自己的一部分實(shí)現(xiàn),再加上一些膠水代碼(glue code)柿估,或者在原開源代碼的基礎(chǔ)上進(jìn)行封裝循未,就能把整個(gè)系統(tǒng)實(shí)現(xiàn)出來。這是最好的情況秫舌,工作量大大減少的妖。
必須改動(dòng)原來的開源代碼绣檬,重新編譯,才能實(shí)現(xiàn)自己的需求嫂粟。這種情況一般來說比較糟糕娇未,主要是日后的維護(hù)可能會成問題。一方面赋元,我們產(chǎn)生了一份與原開源項(xiàng)目差別很大的代碼分支忘蟹,而且沒法合并回開源項(xiàng)目飒房;另一方面搁凸,開源代碼通常要考慮更通用的一些應(yīng)用場景,它涉及到的問題域可能遠(yuǎn)遠(yuǎn)大于我們要解決的狠毯。簡單來說就是护糖,開源代碼中有大量的與我們的實(shí)際需求無關(guān)的代碼,如果我們要改動(dòng)這份代碼嚼松,我們所需要掌握的信息要遠(yuǎn)遠(yuǎn)大于自己系統(tǒng)實(shí)際的要求嫡良。特別是在以后團(tuán)隊(duì)人員變動(dòng)的時(shí)候,這份代碼很可能變得沒有人敢動(dòng)献酗。再就是寝受,當(dāng)原開源代碼升級的時(shí)候,我們很難跟著升級罕偎。所以很澄,如果是決定作出這種對開源代碼進(jìn)行私有方式的改動(dòng)的話,請慎重颜及,并留下足夠的文檔說明甩苛。
開源代碼與我們的需求相差太遠(yuǎn),或者找不到開源的實(shí)現(xiàn)俏站,那么只能完全自己實(shí)現(xiàn)了讯蒲。還有一個(gè)迫使我們重新實(shí)現(xiàn)的現(xiàn)實(shí)原因,可能是項(xiàng)目體積肄扎。如果我們想在客戶端引用的話墨林,一個(gè)太重的實(shí)現(xiàn)就是不太合適的。我們希望引入的東西盡量簡單犯祠,體積小旭等。
總之,這里的選擇過程是比較痛苦的雷则,因?yàn)樗鼘竺娴膶?shí)現(xiàn)工作以及日后的維護(hù)影響很大辆雾。具體如何選擇,除了要考慮開源實(shí)現(xiàn)與當(dāng)前系統(tǒng)的實(shí)際需求之間的匹配程度月劈,還要考慮預(yù)期收益和項(xiàng)目預(yù)算(budget)度迂,你有多少時(shí)間去完成整個(gè)的事情藤乙。
系統(tǒng)實(shí)現(xiàn)的過程
現(xiàn)在進(jìn)入很關(guān)鍵的實(shí)現(xiàn)階段了。實(shí)際上惭墓,對于一個(gè)復(fù)雜的系統(tǒng)坛梁,在真正寫代碼之前,需要首先進(jìn)行設(shè)計(jì)腊凶,系統(tǒng)架構(gòu)的設(shè)計(jì)和軟件接口的設(shè)計(jì)划咐。這個(gè)過程非常重要,花費(fèi)的時(shí)間和精力很可能超過代碼編寫的過程钧萍。這個(gè)過程逼迫你在真正實(shí)現(xiàn)之前就必須想清楚系統(tǒng)在各個(gè)層面上是如何運(yùn)行的褐缠,確保不會實(shí)現(xiàn)到一半推翻重做。
首先风瘦,系統(tǒng)架構(gòu)的設(shè)計(jì)队魏,劃分出組成系統(tǒng)的各個(gè)組件(各個(gè)獨(dú)立的進(jìn)程,通過網(wǎng)絡(luò)進(jìn)行交互)万搔。有兩個(gè)問題需要在設(shè)計(jì)時(shí)就重點(diǎn)考慮:一個(gè)是可擴(kuò)展性胡桨;一個(gè)是容錯(cuò)性∷脖ⅲ可擴(kuò)展性說的是昧谊,當(dāng)流量逐漸變大的時(shí)候,你的系統(tǒng)如何擴(kuò)展酗捌。系統(tǒng)中有些組件是無狀態(tài)的呢诬,有些是有狀態(tài)的。無狀態(tài)的組件一般通過增加節(jié)點(diǎn)意敛,應(yīng)用簡單的負(fù)載均衡策略就可以擴(kuò)展馅巷;而有狀態(tài)的組件需要明確擴(kuò)展的方式。容錯(cuò)性說的是草姻,系統(tǒng)應(yīng)該主動(dòng)處理失敗情況钓猬,在設(shè)計(jì)中就應(yīng)該考慮進(jìn)去。比如撩独,你想做到不丟消息敞曹,那么必須把網(wǎng)絡(luò)丟包和處理異常的情況當(dāng)做正常情況來考慮,設(shè)計(jì)重傳機(jī)制综膀;既然有了重傳澳迫,就不得不考慮去重機(jī)制。容錯(cuò)性還包括剧劝,系統(tǒng)應(yīng)該具有從錯(cuò)誤狀態(tài)中恢復(fù)的傾向橄登。當(dāng)然,系統(tǒng)架構(gòu)的設(shè)計(jì)還有很多因素需要考慮,比如高可用拢锹、高性能谣妻、可維護(hù),等等卒稳,我們這里就不展開說了蹋半。
其次,在更細(xì)的層面充坑,要完成接口設(shè)計(jì)减江,也就是俗稱的「面向接口編程」。這個(gè)過程的重要性怎么強(qiáng)調(diào)都不為過捻爷。我們都知道「面向接口編程」辈灼,在面試的時(shí)候也經(jīng)常討論設(shè)計(jì)模式,但實(shí)際中真正按這種方式工作的人少之又少役衡。造成這種狀況的原因可能是茵休,我們平常做業(yè)務(wù)開發(fā)薪棒,在大部分情況下手蝎,都不用自己設(shè)計(jì)接口。比如做客戶端開發(fā)俐芯,各種MVC, MVP模式已經(jīng)把代碼框架都定義好了棵介,我們只用往接口實(shí)現(xiàn)里填東西。
但我們應(yīng)該知道吧史,當(dāng)為一個(gè)新系統(tǒng)編寫代碼的時(shí)候邮辽,代碼應(yīng)該從接口設(shè)計(jì)開始。先用代碼定義出各層的接口(包括回調(diào)接口)贸营,沒有實(shí)現(xiàn)吨述,只是能夠編譯通過。有了這些接口钞脂,就可以拿它們與同事進(jìn)行非常細(xì)節(jié)的討論了揣云。應(yīng)該先把接口討論得足夠清楚,再進(jìn)行下一步的具體實(shí)現(xiàn)冰啃。這也是一個(gè)比較痛苦的過程邓夕,我們需要反復(fù)抉擇,而通逞忠悖「選擇」就意味著痛苦焚刚。根據(jù)我個(gè)人的經(jīng)驗(yàn),設(shè)計(jì)接口代碼的過程扇调,一般都要前后改很多遍矿咕,才能達(dá)到令自己基本滿意的程度。
接口設(shè)計(jì)的時(shí)候,要時(shí)刻考慮這兩個(gè)問題:
功能層次。也就是系統(tǒng)包括哪些接口望蜡,哪些功能放到哪些接口里面阁猜,不同的接口之間的關(guān)系如何。我們可能還需要畫出類似UML(Unified Modeling Language)那樣的類圖锦援。
實(shí)例運(yùn)行模型。系統(tǒng)運(yùn)行起來之后剥悟,接口的各個(gè)實(shí)例的生命周期灵寺,以及各個(gè)實(shí)例之間的交互關(guān)系和數(shù)量關(guān)系,是一對一区岗,還是一對多略板。雖然在編寫接口代碼的時(shí)候,還不要求寫出實(shí)現(xiàn)慈缔,但是一個(gè)不錯(cuò)的實(shí)踐方式是叮称,寫完接口,先生成一個(gè)空的實(shí)現(xiàn)類藐鹤,然后把能表明實(shí)例引用關(guān)系的代碼先寫出來瓤檐,再進(jìn)一步把各個(gè)接口的實(shí)例創(chuàng)建代碼寫出來(解決了實(shí)現(xiàn)參數(shù)的注入問題),這樣一個(gè)系統(tǒng)的「骨架」就出來了娱节。
在編寫和修改接口代碼的過程中挠蛉,還有幾個(gè)問題值得考慮:
是否引入響應(yīng)式編程(Reactive Programming)的思想。實(shí)踐證明肄满,采用響應(yīng)式編程和傳統(tǒng)的回調(diào)方式(callback)設(shè)計(jì)出來的接口形式谴古,存在很大的不同。
給接口起名字非常重要(包括各個(gè)類名稠歉、方法名掰担、參數(shù)名等)。起名字其實(shí)是個(gè)大問題怒炸,就像給自己的小孩起名字一樣難带饱!名字起的好不好,直接反映了通過系統(tǒng)抽象劃分出來的各個(gè)角色是不是合理横媚。
能稱得上「接口」的代碼纠炮,從一開始編寫就要有非常詳細(xì)的代碼注釋。
考慮線程模型灯蝴。被上層調(diào)用的代碼預(yù)期在哪些線程上執(zhí)行恢口,回調(diào)的代碼又在哪些線程上執(zhí)行。是多線程的環(huán)境穷躁,還是單線程的環(huán)境耕肩,這直接影響后面的實(shí)現(xiàn)應(yīng)該怎么來做因妇。一般來說,多線程的環(huán)境是存在一個(gè)線程池猿诸,這個(gè)線程池是外部調(diào)用者提供婚被,還是接口內(nèi)的實(shí)現(xiàn)來提供,這個(gè)要規(guī)定清楚梳虽。另外就是考慮能否把多線程問題規(guī)避址芯,變成單線程的編程問題。比如窜觉,在有些異步編程的情況下谷炸,充分利用Java的Executor,或者Android開發(fā)中的Looper禀挫,或者RxJava之類的框架旬陡,就可能達(dá)到類似的目的。
最后语婴,就是愉快地實(shí)現(xiàn)了描孟。只要前面的過程做得比較細(xì)致,編寫實(shí)現(xiàn)代碼基本就是水到渠成了砰左。在實(shí)現(xiàn)中有一個(gè)非常重要但容易被忽視的問題是——日志(log)匿醒。每個(gè)人都知道怎么打日志,但打一份好的日志菜职,實(shí)際沒有幾個(gè)人能夠做到的青抛。一般來說,如果沒有足夠的重視酬核,工程師打出來的日志,或者過于隨意适室,或者邏輯缺失嫡意。一份好的日志其實(shí)要花很多精力來調(diào)整細(xì)節(jié),把程序運(yùn)行看成一個(gè)狀態(tài)機(jī)捣辆,每一個(gè)關(guān)鍵的狀態(tài)變化蔬螟,都要在日志中記錄。一份好的日志其實(shí)反映了一套好的程序邏輯汽畴【山恚總之,打日志的目標(biāo)是:如果線上發(fā)生奇怪的情況忍些,拿過這份日志來就能分析出問題所在鲁猩。這在客戶端上分析線上問題的時(shí)候尤其有用。
前面講到的各個(gè)過程并不是要嚴(yán)格按照這樣的步驟進(jìn)行罢坝,實(shí)際中有些過程要前后交叉廓握,甚至反復(fù)進(jìn)行。中間碰到問題,可能還要退回到前面的步驟隙券,重新進(jìn)行男应。
在時(shí)間、精力和項(xiàng)目進(jìn)度各種條件允許的情況下娱仔,盡量把事情做到當(dāng)前認(rèn)為「最好」的狀態(tài)沐飘。當(dāng)然,如果由于客觀條件牲迫,一時(shí)沒有那么多時(shí)間去做到完美薪铜,也不要太過沮喪,后面能夠持續(xù)優(yōu)化才是最重要的恩溅。
進(jìn)行一項(xiàng)技術(shù)攻關(guān)隔箍,從這個(gè)過程中學(xué)習(xí)新的東西,這是一個(gè)利用現(xiàn)有各種資源來學(xué)習(xí)和解決問題的過程脚乡。每一步并非必不可少蜒滩。你參考的東西越多,做出一個(gè)差勁的實(shí)現(xiàn)的可能性就越小奶稠,但付出的精力也就越多俯艰。
關(guān)鍵的關(guān)鍵,當(dāng)團(tuán)隊(duì)中出現(xiàn)現(xiàn)有經(jīng)驗(yàn)無法解決的問題的時(shí)候锌订,你能夠站出來竹握,勇于承擔(dān)。這樣辆飘,你的技術(shù)之路也會越來越寬廣啦辐。
(完)有時(shí)候?qū)扅c(diǎn)技術(shù)干貨,有時(shí)候?qū)扅c(diǎn)有趣的文章蜈项。
阿里Java高級大牛直播講解知識點(diǎn)芹关,分享知識,五大專題都是各位老師多年工作經(jīng)驗(yàn)的梳理和總結(jié)紧卒,帶著大家全面侥衬、科學(xué)地建立自己的技術(shù)體系和技術(shù)認(rèn)知扣群Java大神高級架構(gòu)群:658362658備注好信息!