1.摘要
這是爛代碼系列的第二篇,在文章中我會跟大家討論一下如何盡可能高效和客觀的評價代碼的優(yōu)劣错忱。
在發(fā)布了關(guān)于爛代碼的那些事(上)之后,發(fā)現(xiàn)這篇文章竟然意外的很受歡迎,很多人也描(tu)述(cao)了各自代碼中這樣或者那樣的問題楼咳。
最近部門在組織bootcamp,正好我負(fù)責(zé)培訓(xùn)代碼質(zhì)量部分烛恤,在培訓(xùn)課程中讓大家花了不少時間去討論母怜、改進(jìn)、完善自己的代碼缚柏。雖然剛畢業(yè)的同學(xué)對于代碼質(zhì)量都很用心糙申,但最終呈現(xiàn)出來的質(zhì)量仍然沒能達(dá)到“十分優(yōu)秀”的程度。 究其原因船惨,主要是不了解好的代碼“應(yīng)該”是什么樣的柜裸。
2.什么是好代碼
寫代碼的第一步是理解什么是好代碼。在準(zhǔn)備bootcamp的課程的時候粱锐,我就為這個問題犯了難疙挺,我嘗試著用一些精確的定義區(qū)分出“優(yōu)等品”、“良品”怜浅、“不良品”铐然;但是在總結(jié)的過程中,關(guān)于“什么是好代碼”的描述卻大多沒有可操作性
2.1.好代碼的定義
隨便從網(wǎng)上搜索了一下“優(yōu)雅的代碼”恶座,找到了下面這樣的定義:
Bjarne Stroustrup搀暑,C++之父:
邏輯應(yīng)該是清晰的,bug難以隱藏跨琳;
依賴最少自点,易于維護(hù);
錯誤處理完全根據(jù)一個明確的策略脉让;
性能接近最佳化桂敛,避免代碼混亂和無原則的優(yōu)化;
整潔的代碼只做一件事溅潜。
Grady Booch术唬,《面向?qū)ο蠓治雠c設(shè)計》作者:
整潔的代碼是簡單、直接的滚澜;
整潔的代碼粗仓,讀起來像是一篇寫得很好的散文;
整潔的代碼永遠(yuǎn)不會掩蓋設(shè)計者的意圖,而是具有少量的抽象和清晰的控制行借浊。
Michael Feathers眶掌,《修改代碼的藝術(shù)》作者:
整潔的代碼看起來總是像很在乎代碼質(zhì)量的人寫的;
沒有明顯的需要改善的地方巴碗;
代碼的作者似乎考慮到了所有的事情朴爬。
看起來似乎說的都很有道理,可是實(shí)際評判的時候卻難以參考橡淆,尤其是對于新人來說召噩,如何理解“簡單的、直接的代碼”或者“沒有明顯的需要改善的地方”逸爵?
而實(shí)踐過程中具滴,很多同學(xué)也確實(shí)面對這種問題:對自己的代碼總是處在一種心里不踏實(shí)的狀態(tài),或者是自己覺得很好了师倔,但是卻被其他人認(rèn)為很爛构韵,甚至有幾次我和新同學(xué)因?yàn)榇a質(zhì)量的標(biāo)準(zhǔn)一連討論好幾天,卻誰也說服不了誰:我們都堅持自己對于好代碼的標(biāo)準(zhǔn)才是正確的趋艘。
在經(jīng)歷了無數(shù)次code review之后疲恢,我覺得這張圖似乎總結(jié)的更好一些:
代碼質(zhì)量的評價標(biāo)準(zhǔn)某種意義上有點(diǎn)類似于文學(xué)作品,比如對小說的質(zhì)量的評價主要來自于它的讀者瓷胧,由個體主觀評價形成一個相對客觀的評價显拳。并不是依靠字?jǐn)?shù),或者作者使用了哪些修辭手法之類的看似完全客觀但實(shí)際沒有什么意義的評價手段搓萧。
但代碼和小說還有些不一樣杂数,它實(shí)際存在兩個讀者:計算機(jī)和程序員。就像上篇文章里說的瘸洛,即使所有程序員都看不懂這段代碼揍移,它也是可以被計算機(jī)理解并運(yùn)行的。
所以對于代碼質(zhì)量的定義我需要于從兩個維度分析:主觀的反肋,被人類理解的部分那伐;還有客觀的,在計算機(jī)里運(yùn)行的狀況囚玫。
既然存在主觀部分喧锦,那么就會存在個體差異读规,對于同一段代碼評價會因?yàn)榭创a的人的水平不同而得出不一樣的結(jié)論抓督,這也是大多數(shù)新人面對的問題:他們沒有一個可以執(zhí)行的評價標(biāo)準(zhǔn),所以寫出來的代碼質(zhì)量也很難提高束亏。
有些介紹代碼質(zhì)量的文章講述的都是傾向或者原則铃在,雖然說的很對,但是實(shí)際指導(dǎo)作用不大。所以在這篇文章里我希望盡可能把評價代碼的標(biāo)準(zhǔn)用(我自認(rèn)為)與實(shí)際水平無關(guān)的評價方式表示出來定铜。
2.2.可讀的代碼
在權(quán)衡很久之后阳液,我決定把可讀性的優(yōu)先級排在前面:一個程序員更希望接手一個有bug但是看的懂的工程,還是一個沒bug但是看不懂的工程揣炕?如果是后者帘皿,可以直接關(guān)掉這個網(wǎng)頁,去做些對你來說更有意義的事情畸陡。
2.2.1.逐字翻譯
在很多跟代碼質(zhì)量有關(guān)的書里都強(qiáng)調(diào)了一個觀點(diǎn):程序首先是給人看的鹰溜,其次才是能被機(jī)器執(zhí)行,我也比較認(rèn)同這個觀點(diǎn)丁恭。在評價一段代碼能不能讓人看懂的時候曹动,我習(xí)慣讓作者把這段代碼逐字翻譯成中文,試著組成句子牲览,之后把中文句子讀給另一個人沒有看過這段代碼的人聽墓陈,如果另一個人能聽懂,那么這段代碼的可讀性基本就合格了第献。
用這種判斷方式的原因很簡單:其他人在理解一段代碼的時候就是這么做的贡必。閱讀代碼的人會一個詞一個詞的閱讀,推斷這句話的意思庸毫,如果僅靠句子無法理解赊级,那么就需要聯(lián)系上下文理解這句代碼,如果簡單的聯(lián)系上下文也理解不了岔绸,可能還要掌握更多其它部分的細(xì)節(jié)來幫助推斷理逊。大部分情況下,理解一句代碼在做什么需要聯(lián)系的上下文越多盒揉,意味著代碼的質(zhì)量越差晋被。
逐字翻譯的好處是能讓作者能輕易的發(fā)現(xiàn)那些只有自己知道的、沒有體現(xiàn)在代碼里的假設(shè)和可讀性陷阱刚盈。無法從字面意義上翻譯出原本意思的代碼大多都是爛代碼羡洛,比如“ms代表messageService“,或者“ms.proc()是發(fā)消息“藕漱,或者“tmp代表當(dāng)前的文件”欲侮。
2.2.2.遵循約定
約定包括代碼和文檔如何組織,注釋如何編寫肋联,編碼風(fēng)格的約定等等威蕉,這對于代碼未來的維護(hù)很重要。對于遵循何種約定沒有一個強(qiáng)制的標(biāo)準(zhǔn)橄仍,不過我更傾向于遵守更多人的約定韧涨。
與開源項(xiàng)目保持風(fēng)格一致一般來說比較靠譜牍戚,其次也可以遵守公司內(nèi)部的編碼風(fēng)格。但是如果公司內(nèi)部的編碼風(fēng)格和當(dāng)前開源項(xiàng)目的風(fēng)格沖突比較嚴(yán)重虑粥,往往代表著這個公司的技術(shù)傾向于封閉如孝,或者已經(jīng)有些跟不上節(jié)奏了。
但是無論如何娩贷,遵守一個約定總比自己創(chuàng)造出一些規(guī)則要好很多第晰,這降低了理解、溝通和維護(hù)的成本彬祖。如果一個項(xiàng)目自己創(chuàng)造出了一些奇怪的規(guī)則但荤,可能意味著作者看過的代碼不夠多。
一個工程是否遵循了約定往往需要代碼閱讀者有一定經(jīng)驗(yàn)涧至,或者需要借助checkstyle這樣的靜態(tài)檢查工具腹躁。如果感覺無處下手,那么大部分情況下跟著google做應(yīng)該不會有什么大問題:可以參考google code style南蓬,其中一部分有對應(yīng)的中文版纺非。
另外,沒有必要糾結(jié)于遵循了約定到底有什么收益赘方,就好像走路是靠左好還是靠右好一樣烧颖,即使得出了結(jié)論也沒有什么意義,大部分約定只要遵守就可以了窄陡。
2.2.3.文檔和注釋
文檔和注釋是程序很重要的部分炕淮,他們是理解一個工程或項(xiàng)目的途徑之一。兩者在某些場景下定位會有些重合或者交叉(比如javadoc實(shí)際可以算是文檔)跳夭。
對于文檔的標(biāo)準(zhǔn)很簡單涂圆,能找到、能讀懂就可以了币叹,一般來說我比較關(guān)心這幾類文檔:
對于項(xiàng)目的介紹润歉,包括項(xiàng)目功能、作者颈抚、目錄結(jié)構(gòu)等踩衩,讀者應(yīng)該能3分鐘內(nèi)大致理解這個工程是做什么的。
針對新人的QuickStart贩汉,讀者按照文檔說明應(yīng)該能在1小時內(nèi)完成代碼構(gòu)建和簡單使用驱富。
針對使用者的詳細(xì)說明文檔,比如接口定義匹舞、參數(shù)含義褐鸥、設(shè)計等,讀者能通過文檔了解這些功能(或接口)的使用方法策菜。
有一部分注釋實(shí)際是文檔晶疼,比如之前提到的javadoc酒贬。這樣能把源碼和注釋放在一起又憨,對于讀者更清晰翠霍,也能簡化不少文檔的維護(hù)的工作。
還有一類注釋并不作為文檔的一部分蠢莺,比如函數(shù)內(nèi)部的注釋寒匙,這類注釋的職責(zé)是說明一些代碼本身無法表達(dá)的作者在編碼時的思考,比如“為什么這里沒有做XXX”躏将,或者“這里要注意XXX問題”锄弱。
一般來說我首先會關(guān)心注釋的數(shù)量:函數(shù)內(nèi)部注釋的數(shù)量應(yīng)該不會有很多,也不會完全沒有祸憋,個人的經(jīng)驗(yàn)值是滾動幾屏幕看到一兩處左右比較正常会宪。過多的話可能意味著代碼本身的可讀性有問題,而如果一點(diǎn)都沒有可能意味著有些隱藏的邏輯沒有說明蚯窥,需要考慮適當(dāng)?shù)脑黾右稽c(diǎn)注釋了掸鹅。
其次也需要考慮注釋的質(zhì)量:在代碼可讀性合格的基礎(chǔ)上,注釋應(yīng)該提供比代碼更多的信息拦赠。文檔和注釋并不是越多越好巍沙,它們可能會導(dǎo)致維護(hù)成本增加。關(guān)于這部分的討論可以參考簡潔部分的內(nèi)容荷鼠。
2.2.4.推薦閱讀
《代碼整潔之道》
2.3.可發(fā)布的代碼
新人的代碼有一個比較典型的特征句携,由于缺少維護(hù)項(xiàng)目的經(jīng)驗(yàn),寫的代碼總會有很多考慮不到的地方允乐。比如說測試的時候似乎沒什么異常矮嫉,項(xiàng)目發(fā)布之后才發(fā)現(xiàn)有很多意料之外的狀況;而出了問題之后不知道從哪下手排查牍疏,或者僅能讓系統(tǒng)處于一個并不穩(wěn)定的狀態(tài)敞临,依靠一些巧合勉強(qiáng)運(yùn)行。
2.3.1.處理異常
新手程序員普遍沒有處理異常的意識麸澜,但代碼的實(shí)際運(yùn)行環(huán)境中充滿了異常:服務(wù)器會死機(jī)挺尿,網(wǎng)絡(luò)會超時,用戶會胡亂操作炊邦,不懷好意的人會惡意攻擊你的系統(tǒng)编矾。
我對一段代碼異常處理能力的第一印象來自于單元測試的覆蓋率。大部分異常難以在開發(fā)或者測試環(huán)境里復(fù)現(xiàn)馁害,即使有專業(yè)的測試團(tuán)隊也很難在集成測試環(huán)境中模擬所有的異常情況窄俏。
而單元測試可以比較簡單的模擬各種異常情況,如果一個模塊的單元測試覆蓋率連50%都不到碘菜,很難想象這些代碼考慮了異常情況下的處理凹蜈,即使考慮了限寞,這些異常處理的分支都沒有被驗(yàn)證過,怎么指望實(shí)際運(yùn)行環(huán)境中出現(xiàn)問題時表現(xiàn)良好呢仰坦?
2.3.2.處理并發(fā)
我收到的很多簡歷里都寫著:精通并發(fā)編程/熟悉多線程機(jī)制履植,諸如此類,跟他們聊的時候也說的頭頭是道悄晃,什么鎖啊互斥啊線程池啊同步啊信號量啊一堆一堆的名詞滔滔不絕玫霎。而給應(yīng)聘者一個實(shí)際場景,讓應(yīng)聘者寫一段很簡單的并發(fā)編程的小程序妈橄,能寫好的卻不多庶近。
實(shí)際上并發(fā)編程也確實(shí)很難,如果說寫好同步代碼的難度為5眷蚓,那么并發(fā)編程的難度可以達(dá)到100鼻种。這并不是危言聳聽,很多看似穩(wěn)定的程序沙热,在面對并發(fā)場景的時候仍然可能出現(xiàn)問題:比如最近我們就碰到了一個linux kernel在調(diào)用某個系統(tǒng)函數(shù)時由于同步問題而出現(xiàn)crash的情況叉钥。
而是否高質(zhì)量的實(shí)現(xiàn)并發(fā)編程的關(guān)鍵并不是是否應(yīng)用了某種同步策略,而是看代碼中是否保護(hù)了共享資源:
局部變量之外的內(nèi)存訪問都有并發(fā)風(fēng)險(比如訪問對象的屬性校读,訪問靜態(tài)變量等)
訪問共享資源也會有并發(fā)風(fēng)險(比如緩存沼侣、數(shù)據(jù)庫等)。
被調(diào)用方如果不是聲明為線程安全的歉秫,那么很有可能存在并發(fā)問題(比如java的hashmap)蛾洛。
所有依賴時序的操作,即使每一步操作都是線程安全的雁芙,還是存在并發(fā)問題(比如先刪除一條記錄轧膘,然后把記錄數(shù)減一)。
前三種情況能夠比較簡單的通過代碼本身分辨出來兔甘,只要簡單培養(yǎng)一下自己對于共享資源調(diào)用的敏感度就可以了谎碍。
但是對于最后一種情況,往往很難簡單的通過看代碼的方式看出來洞焙,甚至出現(xiàn)并發(fā)問題的兩處調(diào)用并不是在同一個程序里(比如兩個系統(tǒng)同時讀寫一個數(shù)據(jù)庫蟆淀,或者并發(fā)的調(diào)用了一個程序的不同模塊等)。但是澡匪,只要是代碼里出現(xiàn)了不加鎖的熔任,訪問共享資源的“先做A,再做B”之類的邏輯唁情,可能就需要提高警惕了疑苔。
2.3.3.優(yōu)化性能
性能是評價程序員能力的一個重要指標(biāo),很多程序員也對程序的性能津津樂道甸鸟。但程序的性能很難直接通過代碼看出來惦费,往往要借助于一些性能測試工具兵迅,或者在實(shí)際環(huán)境中執(zhí)行才能有結(jié)果。
如果僅從代碼的角度考慮薪贫,有兩個評價執(zhí)行效率的辦法:
算法的時間復(fù)雜度恍箭,時間復(fù)雜度高的程序運(yùn)行效率必然會低。
單步操作耗時后雷,單步耗時高的操作盡量少做季惯,比如訪問數(shù)據(jù)庫吠各,訪問io等臀突。
而實(shí)際工作中,也會見到一些程序員過于熱衷優(yōu)化效率贾漏,相對的會帶來程序易讀性的降低候学、復(fù)雜度提高、或者增加工期等等纵散。對于這類情況梳码,簡單的辦法是讓作者說出這段程序的瓶頸在哪里,為什么會有這個瓶頸伍掀,以及優(yōu)化帶來的收益掰茶。
當(dāng)然,無論是優(yōu)化不足還是優(yōu)化過度蜜笤,判斷性能指標(biāo)最好的辦法是用數(shù)據(jù)說話濒蒋,而不是單純看代碼焕襟,性能測試這部分內(nèi)容有些超出這篇文章的范圍组力,就不詳細(xì)展開了氯窍。
2.3.4.日志
日志代表了程序在出現(xiàn)問題時排查的難易程度激率,經(jīng)(jing)驗(yàn)(chang)豐(cai)富(keng)的程序員大概都會遇到過這個場景:排查問題時就少一句日志居触,查不到某個變量的值不知道是什么读跷,導(dǎo)致死活分析不出來問題到底出在哪革答。
對于日志的評價標(biāo)準(zhǔn)有三個:
日志是否足夠榄融,所有異常缕贡、外部調(diào)用都需要有日志翁授,而一條調(diào)用鏈路上的入口、出口和路徑關(guān)鍵點(diǎn)上也需要有日志晾咪。
日志的表達(dá)是否清晰收擦,包括是否能讀懂,風(fēng)格是否統(tǒng)一等禀酱。這個的評價標(biāo)準(zhǔn)跟代碼的可讀性一樣炬守,不重復(fù)了。
日志是否包含了足夠的信息剂跟,這里包括了調(diào)用的上下文减途、外部的返回值酣藻,用于查詢的關(guān)鍵字等,便于分析信息鳍置。
對于線上系統(tǒng)來說辽剧,一般可以通過調(diào)整日志級別來控制日志的數(shù)量,所以打印日志的代碼只要不對閱讀造成障礙税产,基本上都是可以接受的怕轿。
2.3.5.擴(kuò)展閱讀
《Release It!: Design and Deploy Production-Ready Software》(不要看中文版,翻譯的實(shí)在是太爛了)
Numbers Everyone Should Know
2.4.可維護(hù)的代碼
相對于前兩類代碼來說辟拷,可維護(hù)的代碼評價標(biāo)準(zhǔn)更模糊一些撞羽,因?yàn)樗獙?yīng)的是未來的情況,一般新人很難想象現(xiàn)在的一些做法會對未來造成什么影響衫冻。不過根據(jù)我的經(jīng)驗(yàn)诀紊,一般來說,只要反復(fù)的提問兩個問題就可以了:
他離職了怎么辦隅俘?
他沒這么做怎么辦邻奠?
2.4.1.避免重復(fù)
幾乎所有程序員都知道要避免拷代碼,但是拷代碼這個現(xiàn)象還是不可避免的成為了程序可維護(hù)性的殺手为居。
代碼重復(fù)分為兩種:模塊內(nèi)重復(fù)和模塊間重復(fù)碌宴。無論何種重復(fù),都在一定程度上說明了程序員的水平有問題蒙畴,模塊內(nèi)重復(fù)的問題更大一些贰镣,如果在同一個文件里都能出現(xiàn)大片重復(fù)的代碼,那表示他什么不可思議的代碼都有可能寫出來忍抽。
對于重復(fù)的判斷并不需要反復(fù)閱讀代碼八孝,一般來說現(xiàn)代的IDE都提供了檢查重復(fù)代碼的工具,只需點(diǎn)幾下鼠標(biāo)就可以了鸠项。
除了代碼重復(fù)之外干跛,很多熱衷于維護(hù)代碼質(zhì)量的程序員新人很容易出現(xiàn)另一類重復(fù):信息重復(fù)。
我見過一些新人喜歡在每行代碼前面寫一句注釋祟绊,比如:
// 成員列表的長度>0并且<200
if(memberList.size() > 0 && memberList.size() < 200) {
// 返回當(dāng)前成員列表
return memberList;
}
看起來似乎很好懂楼入,但是幾年之后,這段代碼就變成了:
// 成員列表的長度>0并且<200
if(memberList.size() > 0 && memberList.size() < 200 || (tmp.isOpen() && flag)) {
// 返回當(dāng)前成員列表
return memberList;
}
再之后可能會改成這樣:
// edit by axb 2015.07.30
// 成員列表的長度>0并且<200
//if(memberList.size() > 0 && memberList.size() < 200 || (tmp.isOpen() && flag)) {
// ? ? 返回當(dāng)前成員列表
// ? ?return memberList;
//}
if(tmp.isOpen() && flag) {
return memberList;
}
隨著項(xiàng)目的演進(jìn)牧抽,無用的信息會越積越多嘉熊,最終甚至讓人無法分辨哪些信息是有效的,哪些是無效的扬舒。
如果在項(xiàng)目中發(fā)現(xiàn)好幾個東西都在做同一件事情阐肤,比如通過注釋描述代碼在做什么,或者依靠注釋替代版本管理的功能,那么這些代碼也不能稱為好代碼孕惜。
2.4.2.模塊劃分
模塊內(nèi)高內(nèi)聚與模塊間低耦合是大部分設(shè)計遵循的標(biāo)準(zhǔn)愧薛,通過合理的模塊劃分能夠把復(fù)雜的功能拆分為更易于維護(hù)的更小的功能點(diǎn)。
一般來說可以從代碼長度上初步評價一個模塊劃分的是否合理衫画,一個類的長度大于2000行毫炉,或者一個函數(shù)的長度大于兩屏幕都是比較危險的信號。
另一個能夠體現(xiàn)模塊劃分水平的地方是依賴削罩。如果一個模塊依賴特別多瞄勾,甚至出現(xiàn)了循環(huán)依賴,那么也可以反映出作者對模塊的規(guī)劃比較差弥激,今后在維護(hù)這個工程的時候很有可能出現(xiàn)牽一發(fā)而動全身的情況进陡。
一般來說有不少工具能提供依賴分析,比如IDEA中提供的Dependencies Analysis功能秆撮,學(xué)會這些工具的使用對于評價代碼質(zhì)量會有很大的幫助四濒。
值得一提的是换况,絕大部分情況下职辨,不恰當(dāng)?shù)哪K劃分也會伴隨著極低的單元測試覆蓋率:復(fù)雜模塊的單元測試非常難寫的,甚至是不可能完成的任務(wù)戈二。所以直接查看單元測試覆蓋率也是一個比較靠譜的評價方式舒裤。
2.4.3.簡潔與抽象
只要提到代碼質(zhì)量,必然會提到簡潔觉吭、優(yōu)雅之類的形容詞腾供。簡潔這個詞實(shí)際涵蓋了很多東西,代碼避免重復(fù)是簡潔鲜滩、設(shè)計足夠抽象是簡潔伴鳖,一切對于提高可維護(hù)性的嘗試實(shí)際都是在試圖做減法。
編程經(jīng)驗(yàn)不足的程序員往往不能意識到簡潔的重要性徙硅,樂于搗鼓一些復(fù)雜的玩意并樂此不疲榜聂。但復(fù)雜是代碼可維護(hù)性的天敵,也是程序員能力的一道門檻嗓蘑。
跨過門檻的程序員應(yīng)該有能力控制逐漸增長的復(fù)雜度须肆,總結(jié)和抽象出事物的本質(zhì),并體現(xiàn)到自己設(shè)計和編碼中桩皿。一個程序的生命周期也是在由簡入繁到化繁為簡中不斷迭代的過程豌汇。
對于這部分我難以總結(jié)出簡單易行的評價標(biāo)準(zhǔn),它更像是一種思維方式泄隔,除了要理解拒贱、還需要練習(xí)。多看佛嬉、多想逻澳、多交流岩调,很多時候可以簡化的東西會大大超出原先的預(yù)計。
2.2.4.推薦閱讀
《重構(gòu)-改善既有代碼的設(shè)計》
《設(shè)計模式-可復(fù)用面向?qū)ο筌浖幕A(chǔ)》
《Software Architecture Patterns-Understanding Common Architecture Patterns and When to Use Them》
3.結(jié)語
這篇文章主要介紹了一些評價代碼質(zhì)量優(yōu)劣的手段赡盘,這些手段中号枕,有些比較客觀,有些主觀性更強(qiáng)陨享。之前也說過葱淳,對代碼質(zhì)量的評價是一件主觀的事情,這篇文章里雖然列舉了很多評價手段抛姑。但是實(shí)際上赞厕,很多我認(rèn)為沒有問題的代碼也會被其他人吐槽,所以這篇文章只能算是初稿定硝,更多內(nèi)容還需要今后繼續(xù)補(bǔ)充和完善皿桑。
雖然每個人對于代碼質(zhì)量評價的傾向都不一樣,但是總體來說評價代碼質(zhì)量的能力可以被比作程序員的“品味”蔬啡,評價的準(zhǔn)確度會隨著自身經(jīng)驗(yàn)的增加而增長诲侮。在這個過程中,需要隨時保持思考箱蟆、學(xué)習(xí)和批判的精神沟绪。