不要和一種程式語言廝守終生:為工作正確選擇

2016-01-05    分類:程式設計師人生、首頁精華3人評論發表於2016-01-05

本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

我們程式設計師在著手一個專案時,需要做的關鍵決定之一就是選擇一種語言,或一組語言,用於實施該系統。這一決定不僅會影響系統的實現,也會影響設計。例如,我們應該使用物件導向的語言還是過程語言?選擇什麼語言對專案以及作為專案一部分的程式的生命週期有著深遠的影響,很多次,我們基於一些非常善變的因素,沒有思考太多就去選語言:這語言是我慣常用來實現這類系統的;這語言我瞭解得最透徹;這是我最喜歡的語言,我很享受於用這種語言程式設計;等等。

既然這個決定會導致深刻而長遠的結果,那麼我們是不是在做這個抉擇時應該更加務實?很多時候,我們會盲目地偏頗於我們選擇的語言。而且,有時候我們之所以不喜歡選擇這種語言的原因可能正是為什麼我們要選擇那種語言的原因。

如果我們能夠放開胸懷,坦誠地對待自己持有的偏見,那麼我們就可以減輕一些類似在裝修時硬要將方釘釘進圓形孔的痛苦。雖然我們沒有什麼祕訣來為專案選擇完美語言,但還是可以遵循一些原則,幫助我們做出一個更好,更合適的語言選擇。

沒有完美的語言

這一點對任何人,甚至是新手而言,都是在意料之中的,並且我們很多人都願意承認,“當然,這種語言並不是完美的語言,”但與此同時,我們很多人還是會說,“這語言是最好的程式語言”。說一種語言是專案的最好語言的關鍵是專案的背景,也就是說,最好的語言只存在於一定的範圍內。這就是我們的第一條原則:

沒有完美的語言:每一種語言都有它的優點和缺點。

例如,許多通常使用執行時語言,如Java或Python的開發人員,聲稱C或C ++令人透不過氣來,會因為關注例如記憶體管理這類低層次的細節,或關心編譯時型別檢查的嚴格粒度,而扼殺分置於開發人員的職責。這是事實,只要我們正在開發的專案不關注看似瑣碎的任務,如記憶體管理或發生在單一迴圈中的copy-assignment的數量。

相反,如果我們工作在一個專案,或專案的一部分,那麼對於程式碼應該如何高效以及程式的關鍵性安全的偏見需求是自然而然的,這些看似繁瑣的細節可能正是我們正在尋找的粒度水平。在這種新的背景下,Java或Python的執行時性質似乎過於漠不關心或過於心不在焉。相反,我們希望當記憶體分配和釋放的時候,能夠嚴格控制有多少move-assignment和copy-assignment被執行,並在編譯時捕捉儘可能多的錯誤,而不是讓錯誤滲入執行時(表現為執行時異常)。

雖然在理論上“沒有完美的語言”這一點聽起來是顯而易見的,但是我們作為開發人員的行為通常會背離這個概念:我們說我們知道我們最喜歡的語言是不完美的,但我們還是繼續對我們開發的專案使用這種語言,不管它是否適合。此外,當其他的開發人員質疑我們選擇的語言時,我們會堅決捍衛我們的選擇,而不願意從他或她的反駁中看見事實的真相。請記住:每一種語言都有它的優點和缺點。瞭解你掌握的語言的優點和缺點,然後根據實際情況做出選擇。

你不喜歡一種語言的原因可能就是你應該使用它的原因

這似乎違反直覺,但有的時候,我們之所以不喜歡一門語言可能正是使用某種語言的原因。還是上面的例子,在我作為一個C ++開發人員的經驗中,很多時候因為有那麼多不同的概念要跟蹤(記憶體管理和物件壽命時間,C ++程式設計三原則等),以致於完成專案的一個簡單功能都會變得繁瑣不堪。在用C ++開發幾周之後,使用Python,Java或另一種“更高階”的語言,簡直就像上天的恩賜:但真的是這樣的嗎?

