相比于之前的全手工測試,現(xiàn)在的測試無疑自動化的多,回首看頗有封建社會過渡到資本主義社會之感。已經(jīng)“自動化”了好幾個月了,一直想總結(jié)總結(jié)這種由鳥槍更換成的大炮到底給我們測試帶來多少生產(chǎn)力的提高,它適用什么場景,它對于測試的最終目的有多少幫助,又會帶來多大的影響?
其實說起來聽可笑的,我對于自動化測試起初還是挺抵觸的,總覺得自動化了之后會有一些很“隱藏”的缺陷會被放掉,而且針對小作坊式的軟件生產(chǎn),不需要對每個軟件模塊都進行全方位測試。往往將前后端一集成,發(fā)布一個包,部署給環(huán)境,測試就好了,沒有那么多的要求。可是當(dāng)軟件進入批量和大規(guī)模之后,各個模塊之間的接口通信就變得異常重要,每個環(huán)節(jié)首先必須保證自己是沒有問題的才能集成進環(huán)境,還有軟件開發(fā)都是這樣,先后臺再前端,往往到了項目后期,才集成UI聯(lián)調(diào),此時后端的功能和接口都必須已經(jīng)測試過保證沒有大問題的情況下進行的;再者軟件后臺的程序都屬于項目前期開發(fā),更多的不確定和更多的缺陷等著測試人員去發(fā)掘。在這種情況下手工測試的缺點就暴露出來,一是不能及時提供有效的頁面給予手工測試,二是不停的代碼變更讓手工測試已經(jīng)很難滿足復(fù)用的需要,這時候的自動化就猶顯重要。
啰嗦了一堆,其實就是想說自動化在軟件進入規(guī)模化生產(chǎn)之后測試人員的必經(jīng)之路,可以大大的提升測試效率和節(jié)省測試時間,讓這個軟件過程在最短的時間內(nèi)完成。
前面提到了自動化測試適用的測試過程,現(xiàn)在結(jié)合幾個月測試過程簡單的談?wù)勛詣踊膬?yōu)缺點,共享資源。
自動化適用的用例程度最好的就是參數(shù)值校驗的用例了,對于自動化腳本來說,無論是腳本語言還是高級語言都可以采用一個模板,就是一個套子,每次使用的時候只需要更換傳遞的參數(shù)即可。這種測試,同樣基于最基本的等價類邊界值的用例劃分,測試設(shè)計的基本思想,自動化同樣適用。
其實對于參數(shù)值用例校驗本身,其集成在功能模塊測試之中,每個用例都最原始功能模塊的一部分,軟件的程序就是這樣,我們測試每個功能模塊是否有缺陷也就是靠傳遞參數(shù)查看其返回是否達到期望結(jié)果。PS:不能向拆開汽車或者X光檢查身體那樣…………
自動化測試無法比手工測試發(fā)揮更好的地方就是執(zhí)行用戶級用例的時候,具體到執(zhí)行的時候就是界面測試和用戶場景測試,其實這兩種測試有交集的,都已直接和用戶打交道為主,因為是人,所以自動化即使執(zhí)行通過不代表易用性等等方面達到要求,還是要具體使用情況。
自動化測試適用前期沒有頁面、需要驗證程序功能模塊的情況,不但能夠盡早的發(fā)現(xiàn)問題,而且自動化本身的復(fù)用性也讓后期的回歸測試和冒煙測試變得效率十足。對于測試前端頁面和用戶體驗性測試,不建議使用,因為自動化腳本編寫和調(diào)試本身就很耗時,保證腳本的正確性也需要費些周折,測試腳本執(zhí)行完成后還需要測易用性測試,時間上需要花費的更多。
Oracle服務(wù)端口方面會有很多的問題,下面就將為您介紹在防火墻上開放Oracle服務(wù)端口的方法,希望對您學(xué)習(xí)Oracle服務(wù)端口方面能有所幫助。
要使Oracle客戶端能正常連接到設(shè)置有防火墻的安裝在windows上的Oracle服務(wù)器,單開放一個1521或自定義的監(jiān)聽端口是不夠的。
我們有的時候需要映射端口遠程去訪問Oracle數(shù)據(jù)庫,這里有個防火墻的問題,在unix上沒有問題,但是在win 平臺上卻無法正確訪問,下面的可以解決這個問題,:
近來由于工作需要,在Windows XP平臺上安裝了Oracle9i數(shù)據(jù)庫作為測試之用,一切正常。但當(dāng)客戶機連接服務(wù)器時卻總是超時,我首先想到了防火墻,當(dāng)我打開1521端口時,連接操作仍然失敗。我又懷疑網(wǎng)絡(luò)有問題,用telnet server_ip:1521嘗試,連接被接受,說明1521端口已經(jīng)被打開。
沒有辦法,查詢Oracle資料后才明白,network listener只起一個中介作用,當(dāng)客戶連接它時,它根據(jù)配置尋找到相應(yīng)的數(shù)據(jù)庫實例進程,然后spawned一個新的數(shù)據(jù)庫連接,這個連接端口由network listener傳遞給客戶機,此后客戶機就不再和打交道了,即使listener停止了工作。這個新的連接端口是不可預(yù)知的,因而會被防火墻阻止。
Windows Socket2 規(guī)范有一個新的特性,就是Shared Socket,所謂共享套接字是指一個進程共享另一個進程的套接字(詳見MSDN相關(guān)參考)。如果讓network listener與數(shù)據(jù)庫服務(wù)進程共享套接字,那么連接端口就不會變化。
如何設(shè)置Shared Socket?
在注冊表:HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOME0上新建一個字符串值:USE_SHARED_SOCKET=true。如果安裝了多個目錄,則每個類似的目錄都要設(shè)置:HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOMEx (x目錄編號)
設(shè)置后要求重新啟動實例(只重啟listener發(fā)現(xiàn)沒有效果)
Oracle客戶端連接服務(wù)器,首先去找1521監(jiān)聽端口,服務(wù)器的1521監(jiān)聽端口再向server process進程發(fā)出請求,并返回一個隨機端口,返回給客戶端,客戶端再來連接這個端口。 這樣就給服務(wù)器上的防火墻設(shè)置帶來了麻煩,這個端口是隨機的,如何開放?
windows平臺上的這個問題成了一大難題,很多論壇都有人問,但很少有人能解決。unix平臺不用擔(dān)心,系統(tǒng)自動會解決這個問題. Matalink上提供了三種解決辦法,實際上USE_SHARED_SOCKET是最有效最方便的。但經(jīng)過無數(shù)次實現(xiàn),仍然沒有成功,最后終于發(fā)現(xiàn)是Oracle 8.1.7的bug 需要打補丁,升級到Oracle 8.1.7.1.2
需要在MTS模式下(共享模式) Oracle默認(rèn)是專用模式。
經(jīng)試驗發(fā)現(xiàn),如果不在init文件中設(shè)參數(shù)的話,Oracle仍然會要求一個隨機端口和1521端口來共同通訊,只是這個隨機端口,并不隨客戶端會話和登錄的變化而變化,在沒有重啟服務(wù)器時,是固定的。(試驗發(fā)現(xiàn),在專用模式下,每次連接,oracle服務(wù)器會按+1方式,提供一個非1521的端口。)所以,還需要在init.ora文件的最后加上一條參數(shù):
mts_dispatchers="(address=(protocol=tcp)(host=myoradb)(port=1521))(dispatchers=1)"
設(shè)置后要求重新啟動實例。
“1人100個月完成的項目,不是100個人1個月就可以完成。”
項目管理是讓項目活動中相互競爭的各類制約因素:質(zhì)量、進度、資源、風(fēng)險等取得平衡的藝術(shù),同時也是平衡項目干系人的各種需要、關(guān)注和期望,帶領(lǐng)不同的人朝著相同目標(biāo)邁進的領(lǐng)導(dǎo)藝術(shù)。
成功的項目管理可以簡單理解為:按時、在預(yù)算內(nèi)+滿足產(chǎn)品需求+滿足質(zhì)量需求 地完成項目。
以下是我對項目管理的一點體會記錄。
需求等級
視覺 A:圖片沒有分享功能嗎?
技術(shù) K:圖片有鏈接轉(zhuǎn)發(fā)分享、微博或郵件形式分享等多種分享,全部開發(fā)的話需要推延時間表。
策劃 D:圖片只做預(yù)覽、下載已經(jīng)足夠了,暫時不做分享。
交互 E:如果我們的用戶是基于郵箱用戶,圖片的郵件分享還是建議做。
… …
如果在前期產(chǎn)品需求文檔中沒有明確定義每個需求的優(yōu)先等級,或者說項目成員對需求的優(yōu)先等級沒有明確的意識,可能類似的爭論會時常發(fā)生在項目成員之間,每個人會基于自己對產(chǎn)品目標(biāo)的理解來考慮這個需求是否要做,什么時候做,做到什么程度而產(chǎn)生分歧,因而增加項目推進的阻力。
所以在前期產(chǎn)品需求文檔中,必須明確定義出每個需求的優(yōu)先等級,需求的粒度可細化到每個大功能下的子功能需求,如:圖片分享功能的轉(zhuǎn)發(fā)鏈接分享、郵件形式分享這樣的子功能需求。等級的劃分依賴于前期的用戶需求調(diào)研、產(chǎn)品的預(yù)定目標(biāo)、開發(fā)成本、運營計劃等;
一般的需求等級劃分:
P0 -Must have: 如果缺失,產(chǎn)品不能發(fā)布
P1 -Should have: 如果缺失,產(chǎn)品能發(fā)布,但不能達到預(yù)定目標(biāo)(功能/性能)
P2 -Nice to have: 做了則更好
P3 -Neutral: 對產(chǎn)品沒有明顯的好處,用戶不在意
… …
每個需求的優(yōu)先等級確定之后,產(chǎn)品經(jīng)理根據(jù)產(chǎn)品預(yù)定目標(biāo)、開發(fā)成本、運營計劃等來定義一個等級分界線,高于或等于這個等級分界線的需求在本期開發(fā),部分根據(jù)成本、運營計劃等因素調(diào)整到下期開發(fā),而低于這個等級分界線的需求則只會在下期開發(fā),這樣讓全體項目成員對本期要做的需求達成共識。
“1人100個月完成的項目,不是100個人1個月就可以完成。”
項目管理是讓項目活動中相互競爭的各類制約因素:質(zhì)量、進度、資源、風(fēng)險等取得平衡的藝術(shù),同時也是平衡項目干系人的各種需要、關(guān)注和期望,帶領(lǐng)不同的人朝著相同目標(biāo)邁進的領(lǐng)導(dǎo)藝術(shù)。
成功的項目管理可以簡單理解為:按時、在預(yù)算內(nèi)+滿足產(chǎn)品需求+滿足質(zhì)量需求 地完成項目。
以下是我對項目管理的一點體會記錄。
需求等級
視覺 A:圖片沒有分享功能嗎?
技術(shù) K:圖片有鏈接轉(zhuǎn)發(fā)分享、微博或郵件形式分享等多種分享,全部開發(fā)的話需要推延時間表。
策劃 D:圖片只做預(yù)覽、下載已經(jīng)足夠了,暫時不做分享。
交互 E:如果我們的用戶是基于郵箱用戶,圖片的郵件分享還是建議做。
… …
如果在前期產(chǎn)品需求文檔中沒有明確定義每個需求的優(yōu)先等級,或者說項目成員對需求的優(yōu)先等級沒有明確的意識,可能類似的爭論會時常發(fā)生在項目成員之間,每個人會基于自己對產(chǎn)品目標(biāo)的理解來考慮這個需求是否要做,什么時候做,做到什么程度而產(chǎn)生分歧,因而增加項目推進的阻力。
所以在前期產(chǎn)品需求文檔中,必須明確定義出每個需求的優(yōu)先等級,需求的粒度可細化到每個大功能下的子功能需求,如:圖片分享功能的轉(zhuǎn)發(fā)鏈接分享、郵件形式分享這樣的子功能需求。等級的劃分依賴于前期的用戶需求調(diào)研、產(chǎn)品的預(yù)定目標(biāo)、開發(fā)成本、運營計劃等;
一般的需求等級劃分:
P0 -Must have: 如果缺失,產(chǎn)品不能發(fā)布
P1 -Should have: 如果缺失,產(chǎn)品能發(fā)布,但不能達到預(yù)定目標(biāo)(功能/性能)
P2 -Nice to have: 做了則更好
P3 -Neutral: 對產(chǎn)品沒有明顯的好處,用戶不在意
… …
每個需求的優(yōu)先等級確定之后,產(chǎn)品經(jīng)理根據(jù)產(chǎn)品預(yù)定目標(biāo)、開發(fā)成本、運營計劃等來定義一個等級分界線,高于或等于這個等級分界線的需求在本期開發(fā),部分根據(jù)成本、運營計劃等因素調(diào)整到下期開發(fā),而低于這個等級分界線的需求則只會在下期開發(fā),這樣讓全體項目成員對本期要做的需求達成共識。
“1人100個月完成的項目,不是100個人1個月就可以完成。”
項目管理是讓項目活動中相互競爭的各類制約因素:質(zhì)量、進度、資源、風(fēng)險等取得平衡的藝術(shù),同時也是平衡項目干系人的各種需要、關(guān)注和期望,帶領(lǐng)不同的人朝著相同目標(biāo)邁進的領(lǐng)導(dǎo)藝術(shù)。
成功的項目管理可以簡單理解為:按時、在預(yù)算內(nèi)+滿足產(chǎn)品需求+滿足質(zhì)量需求 地完成項目。
以下是我對項目管理的一點體會記錄。
需求等級
視覺 A:圖片沒有分享功能嗎?
技術(shù) K:圖片有鏈接轉(zhuǎn)發(fā)分享、微博或郵件形式分享等多種分享,全部開發(fā)的話需要推延時間表。
策劃 D:圖片只做預(yù)覽、下載已經(jīng)足夠了,暫時不做分享。
交互 E:如果我們的用戶是基于郵箱用戶,圖片的郵件分享還是建議做。
… …
如果在前期產(chǎn)品需求文檔中沒有明確定義每個需求的優(yōu)先等級,或者說項目成員對需求的優(yōu)先等級沒有明確的意識,可能類似的爭論會時常發(fā)生在項目成員之間,每個人會基于自己對產(chǎn)品目標(biāo)的理解來考慮這個需求是否要做,什么時候做,做到什么程度而產(chǎn)生分歧,因而增加項目推進的阻力。
所以在前期產(chǎn)品需求文檔中,必須明確定義出每個需求的優(yōu)先等級,需求的粒度可細化到每個大功能下的子功能需求,如:圖片分享功能的轉(zhuǎn)發(fā)鏈接分享、郵件形式分享這樣的子功能需求。等級的劃分依賴于前期的用戶需求調(diào)研、產(chǎn)品的預(yù)定目標(biāo)、開發(fā)成本、運營計劃等;
一般的需求等級劃分:
P0 -Must have: 如果缺失,產(chǎn)品不能發(fā)布
P1 -Should have: 如果缺失,產(chǎn)品能發(fā)布,但不能達到預(yù)定目標(biāo)(功能/性能)
P2 -Nice to have: 做了則更好
P3 -Neutral: 對產(chǎn)品沒有明顯的好處,用戶不在意
… …
每個需求的優(yōu)先等級確定之后,產(chǎn)品經(jīng)理根據(jù)產(chǎn)品預(yù)定目標(biāo)、開發(fā)成本、運營計劃等來定義一個等級分界線,高于或等于這個等級分界線的需求在本期開發(fā),部分根據(jù)成本、運營計劃等因素調(diào)整到下期開發(fā),而低于這個等級分界線的需求則只會在下期開發(fā),這樣讓全體項目成員對本期要做的需求達成共識。
通常的做法是通過更多的
單元測試 (Unit
test) 和code review,使得我們在開發(fā)階段發(fā)現(xiàn)更多的問題,從而減少bug數(shù)。的確,開發(fā)人員經(jīng)常單元測試,具有良好的測試和編程習(xí)慣,在每次check-in之前,或每次打baseline之前,項目組都有代碼cross review,同級或跨級評審,自己代碼每日評審能大大保證代碼質(zhì)量,在提交給測試組之前就消除大量的bug。但往往發(fā)現(xiàn)更大多數(shù)的bug是我們通過 Unit test和code review所不能發(fā)現(xiàn)的。為什么?
1、首先是需求的不明確,比如客戶原先對軟件的部署的需求就是和一般軟件一樣,沒啥特定需求,后來項目進行到后期部署階段發(fā)現(xiàn)有更多的部署需求,比如Failover,并行部署,對vista的兼容性等等。這些都帶來的新的問題和代碼修改量。
2、其次是需求理解的偏差,設(shè)計理解的偏差,比如一個員工對保險業(yè)務(wù)不熟悉,去開發(fā)保險業(yè)務(wù)IT系統(tǒng)的時候,往往開發(fā)出來的功能和實際業(yè)務(wù)需求相差很遠。對需求理解的偏差,以及對設(shè)計理解的偏差,也有部分原因是因為溝通,沒有良好的溝通,導(dǎo)致沒有傾聽客戶的訴求和用戶的反饋,和客戶溝通的問題導(dǎo)致需求偏差,軟件沒有對客戶產(chǎn)生價值,這種bug的比例非常高。
3、再次是程序員本身能力的限制,比如代碼前期都認(rèn)真經(jīng)過了單元測試和功能測試,但后期發(fā)現(xiàn)運行效率很低,性能不好,原因在于程序員是用他們不熟悉的語言進行開發(fā),而且對性能設(shè)計沒有經(jīng)驗,開發(fā)中根本沒有性能上的考慮。如何保證一個程序員進入一個項目開發(fā)之前,已經(jīng)掌握了足夠的編程語言知識和技能,已經(jīng)掌握了足夠的業(yè)務(wù)知識?如果這些程序員經(jīng)過技術(shù)和業(yè)務(wù)兩方面的培訓(xùn),可能會避免這方面的問題。
4、最后是沒有一套好的研發(fā)流程,質(zhì)量管理體系,和配套的支持工具。這是最大的一個問題。如何找到一個適合自身公司文化和項目情況的process?
總之,軟件開發(fā)和編程是一項智力活動,從獲得需求、理解需求、程序設(shè)計、程序編碼(數(shù)據(jù)結(jié)構(gòu) + 算法)、單元測試、功能測試、提交的整個過程中,任何一步出現(xiàn)偏差都可能產(chǎn)生bug。
當(dāng)然,測試組的嚴(yán)格測試能保證軟件的質(zhì)量,但問題是如何主動防范bug?
1、程序員的技術(shù)能力和經(jīng)驗很重要,比如:代碼設(shè)計能力,良好的編程習(xí)慣,良好的數(shù)據(jù)結(jié)構(gòu)和算法,編程規(guī)范的遵守,隨時資源的釋放,避免內(nèi)存泄漏,避免導(dǎo)致性能下降的代碼,異常處理,以及對維護、部署、可用性、性能、穩(wěn)定性的全面,良好的文檔和注釋習(xí)慣等等。另外,項目采用新的架構(gòu)、框架或技術(shù)(例如Spring, Castle, WCF),都會因為程序員不熟悉而引入更多的bug和風(fēng)險。
2、程序員的業(yè)務(wù)積累和經(jīng)驗很重要,大大有助于對需求的理解和把握。這非常關(guān)鍵。例如一個程序員做過老版本的銀行清算系統(tǒng),他不僅熟悉清算業(yè)務(wù)流程,而且知道老系統(tǒng)存在的問題,就會主動防止這些問題,準(zhǔn)備高效的實現(xiàn)新系統(tǒng)。
3、測試組的測試活動不僅僅是找出bug,而且要通過測試來規(guī)范項目開發(fā)過程,從而提高軟件產(chǎn)品的質(zhì)量。測試通過了,bug都改完了,項目結(jié)束了?其實測試組可以總結(jié)和分析下bug產(chǎn)生的原因和分布,這個bug list和分布圖交給開發(fā)組長和開發(fā)人員,可以分析發(fā)現(xiàn)開發(fā)人員經(jīng)常哪兒引入bug,從而在以后的開發(fā)活動中避免這些問題,實現(xiàn)項目組的積累。其實可能80%的bug分布在20%的模塊,因此從各個方面分析bug的根源,可以總結(jié)出項目組可以改進的地方。
最后,從根本上來說,作為軟件產(chǎn)品與服務(wù)的提供者,只有真正理解客戶的業(yè)務(wù)、順應(yīng)客戶的需求才能提供令客戶滿意的產(chǎn)品與服務(wù)。應(yīng)當(dāng)以一個用戶角色的眼光去重新審視為用戶提供的技術(shù)解決方案和產(chǎn)品,是否是用戶所真正關(guān)心的,是否真正解決了用戶的問題。對于客戶而言,最有價值的不是你掌握哪些技術(shù),而是你能幫他們解決哪些問題,產(chǎn)生哪些價值。IBM推行OnDemand隨需應(yīng)變的服務(wù), 因為在當(dāng)今市場競爭日趨激烈的今天,“求變” 已經(jīng)是必不可少的生存法則。這個求變的過程,需要軟件公司到技術(shù)人員的蛻變,從靈活多變的業(yè)務(wù),到隨需應(yīng)變的技術(shù),不管客戶的業(yè)務(wù)和管理流程、需求如何變化,技術(shù)都只是業(yè)務(wù)變革的推進動力和實現(xiàn)工具,bug free(無缺陷)的軟件背后其實是對業(yè)務(wù)和需求的深刻理解和行業(yè)積累,先進的技術(shù)實力,完善的質(zhì)量管理體系,和軟件開發(fā)流程。
背景信息:央視:彩票站的驚天秘密,站主利用漏洞中獎2800萬,2011年11月24日...本案例的主人公利用漏洞,知道中獎號碼后在買,5分鐘漏洞造就2800萬神話,數(shù)千次兌獎福彩未察覺。
看到這個新聞,不由得讓從事軟件測試的我們引發(fā)很多思考,從某種意義上來說,我不得不佩服這個站主的思維方式,很顯然的是,整個福彩的軟硬件系統(tǒng)肯定是經(jīng)過相對嚴(yán)格的軟件測試和硬件測試的。那為什么還有出現(xiàn)這么低級的“軟件漏測”呢?到底是軟件測試的意識有問題?軟件測試工程師的責(zé)任心有問題?還是軟件測試需求分析與設(shè)計有問題?(也就是說根本就沒有想到這一點?)還是軟件測試管理層面的問題?但是不管是哪一個方面的問題,這個事件注定會給整個彩票行業(yè)帶來深刻的反省和思考,也會給軟件行業(yè)帶來反省和思考,更會給軟件測試帶來反省和思考。這個聯(lián)想到淘寶將很多賣家“商品價格被改為1元”軟件故障事件來看,不由讓人膽寒。在軟件測試行業(yè)里面來看,相對于其他企業(yè)而言,阿里巴巴集團包括淘寶都是比較重視軟件測試的,從51Testing企業(yè)招聘板塊也經(jīng)常可以看到他們的招聘信息。從這一點來看,中國軟件質(zhì)量、中國軟件測試任重而道遠。
分析這兩個事情,我發(fā)現(xiàn)這里面最根本的問題還是解決軟件測試質(zhì)量根本之道的軟件測試需求分析與軟件測試設(shè)計,一個企業(yè)重視測試還是不重視軟件測試,軟件測試做得好還是不好,第一步也是最重要的一步是解決What to test和How to test。而不是盲目地去做自動化,盲目的測試開發(fā)。對于一個優(yōu)秀的測試工程師而言,首先也是必須要會的就是測試分析與設(shè)計。那么接下來,我們來分析下,怎么樣才能做好軟件測試需求分析與軟件測試設(shè)計。從福彩的這個漏洞來看,是站主利用了這個漏洞,而不是普通的彩民。那為什么會這樣呢?我臆想下,可能當(dāng)初在測試整個系統(tǒng)的時候更多的是從買彩票的彩民的角度來測試,本沒有過多考慮到彩票站站主這樣一類用戶。在做好軟件測試需求分析相關(guān)的方法論上有一種方法叫做“關(guān)聯(lián)圖分析法”這種方法簡單地來說,是從不同的“用戶類”的角度來思考,所謂用戶類用戶類不一定指人,可以把其他應(yīng)用程序或者系統(tǒng)接口所用到的硬件組件也可以看成是附加用戶類成員。有一些受產(chǎn)品影響的人并不一定是產(chǎn)品的直接使用者,而是通過報表或者其他應(yīng)用程序訪問產(chǎn)品的數(shù)據(jù)和服務(wù),比如站長是區(qū)別與彩民之外的另一類用戶類。用戶類可以是執(zhí)行者,也可以是應(yīng)用軟件、系統(tǒng)硬件、目標(biāo)實體、接口實體或者三維空間、時間等等。應(yīng)用軟件:是指用戶通過其他軟件來操作被測特性的軟件。系統(tǒng)硬件:理解范圍可以寬些,系統(tǒng)有硬件和軟件組成,直接影響被測特性運行的硬件都認(rèn)為是系統(tǒng)硬件。目標(biāo)實體:可以理解為影響被測特性的公共模塊或者實體。接口實體:是指和被測特性有關(guān)聯(lián)的外界接口實體。三維空間、時間:可以理解為時間、空間、環(huán)境對被測特性的影響。比如:這個案例里面的福彩系統(tǒng)在開獎一段時間內(nèi)在檢查。更通俗地說,我們測試一個系統(tǒng),要關(guān)注的是全方位的,比如這個系統(tǒng)影響了誰?誰在用這個系統(tǒng)?誰為這個系統(tǒng)提供數(shù)據(jù)?誰來維護系統(tǒng)?這個系統(tǒng)在特殊的時間下是否有特殊的用戶行為等?
當(dāng)然這個案例很容易想到要用這一種方法,其實軟件測試的方法和很多,好比軟件測試武功的武功秘籍,最重要的是掌握的方法要全面,并且要知道每一種方法的優(yōu)點、缺點、適應(yīng)范圍,就好比跆拳道中短距離進攻優(yōu)勢很明顯,泰拳靠的是力量,柔術(shù)一定是貼身的,太極靠的是借力打力的套路。下面一個圖可以幫助大家更清晰地了解軟件測試的技術(shù)體系,其中包括最為重要的方法論體系。當(dāng)然大家也可以關(guān)注我以前的一個文章:http://www.51testing.com/index.php?uid-94273-action-viewspace-itemid-197958
版權(quán)聲明:本文出自 linlinxu 的51Testing軟件測試博客:http://www.51testing.com/?94273
原創(chuàng)作品,轉(zhuǎn)載時請務(wù)必以超鏈接形式標(biāo)明本文原始出處、作者信息和本聲明,否則將追究法律責(zé)任。
自動化測試測試平臺策略 之模塊交互策略
序言:要做一個自動化測試平臺,越強大的平臺,其模塊之間的交互越難,也就是各個模塊之間的接口定義越難,而如何采用一種策略去規(guī)范各個模塊的接口、消息格式和交互方式更是難,這一點,我覺得可以從學(xué)習(xí)網(wǎng)絡(luò)協(xié)議中找到一絲靈感,那些協(xié)議的交互方式以及消息的格式傳遞都是值得學(xué)習(xí)的,以前覺得學(xué)習(xí)協(xié)議純粹是為了了解,現(xiàn)在學(xué)習(xí)真的是想掌握其幾點精華思想,突然能夠想象到:一群人在一起思想的碰撞,不斷的去總結(jié),去發(fā)現(xiàn),去實用,才有了現(xiàn)在的協(xié)議標(biāo)準(zhǔn)。覺得,不一樣的領(lǐng)域都去發(fā)現(xiàn)才能有所感悟。
一、自動化測試平臺中的模塊
1、軟件產(chǎn)品是具有一系列特定功能的組件組成,其系統(tǒng)可以被分為一系列的功能模塊,每個模塊所特有的信息處理過程都被包含在模塊的內(nèi)部,如同一個“黑箱”,這就是“封裝性”,然后模塊與模塊之間按照一定的規(guī)則相連則成了一個復(fù)雜的系統(tǒng)(一個系統(tǒng)也可以作為一個模塊,去組成更復(fù)雜的系統(tǒng))。
2、而在自動化測試平臺的系統(tǒng)開發(fā)中,首先,按照其抽象出來的自動化測試流程和方式劃分一系列的功能模塊,這些功能模塊都能脫離系統(tǒng)獨自使用,有的模塊獨自使用能夠提高一些效率(像CLI測試中的基于腳本的自動化測試框架,GUI測試中的基于工具的自動化測試框架等都是一種模塊,還有一些測試工具),然后在此些模塊的基礎(chǔ)上,我們定義一些交互規(guī)則,將他們以最好的方式進行安排在自動化測試流水線上,然后提供一個統(tǒng)一管理的界面,慢慢的,就構(gòu)建成了一個自動化測試平臺。(關(guān)鍵點:必須在測試功能模塊獨自提高效率的基礎(chǔ)上,能夠在測試流程中加以應(yīng)用,平臺的作用伴隨更多的服務(wù),將他們流水線化)
二、自動化測試平臺平臺構(gòu)建難點
1、如何在測試流程中提煉自動化測試流程,然后抽象出自動化測試流水線。
2、如何能夠統(tǒng)一規(guī)劃整個測試部門的測試資源,這需要一個服務(wù)器去統(tǒng)一存儲和調(diào)度管理。
3、然后,很關(guān)鍵的一步:如何將已有的功能測試模塊結(jié)合起來,即建立一套良好的交互協(xié)議和交互消息格式,使其能夠很好的交互和互補,真正完成自動化測試流水線的運作。
三、自動化測試平臺模塊交互策略分析
以下策略是自己對測試平臺建設(shè)中的一些提煉,不一定完全適合,可以參考
1、策略1:服務(wù)注冊機制
即定義一個框架,其框架提供相應(yīng)的API,所有的模塊利用這個API遵循一定的規(guī)則都可以作為服務(wù)注冊到這個框架中,注冊的同時,也對該服務(wù)的發(fā)送和接收的消息進行了規(guī)定,不同的消息可以調(diào)用其模塊不同的功能,然后,模塊則可以以這個框架為媒介,以傳遞消息的方式互相控制。當(dāng)然,對于數(shù)據(jù)的存儲,需要單獨提供一個空間,可以是服務(wù)器,也可以是內(nèi)存機制。
2、策略2:消息分發(fā)統(tǒng)一機制
即定義一個消息分發(fā)模塊,模塊的交互都會經(jīng)過這個消息分發(fā)模塊,這個消息分發(fā)模塊將消息進行解析,然后傳送到對應(yīng)的模塊。
這里,兩種策略都需要統(tǒng)一規(guī)定好消息的格式。可以參考網(wǎng)絡(luò)協(xié)議中的一些消息格式,例如一個簡單的:
總之,個人上次聽過一句話,如果你在一個行業(yè)領(lǐng)域已經(jīng)停滯不前,那么就將眼光放寬,去另外一個領(lǐng)域去看看,往往這樣,會激發(fā)你無限的靈感。這也許是真理啊,喬布斯不就很愛好藝術(shù)嗎?馬云不就是個金庸迷嗎?當(dāng)然,不是說要去復(fù)制,個人覺得,說的是不要閉門造船吧,而是學(xué)會提煉共性,在思想中升華吧。
程序員如何讓你的變量名更加精確
字體: 小 中 大 | 上一篇 下一篇 | 打印 | 我要投稿 | 推薦標(biāo)簽: 軟件開發(fā) java

