前言。
技術(shù)服務(wù)于業(yè)務(wù),今天來(lái)梳理一下。
技術(shù)的變化,從一開(kāi)始的 jsp+ssm到現(xiàn)在的springboot+mybatis+vue,框架越來(lái)越便捷,正如曾經(jīng)看到的那句話,底層越來(lái)越復(fù)雜,頂層越來(lái)越無(wú)腦。開(kāi)發(fā)門(mén)檻越來(lái)越低,但是你懂的越來(lái)越少。原理跟基礎(chǔ),在網(wǎng)上java資料都很泛濫,但是碰到問(wèn)題,怎么處理問(wèn)題,怎么去解決問(wèn)題,或者預(yù)防問(wèn)題變成真正含金量的東西。人應(yīng)該對(duì)技術(shù)做怎么樣的思考,或許是之前走的太快太忙,沒(méi)有好好思考過(guò)。
業(yè)務(wù)的變化,業(yè)務(wù)初步給人的感覺(jué)就是產(chǎn)品經(jīng)理在巴拉巴拉的一頓亂說(shuō),好像給在專注寫(xiě)代碼的你套上了過(guò)來(lái)開(kāi)個(gè)會(huì)的枷鎖。一開(kāi)始也煩業(yè)務(wù),為什么不讓我好好寫(xiě)增刪改查,打擾我寶貴的敲代碼時(shí)間。后面被現(xiàn)實(shí)教育了。開(kāi)始重新審視業(yè)務(wù)。首先,你的代碼不值錢(qián),你的增刪改查來(lái)個(gè)實(shí)習(xí)也可以干,你的ctrl+c,ctrl+v ,實(shí)習(xí)的比你更加熟練,其次你的代碼單純的拿出來(lái),沒(méi)有變現(xiàn)價(jià)值,你的嘗試都是偏向表面,或許你寫(xiě)的,都是可以百度到的寫(xiě)法,沒(méi)有對(duì)某個(gè)點(diǎn)進(jìn)行優(yōu)化,涉及底層的東西,真的有價(jià)值嗎?面試問(wèn)的很多項(xiàng)目經(jīng)驗(yàn),都是問(wèn)遇到什么問(wèn)題,你怎么解決問(wèn)題?更看重你對(duì)待技術(shù)的態(tài)度,跟處理方法,以及一個(gè)處理bug的思路。技術(shù)是服務(wù)于業(yè)務(wù)的,在這個(gè)前提下,你的業(yè)務(wù)可以自己去了解新的技術(shù),去開(kāi)源編寫(xiě)一些場(chǎng)景下的框架或者代碼。
你可以進(jìn)行的思考
1.復(fù)雜的邏輯條件,是否可以調(diào)整順序,讓程序更高效
代碼基本是增刪改查,只有跟對(duì)應(yīng)邏輯集合在一起,才是一個(gè)功能模塊。一般接收到一個(gè)需求,往往就是直接開(kāi)干,if-else一次性寫(xiě)下來(lái),邏輯在哪里出現(xiàn)分支就是一個(gè)if-else,如果分支在很前面,可能對(duì)應(yīng)代碼就是要寫(xiě)二次,然而其中分支變化點(diǎn)可能就是狀態(tài)的不同。這里的基本思路是把重要的分支點(diǎn)盡量提前,把重復(fù)的代碼提取出來(lái)。這是一個(gè)代碼優(yōu)化很重要的點(diǎn),讓你的代碼具備可復(fù)用性,以及別人可以看到你提取出來(lái)是對(duì)一個(gè)邏輯的進(jìn)行處理,提高可讀性。另外是否可以調(diào)整順序,其中某些值的校驗(yàn)無(wú)疑是放到比較靠前的,因?yàn)槿绻r?yàn)不通過(guò),根本無(wú)法走到下面流程。這些判斷都是業(yè)務(wù)支持提供的。
2.你的程序是否創(chuàng)建了不必要的對(duì)象。
每一個(gè)對(duì)象的應(yīng)用都有開(kāi)銷,如何讓你的代碼用到的對(duì)象是都需要用到的。這里有二個(gè)點(diǎn),一個(gè)點(diǎn)是在代碼完成后,代碼優(yōu)化這個(gè)環(huán)節(jié),你刪除沒(méi)有引用到的包或者對(duì)象 這里主要是指 多余的import類,第二個(gè)是把重復(fù)都在用的提取出來(lái),比如支付寶對(duì)接時(shí)候,支付寶基本信息那個(gè)類就是都要使用的,用單例模式,懶漢加載。而不是用到的時(shí)候,重新new一個(gè),這種代碼也是可以優(yōu)化的。
3.查詢數(shù)據(jù)庫(kù)時(shí)候,你是否查詢了表的所有數(shù)據(jù)
查詢sql的編寫(xiě),一般情況都有很經(jīng)典的select * from xx,查詢?nèi)韮?nèi)容,但是這個(gè)是不提倡的,因?yàn)楸頂?shù)據(jù)會(huì)越來(lái)越大,以及一些表的數(shù)據(jù)是盡量不要全帶出來(lái),同樣優(yōu)化時(shí)候,用具體字段代替 select *,最差也是全字段查詢,也就是一個(gè)優(yōu)于等于 select * 的選擇題。
4.加上一行 你覺(jué)得不怎么重要的代碼 ,是否會(huì)影響到主要流程
我項(xiàng)目中遇到過(guò),想查看用戶的所在地,這里有二個(gè)切入點(diǎn),一個(gè)是用戶手機(jī)和用戶ip,都可以大概顯示用戶所在地,這個(gè)是不重要的數(shù)據(jù),就選擇了用戶手機(jī),因?yàn)橛脩羰謾C(jī)唯一確定。我寫(xiě)在用戶新增部分,手機(jī)號(hào)碼查詢歸屬地是調(diào)用第三方接口。測(cè)試時(shí)候,都是正常的。然后線上用戶新增失敗報(bào)錯(cuò)。排查時(shí)候是第三方接口出現(xiàn)波動(dòng),導(dǎo)致報(bào)錯(cuò),然后原本正常的用戶新增失敗,因?yàn)橛脩粜略霾糠质亲骰貪L,但是手機(jī)號(hào)碼查詢歸屬地是寫(xiě)在controller層調(diào)用的,所以出現(xiàn)用戶新增實(shí)際是成功的,但是用戶頁(yè)面出現(xiàn)你注冊(cè)失敗,再一次去注冊(cè)就出現(xiàn)了你號(hào)碼已經(jīng)注冊(cè)。所以這個(gè)影響到主要流程了。該怎么處理,最簡(jiǎn)單,就是調(diào)用第三方接口去捕獲異常處理,這個(gè)不那么重要的信息獲取,即使失敗也不會(huì)影響主要流程,然后是如果有及時(shí)性,那么就另開(kāi)異步線程去處理,即使失敗也不會(huì)影響到當(dāng)前流程。又或者是跑定時(shí),當(dāng)一天結(jié)束后,對(duì)手機(jī)號(hào)碼歸屬地為null的數(shù)據(jù),都調(diào)用第三方接口去查詢手機(jī)號(hào)碼歸屬地,然后回寫(xiě)到數(shù)據(jù)庫(kù)中。
5.對(duì)空指針引起重視
任何判斷都應(yīng)該要知道是否值可能存在為空的情況,所以空指針的判斷是擺在首位的。優(yōu)先是確定不為空的值放在前面,然后再是.equals(傳入的值),這個(gè)要養(yǎng)成習(xí)慣,不然線上如果數(shù)據(jù)哪里出問(wèn)題了,拿某個(gè)對(duì)象里面某個(gè)值進(jìn)行對(duì)比,那個(gè)值碰巧是空,報(bào)錯(cuò)的話,代價(jià)很大,切勿輕易嘗試。
6.你的關(guān)鍵業(yè)務(wù)代碼是否有日志輸出
線上不可能讓你打斷點(diǎn)去排查,所以你的排查極大程度是依賴日志,你的每個(gè)操作數(shù)據(jù)庫(kù)不可能都記錄,那么對(duì)數(shù)據(jù)庫(kù)開(kāi)銷很大,所以一般是依賴日志。對(duì)應(yīng)操作需要打印對(duì)應(yīng)日志,基本的日志 輸出我比較推薦 logger.infoFrom 這個(gè) 一般記錄 調(diào)用接口,操作人,調(diào)用結(jié)果,調(diào)用傳參,對(duì)應(yīng)數(shù)量 等等。另外info跟error的日志輸出級(jí)別也要注意。如果你還對(duì)接了微信,微信有一個(gè)微信報(bào)警,企業(yè)有對(duì)應(yīng)企業(yè)賬號(hào)的話,可以去了解一下。你可以把即為關(guān)鍵的信息報(bào)警。比如用戶下單失敗,用戶簽約失敗,用戶付款異常失敗等等,都可以報(bào)警給你
7.化整為零
你的代碼寫(xiě)成一坨,別人就需要一行一行看下來(lái),而且很多都是重復(fù)的,可能就是狀態(tài)某個(gè)值不一樣,其他都一樣。那樣的代碼重復(fù)太多,可以提取出來(lái),劃分成功能單一的小函數(shù),這個(gè)有一個(gè)說(shuō)法,盡量代碼一個(gè)函數(shù)不要超過(guò)50行,除非真的特別長(zhǎng),50行一拉到底,一氣呵成,方便你對(duì)這個(gè)代碼進(jìn)行了解,也方便別人調(diào)用。如果你代碼是提供給別人對(duì)接,那么更加需要拆分,因?yàn)槿绻枨蟾淖?,別人同樣還是調(diào)用你的代碼,那么就是你自己動(dòng)大手術(shù)還是小手術(shù)的區(qū)別了。寫(xiě)在一起,可能都要更改,但是你做好了拆分,可能你就更換零件就可以了。你懂的。
8.可變因素,是否最好都有一個(gè)字典表去支持
配置這東西,我接觸的項(xiàng)目中,有網(wǎng)頁(yè)的其中涉及客服的二維碼,這里處理方式有既然是頁(yè)面的圖片,那么頁(yè)面寫(xiě)死,可以這樣做。但是客服每天都要更換,那么天天修改頁(yè)面,先客服圖片給你,上傳到oss,然后對(duì)應(yīng)cdn加速,最終的網(wǎng)址你給前端,然后前端修改頁(yè)面,每天都這樣。程序員要做的就是把重復(fù)的動(dòng)作給提取出來(lái),然后做成程序,這樣就是一個(gè)價(jià)值。后面創(chuàng)建字典表,前端去讀取字典二維碼數(shù)據(jù),后端提供給客服上傳二維碼功能,上傳的二維碼網(wǎng)址回寫(xiě)更新字典表的數(shù)據(jù)。那么每天客服自己去修改就可以了,甚至可以短時(shí)間內(nèi)多次修改,都滿足。
9.查詢大表,是否加了索引
查詢數(shù)量表比較大的表時(shí),我們需要確認(rèn)三點(diǎn)A.表是否建了索引 B.查詢sql是否命中索引 C.sql是否還有優(yōu)化的余地
10.你的方法返回一個(gè)空集還是null
mybatis中有返回一個(gè)對(duì)象類 也有一個(gè)對(duì)象list的,其中判空標(biāo)準(zhǔn)不一樣,如果是類,判斷是否等于null,如果是對(duì)象list的,是空集,不為null,需要判斷對(duì)象list.size()==0
11.查詢數(shù)據(jù)庫(kù),如果數(shù)據(jù)返回太多,考慮分批處理
這里用到的是數(shù)據(jù)導(dǎo)出,用戶數(shù)據(jù)導(dǎo)出一個(gè)案例,查詢出來(lái)的數(shù)據(jù)導(dǎo)出成excel表在瀏覽器自動(dòng)下載。本地測(cè)試是沒(méi)問(wèn)題的,因?yàn)楸镜販y(cè)試數(shù)據(jù)庫(kù)的數(shù)據(jù)不多,就是簡(jiǎn)單測(cè)試一下功能,但是放到線上測(cè)試環(huán)境就導(dǎo)不出,打印日志,也基本都是正常的,就是最后一步在瀏覽器自動(dòng)下載沒(méi)有實(shí)現(xiàn),之后是對(duì)應(yīng)用戶表數(shù)據(jù)傳輸?shù)奖镜?,發(fā)現(xiàn)也導(dǎo)出失敗,最后排查是數(shù)據(jù)過(guò)多,那么就考慮分批處理,獲取對(duì)應(yīng)總條數(shù)然后進(jìn)行500條一批,也就是 對(duì)象list.size() / 500 + 1 作為總導(dǎo)出的次數(shù),然后再走原先流程,完成用戶數(shù)據(jù)excel導(dǎo)出。
12.你的接口是否考慮到冪等性,并發(fā)情況呢
冪等性是什么?一次和多次請(qǐng)求某個(gè)資源對(duì)于資源本身應(yīng)該具有同樣的結(jié)果,就是說(shuō),其任意多次執(zhí)行對(duì)資源本身所產(chǎn)生的影響均與一次執(zhí)行的影響相同
比如你點(diǎn)擊下單,不可能連續(xù)點(diǎn)多次提交訂單,就生成多個(gè)訂單吧
這個(gè)極大程度是出現(xiàn)在資金沖突情況,某個(gè)接口可以進(jìn)行資金的增加減少。開(kāi)二個(gè)頁(yè)面,對(duì)同一個(gè)用戶的資金進(jìn)行增加減少,首先是查詢出來(lái),然后做加減。這種處理方法要用到version版本號(hào)來(lái)確定你當(dāng)前操作是否同一條數(shù)據(jù),如果不是,返回重新操作。或者使用update ,對(duì)在sql語(yǔ)句中對(duì)對(duì)應(yīng)數(shù)據(jù)進(jìn)行操作,記得結(jié)果值不能小于0,利用數(shù)據(jù)表自身的修改語(yǔ)句鎖行來(lái)進(jìn)行處理并發(fā)
13.redis的使用
很多數(shù)據(jù)只是本次使用比較頻繁,到下次就不用了,比如token,對(duì)于本次登錄,用戶操作,每個(gè)請(qǐng)求都要校驗(yàn)token,如果每次都取mysql數(shù)據(jù)庫(kù)的token數(shù)據(jù)就消耗資源,所以這里用redis做緩存,將不變的用戶數(shù)據(jù),緩存起來(lái),這樣性能有所提升。
以上原創(chuàng)來(lái)自?https://mp.weixin.qq.com/s/9l1AvpSa9m5QINrVicejxw
同時(shí)加上自己的一些理解跟案例