有時候,可能我們不喜歡一門語言的原因正是我們要使用該語言的原因。如果我正在開發一個驅動程式或一些關鍵性安全,實時的系統,上面表述的繁瑣不堪的原因可能正是這個語言的最大優勢。例如,C ++提供了一種機制用於表達當物件被複制時被執行的邏輯,這在效率和嚴謹性井然有序的時候是非常寶貴的。

這可能看上去都很好都很棒,因此我們很難確切指出在某個背景下,某種你看不順眼的語言可能反而更有幫助。那麼,我們該怎麼知道哪些你不喜歡的語言是有幫助的呢?這就引出了我們的第二條原則:

對自己要誠實:知道自己為什麼不喜歡一門語言,不要教條化自己的憎惡。

例如,在上面那個C ++的例子中,我之所以不喜歡長時間地用C ++程式設計,是因為這語言要求思想嚴謹,否則很容易犯錯,就像是被困於叢林中(過多地關注樹木,而不是樹林這個整體)。這種嚴謹會妨礙開發人員去質疑,如,“我要在堆疊上或堆上建立物件嗎,或者部分在堆疊上,另一部分在堆上?”或“要讓這個類可擴充套件,應該通過模板引數還是通過繼承?”等決定。在其他語言中,開發人員只需分別建立一個物件以及使用物件導向的繼承就可以完成這些任務,然後進入到下一個功能,因為語言(或者,更準確地說,編譯器或直譯器)關注這些細節。

但是,如果我對自己誠實的話,我會承認,我之所以不喜歡C ++的這些功能,是因為它將表達這些細節的責任歸咎於我。在其他語言中,我不僅不需要負責這些細節,而且我也沒有責任表達這些細節:它們被抽象遠離開發人員。在一個這些細節是必不可少的上下文中,我不喜歡C ++的原因正是我應該使用這種語言的原因。

這是否意味著,我們應該愁眉苦臉地使用這些會讓我們對這語言惱怒的功能?也沒有必要。或許你可以換個角度:不要將這些功能當作缺點,也許我們應該擁抱它們,將它們當作完成任務的必需品。我們不應該說“這真是一個悲劇,”而應該說,“謝天謝地,我居然能用這種語言做到這一點。”請記住:在某些背景下,這些功能將是上天的恩賜,而在其他情況下,它們 才是累贅。至於為什麼不喜歡某一門語言的功能,請誠實地告訴自己。

越熟悉其他語言,越好

對於這一點,就是我們要說的第三個原則:

如果你擁有的唯一工具是一個錘子,那麼你看每一個問題都像是釘子。

這條規則並不適用於軟體工程,但它尖銳地表現了許多軟體開發的情況。很多時候,我們選擇一種語言,或一種語言支援的工具(如Java的JMS,Python的ASYNCIO,Rails的Ruby等),是因為我們知道它們存在。如果我們唯一熟悉的語言是Java,那麼我們會將我們碰到的所有問題都適應到Java的上下文中。例如,“我需要為一個通訊應用建立一個路由框架。在Java中我該怎麼做呢?”這就限制了可供我們使用的工具,並人為地限制我們為完成工作選擇合適工具的餘地。

解決這個問題的方法是擴大你的視野,瞭解其他語言的的功能和錯綜複雜之處。正如Andrew Hunt和David Thomas在《The Pragmatic Programmer》中給出的建議,一個好的做法就是,每年學習一門新的語言。這可不沒有聽上去那麼容易,學習一門語言對不同的人將意味著不同的事情。還有一個衍生問題是,我們對正在進行中的專案往往只會使用這一種語言,從而使得學習的另一種語言顯得毫無用處。例如,假設我是一個Android開發人員,基本上每天只用Java,那麼學習C#可能就會顯得不合時宜地浪費時間。