關(guān)鍵點
“別人還能把這個名字理解成什么意思?”通過不斷的問自己這個問題來積極檢查每一個命名。
事實上,這種富有創(chuàng)造性的、不斷嘗試“錯誤理解”的方法,能夠有效的發(fā)現(xiàn)歧義的命名,并修正它們。正如本文中的示例,我們將隨時通過“騎驢看唱本 ——邊走邊瞧”的方式來 探討所見到名字的誤解之處,然后選取一個更好的名字。
示例:Filter()
假設(shè)寫了一段代碼來操作數(shù)據(jù)庫結(jié)果的集合:
results= Database.all_objects.filter("year <= 2011")
那么,results包含什么數(shù)據(jù)呢?
所有滿足year<=2011的對象
所有不滿足year<=2011的對象
問題的由來是從filter這個有歧義的詞開始的,它沒有清楚表達它的意思是“選取”還是“剔除”。因此,應(yīng)該避免使用filter,它太容易造 成誤解!
如果這里想要的效果是“選取”,一個更好的名字是select;如果想要的是“剔除”,更好的名字則是exclude。
為布爾值取名
當(dāng)為布爾值變量命名或者函數(shù)返回布爾值的時候,要特別注意真和假所表達出來的真實意思,這里就有一個很危險的例子:
bool read_password= true;
這句代碼意思取決于當(dāng)時怎么閱讀的(沒有其他的意思了),顯然這里有兩種截然不同的理解:
需要讀密碼
密碼已經(jīng)被讀過了
在這個用例下,做好避免用單詞read,可以考慮使用need_password或者user_is_authenticated來代替。
通常情況下,添加單詞is、has、can或者should可以讓布爾值的意思更加清晰易懂。
比如說有個函數(shù)叫SpaceLeft(),乍一看,就會想到這個函數(shù)返回的值是數(shù)字。如果需要明確返回值是布爾值,一個更好的名字是 HasSpaceLeft()。
還有,盡量避免使用反義短句來命名。例如:
改成如下代碼則更容易理解,同時更契合原意:
符合用戶期望
很多名字是帶有誤導(dǎo)性的,因為對于某個名字,用戶自已有一個預(yù)想的定義,但是代碼的意思可能恰恰不是這個意思。如此情況下,最好作出“讓步”并改 變名字,消除 誤導(dǎo)性。
示例:get*()
許多程序員都在使用這樣的編碼規(guī)范:某個方法以get開頭來表達一個“輕量級的訪問器”以返回內(nèi)部成員。違反這個規(guī)范將很容易誤導(dǎo)用戶。 避免下面的例子中java代碼段的做法:
public class StatisticsCollector { public void addSample(double x) { ... } public double getMean() { // Iterate through all samples and return total / num_samples } ...} |
這里,getMean的實現(xiàn)是枚舉過去所有的數(shù)據(jù),并計算其平均值。如果數(shù)據(jù)量很大的時候,這一步的開銷將會是非常大的。但是,一個不了解情況的 程 序員則會很粗心的調(diào)用它并且假設(shè)這是一個很廉價的調(diào)用。
因此,這個方法應(yīng)該改名成類似computeMean()這樣的,看起來這樣就是一個代價高昂的操作了(或者,另一個選擇就是改寫其實現(xiàn),變成一 個名副其實的輕量級操作)。
示例:list::size()
這里講一個C++標(biāo)準(zhǔn)庫里的命名問題。這段代碼導(dǎo)致的結(jié)果是,很難定位和修復(fù)類似導(dǎo)致服務(wù)器龜速運行之類的問題:
void ShrinkList(list<Node>& list, int max_size) { while (list.size()>max_size) { FreeNode(list.back()); list.pop_back(); }} |
這樣的bug的導(dǎo)致是作者沒有意識到list.size()是一個O(n)復(fù)雜度的操作——它挨個計數(shù)鏈表的節(jié)點得出總數(shù)而不是返回已計算 好的總個數(shù),這將導(dǎo)致ShrintList是一個O(n2) 的操作。
從技術(shù)角度講,這段代碼沒有問題,也能通過所有的單元測試。但是當(dāng)調(diào)用ShrintList()并傳入一個包含上億數(shù)量級的list時,它可能將 耗費數(shù)小時的時間。
或許你會認(rèn)為,這個是調(diào)用者的錯誤使用,他/她沒有認(rèn)真仔細的閱讀相關(guān)的文檔!確實是這樣的,但是,事實上,這里的list.size()不是一 個恒準(zhǔn)時(constant-time)操作,這太意外了!其他所有的C++容器類都是恒準(zhǔn)時的size()方法呀。
假如把size()更名成countSize()或者countElements(),類似的錯誤就會大大減少了。C++標(biāo)準(zhǔn)庫的實現(xiàn)者可能想的 是使用一個size()方法去和其他的容器匹配,像vector和map,這樣API的一致性看起來更好。正是由于這樣的做了,導(dǎo)致程序員容易誤 用并認(rèn)為這是一個很快的操作,和其他的容器一樣!幸運的是,最新的C++標(biāo)準(zhǔn)要求size()是O(1)復(fù)雜度。
查看Linux系統(tǒng)的平均負載
1、Linux系統(tǒng)的平均負載的概念
有時候我們會覺得系統(tǒng)響應(yīng)很慢,但是又找不到原因,這時就要查看平均負載了,看它是否有大量的進程在排隊等待。特定時間間隔內(nèi)運行隊列中的平均進程數(shù)可以反映系統(tǒng)的繁忙程度,所以我們通常會在自己的網(wǎng)站或系統(tǒng)變慢時第一時間查系統(tǒng)的負載,即CPU的平均負載。
2、查看平均負載
究竟應(yīng)該如何查看平均負載呢?最簡單的命令是uptime,如下所示:
[root@localhost ~]# uptime 11:31:11 up 11 days, 19:01, 2 users, load average: 0.02, 0.01, 0.00 |
目前的主流服務(wù)器都是雙四核,有相當(dāng)強悍的CPU,做一般的應(yīng)用服務(wù)的話,Linux系統(tǒng)的負載這塊倒不用我們擔(dān)心。
還可以用w命令來查看,順便可以查看一下系統(tǒng)當(dāng)前有哪些用戶,他們占用了哪些終端,如下所示:
[root@localhost ~]# w 11:33:00 up 11 days, 19:03, 2 users, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/1113.57.224.3 09:032:11m 0.04s 0.04s -bash root pts/2113.57.224.3 11:310.00s 0.02s 0.00s w |
另外,還有動態(tài)命令top,這個命令也可以反映系統(tǒng)負載情況。在下面的命令提示中,我們只關(guān)心加粗字體部分。
[root@localhost ~]# top top - 11:37:47 up 11 days, 19:08, 2 users, load average: 0.00, 0.00, 0.00 Tasks: 122 total, 1 running, 121 sleeping, 0 stopped, 0 zombie Cpu(s): 0.1%us, 0.0%sy, 0.0%ni, 99.9%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 4044136k total, 1435504k used, 2608632k free, 274740k buffers Swap: 8193140k total,0k used, 8193140k free, 941884k cached |
上面加粗字體顯示的內(nèi)容是什么意思呢?再通過uptime查看一下。
[root@localhost ~]# uptime 11:39:36 up 11 days, 19:16, 1 user, load average: 0.09, 0.03, 0.01 |
原來它所表示的是過去的1分鐘、5分鐘和15分鐘內(nèi)進程隊列中的平均進程數(shù)量。
那么,如何衡量當(dāng)前系統(tǒng)是否負載過高呢?可以從以下幾點來考慮。
如果每個CPU(可以按CPU核心的數(shù)量計算)當(dāng)前的活動進程數(shù)不大于3,則系統(tǒng)性能良好。
如果每個CPU當(dāng)前的活動進程數(shù)不大于4,表示可以接受。
如果每個CPU當(dāng)前的活動進程數(shù)大于5,則系統(tǒng)性能問題嚴(yán)重。
還可以結(jié)合vmstat命令來判斷我們的系統(tǒng)是否過于繁忙,如果確定很繁忙的話,就要考慮是否更換服務(wù)器或增加CPU的個數(shù)了。總結(jié)如下:
如果r經(jīng)常大于3或4,且id經(jīng)常少于50,則表示CPU的負荷很重。
在上面例子中,我的服務(wù)器是PowerEdge 2850,CPU是雙核雙線程的,則0.09/2=0.045(即負載值/真實CPU個數(shù)),此系統(tǒng)的CPU負載基本可以忽略了。事實上,現(xiàn)在主流服務(wù)器的CPU都很強悍,如果不是應(yīng)用虛擬化等特殊場景,基本上負載都很小。
按照前面的計算公式,我所配置Nagios報警的CPU負載閾值為CPU核心的數(shù)量(即CPU的物理個數(shù)×核數(shù))。還是以我的服務(wù)器PowerEdge 2850為例,其CPU核心的數(shù)量為2×2=4,則設(shè)置報警值為4。這樣設(shè)置是合理的,因為畢竟不是每個應(yīng)用服務(wù)器的CPU都支持多核心,畢竟整個網(wǎng)站中還有些性能比較弱的服務(wù)器是用來做備份的。
昨天有一個比較愛思考的同事和我提起一個問題:為什么匿名內(nèi)部類使用的局部變量和參數(shù)需要final修飾,而外部類的成員變量則不用?對這個問題我一直作為默認(rèn)的語法了,木有仔細想過為什么(在分析完后有點印象在哪本書上看到過,但是就是沒有找到,難道是我的幻覺?呵呵)。雖然沒有想過,但是還是借著之前研究過字節(jié)碼的基礎(chǔ)上,分析了一些,感覺上是找到了一些答案,分享一下;也希望有大牛給指出一些不足的地方。
假如我們有以下的代碼:
interface Printer { public void print(); } class MyApplication { private int field = 10; public void print(final Integer param) { final long local = 100; final long local2 = param.longValue() + 100; Printer printer = new Printer() { @Override public void print() { System.out.println("Local value: " + local); System.out.println("Local2 value: " + local2); System.out.println("Parameter: " + param); System.out.println("Field value: " + field); } }; printer.print(); } } |
這里因為param要在匿名內(nèi)部類的print()方法中使用,因而它要用final修飾;local/local2是局部變量,因而也需要final修飾;而field是外部類MyApplication的字段,因而不需要final修飾。這種設(shè)計是基于什么理由呢?
我想這個問題應(yīng)該從Java是如何實現(xiàn)匿名內(nèi)部類的。其中有兩點:
1、匿名內(nèi)部類可以使用外部類的變量(局部或成員變來那個)。
2、匿名內(nèi)部類中不同的方法可以共享這些變量。
根據(jù)這兩點信息我們就可以分析,可能這些變量會在匿名內(nèi)部類的字段中保存著,并且在構(gòu)造的時候?qū)⑺麄兊闹?引用傳入內(nèi)部類。這樣就可以保證同時實現(xiàn)上述兩點了。
事實上,Java就是這樣設(shè)計的,并且所謂匿名類,其實并不是匿名的,只是編譯器幫我們命名了而已。這點我們可以通過這兩個類編譯出來的字節(jié)碼看出來:
class levin.test.anonymous.MyApplication$1 implements levin.test.anonymous.Printer { final synthetic levin.test.anonymous.MyApplication this$0; private final synthetic long val$local2; private final synthetic java.lang.Integer val$param; MyApplication$1(levin.test.anonymous.MyApplication arg0, long arg1, java.lang.Integer arg2); 0 aload_0 [this] 1 aload_1 [arg0] 2 putfield levin.test.anonymous.MyApplication$1.this$0 : levin.test.anonymous.MyApplication [16] 5 aload_0 [this] 6 lload_2 [arg1] 7 putfield levin.test.anonymous.MyApplication$1.val$local2 : long [18] 10 aload_0 [this] 11 aload 4 [arg2] 13 putfield levin.test.anonymous.MyApplication$1.val$param : java.lang.Integer [20] 16 aload_0 [this] 17 invokespecial java.lang.Object() [22] 20 return Line numbers: [pc: 0, line: 1] [pc: 16, line: 13] Local variable table: [pc: 0, pc: 21] local: this index: 0 type: new levin.test.anonymous.MyApplication(){} public void print(); 0 getstatic java.lang.System.out : java.io.PrintStream [30] 3 ldc <String "Local value: 100"> [36] 5 invokevirtual java.io.PrintStream.println(java.lang.String) : void [38] 8 getstatic java.lang.System.out : java.io.PrintStream [30] 11 new java.lang.StringBuilder [44] 14 dup 15 ldc <String "Local2 value: "> [46] 17 invokespecial java.lang.StringBuilder(java.lang.String) [48] 20 aload_0 [this] 21 getfield levin.test.anonymous.MyApplication$1.val$local2 : long [18] 24 invokevirtual java.lang.StringBuilder.append(long) : java.lang.StringBuilder [50] 27 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [54] 30 invokevirtual java.io.PrintStream.println(java.lang.String) : void [38] 33 getstatic java.lang.System.out : java.io.PrintStream [30] 36 new java.lang.StringBuilder [44] 39 dup 40 ldc <String "Parameter: "> [58] 42 invokespecial java.lang.StringBuilder(java.lang.String) [48] 45 aload_0 [this] 46 getfield levin.test.anonymous.MyApplication$1.val$param : java.lang.Integer [20] 49 invokevirtual java.lang.StringBuilder.append(java.lang.Object) : java.lang.StringBuilder [60] 52 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [54] 55 invokevirtual java.io.PrintStream.println(java.lang.String) : void [38] 58 getstatic java.lang.System.out : java.io.PrintStream [30] 61 new java.lang.StringBuilder [44] 64 dup 65 ldc <String "Field value: "> [63] 67 invokespecial java.lang.StringBuilder(java.lang.String) [48] 70 aload_0 [this] 71 getfield levin.test.anonymous.MyApplication$1.this$0 : levin.test.anonymous.MyApplication [16] 74 invokestatic levin.test.anonymous.MyApplication.access$0(levin.test.anonymous.MyApplication) : int [65] 77 invokevirtual java.lang.StringBuilder.append(int) : java.lang.StringBuilder [71] 80 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [54] 83 invokevirtual java.io.PrintStream.println(java.lang.String) : void [38] 86 return Line numbers: [pc: 0, line: 16] [pc: 8, line: 17] [pc: 33, line: 18] [pc: 58, line: 19] [pc: 86, line: 20] Local variable table: [pc: 0, pc: 87] local: this index: 0 type: new levin.test.anonymous.MyApplication(){} Inner classes: [inner class info: #1 levin/test/anonymous/MyApplication$1, outer class info: #0 inner name: #0, accessflags: 0 default] Enclosing Method: #66 #77 levin/test/anonymous/MyApplication.print(Ljava/lang/Integer;)V } |
這些字段在構(gòu)造函數(shù)中賦值,而構(gòu)造函數(shù)則是在MyApplication.print()方法中調(diào)用。
由此,我們可以得出一個結(jié)論:Java對匿名內(nèi)部類的實現(xiàn)是通過編譯器來支持的,即通過編譯器幫我們產(chǎn)生一個匿名類的類名,將所有在匿名類中用到的局部變量和參數(shù)做為內(nèi)部類的final字段,同是內(nèi)部類還會引用外部類的實例。其實這里少了local的變量,這是因為local是編譯器常量,編譯器對它做了替換的優(yōu)化。
其實Java中很多語法都是通過編譯器來支持的,而在虛擬機/字節(jié)碼上并沒有什么區(qū)別,比如這里的final關(guān)鍵字,其實細心的人會發(fā)現(xiàn)在字節(jié)碼中,param參數(shù)并沒有final修飾,而final本身的很多實現(xiàn)就是由編譯器支持的。類似的還有Java中得泛型和逆變、協(xié)變等。這是題外話。
有了這個基礎(chǔ)后,我們就可以來分析為什么有些要用final修飾,有些卻不用的問題。
首先我們來分析local2變量,在”匿名類”中,它是通過構(gòu)造函數(shù)傳入到”匿名類”字段中的,因為它是基本類型,因而在夠著函數(shù)中賦值時(撇開對函數(shù)參數(shù)傳遞不同虛擬機的不同實現(xiàn)而產(chǎn)生的不同效果),它事實上只是值的拷貝;因而加入我們可以在”匿名類”中得print()方法中對它賦值,那么這個賦值對外部類中得local2變量不會有影響,而程序員在讀代碼中,是從上往下讀的,所以很容易誤認(rèn)為這段代碼賦值會對外部類中得local2變量本身產(chǎn)生影響,何況在源碼中他們的名字都是一樣的,所以我認(rèn)為了避免這種confuse導(dǎo)致的一些問題,Java設(shè)計者才設(shè)計出了這樣的語法。
對引用類型,其實也是一樣的,因為引用的傳遞事實上也只是傳遞引用的數(shù)值(簡單的可以理解成為地址),因而對param,如果可以在”匿名類”中賦值,也不會在外部類的print()后續(xù)方法產(chǎn)生影響。雖然這樣,我們還是可以在內(nèi)部類中改變引用內(nèi)部的值的,如果引用類型不是只讀類型的話;在這里Integer是只讀類型,因而我們沒法這樣做。(如果學(xué)過C++的童鞋可以想想常量指針和指針常量的區(qū)別)。
現(xiàn)在還剩下最后一個問題:為什么引用外部類的字段卻是可以不用final修飾的呢?細心的童鞋可能也已經(jīng)發(fā)現(xiàn)答案了,因為內(nèi)部類保存了外部類的引用,因而內(nèi)部類中對任何字段的修改都回真實的反應(yīng)到外部類實例本身上,所以不需要用final來修飾它。
這個問題基本上就分析到這里了,不知道我有沒有表達清楚了。
加點題外話吧。
首先是,對這里的字節(jié)碼,其實還有一點可以借鑒的地方,就是內(nèi)部類在使用外部類的字段時不是直接取值,而是通過編譯器在外部類中生成的靜態(tài)的access$0()方法來取值,我的理解,這里Java設(shè)計者想盡量避免其他類直接訪問一個類的數(shù)據(jù)成員,同時生成的access$0()方法還可以被其他類所使用,這遵循了面向?qū)ο笤O(shè)計中的兩個重要原則:封裝和復(fù)用。
另外,對這個問題也讓我意識到了即使是語言語法層面上的設(shè)計都是有原因可循的,我們要善于多問一些為什么,理解這些設(shè)計的原因和局限,記得曾聽到過一句話:知道一門技術(shù)的局限,我們才能很好的理解這門技術(shù)可以用來做什么。也只有這樣我們才能不斷的提高自己。在解決了這個問題后,我突然冒出了一句說Java這樣設(shè)計也是合理的。是啊,語法其實就一幫人創(chuàng)建的一種解決某些問題的方案,當(dāng)然有合理和不合理之分,我們其實不用對它視若神圣。
之前有進過某著名高校的研究生群,即使在那里,碼農(nóng)論也是甚囂塵上,其實碼農(nóng)不碼農(nóng)并不是因為程序員這個職位引起的,而是個人引起的,我們要不斷理解代碼內(nèi)部的本質(zhì)才能避免一直做碼農(nóng)的命運那。個人愚見而已,呵呵。
修正一個bug的風(fēng)險到底有多大?或許,你會說,這要看bug是發(fā)生在什么地方,的確,UI層的樣式問題、后臺邏輯調(diào)用層的錯誤、數(shù)據(jù)訪問層的異常、數(shù)據(jù)庫級別函數(shù)或存儲過程的修改……一個bug產(chǎn)生的影響可能微乎其微,當(dāng)然也可能會影響廣泛,甚至影響到程序架構(gòu)!
撇開比較極端的情況,今天想要說的是我們?nèi)粘?a target="_self" style="word-break: break-all; color: #333333; text-decoration: none; line-height: normal !important; ">工作中遭遇頻率最高的一類bug:主要發(fā)生在UI層、數(shù)據(jù)邏輯層的常見bug。對于這種bug,我們又有過多少次因忽略其上下文關(guān)聯(lián),或者沒有添加完整的條件驗證和條件處理,導(dǎo)致程序異常,不得不再次修改的經(jīng)歷呢?
這里并不是要批判我們的“粗心大意”,只是要說明這樣一個事實:作為一名開發(fā)人員,在處理一個bug的時候,很容易因過于關(guān)注bug的細節(jié)而“忽視”與其關(guān)聯(lián)的上下文;或在沒有完全理解原代碼工作完整工作機制的情況下就動手修改bug,導(dǎo)致問題層出不窮……相對前者來說,后者的影響更加的廣泛,所以,一般情況下,團隊Leader都會指派對某功能模塊最為熟悉的人員來處理相關(guān)bug,這其實就是一種最為常見的減少風(fēng)險的方法。
根據(jù)自己在類似問題上多次碰壁經(jīng)驗來看,最為成熟和有效的方法,其實就是從完善我們自己修改bug的流程開始的!為什么這么說呢?打個比方,老婆昨天去醫(yī)院拔牙,后來把醫(yī)生的單據(jù)給我看,發(fā)現(xiàn)醫(yī)生也是在按照成熟的流程進行作業(yè)的,可見一個相對成熟的流程對于我們處理問題是多么地重要!
回到咱們的主題,處理bug時,我們是不是按照一個自己認(rèn)為合理的流程進行的呢?我想每個人可能有屬于自己的流程,這里僅僅是自己的一點兒看法,僅供參考:
(1)打開bug列表,你可能使用的是bug tracker或其他bug跟蹤工具,這個無所謂。查找你負責(zé)的bug項。
(2)逐條地對bug進行處理,我比較傾向于將當(dāng)前處理的bug再拷貝一份到自己的bug list文檔中,我會添加一些個人的備注,例如,bug的原因,目前的進展,是否需要進行再次驗證或與產(chǎn)品經(jīng)理進行討論等等,主要是方便自己對bug進行完整的跟蹤。
(3)仔細閱讀bug標(biāo)題和詳細內(nèi)容明細,一般情況下,帶注釋的截圖是非常直觀的,個人比較喜歡。如果有疑問的話,需要馬上找提交bug的測試人員進行確認(rèn),并注意記錄發(fā)生bug時的關(guān)鍵數(shù)據(jù)。
(4)在自己的開發(fā)機器上重現(xiàn)bug,起初應(yīng)該盡可能地按照測試人員提供的關(guān)鍵步驟進行操作,以便迅速重現(xiàn),如果經(jīng)過簡單分析就可以推斷問題的根源的話,可以常識性地進行一些bug驗證。
(5)開啟調(diào)試功能,重現(xiàn)bug并跟蹤代碼,找出問題的原因,一般情況下,如果是因?qū)ο蟛淮嬖诨蛸x值錯誤導(dǎo)致的異常,我們可以直接修正,如果涉及到數(shù)據(jù)異常的情況,可能我們就需要對產(chǎn)生bug的代碼捎帶其上下文進行一下排查,因為很有可能是因為數(shù)據(jù)提供方或者處理方導(dǎo)致了最終的異常。
(6)確定問題根源,并進行修改后,我們需要進行自我驗證!這一步是非常關(guān)鍵的,以至于大家可能很容易忽視!自己也是常常因為覺得一個bug并不難,于是順手就改了,應(yīng)該不會有啥問題,然后就check in了,后來的情況大家想必也猜到了,bug被測試打了回來,這還沒什么,如果要是需要直接提交給實施或者客戶的程序,那后果可就不堪設(shè)想啦!這里還有一點需要注意,我們不僅要按照原bug關(guān)鍵步驟進行重復(fù)測試,同時還要對相關(guān)的流程進行排查性測試,因為我們的修改很有可能影響到周邊相關(guān)的功能,而當(dāng)我們對此功能模塊不是太熟悉的時候,這種風(fēng)險尤其大,必須要格外留意。
(7)再經(jīng)過上面一步非常重要的自我驗證后,我們就可以提交我們的代碼了,這里同樣有一個很容易被忽略的細節(jié):填寫bug備注。因為這是別人了解你此次提交更改的唯一途徑,如果馬馬虎虎,或者是干脆不寫的話,那么你的修改出現(xiàn)問題,光追查原因就要浪費很多的時間,如果那哥們?nèi)绻呀?jīng)遠走高飛以后,那就更加的棘手了!為別人著想也就是為自己著想。
(8)及時向相關(guān)測試人員提供你此次修改的一些情況,尤其是如果涉及范圍較大,需要進行排查性驗證的時候,一定要向測試人員交待清楚,因為盡管我們做了測試,但依舊有可能有所遺漏。
(9)定期查看bug列表,跟蹤自己負責(zé)的bug,并及時更新自己的bug list文檔。
以上就是自己在處理bug時采取的一般流程,自從自己將這個流程形成文字后,遇到的因bug修改不完全導(dǎo)致的問題明顯減少了,因為這些問題都在自己進行自我測試及排他驗證的時候發(fā)現(xiàn)了,并在提交之前都進行了處理。以前自己因為這樣的情況經(jīng)常發(fā)生,經(jīng)常會感到非常氣餒,也懷疑過自己的能力啥的,后來經(jīng)過一個做測試的哥們提醒才豁然開朗,每個人都會遇到“焦點關(guān)注”的問題,因為過于關(guān)注于技術(shù)細節(jié)而忽視前后邏輯關(guān)聯(lián),這也是造成這個問題的主因。所以說,自己要努力通過完善合理的流程來減少其造成的后果,而不是盲目地進行否認(rèn)~
希望能對你有所幫助~