自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

每個(gè)程序員都應(yīng)注意的9種反面模式

開發(fā) 后端 前端
某種健康的自我批評(píng)對(duì)于專業(yè)和個(gè)人成長(zhǎng)是至關(guān)重要的。對(duì)于編程而言,這種自我批評(píng)的意義需要檢測(cè)出在設(shè)計(jì)、代碼、過程和行為中的低效和反效果的模式。這就是對(duì)反面模式【注1】的理解為什么對(duì)于任何程序員都非常有用的原因。本文基于我遇到它們的頻率以及花費(fèi)多長(zhǎng)時(shí)間才能消除它們引起的破壞做了反面模式的討論,通過我發(fā)現(xiàn)的反復(fù)出現(xiàn)的、粗略地組織起來。

某種健康的自我批評(píng)對(duì)于專業(yè)和個(gè)人成長(zhǎng)是至關(guān)重要的。對(duì)于編程而言,這種自我批評(píng)的意義需要檢測(cè)出在設(shè)計(jì)、代碼、過程和行為中的低效和反效果的模式。這就是對(duì)反面模式【注1】的理解為什么對(duì)于任何程序員都非常有用的原因。本文基于我遇到它們的頻率以及花費(fèi)多長(zhǎng)時(shí)間才能消除它們引起的破壞做了反面模式的討論,通過我發(fā)現(xiàn)的反復(fù)出現(xiàn)的、粗略地組織起來。

討論到的某些反面模式和認(rèn)知偏誤有些共通的地方,或由它們直接引起的。在我們本文繼續(xù)之前,關(guān)于認(rèn)知偏誤的相關(guān)鏈接也被提供了。維基百科也有不錯(cuò)的認(rèn)知偏誤詞條供你參考【注9】。

在開始之前,我們要切記,教條式思考阻礙了增長(zhǎng)和創(chuàng)新,因此把下面的列表做為一套指南、而非一成不變的規(guī)則。如果我錯(cuò)過了你認(rèn)為重要的東東,請(qǐng)?jiān)谙旅娴脑u(píng)論留言!

反面模式的清單包括:

  1. 不成熟的優(yōu)化
  2. 單車車庫(kù)【注2】
  3. 分析癱瘓(Analysis paralysis)
  4. 上帝類【注3】
  5. 害怕新增類
  6. 內(nèi)部平臺(tái)效應(yīng)(Inner-platform effect)
  7. 魔術(shù)數(shù)字和字符串【注4】
  8. 目標(biāo)管理【注6】
  9. 無用的(幽靈)類【注8】

1、不成熟的優(yōu)化

“在 97% 的時(shí)間里,我們應(yīng)該忘記微不足道的效率:過早的優(yōu)化是萬惡之源。然而在關(guān)鍵的 3% 我們不應(yīng)該錯(cuò)過優(yōu)化的機(jī)會(huì)。” ——Donald Knuth

“不假思索就動(dòng)手還不如不做。” ——Tim Peters,《The Zen of Python》【注5】

意思

對(duì)于在哪里優(yōu)化、如何去優(yōu)化,在你有足夠信息做出有意義的結(jié)論之前,就開展的優(yōu)化。

糟糕的原因

難以確切地知道實(shí)踐中的瓶頸。企圖在得到實(shí)驗(yàn)數(shù)據(jù)之前優(yōu)化,伴隨著微不足道的改進(jìn),有可能增加代碼復(fù)雜度和 bug 產(chǎn)生的空間。

如何避免

把編寫整潔、可讀性強(qiáng)的、能運(yùn)行的代碼擺在首位,使用已知的和測(cè)試過的算法和工具。當(dāng)需要找到瓶頸和優(yōu)化優(yōu)先級(jí)時(shí),再使用分析工具。依靠策略而非臆測(cè)和推斷。

例子和信號(hào)

在企圖找到瓶頸之前做緩存。使用復(fù)雜的、未經(jīng)通過的“啟發(fā)式”,而不是知名的、數(shù)學(xué)上正確的算法。選擇一種新的、未經(jīng)測(cè)試的實(shí)驗(yàn)性框架,在理論上可以減少高負(fù)載下的請(qǐng)求延遲,當(dāng)你處于早期階段時(shí),你的服務(wù)器大部分時(shí)間處于空轉(zhuǎn)狀態(tài)。