不要被假象所矇蔽。學習其他語言的優勢體現在我們能從不同的角度去看問題,並且使用最適合該問題的工具。為了做到這一點,我們必須學習其他語言的相關警告,以及開發人員使用這些語言解決問題的方式。例如,如果一個開發人員想用C ++執行超程式設計,那麼他或她可以使用C ++中的Template Metaprogrammming(TMP),但他或她也可以使用Java中的反射。理解其他語言是如何解決類似問題的,可以減少我們認為它毫無用處的風險。

再說一個例子,如果我們需要能夠改變一個類的執行時特徵,那麼一個深入熟悉C ++錯綜複雜性的C ++開發人員,可能會試圖編造一個延伸這個編譯時語言的界限的解決方案。而另一個C ++開發人員,由於對Java也有一定的瞭解,就能夠說,“我喜歡C ++,但Java的執行時反射更適合解決這個問題。”

因為有如此之多的程式語言任開發人員擇選,因此,優先安排學習什麼語言很重要。不妨從當今最流行的語言入手(可參考《most popular languages on Github》,《Language Trends on Github》,《The 9 most popular computer languages》,《according to the Facebook for programmers》等)。

語言是手段而不是目的

這是第四條,也是最後一條原則,聽上去可能最哲學,但也可以說是最重要的:

程式語言是一種手段,而不是目的。

除非你是一個語言標準的作者或是一個編譯器的作者,否則你就應該將程式語言當作是一種手段而不是目的,目的是完成專案:最終的目標是要完成專案,而不是使用特定的語言。這並不意味著每個開發人員就無權要求他或她喜歡或不喜歡的語言(實際上,如果我們對自己誠實的話,這些好惡反而能夠讓我們受惠;參見上面的第二條原則),但我們不應該自欺欺人作出這樣的決定,如,“這對我來說是使用該語言這一功能的一個很好的機會”,除非該語言的功能真正適合專案的需求。

重要的是要記住,語言只是表達如何解決手頭問題的一種方法:請確保你選擇了最能表達解決問題域的語言。

其他需要考慮的地方

下面是一些我們在選擇語言的時候,需要補充考慮的地方:

考慮語言如何與其他語言的互動。例如,如果你認定Python是完成大部分專案的最好語言,但在你的專案中有一個定義良好的元件,需要極高水平的粒度或效率(更適合用C或C++ ),這並不意味著你不能在這個專案上使用Python。相反,考慮使用Python,特定元件用C或C ++寫,然後使用Python C API介面此元件。請注意,要制定這樣的解決方案,我們需要知道Python有一個C API;因此,瞭解最流行語言的這些功能是很有幫助的。

中介軟體可以允許使用多種語言。例如,如果有兩個必須進行通訊的應用程式,如移動裝置和一個伺服器應用程式,但這並不意味著它們必須使用相同的語言(當然也可以相同,如果你判斷認為這是最好決定的話)。如果這個移動裝置是一款Android手機,而伺服器應用程式非常適合作為一個Python應用程式的話,那麼使用一個訊息代理,如RabbitMQ,可以讓你在通訊的同時使用這兩種語言:Android應用程式可以使用Java RabbitMQ API,而伺服器應用程式可以使用Python RabbitMQ API。

擁抱其他語言的古怪之處。如果你是一個Java開發人員,那麼你會使用包來分隔原始碼的邏輯單元;如果你是一個Python開發人員,那麼你會使用Python的包結構做相同的事情;如果你是一個C ++開發人員,那麼你會使用名稱空間或字首的類名(即“DZone_MyClassName”)。瞭解你正在使用的語言的特別之處,並擁抱它們:在羅馬,就入鄉隨俗。否則的話就像是因為你更喜歡單詞用義大利語發音,而用義大利口音說德語,這樣就顯得不倫不類了。當然也有可能一種語言的一個功能長期存在,但是這樣的話,其中必有其原因:確保自己明白其中的道理。

譯文連結:http://www.codeceo.com/article/do-not-marry-a-language.html
英文原文:Do Not Marry a Language: Selecting the Correct Language for the Job
翻譯作者:碼農網 – 小峰
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章