摘要:最近在維護(hù)一個(gè)三年前的舊代碼,用的是框架。單元測(cè)試和語(yǔ)言并發(fā)控制實(shí)際上是個(gè)蛋疼的問(wèn)題,夸張一點(diǎn)說(shuō),當(dāng)時(shí)的并不能特別輕松地實(shí)現(xiàn)并發(fā),甚至不能實(shí)現(xiàn)并發(fā)。語(yǔ)言的功能之一就是自帶單元測(cè)試。用語(yǔ)言之前,我的習(xí)慣是不寫(xiě)單元測(cè)試。
最近在維護(hù)一個(gè)三年前的舊代碼,用的是laravel框架。
從某些方面來(lái)講,這個(gè)代碼算是比較標(biāo)準(zhǔn)為了實(shí)現(xiàn)“在規(guī)定的時(shí)間內(nèi)完成相關(guān)功能”,同時(shí)“程序員水平不高”、“經(jīng)過(guò)大量?jī)?yōu)化”之后,變地特別爛的。但是其中,程序員的水平和態(tài)度是最主要的,其他相對(duì)于而言都是次要的。
當(dāng)然,我就是那幾個(gè)程序員之一,所以我可以放心大膽地說(shuō)自己的壞話(huà)。
另外本文會(huì)多次提到語(yǔ)言間的對(duì)比,當(dāng)然本文的目的并不在此。
框架之爭(zhēng)無(wú)論是當(dāng)年來(lái)看還是現(xiàn)在來(lái)看,Laravel框架思想還是結(jié)構(gòu),都算得上是“Modern PHP”的典范。
Laravel之于php,就相當(dāng)于springboot之于java。
Laravel針對(duì)http請(qǐng)求引入了中間件,稍微配置一下便可以很方便地使用類(lèi)似servlet的攔截器,功能還遠(yuǎn)比servlet強(qiáng)大。
針對(duì)ORM類(lèi)的需求,自創(chuàng)了eloquent框架,使用的簡(jiǎn)潔性上也算得上是一流。
至于安裝、配置、部署、依賴(lài)等等,laravel也都提供了完全通用的方案,這就很可怕了。
可以這么說(shuō),如果我們完全按照l(shuí)aravel的架構(gòu),完全遵照l(shuí)aravel的文檔,寫(xiě)出來(lái)的代碼即便不會(huì)很優(yōu)雅,但是也絕對(duì)不會(huì)特別坑。
當(dāng)然,laravel缺點(diǎn)也是很明顯的。最重要的一個(gè)缺點(diǎn),性能。
作為PHP框架,laravel的性能無(wú)意識(shí)特別拖后腿的地方。我們這里已經(jīng)沒(méi)有詳細(xì)數(shù)據(jù),但是大概的數(shù)據(jù)我們可以提供一下:一個(gè)最簡(jiǎn)單的路由,里面只有Redis::set這一個(gè)操作,并且沒(méi)有任何中間件或者計(jì)算邏輯,24C64G的機(jī)器,只能支撐到大約300+QPS,即便開(kāi)了opcache等也沒(méi)有質(zhì)的提升。至于php7,第一個(gè)7.0版本是發(fā)布在15年12月,項(xiàng)目上線(xiàn)四個(gè)月后,不要說(shuō)還要等laravel支持PHP7,更不要說(shuō)php7也滿(mǎn)足不了性能需求。
這也就是我們第一版代碼就已經(jīng)是兩種語(yǔ)言異構(gòu)的原因。
PHP部分用于處理正常業(yè)務(wù)請(qǐng)求,Go部分用于處理心跳等其他請(qǐng)求。
技術(shù)和能力在后續(xù)的幾年內(nèi)我們也在反思這個(gè)問(wèn)題。
如果我們當(dāng)初做的是采用tcp協(xié)議進(jìn)行傳輸數(shù)據(jù),服務(wù)端也用Go,那么我們還可以做很多“看上去很酷”的事情,例如:我們可以實(shí)現(xiàn)并到處宣揚(yáng)C10K、C100K,可以到處宣揚(yáng)實(shí)現(xiàn)了十萬(wàn)百萬(wàn)MPS(Message per second),可以將所有的任務(wù)結(jié)果流式傳輸?shù)椒?wù)端,可以做到同步返回結(jié)果,可以讓用戶(hù)體驗(yàn)上更好。
但是如果這樣做的話(huà),無(wú)狀態(tài)、流量、日志存儲(chǔ)等便是要考慮的新問(wèn)題。這可能會(huì)把我們培養(yǎng)成技術(shù)流,但是也可能把我們的項(xiàng)目變成新的“技術(shù)瘤”。
現(xiàn)在回想起當(dāng)年,更重要的問(wèn)題在于,我們確定當(dāng)時(shí)參與者沒(méi)有人敢提出這種方案,更沒(méi)有人能駕馭住這個(gè)方案。
維護(hù)成本維護(hù)成本無(wú)疑是后期最大的成本。
早期我們依賴(lài)supervisord,在最早期我們經(jīng)歷過(guò)supervisord和docker的supervisord沖突的故障,后期我們也經(jīng)歷過(guò)其他項(xiàng)目也依賴(lài)supervisord、因?yàn)榕渲迷驅(qū)е缕渌?xiàng)目被停止的故障。故障么,自己的鍋?zhàn)约罕?,也沒(méi)什么好說(shuō)的。
但是其他的維護(hù)成本是比較多的。
你所能想到的,例如agent的?;?,算是比較常見(jiàn)的問(wèn)題,幾十上百個(gè)agent總會(huì)有一兩個(gè)出問(wèn)題,這個(gè)我們也都習(xí)以為常了,甚至自己做一做自動(dòng)修復(fù)也能解決問(wèn)題。
你所不能想到的,有些人將環(huán)境相關(guān)的任務(wù)也給算到你的頭上。有些人會(huì)因?yàn)椤澳氵@個(gè)系統(tǒng)怎么在這個(gè)環(huán)境出現(xiàn)了這個(gè)問(wèn)題”,查了半天,對(duì)方端口沒(méi)有打開(kāi)。
這點(diǎn)在我們中間件相關(guān)的項(xiàng)目比較常見(jiàn)。通常他們會(huì)上來(lái)就問(wèn)這個(gè)中間件怎么出這種問(wèn)題了,實(shí)際上呢,讓他們把堆棧完整地發(fā)出來(lái)之后,告訴他們“caused by里寫(xiě)明了,unknown host,就是你的XXX域名沒(méi)配嘛”。每天都有四五個(gè)人問(wèn)這種問(wèn)題,也會(huì)給答疑方帶來(lái)很大的壓力。
在我們的其他工作中,也在不斷地探索如何減少教育成本,F(xiàn)AQ、培訓(xùn)似乎收效都不高。
假裝噴人似乎有效,例如“你XX的是不是又開(kāi)遠(yuǎn)程調(diào)試了(此處請(qǐng)腦補(bǔ)意大利炮)”,但是這種操作也不能每天都能做的。
如何降低教育成本、讓開(kāi)發(fā)者自己擁有自己解決問(wèn)題的能力,一直是我們工作的重點(diǎn)。但是目前看起來(lái),我們?cè)谶@方面收效甚微。
需求、功能、BUG和變遷這個(gè)項(xiàng)目我們也算是頂住了很大壓力,沒(méi)有接新的需求,也沒(méi)有再去增加新的功能。
我們當(dāng)時(shí)的理由是“他僅僅是個(gè)任務(wù)的服務(wù)端”,“你只要如此這般寫(xiě)這個(gè)任務(wù)便可以實(shí)現(xiàn)這個(gè)功能了”。
但是后續(xù)系統(tǒng)變遷是我們當(dāng)時(shí)所沒(méi)有考慮的。
后續(xù)我們有了一個(gè)新的任務(wù)管理界面,有了新的統(tǒng)一登錄接口,CMDB的接口也幾經(jīng)變化。
最終這個(gè)系統(tǒng)只剩下API每天任勞任怨地工作著。
按理來(lái)說(shuō)沒(méi)人訪(fǎng)問(wèn)的接口和界面就應(yīng)該直接下掉。可是至少這也是親生的bug,我也心軟,沒(méi)辦法下手。
根據(jù)其他系統(tǒng)的經(jīng)驗(yàn),有時(shí)候我們是不得不添加部分功能的,而這部分功能我們可能會(huì)引入很多問(wèn)題。
舉個(gè)例子,某些人吐槽為什么大公司的代碼如此之爛,一個(gè)項(xiàng)目中httpclient就有四個(gè)版本。
這件事情可以理解,例如早期可能只用了HttpURLConnection進(jìn)行g(shù)et請(qǐng)求,中期為了支撐post請(qǐng)求,支持參數(shù),支持超時(shí),分別對(duì)HTTPClient了封裝,后期因?yàn)橐隞WTs,又封裝了一次。代碼冗余度變高,但是既然“系統(tǒng)跑得很好”,也就“沒(méi)有精簡(jiǎn)的必要”。
可以理解,但是不代表可以接受。
代碼冗余一直是內(nèi)部項(xiàng)目重構(gòu)時(shí)常見(jiàn)的問(wèn)題,通常表現(xiàn)為為了不影響原有代碼的執(zhí)行,把現(xiàn)有的代碼拷貝一份,換個(gè)名稱(chēng),修改一下交給新接口來(lái)調(diào)用。
Java等靜態(tài)語(yǔ)言合并冗余代碼比較簡(jiǎn)單,編譯成功即可保證大部分功能可用。但是php等動(dòng)態(tài)語(yǔ)言我們則不敢這么做。PHP做不到“編譯成功便保證基本沒(méi)問(wèn)題”。
就這個(gè)例子來(lái)看,一方面是開(kāi)發(fā)對(duì)HttpClient的認(rèn)知不足,另一方面則是開(kāi)發(fā)對(duì)代碼的抽象能力不夠,也未留下適當(dāng)?shù)慕涌跐M(mǎn)足未來(lái)的需求,才會(huì)出現(xiàn)“一個(gè)項(xiàng)目中httpclient就有四個(gè)版本”的噩夢(mèng)。
有些內(nèi)部系統(tǒng)也會(huì)和早期的我們一樣,首先為了做出成果,然后才是追求更高層次。
但是這并不是一個(gè)做技術(shù)的人應(yīng)該有的態(tài)度。
優(yōu)秀程序員的價(jià)值,不在于其所掌握的幾招屠龍之術(shù),而是在細(xì)節(jié)中見(jiàn)真著。
如果我們可以一次把事情做對(duì),并且做好,在允許的范圍內(nèi)盡可能追求卓越,為什么不去做呢?
成果是要有的,但是一個(gè)做技術(shù)的人,應(yīng)該有對(duì)職業(yè)的自我尊重、對(duì)自我價(jià)值的追求和對(duì)卓越的理解和渴求。
完美有多遠(yuǎn)?不知道,但是我以后肯定會(huì)多走幾步。
單元測(cè)試和語(yǔ)言并發(fā)控制實(shí)際上是個(gè)蛋疼的問(wèn)題,夸張一點(diǎn)說(shuō),當(dāng)時(shí)的PHP并不能特別輕松地實(shí)現(xiàn)并發(fā),甚至不能實(shí)現(xiàn)并發(fā)。我們目前的服務(wù)端實(shí)際上只是做了任務(wù)轉(zhuǎn)發(fā),采用了一些取巧的方法實(shí)現(xiàn)并發(fā)(curl_multi),但是我們并不能實(shí)現(xiàn)并發(fā)控制等功能。至于說(shuō)多線(xiàn)程(pthreads)和多進(jìn)程(pcntl)的方案,實(shí)測(cè)下來(lái)也并不穩(wěn)定,測(cè)試階段便會(huì)產(chǎn)生coredump。
并且經(jīng)過(guò)多次調(diào)優(yōu),我們也最終解決了curl_multi的性能問(wèn)題,可以達(dá)到成千上萬(wàn)的并發(fā),并且性能還算可以。
現(xiàn)在復(fù)盤(pán)一下,如果用的是Go的話(huà),可以很輕松地用5-6行代碼增加并發(fā)控制。Go語(yǔ)言自身性能不錯(cuò),并發(fā)也很好。
Go語(yǔ)言的功能之一就是自帶單元測(cè)試。這點(diǎn)和maven差不多,但是Go是少數(shù)幾個(gè)語(yǔ)言層提供測(cè)試工具鏈的語(yǔ)言之一。
相比于動(dòng)態(tài)語(yǔ)言,靜態(tài)語(yǔ)言的優(yōu)勢(shì)之一便是安全。
可以稍微夸張點(diǎn)講,靜態(tài)語(yǔ)言一旦編譯成功,除非有RuntimeExcetion,不然基本不會(huì)出問(wèn)題。
而PHP這種動(dòng)態(tài)類(lèi)型的語(yǔ)言,就比較蛋疼了:不僅寫(xiě)的時(shí)候可能會(huì)有問(wèn)題,很多IDE也無(wú)法意識(shí)到你到底是不是寫(xiě)了個(gè)bug,甚至過(guò)幾年回來(lái)閱讀代碼,即便是自己參與過(guò)的項(xiàng)目,讀起來(lái)代碼也很蛋疼。PHP也意識(shí)到了這一點(diǎn),從PHP7引入了類(lèi)型聲明,也能緩解這個(gè)問(wèn)題。
用Go語(yǔ)言之前,我的習(xí)慣是不寫(xiě)單元測(cè)試。用了Go語(yǔ)言之后,我開(kāi)始養(yǎng)成對(duì)所有函數(shù)都寫(xiě)單元測(cè)試的習(xí)慣。
我們本文中提到了很多次Go語(yǔ)言,實(shí)際上語(yǔ)言對(duì)項(xiàng)目的影響并不大,真正起主導(dǎo)作用的,還是人。
規(guī)范運(yùn)維規(guī)范對(duì)本項(xiàng)目的影響并不大,主要是開(kāi)發(fā)規(guī)范。
后續(xù)的工作中,我不止一次·告誡業(yè)務(wù)開(kāi)發(fā),我們目前所有的規(guī)范,無(wú)論是運(yùn)維規(guī)范、數(shù)據(jù)庫(kù)開(kāi)發(fā)規(guī)范,或者任何代碼開(kāi)發(fā)規(guī)范,都是我們一次一次地踩坑鋪出來(lái)的路。
如果當(dāng)初我們有數(shù)據(jù)庫(kù)開(kāi)發(fā)規(guī)范的話(huà),表結(jié)構(gòu)也不會(huì)這么坑。就像laravel框架一樣,我們按照規(guī)范來(lái)寫(xiě),不至于讓代碼上升一側(cè)層次,但是也不至于讓代碼爛出水平。
在此我們強(qiáng)烈對(duì)小公司和開(kāi)發(fā)人員推薦《阿里巴巴Java開(kāi)發(fā)手冊(cè)》,不僅有開(kāi)發(fā)規(guī)范、還有表結(jié)構(gòu)規(guī)范,無(wú)論是對(duì)開(kāi)發(fā)或是對(duì)公司都有好處。
語(yǔ)言對(duì)項(xiàng)目的影響并不大,真正起主導(dǎo)作用的,還是人。
如果人的平均素質(zhì)并不能達(dá)到優(yōu)秀的話(huà),那么完善的流程和規(guī)范將能很大程度上影響一個(gè)項(xiàng)目的質(zhì)量。
總結(jié)教育成本是后期維護(hù)的主要成本之一,我們也一直嘗試賦予開(kāi)發(fā)者自己解決問(wèn)題的能力,雖然很難。
人的素質(zhì)無(wú)疑能直接決定一個(gè)項(xiàng)目的質(zhì)量。
當(dāng)然,對(duì)于普通公司、新人這種平均素質(zhì)達(dá)不到優(yōu)秀的情況,完善的流程和規(guī)范將很大程度上保障一個(gè)項(xiàng)目的質(zhì)量。
靜態(tài)語(yǔ)言、單元測(cè)試等手段是保障項(xiàng)目穩(wěn)健性的重要方式。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/29336.html
摘要:爆款車(chē)?yán)遄拥淖杂少u(mài)相好看色澤鮮艷的車(chē)?yán)遄诱谴汗?jié)期間討喜的送禮熱門(mén)貨之一。智利農(nóng)業(yè)部樂(lè)觀預(yù)計(jì),本次出口季銷(xiāo)售成績(jī)有望實(shí)現(xiàn)的增長(zhǎng),而中國(guó)人的春節(jié)消費(fèi)成了智利果農(nóng)今年最大的期盼。 本博客 貓叔的博客,轉(zhuǎn)載請(qǐng)申明出 前言 本系列主要是貓叔對(duì)互聯(lián)網(wǎng)相關(guān)產(chǎn)品(兼任產(chǎn)品經(jīng)理)路上的視野擴(kuò)展與信息記錄,每日三篇,記錄分享。 爆款車(chē)?yán)遄拥淖杂?賣(mài)相好看、色澤鮮艷的車(chē)?yán)遄诱谴汗?jié)期間討喜的送禮熱門(mén)貨之一...
摘要:作為文科專(zhuān)業(yè)畢業(yè),無(wú)名校背景,無(wú)任何關(guān)系,沒(méi)有接受過(guò)任何專(zhuān)業(yè)培訓(xùn),完全靠自學(xué)和看書(shū)看視頻做了五年前端,在外包公司,創(chuàng)業(yè)公司,級(jí)公司再到新型互聯(lián)網(wǎng)公司都呆過(guò),想結(jié)合自己的經(jīng)歷談?wù)剬?duì)于自學(xué)前端的一些看法學(xué)習(xí)大綱關(guān)于技術(shù)棧學(xué)習(xí),網(wǎng)上總會(huì)有各種討論 作為文科專(zhuān)業(yè)畢業(yè),無(wú)名校背景,無(wú)任何關(guān)系,沒(méi)有接受過(guò)任何專(zhuān)業(yè)培訓(xùn),完全靠自學(xué)和看書(shū)看視頻做了五年前端,在外包公司,創(chuàng)業(yè)公司,BAT級(jí)公司再到新型互...
摘要:我們?cè)谄綍r(shí)的工作中,總是會(huì)遇到老舊的系統(tǒng)以及老舊陳的代碼。弊端就是需要維護(hù)兩套代碼,理解兩套技術(shù)選型。那么問(wèn)題就來(lái)了新的代碼如何和舊的代碼解耦新代碼我們當(dāng)然是用新倉(cāng)庫(kù),新選擇,新打包工具。。。 我們?cè)谄綍r(shí)的工作中,總是會(huì)遇到老舊的系統(tǒng)以及老舊陳的代碼。他們是業(yè)務(wù)長(zhǎng)年累月的積累,以及因?yàn)槭侨?、四年前的技術(shù)選型造成的系統(tǒng)架構(gòu)的不合理以及繁瑣的代碼。維護(hù)這些代碼總是很頭疼,程序員遇到這樣的代...
摘要:我們?cè)谄綍r(shí)的工作中,總是會(huì)遇到老舊的系統(tǒng)以及老舊陳的代碼。弊端就是需要維護(hù)兩套代碼,理解兩套技術(shù)選型。那么問(wèn)題就來(lái)了新的代碼如何和舊的代碼解耦新代碼我們當(dāng)然是用新倉(cāng)庫(kù),新選擇,新打包工具。。。 我們?cè)谄綍r(shí)的工作中,總是會(huì)遇到老舊的系統(tǒng)以及老舊陳的代碼。他們是業(yè)務(wù)長(zhǎng)年累月的積累,以及因?yàn)槭侨?、四年前的技術(shù)選型造成的系統(tǒng)架構(gòu)的不合理以及繁瑣的代碼。維護(hù)這些代碼總是很頭疼,程序員遇到這樣的代...
閱讀 982·2023-04-26 01:34
閱讀 3427·2023-04-25 20:58
閱讀 3599·2021-11-08 13:22
閱讀 2167·2019-08-30 14:17
閱讀 2573·2019-08-29 15:27
閱讀 2736·2019-08-29 12:45
閱讀 3096·2019-08-29 12:26
閱讀 2869·2019-08-28 17:51