棘手的地方

棘 手的地方在于知道什么時(shí)候是不成熟的優(yōu)化。提前規(guī)劃對(duì)于增長(zhǎng)是重要的。選擇易于優(yōu)化和成長(zhǎng)的設(shè)計(jì)和平臺(tái)是關(guān)鍵。把“不成熟的優(yōu)化”做為評(píng)判編 寫糟糕代碼的借口也是有可能的。例如:當(dāng)更簡(jiǎn)單的、數(shù)學(xué)上正確的 O (n) 算法存在時(shí),編寫一個(gè) O (n2) 算法來解決問題,僅僅因?yàn)樵胶?jiǎn)單的算法,越難以理解。

總結(jié)

在優(yōu)化之前做分析。在效率被需要、被觀察到的證據(jù)支持之前,避免為了效率而犧牲簡(jiǎn)潔。

#p#

2、單車車庫(kù)

“我 們總是在討論封面的排版和顏色時(shí)出現(xiàn)中斷。每次討論之后,我們被要求投票。我想,對(duì)于我們之前在會(huì)上決定的相同顏色進(jìn)行投票,是最有效率的,但 結(jié)果顯示,我總是處于少數(shù)派!我們最終選擇了紅色。(結(jié)果是藍(lán)色。)” ——Richard Feynman,《你在乎其他人的想法嗎?》

意思

把過多時(shí)間花在瑣碎而且經(jīng)常是主觀問題的辯論和決定上的趨勢(shì)。

糟糕的原因

這是浪費(fèi)時(shí)間。Poul-Henning Kamp 在這封郵件里進(jìn)行了深入討論。

如何避免

當(dāng)你注意到這一點(diǎn)時(shí),鼓勵(lì)團(tuán)隊(duì)成員注意到這種趨勢(shì),把達(dá)成一個(gè)決定做為高優(yōu)先級(jí)(投票、拋硬幣等,如果你不得不這樣做的話)。當(dāng)這個(gè)決定有意義(例如,在兩種不同的 UI 設(shè)計(jì)之間決定)、而不是進(jìn)一步的內(nèi)部討論時(shí),考慮稍后的 A/B 測(cè)試以重新審視這個(gè)決定。

 

[[134927]]

Richard Feynman 不是單車車庫(kù)的粉絲

例子和信號(hào)

花費(fèi)數(shù)小時(shí)或數(shù)天討論你的 app 應(yīng)該使用什么背景色,或者把一個(gè)按鈕放在 UI 的左側(cè)還是右側(cè),或者在你的代碼庫(kù)里的縮進(jìn)使用制表符而非空格。

棘手的地方

在我看來,單車車庫(kù)相較于不成熟的的優(yōu)化,是更容易發(fā)現(xiàn)和防止的。只需要注意到花在做決定和合約上的時(shí)間,問題有多么瑣碎,如有必要就加以干預(yù)。

總結(jié)

不要把過多時(shí)間花在瑣碎的事情上。

#p#

3、分析癱瘓

“想要預(yù)見性,不愿意行動(dòng),而行動(dòng)是簡(jiǎn)單有效的,缺乏清晰的思考,建議混亂……這些構(gòu)成了歷史上無休止重復(fù)的特點(diǎn)。” ——Winston Churchill,國(guó)會(huì)辯論

“做也許好過不做。” ——Tim Peters,《The Zen of Python》

意思

對(duì)問題的過度分析阻礙了行動(dòng)和進(jìn)展。

糟糕的原因

過度分析能夠完全延緩或阻止進(jìn)展。在極端情況下,分析的結(jié)果到了實(shí)施的時(shí)候,會(huì)變得毫無用處;或者更糟糕的是,項(xiàng)目或許從來走不出分析階段。當(dāng)決定難以做出時(shí),更容易臆測(cè)出,更多的資訊將有助于做決定 ——參看 資訊偏誤效度偏誤。

如何避免

重申,意識(shí)是有幫助的。強(qiáng)調(diào)迭代和改善。根據(jù)可用于進(jìn)一步有意義分析的更多的數(shù)據(jù)點(diǎn),每次迭代提供更多的反饋。沒有新的數(shù)據(jù)點(diǎn),更多的分析將變得越來越讓人猜疑。

