電子商務(wù)網(wǎng)站的可持續(xù)發(fā)展
2007年終于過(guò)去了,從焦油坑里爬出來(lái)幸存的人們,互相握手慶幸,喜極而泣,紛紛在博客上寫工作總結(jié)與來(lái)年展望,而我,難得的坐下來(lái),遠(yuǎn)離自己負(fù)責(zé)的網(wǎng)站,想一想來(lái)年的布局。
在國(guó)家大力宣揚(yáng)環(huán)保,可持續(xù)發(fā)展的時(shí)候,從企業(yè),從網(wǎng)站,就我個(gè)人,都要講一個(gè)可持續(xù)發(fā)展,一夜暴富的思想只會(huì)浪費(fèi)精力,沒(méi)有方向,而只有平時(shí)注重積累,厚積薄發(fā),終會(huì)有從量變到質(zhì)變,扭轉(zhuǎn)局面的時(shí)候。
我們發(fā)力在向前奔跑的時(shí)候,也要適時(shí)的停下來(lái),倒掉鞋子里的沙子,讓自己的步伐更輕快。
我所經(jīng)歷過(guò)電子商務(wù)網(wǎng)站都面臨的下面的問(wèn)題,如何讓自己步子慢下來(lái),解決這些問(wèn)題,持續(xù)發(fā)展,是一個(gè)從管理和技術(shù)層面上,都比較有挑戰(zhàn)、讓人興奮的問(wèn)題:
1.膨脹
公司業(yè)務(wù)向好,代碼越加越多,原來(lái)一個(gè)人寫一個(gè)類時(shí),只是完成一兩個(gè)單一的功能,隨著需求的變化,一個(gè)核心類的代碼,不知不覺(jué)膨脹到一兩千行,有的Action代碼,也會(huì)超過(guò)1000行。接手的人,一般不敢動(dòng),也不愿意動(dòng)接手的代碼,也就是說(shuō),他不會(huì)去重構(gòu)以前的代碼,一般就是線性的隨著需求的增加,代碼也不斷的增加,同時(shí)在開(kāi)發(fā)時(shí),總是八股文開(kāi)發(fā),很機(jī)械、迂腐的套用一些重型的、所謂的J2EE設(shè)計(jì)模式,如Factory, DTO, Proxy等等,代碼量和代碼復(fù)雜度最終是線性增加。
則代碼復(fù)雜度和行數(shù)的膨脹,會(huì)是負(fù)面循環(huán),反過(guò)來(lái)影響你面對(duì)需求變化時(shí)態(tài)度。
舉一個(gè)例子,從用戶角度來(lái)講,訂單上增加一個(gè)字段的小需求,應(yīng)當(dāng)是很簡(jiǎn)單的一件事,但是對(duì)開(kāi)發(fā)人員來(lái)說(shuō),增加一個(gè)字段,則要確認(rèn)所有與訂單相關(guān)的頁(yè)面(相關(guān)的界面可能有十幾個(gè))都要修改、重新布局,這個(gè)工作量可不小,而且容易漏改。這不是一個(gè)容易避免的事情,不僅是頁(yè)面,類也要修改。很多人寫的關(guān)聯(lián)查詢,結(jié)果放在DTO類而不是Map,扔到頁(yè)面上的話,則DTO類也要修改。
一般的性能問(wèn)題,總是由開(kāi)發(fā)人員的代碼造成的,而不是由架構(gòu)的Scalability瓶頸所造成的,累積的代碼,就像電器上日積日厚的灰塵一樣危險(xiǎn),隨時(shí)會(huì)短路。以前的僵尸代碼,會(huì)在數(shù)據(jù)量和訪問(wèn)量慢慢增長(zhǎng)到某一個(gè)臨界值的時(shí)候,突然復(fù)活,搞得你灰頭土臉。 如果你只會(huì)批評(píng)開(kāi)發(fā)人員不小心,那種永遠(yuǎn)也解決不了問(wèn)題,讓誰(shuí)寫,都不能保證不會(huì)踩上地雷。領(lǐng)導(dǎo)不出BUG,只是因?yàn)樗麄儾粚懗绦颉?/p>
3. 鐵打的營(yíng)盤,流水的兵
第一個(gè)人下棋,下到中途,離開(kāi)了,第二人接手,接著下,以后可能會(huì)有第三個(gè)人,接手的人,怎么下怎么不順,這時(shí)總想重新下一盤,但沒(méi)有選擇,只能一邊問(wèn)候著前人的老媽,一邊繼續(xù)走。最后,我們?cè)侔堰@盤棋復(fù)盤來(lái)看,做成一個(gè)棋譜,會(huì)有什么的感覺(jué)?
這一般不是兩個(gè)人能力差異的問(wèn)題,是一個(gè)心理的問(wèn)題,每個(gè)人都不愿意看別人的代碼,都覺(jué)得別人的代碼寫的爛,不愿意花點(diǎn)時(shí)間,來(lái)review同事或者前人代碼,他們認(rèn)為這是考古學(xué)家的事情。這樣的結(jié)果,如果不了解別人的代碼,就無(wú)從重構(gòu),在此基礎(chǔ)上增加功能或修改,只能說(shuō)是亂上加亂。
要包容別人的代碼,現(xiàn)在不是找出是誰(shuí)造成的,而是要從自己接手這一刻,開(kāi)始改進(jìn)。
打江山的人,所基于的環(huán)境,是非常惡劣的,是非常不容易的,從無(wú)到有的創(chuàng)建一個(gè)網(wǎng)站的老員工,一個(gè)人做三個(gè)人的活,是非常值得尊敬的,接手別人,再怎么說(shuō),也是站在別人的肩膀上考慮問(wèn)題。其實(shí)讓你先下,讓第二人再接手,他也會(huì)這么有同樣的思維,我們需要的是寬容,寬容與諒解應(yīng)當(dāng)是自上而下的,而不是自下而上,不然就變成,項(xiàng)目經(jīng)理說(shuō):我體諒你們,可領(lǐng)導(dǎo)不體諒我啊。
4.新來(lái)的員工不是考古學(xué)家
新來(lái)的員工抱怨個(gè)不停,確實(shí)是很討厭人,另一方面,從他的角度上來(lái)講,沒(méi)有選擇的權(quán)力,必須在別人代碼的基礎(chǔ)上增加新的功能或修正一些BUG,你不能用你最擅長(zhǎng)的東西,當(dāng)別人的代碼是JSP+Servlet,你就用這個(gè),你必須要遵守這個(gè)規(guī)則,同時(shí)也要遵守別人的開(kāi)發(fā)習(xí)慣。
新員工就像一個(gè)考古者,站在一段象形文字的文物面前,來(lái)想出前人的意圖,確實(shí)非常的艱難。
所以每個(gè)公司的每個(gè)項(xiàng)目組,都應(yīng)當(dāng)向HR部門學(xué)習(xí),制訂一個(gè)良好的新員工入門索引,這個(gè)索引有什么內(nèi)容,每個(gè)人根據(jù)自己的項(xiàng)目,自己來(lái)考慮。這樣的索引目錄可以重用,不用來(lái)一個(gè)要講一遍,占用項(xiàng)目經(jīng)理的時(shí)間。
一般的人,都是被動(dòng)的,8個(gè)小時(shí),怎么過(guò),都是過(guò),平時(shí)不會(huì)去看別人的代碼,只是在自己承擔(dān)一個(gè)任務(wù)時(shí),才會(huì)去看那些相關(guān)的代碼,這樣就會(huì)時(shí)間太緊了,手忙腳亂的,容易出錯(cuò)。所以在平時(shí),就要強(qiáng)制性的review代碼,是必須要的,你不能信賴別人的主動(dòng)性,否則的話就是自食苦果。
5.脆弱的測(cè)試體系
長(zhǎng)期膨脹,得不到改進(jìn)、重構(gòu)的代碼,每有新功能開(kāi)發(fā),測(cè)試的代價(jià)非常、非常的高,因?yàn)榉浅H菀追稿e(cuò)。
很多的公司并沒(méi)有一個(gè)良好的自動(dòng)化回歸測(cè)試體系,所帶來(lái)的人工成本就是非常高,測(cè)試人員所做的工作,就是民工扛水泥包,又臟又累,測(cè)試覆蓋的效率又差。
頻繁ReOpen的BUG,會(huì)牽累process當(dāng)中每個(gè)環(huán)節(jié)的人,配置管理員,測(cè)試人員,開(kāi)發(fā)人員,TeamLeader,也會(huì)影響到考核。帶來(lái)的眾多的參與其中的人,隨著運(yùn)轉(zhuǎn),打標(biāo)簽,提交測(cè)試,打回,修改、再打標(biāo)簽、再提交測(cè)試(此時(shí)所有開(kāi)發(fā)人員的BUG都要改完才能提交),測(cè)試人員重新測(cè)試(原來(lái)已經(jīng)測(cè)試通過(guò)的功能,還要再測(cè)試一遍),重復(fù)N次。
其實(shí)我們自己從開(kāi)發(fā),到測(cè)試部門,都可以不要對(duì)立,坐下面交流,來(lái)去考慮如何改進(jìn)。測(cè)試部門可以指導(dǎo)開(kāi)發(fā)樹(shù)立測(cè)試的意識(shí)、思想、技巧,開(kāi)發(fā)人員必須要承擔(dān)測(cè)試,不僅要寫單元測(cè)試,也要做功能測(cè)試,也要會(huì)自動(dòng)化測(cè)試,這些除了可回歸的單元測(cè)試,很艱難,不容易做,但可以一步步的改進(jìn),其它的比如自動(dòng)化的界面測(cè)試,其實(shí)是很容易的,花個(gè)兩天時(shí)間,把成員關(guān)在會(huì)議室里,搞Win runner界面測(cè)試,編寫可重用的測(cè)試腳本,定制有效的、覆蓋關(guān)鍵路徑的、可重用的數(shù)據(jù)源,還是能收到成效的,這樣當(dāng)需求變化時(shí),那些沒(méi)有變化的功能,其腳本也不變,都可以在短時(shí)間內(nèi)回歸的測(cè)試一遍,而不要把成本直接轉(zhuǎn)嫁到測(cè)試部門。
關(guān)鍵是要不要走出第一步。 不知道為什么領(lǐng)導(dǎo)總是愿意相信冶百病的偏方,相信永動(dòng)機(jī),相信不會(huì)犯錯(cuò),項(xiàng)目不會(huì)延期、百戰(zhàn)百勝的神人。 不要再花錢找一些天橋說(shuō)書、賣大力丸的QA了。其實(shí)沒(méi)有一個(gè)人可以驅(qū)動(dòng)一個(gè)龐大的團(tuán)隊(duì),還是要靠團(tuán)隊(duì)中的核心都行動(dòng)起來(lái)。
5.缺乏從宏觀層面技術(shù)標(biāo)準(zhǔn)的概念統(tǒng)一和定義
隨著業(yè)務(wù)的發(fā)展,有很多的合作型的項(xiàng)目,子系統(tǒng)越來(lái)越多,同時(shí)要外接的系統(tǒng)越來(lái)越多, 做為一個(gè)分銷的平臺(tái),可能要和外接的B2B系統(tǒng)對(duì)接,即要給別人在公網(wǎng)上發(fā)布接口,又要從第三方的系統(tǒng)獲取產(chǎn)品數(shù)據(jù)源,這種系統(tǒng)與系統(tǒng)之間的數(shù)據(jù)交換,缺乏統(tǒng)一的標(biāo)準(zhǔn),各種各樣的技術(shù)都可能有,又有不同的項(xiàng)目組負(fù)責(zé),各自為政,這不是他們的問(wèn)題,他們不是CTO,不是架構(gòu)師。
從全局的基礎(chǔ)上,對(duì)系統(tǒng)的服務(wù)基礎(chǔ)設(shè)施建立一套共同的抽象規(guī)范,從架構(gòu)師的層面,進(jìn)行控制。
主要有:
1.服務(wù)的分類(支付網(wǎng)關(guān)、消息網(wǎng)關(guān)、中央工作流引擎、中心緩存服務(wù)、外部數(shù)據(jù)源對(duì)接服務(wù)、B2B訂單預(yù)訂接口服務(wù)等),以及各類服務(wù)的設(shè)計(jì)原則和建議
2.服務(wù)的技術(shù)標(biāo)準(zhǔn)定義與約束,耦合關(guān)系和原則的設(shè)計(jì)規(guī)范等
3.服務(wù)調(diào)用的接口詳細(xì)定義與約束,如此服務(wù)所支持的并發(fā)數(shù)的限制、超時(shí)調(diào)用的限制等。
4.統(tǒng)一技術(shù)標(biāo)準(zhǔn)和約束(如統(tǒng)一使用spring, ibatis, struts2, jquery等),不濫用,注重有效積累, 減小對(duì)后來(lái)的人增加維護(hù)難度,但確定下來(lái)的技術(shù),新來(lái)的人都要強(qiáng)制先學(xué)習(xí),從心理上接受這些技術(shù),先期消化這些技術(shù)曲線,避免臨陣磨槍,好事變成壞事。
5.被動(dòng)的迎接變化,缺乏主動(dòng)
規(guī)劃是很重要,但總有跟不上變化的時(shí)候,不可能有一勞永逸的架構(gòu)和平臺(tái),初期業(yè)務(wù)和業(yè)務(wù)系統(tǒng)都是不成熟的,你在做一個(gè)系統(tǒng)時(shí),可能只有兩三個(gè)人的團(tuán)隊(duì),所做的也只是一個(gè)初期的業(yè)務(wù),你不可能想到,未來(lái)我的系統(tǒng)可能要與114合做,要與某某網(wǎng)站合做,當(dāng)這個(gè)變化來(lái)時(shí),你才能去做這個(gè)設(shè)計(jì)。
例如你只知道大陸酒店的業(yè)務(wù),當(dāng)你的業(yè)務(wù)要擴(kuò)展到香港、海外的時(shí)候,他們的業(yè)務(wù)規(guī)范與國(guó)內(nèi)的差別非常大,新的業(yè)務(wù)有可能在推翻你前期的設(shè)計(jì)。
你的系統(tǒng)要和某某網(wǎng)站一個(gè)合作業(yè)務(wù),要個(gè)某某銀行合做一個(gè)信用卡聯(lián)名卡業(yè)務(wù),這些合做型的項(xiàng)目,對(duì)方都是強(qiáng)勢(shì)的,你不是規(guī)則的制訂方,你是接受規(guī)則的一方,你在欣喜公司的業(yè)務(wù)蒸蒸日上的同時(shí),恭喜你!你的系統(tǒng)的復(fù)雜度,也在蒸蒸日上。
唯一的辦法,就是要去主動(dòng)的重構(gòu),對(duì)系統(tǒng)和代碼的復(fù)雜度降維,輕裝上陣,在一個(gè)更有利的位置,擁抱變化。當(dāng)然重構(gòu)不是陽(yáng)春白雪,不慎會(huì)帶來(lái)新的不穩(wěn)定因素,只要是對(duì)代碼進(jìn)行變動(dòng),都會(huì)引入風(fēng)險(xiǎn),特別是遺留代碼, 你在擦拭灰塵的時(shí)候,卻不小心把桌上的瓷器給打破了,這時(shí)候主人肯定不會(huì)表?yè)P(yáng)你的勤勞。不管怎么樣,這是你負(fù)責(zé)的項(xiàng)目,你跑不了,主動(dòng)一點(diǎn),總比束手待斃強(qiáng)。
6.人力的焦油坑
人月神話這本書,只是給出版業(yè)帶來(lái)了繁榮,平時(shí)的我們總是一遍又一遍的從一個(gè)焦油坑出來(lái),又掉到另一個(gè)焦油坑里去,可見(jiàn)看書是沒(méi)有用的。
由于難以維護(hù)的系統(tǒng),總是拖累正常配置的人力,使你感覺(jué)到人手總是他媽的緊,連正常的需求開(kāi)發(fā)、BUG修正都滿足不了,那有時(shí)間重構(gòu)。所謂人力惡性循環(huán),就是好不容易一個(gè)熟悉代碼的人,培養(yǎng)起來(lái),他也厭倦了,拍屁股走人了,再招人,就得招兩個(gè)人,因?yàn)橄到y(tǒng)的復(fù)雜度又增加了,需求又增加了。
這樣的結(jié)果很可怕,沒(méi)有時(shí)間來(lái)與時(shí)俱進(jìn),沒(méi)有時(shí)間做提高用戶體驗(yàn)、有價(jià)值的、增強(qiáng)用戶粘性的功能了,沒(méi)有創(chuàng)造性的工作,那些有創(chuàng)造力的人最終會(huì)含狠而去。
增強(qiáng)人力資源的儲(chǔ)備和技術(shù)儲(chǔ)備,是一個(gè)有效的措施,在平時(shí)做,而不是到關(guān)口了才想起,手忙腳亂的。
招聘人,要招self-proactive的人,能夠帶來(lái)變化,能夠解決問(wèn)題,而不是抱怨的人,等著媽媽把飯嚼完送到嘴里的小鳥(niǎo),否則就是效果相反,就造成了,加人,越加越累,因?yàn)槟闼拥?,都不是解決問(wèn)題的人,而且加人的時(shí)機(jī)也不對(duì),平時(shí),都沒(méi)有儲(chǔ)備,關(guān)鍵時(shí)候,才想起要人,太晚了。
考慮一下,隨便招一個(gè)普通的程序員,對(duì)于周圍關(guān)聯(lián)人的影響和所帶來(lái)的成本:
增加一個(gè)測(cè)試人員的工作量(可能他的BUG增多),增加美工的工作量(他不會(huì)寫頁(yè)面,不懂JS,不懂CSS),增加項(xiàng)目經(jīng)理的工作量,增加TeamLeader的工作量(做培訓(xùn)計(jì)劃,講需求,講技術(shù)),增加DBA的工作量(因?yàn)樗欢當(dāng)?shù)據(jù)庫(kù),老寫一些讓服務(wù)器心臟博起的SQL 代碼)。
7. 松散的組織架構(gòu)
一個(gè)網(wǎng)站,大的網(wǎng)站,幾十個(gè)頻道,一般的也有十幾人項(xiàng)目組,他們?cè)诰S護(hù)同一個(gè)網(wǎng)站,彼此之間的聯(lián)系很多,共同點(diǎn)也很多,看起來(lái)應(yīng)當(dāng)統(tǒng)一,都是自己人,也不難統(tǒng)一,但是現(xiàn)實(shí)卻是非常的艱難,卻如此的松散。
任何東西,自下而上,所帶來(lái)的必然是混亂和無(wú)序,考慮一下從組織架構(gòu)上來(lái)改變,建立CTO team,從全局的范圍內(nèi),自上而下的推動(dòng)、控制,加強(qiáng)全局控制力,改變各個(gè)頻道或項(xiàng)目組各自為政的情況。將復(fù)雜的東西控制在上層,而不是程序員中間,任由其蔓延。
改變架構(gòu)師缺位,吃白飯的現(xiàn)狀,公司不是養(yǎng)著架構(gòu)師,學(xué)習(xí)新技術(shù)的,滿口之呼者也,酸腐的人,誰(shuí)都要學(xué)習(xí),但要去一線解決問(wèn)題。
架構(gòu)師要有責(zé)任,要有技術(shù)領(lǐng)導(dǎo)能力,要去Push別人,當(dāng)開(kāi)發(fā)人員在造輪子的時(shí)候,首當(dāng)其首,責(zé)任就是架構(gòu)師,如果開(kāi)發(fā)人員在重復(fù),還要你架構(gòu)師做什么?很多開(kāi)發(fā)人員自己寫,是因?yàn)闆](méi)有辦法,他也不想寫,但是現(xiàn)有的代碼庫(kù)當(dāng)中,沒(méi)有,或者沒(méi)有他適合用的東東。