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