【CSDN編者按】“千帆過盡仍少年”,對于程序員來說,保留技術(shù)初心、不斷提升實力是夯實自己的不二法則。而本文的作者,作為一名有著三十多年開發(fā)經(jīng)驗的“老”程序員,就在本文中詳細(xì)總結(jié)了自己這些年踩過的坑和實踐得出的真理,談到了包括軟件開發(fā)、團(tuán)隊工作、個人成長等方方面面。相信閱讀本文后,會幫助你成為更優(yōu)秀的程序員。
聲明:本文已獲作者 Julio Biason 翻譯授權(quán)。
作者 | Julio Biason
譯者 | 王艷妮,責(zé)編 | 郭芮
以下為譯文:
這是我30年來從事軟件開發(fā)過程中所學(xué)到的一些實際經(jīng)驗,可能有些聽起來憤世嫉俗,但都是我的切身經(jīng)驗之談。
再次強調(diào),有些內(nèi)容真的是憤世嫉俗,有些則是對不同工作崗位的長期觀察。
軟件開發(fā)
先明確問題,再開始寫代碼
如果你不知道你想要解決的問題是什么,那你肯定就不知道要寫些什么代碼。在編寫任何代碼之前,先明確地把應(yīng)用程序是如何工作的寫下來。
“如果沒有需求或設(shè)計,編程就是向空文本文件不斷增加bug的藝術(shù)?!薄狶ouis Srygley
有時,即使只是“電梯演講”(指短時間內(nèi)表述結(jié)果內(nèi)容)那么長——用僅僅兩個自然段來描述這個應(yīng)用程序的功能——也足夠了。
有時候我看著自己的代碼發(fā)呆,不知道下一步該怎么做,其實往往是因為下一步本來就還沒有被定義出來。一般出現(xiàn)這種情況,就意味著是時候停下來,與同事們討論一下了——或者重新考慮解決方案。
將步驟寫為注釋
如果你不知道如何開始,請先用自然語言、英語或你的母語描述應(yīng)用程序的流程,然后用代碼填充注釋之間的空白。比這更好的做法是:將每個注釋視為一個函數(shù),然后編寫出能完全實現(xiàn)其功能的代碼。
Gherkin是幫助你了解期望(expectation)的好幫手
Gherkin是一種測試描述格式,它指出“鑒于系統(tǒng)處于特定狀態(tài),當(dāng)發(fā)生某些事情時,這是預(yù)期的后果”。即使你不使用任何能讀取Gherkin的測試工具,它也會讓你很好地理解應(yīng)用程序的預(yù)期效果。
單元測試很好,集成測試更好
在我目前的工作中,我們只測試模塊和類(例如,我們只為視圖層編寫測試,然后僅測試控制器層,依此類推)。它能讓我們了解到某一部分有沒有出錯,但缺乏對整體的觀察——而集成測試測試了整個系統(tǒng)的行為,在這方面會表現(xiàn)得更好。
測試可以讓API更好
我們在不同層次中編碼:有一個存儲層,應(yīng)該使我們的數(shù)據(jù)永久存儲;有一個處理層,應(yīng)該對存儲的數(shù)據(jù)進(jìn)行一些轉(zhuǎn)換;有一個視圖層,它有關(guān)于數(shù)據(jù)必須如何被展示出來的信息......等等。
正如我所提到的,集成測試感覺更好,但是單獨測試不同層可以讓你更好地了解其API。然后你可以更好地了解如何調(diào)用東西:API是否太復(fù)雜了?是否需要保留大量數(shù)據(jù)才能進(jìn)行一次調(diào)用?
做你知道如何在命令行上運行的測試
也不是說命令行對于任何項目都很重要,但是當(dāng)你知道運行測試的命令時,你就知道如何讓測試的執(zhí)行自動化起來,然后你可以在一個連續(xù)的集成工具中使用這些測試。
時刻準(zhǔn)備好扔掉你的代碼
很多人在剛開始使用TDD(測試驅(qū)動開發(fā),Test-Driven Development)時,一旦被告知他們可能不得不重寫很多東西,就會變得很生氣。
TDD“旨在”扔掉代碼:越了解你的問題,那么你就會越明白,無論你寫了什么,從長遠(yuǎn)來看都無法解決問題。
所以你不應(yīng)該擔(dān)心這個。你的代碼不是一面墻:如果你必須永遠(yuǎn)拋棄它,那也不是白白浪費了材料。當(dāng)然這意味著你編寫代碼的時間一去不復(fù)返了,但是你現(xiàn)在對這個問題有了更好的理解。
好的語言生來帶有綜合測試
可以肯定的是,如果一種語言在其標(biāo)準(zhǔn)庫中自帶一個測試框架——即使小得不能再小——那么與沒有測試框架的語言相比,它周圍的生態(tài)系統(tǒng)仍將擁有更好的測試,無論該語言的外部測試框架有多好。
未來思路是垃圾思路
當(dāng)開發(fā)人員試圖解決問題時,他們有時會試圖找到一種方法來一下解決所有問題,包括未來可能出現(xiàn)的問題。
但現(xiàn)實就是這樣:未來的問題永遠(yuǎn)不會到來,你最終要么必須維護(hù)一堆永遠(yuǎn)不會被完全使用的龐大代碼,要么得整個重新寫,因為有一大堆屁用沒有的東西......
解決你現(xiàn)在遇到的問題,然后解決下一個,然后再下一個。直到有一天,你會發(fā)現(xiàn)這些解決方案中顯現(xiàn)出了一種固定的模式,然后你才能真正地“一次性解決所有問題”。
文檔是寫給未來自己的情書
我們都知道,為函數(shù)、類(class)和模塊編寫該死的文檔是一個痛苦的過程。但是以后當(dāng)你看到文檔就能回想起來當(dāng)時你編寫函數(shù)時的思路,你就會明白將來文檔能在關(guān)鍵時刻救你一命。
功能文檔是份合同
當(dāng)你以編寫文檔作為自己編程工作的起始點時,你實際上是在簽訂合同(可能是跟未來的自己):我說了這個函數(shù)要做這件事情,那么它就必須做這件事情。如果稍后你發(fā)現(xiàn)代碼與文檔不匹配,那你就是代碼出了問題,而不是文檔出了問題。
如果一個函數(shù)的描述包含“和”,這就是不對的
一個函數(shù)應(yīng)該且僅應(yīng)該做一件事,真的。當(dāng)你編寫函數(shù)文檔并發(fā)現(xiàn)你寫了“和”這個字的時候,這意味著該函數(shù)不僅僅是做一件事。那么就需要將該函數(shù)分解為兩個獨立函數(shù)并刪除“和”。
不要使用布爾型變量作為參數(shù)
當(dāng)你設(shè)計一個函數(shù)時,你可能會想要添加一個flag——不要這樣做。
現(xiàn)在,讓我給你舉個栗子:假設(shè)你有一個消息傳遞系統(tǒng),并且有一個函數(shù)可以將所有消息返回給用戶,稱為getUserMessages。但有一種情況是需要返回每條消息的摘要(例如,第一段)或完整消息,因此,你添加一個名為retrieveFullMessage的flag/布爾參數(shù)。
再說一次,不要這樣做。
因為任何讀你代碼的人都會看到getUserMessage(userId,true)并想知道這里的true到底是個什么意思。
你可以將函數(shù)重命名為getUserMessageSummaries并使用另一個getUserMessagesFull或類似的東西,但每個函數(shù)只調(diào)用原始的getUserMessage為true或false——但是類/模塊外部的接口仍然是清晰的。
但是一定“不要”在函數(shù)中添加flags / Boolean作為參數(shù)。
注意界面的變化
在上面幾點中,我提到了重新命名函數(shù)的問題,如果你能控制使用該函數(shù)的整個源頭,那就不算是問題,只需要搜索和替換即可。
但是,如果該函數(shù)實際上是由庫公開的,那么你不能隨便地更改函數(shù)名稱。這將打破你無法控制的許多其他應(yīng)用程序,并惹惱其他人。
你可以通過文檔或某些代碼功能創(chuàng)建新函數(shù)并將當(dāng)前函數(shù)標(biāo)記為已棄用,然后,經(jīng)過幾次釋放后,你終于可以Kill掉原來的函數(shù)了。
(你可以做的一個有些混蛋的舉動是創(chuàng)建新函數(shù),將當(dāng)前函數(shù)標(biāo)記為已棄用,并在函數(shù)開頭添加一個休眠,這樣一來使用舊函數(shù)的人會被迫更新。)
好的語言自帶集成的文檔
如果語言有自己的方式來記錄函數(shù)、類、模塊或其他,而且?guī)в幸粋€哪怕最簡單的文檔生成器,你就可以確切知道所有的函數(shù)、類、模塊、庫、框架都具有良好的文檔了(不是說一定特別好,但至少是比較好的)。
大多數(shù)情況下,沒有集成文檔的語言,文檔方面做得都不怎么樣。
一門語言絕不僅僅是一門語言而已
編程語言就是你寫的、而且能做事情的東西,但在特殊關(guān)鍵詞以外它還有很多別的東西:它有一個構(gòu)建系統(tǒng),它有一個依賴控制系統(tǒng),它有一種使工具/庫/框架互動的方式,它有一個社區(qū),它有一種與人打交道的方式。
不要僅僅因為一種語言容易使用就選擇它。永遠(yuǎn)記住,你可能因為一種語言的語法很簡明而支持這種語言,但是與此同時你也是在支持維護(hù)人員對待這個社區(qū)的方式。
有時候,寧愿讓應(yīng)用程序崩潰也不要什么都不做
雖然這聽起來很奇怪,但即使在處理過程中添加了某些錯誤,也不要默默地捕捉到錯誤但什么都不做。
Java中一個可悲的常見模式是:
try { something_that_can_raise_exception()} catch (Exception ex) { System.out.println(ex);}
這看起來跟處理異常沒有什么關(guān)系——除了重復(fù)了一遍,僅此而已。
如果你不知道如何處理它,那就隨它去吧,你早晚會知道它會發(fā)生什么。
如果你知道如何處理該問題,那么就處理它
與前一點相反:如果你知道什么東西在何時會導(dǎo)致異常/錯誤/某種結(jié)果,并且知道如何處理它,那么就請?zhí)幚硭伞o@示錯誤信息,嘗試將數(shù)據(jù)保存在其他位置,將日志文件中用戶的輸入捕獲到以便以后處理,但要記得處理它。
類型決定你的數(shù)據(jù)是個什么東西
內(nèi)存中只是一串字節(jié)序列;字節(jié)只是0到255之間的數(shù)字組合;這些數(shù)字的真正含義取決于語言的類型系統(tǒng)。
例如,在C中,值為65的char型變量可能是字母“A”,值為65的int型變量是數(shù)字65——處理數(shù)據(jù)時請不要忘記這一點。這也是為什么大多數(shù)人在用布爾型變量做加法以查看True的數(shù)量時經(jīng)常出錯。
現(xiàn)在,讓我展示一下我最近看到的一個JavaScript里的例子:
console.log(true+true === 2);> trueconsole.log(true === 1);> false
如果你的數(shù)據(jù)具有模式(schema),請使用結(jié)構(gòu)(structure)來保留它
你可能會想要使用列表(或元組,如果你用的語言允許的話)來保存數(shù)據(jù),如果它很簡單——比如說,只有2個字段。
但是如果你的數(shù)據(jù)有一個模式(schema),有一個固定的格式——你應(yīng)該每次都使用一些結(jié)構(gòu)來保存它,不管是用struct還是class。
理解并保持cargo cult的方式
“Cargo cult”是一種理念,如果其他人那樣做了,那么我們也可以。大多數(shù)情況下,cargo cult只是對一個問題的偷懶的解決方法:
“如果X這樣做了,我們?yōu)槭裁匆紤]如何正確存儲我們的用戶數(shù)據(jù)?”“如果有某巨頭公司是這樣存儲數(shù)據(jù)的,那么我們也可以”。“如果有某巨頭公司支持這種做法,那就說明這種方法很好?!?.....
不要管所謂的“合適的生產(chǎn)力工具”,你只需要盡力去push進(jìn)程
“合適的生產(chǎn)力工具”其實意味著:對于某件事情,有一個正確的工具和一個錯誤的工具——例如,應(yīng)該使用另外的某種語言/框架而不是當(dāng)前的語言/框架。但每當(dāng)我聽到有人提到這個詞時,他們都是在試圖推銷他們喜歡的語言/框架,而不是合適的語言/框架。
“正確的工具”比你想象的更明顯
也許你當(dāng)前的項目需要處理一些文本,也許你很想說“讓我們用Perl吧!”,因為你知道Perl在處理文本時非常強大。
但你漏掉了哪一點呢?你在一個C的團(tuán)隊工作,每個人會C,而不是Perl。
當(dāng)然,如果它是一個小的、“放在角落”的不起眼的項目,那么用Perl就可以了——但如果它對公司很重要,那么最好還是用C。
PS:你的英雄項目(本文稍后將詳細(xì)介紹)可能因此而失敗。
不要跟你項目之外的事情糾纏
有時人們會試圖改變外部庫/框架,而不是使用適當(dāng)?shù)臄U展工具——例如,直接對WordPress或Django進(jìn)行更改。
這樣很容易讓你的項目秒癱瘓,變得無法維護(hù)。一旦發(fā)布了新版本,你就必須與主項目保持同步,并且很快就會發(fā)現(xiàn)改動不再適用,你將把外部項目留在一個舊版本中,且充滿了安全漏洞。
數(shù)據(jù)流動比模式更重要
(再次說明,這僅僅是個人意見)當(dāng)你了解數(shù)據(jù)如何在代碼中流動時,你的代碼質(zhì)量就會更上一層樓,這比無腦應(yīng)用一堆設(shè)計設(shè)計模式(design pattern)好多了。
設(shè)計模式是用來描述解決方案的,但它不能找到解決方案
(同樣,個人觀點)大多數(shù)時候我看到設(shè)計模式被應(yīng)用的時候,它們被用作尋找解決方案的一種方式,所以你最終會扭曲一個解決方案——有時候,甚至是扭曲問題本身——來適應(yīng)某個設(shè)計模式。
首先,解決你的問題,找到一個好的解決方案,然后你可以檢查模式,以提供如何命名該解決方案的思路。
我經(jīng)??吹竭@種情況發(fā)生:我們有這個問題;一個設(shè)計模式接近正確的解決方案;讓我們使用這個設(shè)計模式吧;現(xiàn)在我們需要在適當(dāng)?shù)慕鉀Q方案基礎(chǔ)上添加很多東西以適應(yīng)這個設(shè)計模式......
學(xué)習(xí)函數(shù)式編程的基礎(chǔ)知識
你不需要徹底搞懂“什么是一個單子(monad)?”和“這是一個函子(functor)?”等問題,但要知道不能一直改變數(shù)據(jù)——使用新值創(chuàng)建一個新元素(將數(shù)據(jù)視為不可變),并盡可能使函數(shù)/類不保留某些內(nèi)部狀態(tài)(純函數(shù)/類)。
認(rèn)知成本是可讀性的殺手
“認(rèn)知失調(diào)”是一種高大上的說法,但其實意思就是“我需要同時記住兩個(或更多)不同的東西才能理解這一點?!卑堰@些不同的東西保留在你的頭腦中會產(chǎn)生成本,并且事物之間關(guān)聯(lián)性越小,這種成本就越會不斷積累(因為你必須把所有這些都記在腦子里)。
例如,將布爾值相加以計算True的數(shù)量就是一種輕微的認(rèn)知不協(xié)調(diào);如果你正在閱讀一段代碼并看到一個sum()函數(shù),你知道它是列表中所有數(shù)字的總和,你就預(yù)料到列表由數(shù)字組成,但我看到過人們使用sum函數(shù)計算布爾值列表中的True的數(shù)量,這也太特么容易讓人糊涂了吧。
Magical Number 7 ,正負(fù)二(7+-2的范圍內(nèi))
“magical number”是一篇心理學(xué)文章中提到的概念,意思指人們可以在同一時間記住的事物的數(shù)量。如果你有一個函數(shù),它調(diào)用一個調(diào)用函數(shù)的函數(shù),該函數(shù)又調(diào)用一個調(diào)用函數(shù)的函數(shù)……再往下說下去你可能要瘋。
想一想:我會得到這個函數(shù)的結(jié)果,然后將它傳遞給第二個函數(shù),得到它的結(jié)果,然后傳遞給第三個函數(shù)。但是:
當(dāng)今,心理學(xué)家更多地談?wù)揗agical Number 4,而不是7。
把函數(shù)當(dāng)成寫作文(如“我將調(diào)用該函數(shù),然后該函數(shù),然后該函數(shù)......”),而不是函數(shù)作為主體(如“該函數(shù)將調(diào)用該函數(shù),將調(diào)用該函數(shù)......”) 。
走捷徑挺nice的,但只是在短期內(nèi)如此
許多語言、庫、框架都有縮短工作時間的方法,減少了需要你打字輸入的內(nèi)容。但是,稍后,這些東西會讓你栽跟頭,你將不得不棄用這些捷徑并懂得人間正道是滄桑的道理。
因此,在使用之前,先了解那些捷徑是如何做事情的。
你不需要先用難的方式寫東西然后再用捷徑的方式清理:你只需要走捷徑在后臺做事情,所以你至少知道使用它可能出錯的地方在哪里,以及如何用非捷徑方式替換它。
抵制“輕松”的誘惑
當(dāng)然IDE會幫助你完成大量的自動填充并讓你輕松構(gòu)建你的項目,但是你明白發(fā)生了什么嗎?你了解你的構(gòu)建系統(tǒng)是如何工作的嗎?如果你必須在沒有IDE的情況下運行你的程序,你知道該怎么做嗎?如果沒有自動填充你能記住你的函數(shù)名嗎?是不是有辦法打破/重命名一些東西讓它們更容易被理解?......
要對窗簾后面的東西保持好奇。
總是在你的日期中使用時區(qū)
處理日期時請始終添加時區(qū)。你的計算機時區(qū)和生產(chǎn)服務(wù)器時區(qū)(或其中一個實例時區(qū))將始終存在問題,你將花大量時間來調(diào)試為什么界面總是顯示錯誤的時間。
總是使用UTF-8
在日期上出現(xiàn)的問題,也將出現(xiàn)在對字符的編碼上。所以時刻記得將你的字符串轉(zhuǎn)換為UTF8,將它們作為UTF8保存在數(shù)據(jù)庫中,在你的API上返回UTF8。
你可以轉(zhuǎn)換為任何其他編碼方式,但UTF8贏得了編碼戰(zhàn)爭,因此更容易保持這種方式。
從笨辦法開始
遠(yuǎn)離IDE的一種方法是“從笨辦法開始”:只需獲取編譯器并獲得一個帶有代碼突出顯示的編輯器(任何編輯器),做你該做的事情:寫代碼,構(gòu)建它,運行它。
不,這并不容易。但是當(dāng)你跳進(jìn)某個IDE時,你看到某個按鈕只會簡單地想,“是的,它會運行它”(順便說一下,這正是IDE所做的)。
日志用于事件,而不是用戶界面
很長一段時間,我使用日志向用戶顯示正在發(fā)生的事情——因為,你知道的,使用單個東西會更容易一些。
使用標(biāo)準(zhǔn)輸出通知用戶發(fā)生了什么事件,使用標(biāo)準(zhǔn)錯誤通知用戶有關(guān)錯誤的信息,但使用日志來捕捉可以在日后輕松處理的東西。
將日志想成是你必須解析以便在那時從中提取一些信息的東西,而不是用戶界面,它不一定要是讓人看得懂的明文。
Debugger們被高估了
我常常聽到很多人抱怨,不能Debug的編輯器有多糟糕。
但是當(dāng)你的代碼投入生產(chǎn)時,你無法運行你喜歡的Debugger;哎呀,你甚至不能運行自己喜歡的IDE;但是logging......logging隨處都可以運行......你可能在崩潰時沒有所需的信息(例如,不同的日志記錄級別),但你可以啟用日志記錄以便稍后找出某些內(nèi)容。
不是說Debugger們很糟糕,只是它們沒有大多數(shù)人想象的那么有用。
始終使用版本控制系統(tǒng)
“這只是個隨便寫的破程序,我只想學(xué)點東西”——這不是一個不使用版本控制系統(tǒng)的好借口。如果你從一開始就使用版本控制系統(tǒng),那么當(dāng)你做了一些傻事時,撤銷會更容易。
每次提交一個更改
我見過人們編寫提交消息,如“修復(fù)了問題#1,#2和#3”。除非所有這些問題都是重復(fù)的——那么其中兩個應(yīng)該已經(jīng)不存在——它們應(yīng)該分三次提交,而不是一次。
嘗試在每次提交中只進(jìn)行一項更改(并且這里的更改并不是“一個文件更改”; 如果一個更改需要更改三個文件,你應(yīng)該將這三個文件一起提交。想想“如果我還原這一步,那是什么消失了?“)
當(dāng)你過度交換時,“git add -p”是你的朋友
(僅限Git的主題)Git允許使用“-p”部分合并文件,這允許你僅選擇相關(guān)更改并不管其他更改——可能是為了新的一項提交。
按數(shù)據(jù)/類型組織項目,而不是功能
大多數(shù)項目的組織如下:
.+-- IncomingModels| +-- DataTypeInterface| +-- DataType1| +-- DataType2| +-- DataType3+-- Filters| +-- FilterInterface| +-- FilterValidDataType2+-- Processors| +-- ProcessorInterface| +-- ConvertDataType1ToDto1| +-- ConvertDataType2ToDto2+-- OutgoingModels +-- DtoInterface +-- Dto1 +-- Dto2
換句話說,它們使數(shù)據(jù)按功能分類組織(所有傳入的模型都在同一目錄/包中,所有過濾器都在同一個目錄/包中,依此類推)。
這很好,很有效。但是當(dāng)你按照數(shù)據(jù)進(jìn)行組織時,將項目拆分到較小的項目中會更容易——因為在某些時候,可能你想要做的與你現(xiàn)在正在做的幾乎一樣,只是有些許小的差異。
.+-- Base| +-- IncomingModels| | +-- DataTypeInterface| +-- Filters| | +-- FilterInterface| +-- Processors| | +-- ProcessorInterface| +-- OutgoingModels| +-- DtoInterface+-- Data1| +-- IncomingModels| | +-- DataType1| +-- Processors| | +-- ConvertDataType1ToDto1| +-- OutgoingModels| +-- Dto1...
現(xiàn)在,你可以創(chuàng)建一個僅處理Data1的模塊,另一個僅適用于Data2的模塊,依此類推,然后你就可以將它們分解為獨立的模塊了。然后當(dāng)你有另一個項目也有Data1但也處理Data3時,你可以重新用上Data1模塊中的大部分內(nèi)容。
創(chuàng)建庫
我已經(jīng)見過很多項目要么創(chuàng)建一個包含不同項目的大型存儲庫,要么保留不同的分支,這些分支不被用作以后加入主要開發(fā)區(qū)域的臨時環(huán)境,而作為一個小而不同的東西延續(xù)下去了(從上文講到的模塊化角度來說,請想象一下,我沒有構(gòu)建一個重用Data1類型的新項目,而是擁有一個具有完全不同的主函數(shù)和Data3類型的分支)。
為什么不將公共部分拆分出來加到庫里并在不同的項目中應(yīng)用它呢?
原因在于,大多數(shù)情況下,“因為人們要么是不知道如何創(chuàng)建庫,要么是他們擔(dān)心如何將這些庫‘發(fā)布’到依賴源中而不致泄露(因此也許你也應(yīng)該了解你的項目管理工具如何檢索依賴項,以便你可以創(chuàng)建自己的依賴項存儲庫)?!?br/>學(xué)會監(jiān)控
從前,為了理解系統(tǒng)的行為方式,我添加了大量的指標(biāo):輸入速度、輸出速度、中間滯留數(shù)量、已處理的數(shù)量......這樣可以很好地了解系統(tǒng)的行為方式:速度在下降嗎?如果是的,那我可以檢查正在輸入系統(tǒng)的內(nèi)容以了解原因。在某些時候下降是否正常?......
事實上,在此之后,試圖查明一個沒有任何監(jiān)控的系統(tǒng)有多健康就變得很奇怪,僅使用“是否應(yīng)答請求”來檢查系統(tǒng)運行狀況不再適用。
盡早添加監(jiān)控將有助于你了解系統(tǒng)的行為方式。
config文件是個好東西
想象一下,你編寫了一個函數(shù),你必須為它傳入一個初始值才能開始運行(例如,一個推特用戶帳戶ID)。但是后來你又必須用兩個值來做,所以你就直接用另一個值再次調(diào)用了該函數(shù)。
使用配置文件更有道理,只需使用兩個不同的config文件運行應(yīng)用程序兩次。
命令行選項很奇怪,但很有幫助
如果你將某樣?xùn)|西移動到config文件,你還可以通過添加選項來選擇配置文件并公開它來幫助用戶。
現(xiàn)在對每種語言的命令行選項都有一些庫可以處理,這將有助于你構(gòu)建一個良好的命令行,并為你的用戶提供一個標(biāo)準(zhǔn)的接口。
不僅僅是功能組成,還有應(yīng)用程序組成
Unix自帶“應(yīng)用程序只做一件事,并且把它做好”的理念。
如今,我說你可以使用一個帶有兩個配置文件的應(yīng)用程序,但是如果你需要兩個應(yīng)用程序的結(jié)果呢?那時你可以編寫一個應(yīng)用程序,用兩個配置文件讀取第一個的結(jié)果并轉(zhuǎn)換為單個結(jié)果。
即使是做APP,也要從原始的東西開始
APP的開發(fā)可能會涉及微服務(wù)——這很好——但微服務(wù)需要一些關(guān)于應(yīng)用程序如何通過線路(協(xié)議等)在彼此之間“對話”的想法。你不需要從那開始,應(yīng)用程序都可以從文件中寫入和讀取,這樣容易多了。
當(dāng)你了解了網(wǎng)絡(luò)是如何工作后,再通過電話進(jìn)行交談時可能會擔(dān)心的吧。
優(yōu)化是面向編譯器的
假設(shè)你需要更高的性能,你可能很想看看你的代碼和“可以在這里擠出更多性能的東西”或“如何在這里刪除幾個循環(huán)來獲得更多速度”。
好吧,猜猜怎么著?編譯器知道如何做到這一點。智能化的編譯器甚至可以刪除你的部分代碼,因為它始終會生成相同的結(jié)果。你需要做的是為代碼考慮更好的設(shè)計,而不是如何改進(jìn)當(dāng)前代碼。
代碼是為了讓人類閱讀的、優(yōu)化面向編譯器的,因此,找到一種智能的方法來解釋你在嘗試做的是什么(在代碼中)而不是使用更少的話語來表述。
通過懶惰(評估)
Lisp很久以前就這么做了,而現(xiàn)在大多數(shù)語言都是這樣做的。
例如,Python有yield語句,它將停止當(dāng)前函數(shù)的執(zhí)行并立即返回值,只有在再次調(diào)用該函數(shù)時才會產(chǎn)生新值。如果你將使用yield的函數(shù)鏈接起來,則不需要像保留返回列表的函數(shù)那樣多的內(nèi)存。
在團(tuán)隊/工作上
code review并不是為了彰顯風(fēng)格
花點時間進(jìn)行code review,指出架構(gòu)或設(shè)計問題,而不是代碼樣式(風(fēng)格)問題。沒有人真正喜歡那些在code review中寫“你在這一行中留下空白了”或“括號前缺少空格”的人。
現(xiàn)在,如果你確實發(fā)現(xiàn)了架構(gòu)或設(shè)計問題,那么你可以順便說一下代碼風(fēng)格問題。
代碼格式化工具還可以,但它們也不是無往不勝的
團(tuán)隊可能想要避免在code review中討論樣式,因而可能會考慮使用代碼格式化工具在提交之前自動格式化代碼。
是的,這部分解決了這個問題,但是還有一個小問題:我們?nèi)祟惒幌裼嬎銠C那樣能靈活地閱讀代碼,計算機可讀的內(nèi)容可能無法被人閱讀。當(dāng)然,有人試圖在有利于人類閱讀的方面創(chuàng)造一些啟發(fā)式方法,但這并不意味著這些方法正確。
如果你使用代碼格式化工具,請使用它來找出最能更改代碼的位置。你可能需要簡化這一部分的代碼,以避免它出現(xiàn)混亂。
代碼風(fēng)格:遵循它就是了
如果你的項目具有已被定義的代碼樣式,則必須遵循它。有時可能不清楚(“這個結(jié)構(gòu)/類應(yīng)該是單數(shù)還是復(fù)數(shù)”?),但請盡力遵循它。
...除非代碼樣式是Google Code樣式
(完全個人觀點,你不同意也沒關(guān)系)每次谷歌發(fā)布自己的編碼風(fēng)格,都是一場垃圾焚燒。社區(qū)之前采用了更好的風(fēng)格方式,谷歌帶來一個與此很不相同的的風(fēng)格,只是為了能使其在自己名下。
C / C ++只有一種編碼風(fēng)格:K&R
(再次,完全個人意見)其他所有編碼風(fēng)格都是錯誤的。(笑)
Python只有一種編碼風(fēng)格:PEP8
社區(qū)(大部分)使用PEP8風(fēng)格,遵循它,那么你的代碼可以順利地與生態(tài)系統(tǒng)中的其他部分集成。
顯式優(yōu)于隱式
你知道什么是有史以來最糟糕的函數(shù)名稱之一嗎?sleep()。
睡了多久?是幾秒還是幾毫秒?
對你使用的東西要表達(dá)地明確一些,sleepForSecs和sleepForMs并不好,但比一個單純的sleep更好。
(當(dāng)你編寫應(yīng)用程序命令行界面或其配置文件時,請考慮這一點。)
(我可以在這里拋出整個“Python之禪”,但我正在努力專注于講個人的,直接的體驗。)
公司想要專才,但全才在公司待的時間更長
如果你對單一語言了解很多,那么它可能會讓你更容易找到一份工作,但從長遠(yuǎn)來看,一門語言的使用可能會消失,你就需要再學(xué)一門別的語言了。適當(dāng)了解許多門其他語言有助于長遠(yuǎn)發(fā)展,更不用說這可能有助于你想出更好的解決方案了。
“一種不能影響你對編程的思考方式的語言,不值得了解?!薄狝lan Perlis
很長一段時間,我遵循著一個簡單的編程規(guī)則:我在家里用來玩的語言不應(yīng)該是我在工作中使用的語言。這使我能夠接觸到后來我在工作代碼庫中應(yīng)用的新內(nèi)容。
我通過編寫Rust代碼了解了泛型如何在Java中工作;我理解了Spring如何完成依賴注入因為我之前有學(xué)過如何在C++中實現(xiàn)。
心中有用戶
想一想你將如何使用你從用戶那里收集的數(shù)據(jù)——這在當(dāng)今“隱私”變?yōu)橐环N奢侈的時代更為普遍。
如果你捕獲任何使用數(shù)據(jù),請記住保護(hù)它免遭未經(jīng)授權(quán)的使用。
處理用戶數(shù)據(jù)的好安全方法是壓根不捕獲它
你可以確定,在某些時候,數(shù)據(jù)會因某些安全漏洞或人為干擾而泄漏。如果你沒有捕獲任何用戶數(shù)據(jù)——或以匿名方式存儲——你將不會遇到任何問題。
記下來那些“讓我花了一個多小時才解決的愚蠢失誤”
我嘗試過,但從未真正建成過一個列表來記錄那些需要花一個多小時才能修正的失誤,這種失誤僅僅是“忘了添加依賴”或“添加注釋”一類,可我不止一次與這些愚蠢的失誤作斗爭了。
但你應(yīng)該嘗試保留一個列表來記錄那些讓你花了一個多小時才解決的愚蠢失誤,因為有了它以后你解決起這類失誤來要更快一些。
如果它無法在你的計算機上運行,那么你就有麻煩了
我看過很多系統(tǒng)永遠(yuǎn)無法在孤立的計算機上運行,比如開發(fā)人員工具,因為系統(tǒng)需要在專門的環(huán)境中運行。
這真的會扼殺生產(chǎn)力。
如果你的系統(tǒng)將在一個專門的環(huán)境中運行——包括“云”——那就去找可以抽象你所用之物的東西。例如,如果你使用的是AWS SQS(隊列),請找到一個可以抽象隊列工作方式的庫,這樣你也可以使用RabbitMQ了,就可以在你自己的計算機上輕松運行了。
如果你使用的是非常專門化的東西,你可能必須自己編寫抽象邏輯了,將其與主系統(tǒng)隔離,這樣你就可以安心開發(fā)主要產(chǎn)品。
個人生活
該停下來的時候,就停下來吧
要知道自己什么時候?qū)懖粍哟a了,要知道自己什么時候?qū)W不動了......不要強迫自己,不然將來只會使事情變得更糟。
有一次偏頭痛時(不嚴(yán)重,但也不算輕),我試著堅持繼續(xù)寫代碼。結(jié)果第二天,當(dāng)我好點了的時候,我不得不將大部分重寫,因為前一天寫的實在太爛了。
CoC保護(hù)的是你,而不是別人
當(dāng)你開始使用任何語言/庫/框架時,請檢查他們的CoC。這會保護(hù)你,不會讓你因為沒能立馬就上手而被別人懟,而不是阻止你告訴別人你的想法。
我提這個因為很多人抱怨CoC,但是他們忘記了正是CoC使他們能加入任何項目而不被白眼,被說是“新手菜雞”或“先去看完文檔,否則別來煩我們”。
此外,請記住,大多數(shù)反對CoC的都是那些希望能直接責(zé)罵任何人的人。
學(xué)會說不
有時,你不得不說:不,我不能這樣做;不,在這個時間之前完不成;不,我覺得不能做到這一點;不,我寫這個感覺不舒服。
有一次我不得不對我們的CTO說:“好的,我會做的,但我想說明,我不認(rèn)同我們正在做的事情?!弊詈?,APP剛好就因為我們做的事情而被禁止了。
你負(fù)責(zé)你代碼的使用
這很難,非常非常難,這就是“自由”和“責(zé)任”之間的區(qū)別。
寫代碼沒有錯,例如,用于捕捉人臉并檢測其種族的軟件,但你必須考慮它將被用在何處。
當(dāng)還沒完成時,不要說“已經(jīng)完成了”
你厭倦了一遍又一遍地運行同樣的事情。有時候即使你記得會發(fā)生一些小故障,但是因為你累了,你就告訴大家“已經(jīng)完成了”。
——不要那樣做。有人會在第一次運行時就遇到故障并立即告訴你它不work。
你將從痛苦中了解你自身
我們對無法編譯的代碼會感到很挫敗,也會對客戶來回詢問一些事情而感到憤怒。當(dāng)發(fā)生這種情況時,我們會遷怒于他人。
生活就是如此,這些都是難免的。
人們之所以會對代碼/架構(gòu)感到生氣/煩惱,是出于關(guān)心
你會發(fā)現(xiàn)自己處于硬幣的另一面:你將描述一些解決方案,人們會對某些解決方案感到惱火/生氣。當(dāng)人們關(guān)心產(chǎn)品/代碼時,他們往往會有這種反應(yīng)。
“是的,你不喜歡那種安靜的解決方案,因為你太在意了”,這是別人對我的最暖心的贊美之一。
從你的煩惱中學(xué)習(xí)
你會煩惱、生氣、沮喪和憤怒,你會看到人們因為這些情緒而陷入困境。所以你必須了解它,不要忽視它。
我從教訓(xùn)中學(xué)到的一件事是,當(dāng)我感到沮喪時,我會變得非常有侵略性?,F(xiàn)在,當(dāng)我注意到我開始感到沮喪時,我會向其他人尋求幫助??吹狡渌艘苍谂鉀Q你的問題,這真的很治愈的感覺。
注意人們對你的反應(yīng)
我有一個“憤怒男人的休息臉”那樣一種臉。
有時候我一問問題,人們就會稍微后退——就好像我在說他們的解決方案是錯的一樣。那時我必須補充道,“我不是說這是錯的,我只是有點困惑”。
這可能會幫助你避免陷入困境。
學(xué)會識別那些人格有毒的人,并遠(yuǎn)離他們
你會發(fā)現(xiàn)那些人,即使他們不對你的事情竊竊私語,他們也會對所有事情都說壞話——甚至是說其他人的壞話——而且是公開地說。
遠(yuǎn)離那些人。
你不知道這種態(tài)度會讓你情緒多么失落。
謹(jǐn)防微觀侵略
“微觀侵略”(Micro-aggressions)是每次小劑量的侵略性評論。就像有人一直稱你為“那個人”或看似人畜無害地評論你在某些政策中的立場。
這種行為很難反擊,因為PR不會聽從你說的話認(rèn)為他們這是在攻擊你。而且,這種行為很難被發(fā)現(xiàn),因為它們看起來足夠小,但是它們會堆積起來,到最后你會一次爆發(fā)你所有的憤怒。
最好遠(yuǎn)離,盡可能避免接觸。
不,我不認(rèn)為這樣的人是“會改正的”
(個人意見)有人可能會說“嘿,也許如果你跟那個人說一下,他們就不會那么做了”。
就個人而言,我認(rèn)為他們不會。這種東西對他們來說已經(jīng)太久了,他們覺得很自然,而且大多數(shù)情況下,你才是做錯的那個人(因為沒有g(shù)et到他們是在開玩笑,例如,真正的“薛定諤的混蛋”風(fēng)格。)
只有當(dāng)你意識到自己是那類有毒的人/微侵略者時,才有可能自己改正
除非你意識到你表現(xiàn)得像一個有毒的人或是在微觀攻擊某人,并且意識到你實際上是在搞破壞,不然沒有辦法改變這些性格特征(再次強調(diào),個人觀點)。
......大多數(shù)情況下,聽到別人批評的聲音可能會讓你覺得,“他們跟我過不去!”
英雄項目:總有一天你必須做的事情
“英雄項目”是你個人認(rèn)為可以解決項目中一系列問題的項目/規(guī)范變更/框架。它可能是不同的架構(gòu)、新的框架甚至是新的語言。
這意味著你將花費你的空閑時間來寫一些已經(jīng)被應(yīng)用的/已經(jīng)存在的東西,只是為了證明自己的一個觀點。
有時它會告訴你錯在哪里。
(但不管如何,你都從中得到一些東西。)
不要混淆“英雄項目”與“英雄綜合癥”
我至少見過兩類這種情況:有人聲稱項目離了他們就玩不轉(zhuǎn),或者聲稱他們不需要任何人的幫助。
這是“英雄綜合癥”,認(rèn)為有人可以自己獨當(dāng)一面。
不要做那種人。
知道何時該果斷辭職
你告訴你的老板你沒有按時完成某項工作,因為一些意料之外的原因,他卻朝你發(fā)飆。
你的一個同事不斷微觀攻擊你。
另一個是那個一直在做愚蠢惡作劇的家伙,不停說廢話以及在背后議論其他的小組。
第三個人總是抱怨說,當(dāng)他不在時,大家的工作就都搞不定了。
現(xiàn)在是時候開始投簡歷了,無論你目前的薪水有多高或項目有多棒。
......除非你想在四十多歲時還經(jīng)常被別人惹惱。
IT世界是一個非常小的“蛋”
我們這里有這么一種說法:“某事物的世界是一個小蛋”,這意味著你生活在一個小世界里,世界整體很小。
IT世界真的很小。
記住今天與你一起工作的人,你可能會在15年后與他重逢,這期間你們可能已經(jīng)各自換過三四份工作了。
你會在中途遇到很多其他的I.T.人。
他們會談?wù)撟约骸?br/>無論你說什么/做什么,都會被大家談?wù)摰剑粋€人會聽到并傳遞給另一個公司,這個公司將傳遞給其他人,再把故事傳遞給另一家公司,然后突然,你意識到了,當(dāng)?shù)貨]有人會雇用你了,因為每個人都知道你搞砸了一個項目或捶了一個同事的臉。
紙質(zhì)筆記實際上很有幫助
我曾經(jīng)多次嘗試“無紙化”。在某些時候,我確實不需要用紙了,但是到最后,在你旁邊如果有一個小筆記本和一支筆來讓你寫下你需要發(fā)送數(shù)據(jù)的那個該死的URL的話,真的挺得勁的。
Trello非??幔玃ost-it更好
沒有什么比在桌子上放一堆Post-it更能顯出你是這樣一個人了:“我真的很忙,但我忙中又井井有條”。
在博客中記錄你笨手笨腳的解決方案仍然比什么都不寫要好
你可能會覺得“我沒有準(zhǔn)備好談?wù)撨@個”或“這太愚蠢了我不應(yīng)該談?wù)撨@個”。
創(chuàng)建一個博客,發(fā)布你那些看起來笨手笨腳的解決方案。不管怎么說,它們肯定還是比某些人的解決方案更聰明。
此外,稍后再回來寫下更好的解決方案,挑戰(zhàn)你自己之前的方案。
以顯示你的成長。
除此之外,博客還可以幫助你保存筆記或待辦事項。
...但請關(guān)閉評論
發(fā)布你笨手笨腳的解決方案的一個問題是,這會吸引一些只想惹毛你的人?!斑@太愚蠢了”,他們會說??赡軙腥苏f,“你好傻”,而他們不知道誰才真的傻。
把評論關(guān)了。不要讓那些人阻止你。
把你的笨手笨腳的解決方案發(fā)布到網(wǎng)上
不要只把那些“很酷,近乎好”的項目放到Github上,你完全可以表現(xiàn)出來,在某些時候,你只是初學(xué)者。
畢竟你總是可以隨時返回并修改代碼。
(或者說不要:我仍然擁有我的第一個Python項目的公共repo,看起來我剛剛將Java翻譯成Python,而不包含有Python特性的部分。)
列出“我不知道的事情”
著名物理學(xué)家理查德費曼保留了一本標(biāo)題為“我不知道的東西”的筆記本。
當(dāng)你發(fā)現(xiàn)一些看起來很酷的東西并且你想知道更多時,創(chuàng)建一個標(biāo)題為“我不知道的東西”的文件/注釋/任何內(nèi)容都行,然后記下你發(fā)現(xiàn)了的/弄清楚了的東西。
原文:https://blog.juliobiason.net/thoughts/things-i-learnt-the-hard-way/
當(dāng)前題目:三十年軟件開發(fā)之路:老碼農(nóng)的自我修養(yǎng)!
文章鏈接:http://jinyejixie.com/news/113994.html
網(wǎng)站建設(shè)、網(wǎng)絡(luò)推廣公司-創(chuàng)新互聯(lián),是專注品牌與效果的網(wǎng)站制作,網(wǎng)絡(luò)營銷seo公司;服務(wù)項目有軟件開發(fā)等
廣告
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源:
創(chuàng)新互聯(lián)