例子和信號(hào)

花費(fèi)數(shù)月、甚至數(shù)年來決定一個(gè)項(xiàng)目的需求、新 UI、或數(shù)據(jù)庫(kù)設(shè)計(jì)。

棘手的地方

棘手的地方在于知道什么時(shí)候該從計(jì)劃、需求收集和設(shè)計(jì)階段轉(zhuǎn)移到實(shí)施和測(cè)試階段。

總結(jié)

寧愿迭代,也不要過度分析和猜測(cè)。

#p#

4、上帝類

“簡(jiǎn)潔勝過復(fù)雜。” ——Tim Peters,《The Zen of Python》

意思

上帝類是控制很多其它類,以及有很多依賴和負(fù)責(zé)過多的類。

糟糕的原因

上帝類傾向于增長(zhǎng)到變成維護(hù)噩夢(mèng)的地步——因?yàn)樗麄冞`反了單一責(zé)任原則,它們難以單元測(cè)試、調(diào)試和記錄文檔。

如何避免

避免把類變成上帝類,可以通過把責(zé)任分解為有著單一化的、清晰定義的、經(jīng)過單元測(cè)試和文檔責(zé)任的更小的類。

例子和信號(hào)

尋找類名包含了“manager”、“controller”、“driver”、“system”、或“engine”的類。當(dāng)心 import 或依賴很多其它類、控制太多其它類、或有很多處理不相關(guān)任務(wù)的方法的類。

 

上地類知道很多類和/或很多控制。

棘手的地方

隨著項(xiàng)目年限、需求和工程師人數(shù)的增長(zhǎng),小型的且有著良好意圖的類慢慢地變成了上帝類。重構(gòu)這些類就變成了浩大的任務(wù)。

總結(jié)

避免有著太多責(zé)任和依賴的龐大的類。

#p#

5、害怕新增類

“間隔勝于緊湊。” ——Tim Peters,《The Zen of Python》

意思

堅(jiān)信更多的類必然使得設(shè)計(jì)更加復(fù)雜,從而對(duì)新增類或把大類分解為一些小類感到恐懼。

糟糕的原因

新增類可以顯著幫助降低復(fù)雜度。貼一副大的雜亂的毛線團(tuán)。當(dāng)解開時(shí),你將得到一些分隔開的毛線團(tuán)。類似地,一些簡(jiǎn)單的、易于維護(hù)、易于記錄文檔的類,要遠(yuǎn)遠(yuǎn)好過于有著太多責(zé)任的、單一龐大的、復(fù)雜類。(參看上面的上帝類的反設(shè)計(jì)模式)

 

[[134929]]

Photo by absolut_feli on Flickr

如何避免

要注意新增類在什么時(shí)候可以簡(jiǎn)化設(shè)計(jì)以及解耦你的代碼中不必要的耦合部分。

例子和信號(hào)

考慮下面一個(gè)簡(jiǎn)單的例子:

class Shape: def __init__(self, shape_type, *args): self.shape_type = shape_type self.args = args def draw (self): if self.shape_type == "circle": center = self.args[0] radius = self.args[1] # Draw a circle... elif self.shape_type == "rectangle": pos = self.args[0] width = self.args[1] height = self.args[2] # Draw rectangle...

現(xiàn)在對(duì)比下面的代碼:

class Shape: def draw (self): raise NotImplemented ("Subclasses of Shape should implement method 'draw'.") class Circle (Shape): def __init__(self, center, radius): self.center = center self.radius = radius def draw (self): # Draw a circle... class Rectangle (Shape): def __init__(self, pos, width, height): self.pos = pos self.width = width self.height = height def draw (self): # Draw a rectangle...

當(dāng)然,這是一個(gè)明顯的例子,但是它揭示了一點(diǎn):內(nèi)部有著依賴性的或復(fù)雜邏輯的大型類,可以、也經(jīng)常應(yīng)該被分解為更小的類。最后的代碼將有更多的類,但是更加小型。

棘手的地方

新增類不是一顆神奇的子彈。通過分解大型類來簡(jiǎn)化設(shè)計(jì),需要對(duì)責(zé)任和需求進(jìn)行深入分析。

總結(jié)

類的數(shù)量多,不一定是糟糕設(shè)計(jì)的信號(hào)。

#p#

6、內(nèi)部平臺(tái)效應(yīng)

“那些不理解 Unix 的人因?qū)ζ洳涣几脑於艿阶l責(zé)。” ——Henry Spencer

“任何 C 或 Fortran 程序復(fù)雜到一定程度之后,都會(huì)包含一個(gè)臨時(shí)開發(fā)的、只有一半功能的、不完全符合規(guī)格的、到處都是 bug 的、運(yùn)行速度很慢的 Common Lisp 實(shí)現(xiàn)。” ——格林斯潘第十法則

意思

復(fù)雜軟件系統(tǒng)傾向于它們所運(yùn)行平臺(tái)、或它們所使用編程語言的、功能的重新實(shí)現(xiàn),通常是不良實(shí)現(xiàn)。

糟糕的原因

像計(jì)劃任務(wù)或磁盤緩沖區(qū)之類的平臺(tái)級(jí)別的任務(wù)不是容易搞定的。糟糕的設(shè)計(jì)方案易于帶來瓶頸和 bug,尤其系統(tǒng)規(guī)模變大后。重新發(fā)明可替代的語言結(jié)構(gòu)來達(dá)到語言已有可能的東東,會(huì)導(dǎo)致難以閱讀的代碼,對(duì)于剛接手代碼庫(kù)的人而言,有著更加陡峭的學(xué)習(xí) 曲線。它還限制了重構(gòu)和代碼分析工具的效用。

如何避免

學(xué)習(xí)使用你的操作系統(tǒng)或平臺(tái)所提供的平臺(tái)和功能。避免創(chuàng)建與已有結(jié)構(gòu)(尤其是因?yàn)槟悴皇煜ば抡Z言而找不到你的舊語言的功能)競(jìng)爭(zhēng)的語言結(jié)構(gòu)的誘惑。

例子和信號(hào)

使用你的 MySQL 數(shù)據(jù)庫(kù)做為工作隊(duì)列。重新實(shí)現(xiàn)你自己的磁盤緩沖區(qū)、而不是依賴你的操作系統(tǒng)。用 PHP 為你的 web 服務(wù)器編寫計(jì)劃任務(wù)。用 C 定義 Python 之類的語言結(jié)構(gòu)的宏。

棘手的地方

在極少情況下,重新實(shí)現(xiàn)平臺(tái)(JVM、Firefox、Chrome 等)的某些部分可能是有必要的。

總結(jié)

避免重新發(fā)明你的操作系統(tǒng)或開發(fā)平臺(tái)已經(jīng)做得很多的功能。

#p#

7、魔術(shù)數(shù)字和字符串

“明了勝于晦澀。” ——Tim Peters,《The Zen of Python》

意思

直接使用數(shù)字或字符串字面量,而不是在代碼里命名的常量。

糟糕的原因

主要問題在于,數(shù)字或字符串字面量的語義由于沒有一個(gè)解釋型的名字或另一種形式的注解,而被部分或完全地隱藏了。這增加了理解代碼的難度,如果必須要修改常量,那么搜索和替換、或其它重構(gòu)工具會(huì)引入微妙的 bug。考慮下面的代碼片段:

def create_main_window : window= Window (600600) # etc...

這兩個(gè)數(shù)字是什么?假定一個(gè)數(shù)字是窗戶的寬度,第二個(gè)是高度。如果需要修改寬度為 800,那么搜索和替換將是危險(xiǎn)的,因?yàn)樵谶@個(gè)例子中,它也將修改高度的值,或許還有代碼庫(kù)里其它出現(xiàn)數(shù)字 600 的地方。

字符串字面量的這些問題貌似不多,但是代碼里有未命名的字符串字面量,將使得國(guó)際化更加困難,對(duì)于有著相同字面量卻有著不同語義的情況,就帶來 了類似的問題。比如,英語中的同義詞在搜索和替換時(shí),能夠產(chǎn)生類似問題;假設(shè)“point”出現(xiàn)了兩次,一個(gè)是指名詞(比如“she has a point”),另一個(gè)是動(dòng)詞(比如“point out the differences……”)。如果一種字符串檢索機(jī)制可以明確地指示語義,那么用這種機(jī)制替換這樣的字符串字面量,將幫助你區(qū)分這兩種情況,當(dāng)你把這 些字符串送去翻譯時(shí),也就方便多了。

如何避免

使用命名的常量、資源檢索方法、或注釋。

例子和信號(hào)

簡(jiǎn)單的例子如上所示。這種特定的反面模式非常容易檢測(cè)到(期待下面提到的一些棘手的情況)。

棘手的地方

有一個(gè)狹窄的灰色地帶,難以區(qū)分特定的數(shù)字是不是魔術(shù)數(shù)字。例如,索引從 0 開始的語言中的數(shù)字 0。其它例子,用 100 來計(jì)算百分比,用 2 做奇偶校驗(yàn)等。

總結(jié)

避免代碼中出現(xiàn)未注解、未命名的數(shù)字和字符串字面量。

#p#

8、目標(biāo)管理

“用代碼行來衡量開發(fā)進(jìn)度,無異于用重量來衡量制造飛機(jī)的進(jìn)度。” ——比爾·蓋茨

意思

嚴(yán)格地依靠數(shù)字來做決定。

糟糕的原因

數(shù) 字是偉大的。避免本文提及的前兩個(gè)反面模式(不成熟的優(yōu)化和單車車庫(kù))的主要策略是分析或 A/B 測(cè)試,幫助你根據(jù)數(shù)字而非臆測(cè)來優(yōu)化或決策。然而,盲目地依賴數(shù)字是危險(xiǎn)的。比如,數(shù)字傾向于比它們有意義的模型要長(zhǎng)久,或者模型過期了、不再精確地代表 現(xiàn)實(shí)。這會(huì)導(dǎo)致錯(cuò)誤的決策,尤其當(dāng)它們完全自動(dòng)化時(shí)——參考自動(dòng)化偏誤

 

[[134930]]

Do you find yourself commiserating with Pryzbylewski from the HBO show The Wire, Season 4?

依賴數(shù)字做決定(不僅僅是告知)的另一個(gè)問題是,策略過程可以隨著時(shí)間來操作,以達(dá)成期望的數(shù)字。參看觀察者期望效應(yīng)【注 7】。分?jǐn)?shù)膨脹就是這種情況的一個(gè)例子。HBO 顯示了 The Wire(順便說一句,如果你還沒有看過,你一定要看?。┏錾孛枋隽艘蕾嚁?shù)字的問題,展現(xiàn)了警察部門和后來的教育系統(tǒng)用數(shù)字游戲取代了有意義的目標(biāo)。如 果你喜歡圖表,下面的圖表展示了 30% 通過率的一場(chǎng)考試的分?jǐn)?shù)分布,極好地說明了這個(gè)觀點(diǎn)。

 

每個(gè)程序員都應(yīng)注意的9種反面模式

波蘭高中畢業(yè)考試中通過率 30% 的分?jǐn)?shù)分布

如何避免

要理智地使用測(cè)量和數(shù)字,而非盲目。

例子和信號(hào)

使用代碼行數(shù)、提交次數(shù)等來評(píng)判程序員的效率。通過員工呆在公司的小時(shí)數(shù)來測(cè)量他們的貢獻(xiàn)。

棘手的地方

運(yùn)營(yíng)規(guī)模越大,需要做出決策的數(shù)字就越高,這意味著自動(dòng)化和盲目依賴數(shù)字做決策開始蔓延到過程里了。

總結(jié)

讓數(shù)字告知你的決策,而不是決定它們。

#p#

9、無用的(幽靈)類

“達(dá)到完美,貌似不是在沒有什么更多的要添加的時(shí)候,而是在沒有什么更多的要去掉的時(shí)候。” ——Antoine de Saint Exupéry

意思

無用類本身沒有真正的責(zé)任,經(jīng)常用來指示調(diào)用另一個(gè)類的方法或增加一層不必要的抽象層。

糟糕的原因

幽靈類增加了復(fù)雜度、要維護(hù)和測(cè)試的額外代碼,降低了代碼可讀性——讀者首先需要意識(shí)到幽靈類做了什么,它們經(jīng)常幾乎沒有用處,然后培養(yǎng)自己在精神上用實(shí)際處理該責(zé)任的類取代幽靈類的使用。

如何避免

不要寫無用類,或者通過重構(gòu)來消除它們。Jack Diederich 的題為“Stop Writing Classes”就是和這種反面模式相關(guān)的。

例子和信號(hào)

多年前,我正忙于我的碩士學(xué)位,當(dāng)時(shí)是大一 Java 編程課的助教。在其中一個(gè)實(shí)驗(yàn)課上,我收到了實(shí)驗(yàn)材料,是關(guān)于使用鏈表來實(shí)現(xiàn)棧的主題。我還被提供了“答案”的參考。下面是給我的答案,一個(gè) Java 文件,幾乎沒做改動(dòng)(限于篇幅我刪除了注釋):

import java.util.EmptyStackException; import java.util.LinkedList; public class LabStack<T> { private LinkedList<T> list; public LabStack { list = new LinkedList<T>; } public boolean empty { return list.isEmpty ; } public T peek throws EmptyStackException { if (list.isEmpty ) { throw new EmptyStackException ; } return list.peek ; } public T pop throws EmptyStackException { if (list.isEmpty ) { throw new EmptyStackException ; } return list.pop ; } public void push (T element) { list.push (element); } public int size { return list.size ; } public void makeEmpty { list.clear ; } public String toString { return list.toString ; } }你能想象出我看到這個(gè)參考答案的困惑,試圖搞清楚 LabStack 類是做什么的,以及學(xué)生應(yīng)該從這個(gè)毫無意義的練習(xí)中學(xué)到什么。在本例中,這個(gè)類的錯(cuò)誤不是太明顯,它絕對(duì)沒有意義!它只是通過實(shí)例化的 LinkedList 對(duì)象傳遞調(diào)用。這個(gè)類修改了很多方法的名字(比如把通用的 clear 換成 makeEmpty),這只會(huì)讓用戶困惑。錯(cuò)誤檢查邏輯完全不必要,因?yàn)?LinkedList 里的方法已經(jīng)做了同樣工作(但是拋出了一個(gè)不同的異常,NoSuchElementException,這是又一個(gè)可能困惑的地方)。直到今天,我還是無法想象當(dāng)學(xué)生拿到這份實(shí)驗(yàn)材料時(shí),作者會(huì)作何感想。當(dāng)你看到和上例相似的類時(shí),重新考慮一下,它們是否真的需要。

棘手的地方

這里的建議初看起來和“害怕新增類”的建議相矛盾。重要的是要明白,類在什么時(shí)候發(fā)揮著有價(jià)值的角色和簡(jiǎn)化設(shè)計(jì),而不是無謂地增加復(fù)雜度卻沒有得到益處。

總結(jié)

避免沒有真正責(zé)任的類。

英文原文:9 Anti-Patterns Every Programmer Should Be Aware Of
責(zé)任編輯:王雪燕 來源: OPEN資訊
相關(guān)推薦

2012-02-28 10:52:13

2018-03-07 12:57:53

2024-04-10 12:36:41

硬件代碼

2023-11-02 14:21:06

2014-07-16 09:34:44

2024-04-01 08:40:23

UML畫法模型圖

2023-03-28 23:08:18

Bash編碼Shell

2021-10-20 06:05:01

編程語言開發(fā)

2013-03-20 17:58:41

虛擬內(nèi)存程序員

2021-10-18 10:21:28

程序員技能優(yōu)化

2022-09-11 15:20:05

程序員命令開發(fā)

2012-10-11 10:32:48

Linux命令程序員

2023-01-31 15:43:47

2015-04-16 10:26:51

程序員 Python Ruby

2011-07-25 10:09:57

Python

2024-04-24 14:52:26

JavaScriptWeb 開發(fā)

2023-12-27 09:00:00

Python魔術(shù)方法開發(fā)

2011-06-16 08:58:57

軟考程序員

2017-04-07 10:40:48

程序員學(xué)習(xí)命令行

2020-09-03 12:54:37

Python程序員macOS
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)