02.27 我從高級軟件工程師身上學到的那些經驗與教訓「轉」

一年之前,我開始在彭博擔任全職工作。從那時起,我就在構思這篇文章。我想象自己能夠在時機成熟時,把自己的想法都傾訴於紙端。但剛剛過去一個月,我就意識到這並非易事:隨著工作的推進,我忘掉了很多自己剛剛學到的東西。這些東西快速內化,使我的大腦開始欺騙自己,令我誤以為自己早就掌握了這些清晰記得的知識,或者是認定自己從未聽說過那些實際上是被忘記了的內容。

正因為如此,我才開始保留自己的日誌。每當遇到有趣的情況,我都會把它記錄下來。感謝坐在我身邊的高級軟件工程師們,我可以認真觀察他們在做什麼、與我的做法又有何區別。我們會經常結對編程,這能夠大大降低工作的難度。另外,在我們的團隊文化當中,“窺探”其他人的編碼過程並不是什麼不光彩的事情。每當我感覺有趣的事情要發生時,總坐很快轉過身去查看。這種敏銳,讓我總能快速弄清事情的來龍去脈。

下面來看看坐在一位高級軟件工程師身旁一年,我都學到了哪些重要經驗。

編寫代碼

如何命名



我在工作中接觸的第一項任務是開發一款 React UI。當時我們擁有一個主組件,用於容納其它所有組件。我喜歡在代碼當中加點幽默元素,所以我把它命名為 GodComponent。但在代碼審查時,我才意識到為什麼命名工作如此重要、也如此困難。

計算機科學領域有兩大難題:緩存失效、命名以及緩衝溢出錯誤。 -—— Leon Bambrick

我命名的每一段代碼都包含隱藏的含義。GodComponent?這個組件的含義,就是我會把所有不知道該放在哪的組件都放在這裡。它囊括一切。如果我把它命名為 LayoutComponent,後續我才會意識到它的作用就是佈局分配,其中不包含任何狀態。

我發現的另一項心得在於:如果其體積過於龐大,就像是這裡提到的包含大量業務邏輯的 LayoutComponent,那麼我就會意識到是時候進行重構了,因為通過名稱就能看出業務邏輯並不屬於這裡。但使用 GodComponent 這個名稱,我們無法判斷業務邏輯出現在這裡是否正常。如何命名集群?最好是在運行了服務之後再對集群進行命名,而後根據運行內容的變化重新調整名稱。最終,我們用自己的團隊名稱完成了集群命名。

函數命名的情況也是一樣。doEverything() 這個名字就不怎麼樣,其會帶來嚴重的後果。如果這項函數能夠完成所有操作,那麼我們將很難測試函數當中的某些特定部分。而且無論這個函數有多大,我們都會覺得很正常,畢竟它的名字可是叫“everything”。所以,最好的辦法當然是更換名稱,進行重構。

但是,我們在命名中也要考慮到另一類問題。如果名稱的含義太過具體並忽略了某些細微差別,該怎麼辦?例如,在 SQLAlchemy 當中調用 session.close() 時,關閉會話不會關閉基礎數據庫連接。(我本應該跳出手冊限制,對這項 bug 進行處理,具體情況將在調試部分進一步說明。)在這種情況下,我們可以考慮 x, y, z 這樣的名稱,而非 count(), close(), insertIntoDB(),從而避免為其分配隱含的意義。太過具體,會迫使我們不得不在後續維護時費力檢查這些函數到底是用來幹嘛的。

最後,當時的我從來沒想到命名會成為值得單獨一提的重要工作。

遺留代碼與下一位開發者

大家有沒有面對一段代碼時,感覺摸不著頭腦?他們為什麼要這麼寫?這完全說不通啊。

我就“有幸”接手過遺留代碼庫。其中就存在類似於“跟穆罕默德確認過情況之後,取消註釋”這類說明。這話是誰說的?穆罕默德又是哪位?

在這方面,我們不妨做個角色轉換——考慮下一位接手我所編寫代碼的開發者。他們同樣會發現我的代碼非常奇怪。同行評審能夠很好地解決這個問題。這不禁讓我想到上下文原則,即:瞭解團隊開展工作時的實際處境。

如果我跑去忙別的事,稍後又回來,我可能也無法重新建立這種上下文。我坐說,“當時我是怎麼想的?這根本沒道理……哦等等,我原來是這麼幹的。”

正是為了實現這種提示作用,文檔與代碼註釋才會如此重要。

文檔與代碼註釋

文檔與代碼註釋的意義,在於保持上下文並分享知識。

正如 Li 在如何構建良好軟件中所言,“軟件的主要價值並不在於生成的代碼,而在於生成代碼的過程中開發者所積累下來的知識。”

“軟件的主要價值並不在於生成的代碼,而在於生成代碼的過程中開發者所積累下來的知識。” - Li

我們當時有一套面向 API 端點的隨機客戶端,好像從來就沒人用過。那麼要不要把它刪除掉?畢竟這也屬於技術債務。

但如果我告訴大家,每年在特定的國家 / 地區,都會有 10 名記者將新聞發送到該端點,又該怎麼辦?我們是如何測試的?如果沒有文檔(也確實沒有),我們找不到答案。因此,我們刪除了該端點,並在對應時間點上發現了問題——這 10 名記者無法發送 10 份重要的報道,因為該端點已經不復存在。

瞭解產品的成員已經離開了團隊,現在只能靠代碼當中的註釋來解釋該端點的作用。

從這件事上,我意識到文檔是每個團隊都在努力解決、但卻難以奏效的問題。除了代碼文檔之外,與代碼相關的流程也有類似的情況。

時至今日,我們也沒有找到完美的解決方案。

原子提交

如果必須要回滾(而且回滾需求早晚會出現,我們將在測試部分具體討論),此次提交還是否有意義?

在刪除垃圾代碼時要充滿信心

刪除垃圾或者過時的代碼總是讓我感覺很不舒服。我總覺得以往的工作成果有種神聖不可侵犯的意義。我那時候認為,“在他們寫與這些代碼時,肯定是有所考量的。”這是一種傳統的理解方式,而且與第一性原則有所衝突。出於類似的理由,我在每年進行代碼審查與清理時也是困難重重。這樣的糟糕習慣,讓我吃了不少苦頭。

我曾經嘗試調整代碼問題,也有些老成員習慣於繞過這些代碼。但刪除,刪除聽起來更嚴重正經。一個永遠用不上的 if 語句、一個永遠用不上的函數,會在我的一聲令下徹底消失,這樣不好。因此,我更多是把自己的函數覆蓋在上面。但這並沒有減少技術債務,只是增加了代碼的複雜性與誤導性。如此一來,後繼者將更難把這些片段以有意義的方式拼湊起來。

我現在採取的方式是:總會存在我們無法理解的代碼,也總會存在我們永遠不會使用的代碼。刪除這些永遠不會使用的代碼,但對無法理解的代碼保持謹慎的態度。

代碼審查

代碼審查是學習中的重要組成部分。審查的過程,就是從編寫代碼、到了解如何更好地編寫代碼的反饋循環。我們自己的編碼思路,跟其他人的編碼思路有何不同?我在每一次代碼審查時都會問自己:“他們為什麼要這樣做?”如果實在找不到合理的答案,我就會跟他們當面聊聊。在第一個月的過渡期結束之後,我開始瘋狂地從同事的代碼當中查找錯誤(當然,他們也不會放過我)。真的很瘋狂,這也讓評審工作變成一項有趣的調劑——或者說像是一種遊戲,能夠改善我們編碼水平的小遊戲。

我的心得:在理解代碼作用之前,不要輕下斷言。

我從高級軟件工程師身上學到的那些經驗與教訓「轉」

測試

我特別喜歡測試這項工作,事實上如果不加測試,我根本就不願意直接在代碼庫中編寫代碼。

如果您的整個應用程序只需要執行一項任務(我在學校裡的實驗性項目就是這樣),那麼手動測試即可解決問題,我以前也一直習慣於這種方式。但是,當應用程序當中包含上百種功能,情況又會如何?我不想拿出大量時間挨個測試,而且我也知道自己肯定會忘掉某些需要測試的部分。這絕對會是一場噩夢。

這時候,我們就該請出測試自動化方案了。

在我看來,測試跟記錄文檔差不多。測試的過程,就是記錄我對於代碼的假設是否正確的過程。測試會告訴我,我自己(或者是當初寫下代碼的開發)當時希望代碼如何運行,以及認為哪裡有可能出問題。

因此,現在再編寫測試時,我會牢記以下兩點:

  1. 演示如何使用我正在測試的類 / 函數 / 系統。
  2. 展示我認為可能出問題的部分。

第一條相信很多朋友都能理解,畢竟在大多數情況下,我們需要測試的其實是行為,而非實現。但我個人總會忽略第 2 條,即 bug 可能出現在哪裡。

因此,每當我發現 bug 時,我都會確保代碼修復程序在相應的測試(也就是迴歸測試)當中記錄下其它有可能引發錯誤的方式。

當然,編寫這類測試本身並不能提供代碼質量,只有真正編寫代碼才會真正影響質量。不過我從閱讀測試結果當中獲得的見解,確實能夠幫助自己編寫出更好的代碼。

這就是測試的宏觀意義。

除此之外,測試還肩負著另一項重要使命:確定部署環境。

大家可能擁有完美的單元測試,但如果沒有進行系統測試,就有可能發生以下情況:

我從高級軟件工程師身上學到的那些經驗與教訓「轉」

鎖到底是好的,還是壞的?

對於經過良好測試的代碼也是如此:如果您的機器上沒有其需要的庫,代碼就會崩潰。

  • 您開發所在的機器環境。(「一切都能在我的機器上正常運行!」)
  • 您測試所在的機器環境。(可能就是您開發所使用的那臺機器。)
  • 最後,您部署所在的機器環境。(請一定換一臺別的機器。)

如果測試與部署機器間的環境不匹配,那一般都會出點問題。而這,正是部署環境的意義所在。我們在自己的機器上使用 docker 構建本地開發環境。

在這套開發環境當中安裝有一組庫(及開發工具),我們則以此為基礎安裝已經編寫完成的代碼。所有與其它依賴系統相關的測試,都在這裡完成。

然後是 beta 測試 / 分段環境,其與生產環境完全一致。

最後是生產環境,也就是負責運行代碼併為實際客戶提供服務的機器。

我們的基本思路是努力捕捉那些不會在單元與系統測試中出現的錯誤。例如,請求與響應系統之間的 API 不匹配問題。

我猜個人項目或者小型企業的情況可能有所不同,畢竟並不是每個人都有資源來設置自己的一套基礎設施。但是,如果大家願意使用 AWS 以及 Azure 等雲服務,這裡提到的方法仍然適合各位。大家可以為開發以及生產環境設置單獨的集群。AWS ECS 利用 docker 鏡像進行部署,因此各環境之間相對一致。比較棘手的部分,就是如果與其它 AWS 服務順利整合。例如,我們是否從正確的環境中調用了正確的端點?

大家甚至可以更進一步:為其它 AWS 服務下載備用容器鏡像,並利用 docker-compose 命令設置完整的本地環境。這樣能夠加速反饋循環。

如此一來,當我的附帶項目啟動並開始運行之後,我就能積累到更多經驗心得。

消除風險

所謂消除風險,就是在部署代碼的過程中儘可能降低風險水平的一種藝術。

那麼,我們可以採取哪些措施來消除災難性後果?

如果我們希望推出的一項突破性的變更,那麼一旦出現問題,如果確保業務儘可能不受嚴重影響?

  • “我們不需要對所有的新變化進行全系統部署!”哦,是嗎……抱歉,我沒想到。*

設計

很多朋友可能會問,我為什麼要把設計放在編寫代碼與完成測試之後?好吧,設計在實際流程中可能比較靠前,但如果沒有在當前環境中進行編碼與測試,我個人很難設計出一套能夠與特定環境完美適配的系統。在設計系統時,我們需要考慮很多問題,包括:

  • 資源使用量是多少?
  • 存在多少用戶?預計用戶會以怎樣的速度增長?(這將直接決定未來存在多少數據庫行)
  • 未來可能出現的陷阱是什麼?

我需要把這些轉化成一份名為“要求彙總”的清單。目前我還沒有積累到充分的相關經驗,根據計劃,明年我的工作內容就是著力解決這方面問題。

這個過程有點違背敏捷原則——在開始實施之前,我們能夠做出多少設計判斷?這是個權衡問題,我們需要選擇在怎樣的時間點上做什麼。我們什麼時候該深入剖析,又該在什麼時候退後一步進行規劃?

當然,這裡收集到的要求不需要也不可能真正全面。我認為把開發的過程納入設計考量也是完全可行的,例如:

  • 本地開發將如何運作?
  • 我們如何打包及部署?
  • 我們如何進行端到端測試?
  • 我們如何對這項新服務進行壓力測試?
  • 我們如何管理保密信息?
  • 我們如何實現 CI/CD 集成?

我們最近為 BNEF 開發出一套新的搜索系統,這方面工作也給了我們很大的啟發。我們必須設計出本地開發流程、思考 DPKG 方法(打包與部署),同時確保敏感信息不致外洩。

那麼,為什麼把保密信息引入生產環境可能引發問題?

  1. 我們不能將其直接添加到代碼當中,否則任何人都能夠直接查看。
  2. 是否應該將其作為環境變量,如同 12 因素應用所要求的那樣?這確實是個好辦法,但我們該如何實現?(在每次機器啟動時都訪問生產設備以填充環境變量,絕對是個痛苦的過程。)
  3. 將其部署為保密文件?那麼該文件來自哪裡?又該如何填充?

最後,整個過程當然不可能手動實現。

總而言之,我們使用了具有角色訪問控制機制的數據庫(只有我們的機器以及我們自己能夠與該數據庫通信)。我們的代碼會在啟動時從該數據庫處獲取保密信息。這部分信息能夠在開發、beta 測試以及生產環境之間順暢複製,且各自保留在對應的數據庫當中。

這裡要再提一句,AWS 等各家雲服務供應商提供的具體方案可能有所區別。大家不用為保密信息費多少心。獲取角色賬戶、在 UI 當中輸入保密信息,而後即可確保代碼在需要時獲取其內容。這些服務能夠顯著簡化整個流程,但之前的探索也並沒有白費——我很高興自己能夠真正理解並欣賞這種簡潔的解決方案。

在設計當中考慮維護要求

設計系統令人興奮,但維護呢?恐怕就沒什麼成就感可言了。

在維護系統的過程中,我想到了這樣一個問題:我們為什麼要進行系統降級,又該如何實現系統降級?

第一部分的答案是,因為總有人不愛丟棄陳舊的部分,而是添加新的部分。厚古而薄今,至少我自己就有這樣的毛病。

至於第二部分,答案是我們在進行系統設計時提出的終極目標,後續可能不再適用。在系統的發展當中,其很可能會以與設計假設相沖突的方式進行使用,這意味著我們當初做出的一切預期需求都不再有效。這時候我們就需要後退一步,層層剝離那些不再適用的部分。

目前,我至少知道三種能夠降低降級率的辦法。

  1. 保證業務邏輯與基礎設施彼此分離:一般來說,需要降級的往往基礎設施部分——例如使用量增加、框架過時、出現零日漏洞等等。
  2. 圍繞維護需求設計流程。對新代碼與舊代碼採用同樣的更新手段,從而防止新舊之間出現差異,確保代碼整體保持“現代”特性。
  3. 始終堅持去掉一切不需要的 / 陳舊的代碼。

部署

我更傾向於把功能捆綁在一起,還是逐一進行部署?

這要取決於現有流程,但如果答案是捆綁部署,那麼很可能會引發後續問題。

這裡我們需要回答的問題是,我們為什麼要把功能捆綁起來加以部署?

  • 是因為部署需要耗費太多時間嗎?
  • 是因為代碼審查比較困難嗎?

無論是因為什麼原因,我們都需要解決瓶頸本身,而不是在部署方法上做出遷就。捆綁方式至少會帶來以下兩大弊端。

  1. 如果其中一項功能出了錯誤,就會阻止另一功能的執行。
  2. 這會提高風險水平,或者說導致發生問題的機率上升。

接下來,無論大家選擇哪一種部署流程,各位肯定是希望自己的機器能像耕牛一樣勤勤懇懇,而不是像寵物那樣動不動耍脾氣。機器必須吃苦耐勞,我們知道每臺機器上運行的是什麼,在宕機時又該如何恢復。一旦發生宕機,我們不會感到沮喪——啟動一臺新的就行。這些設備應該像放養的牛羊,而不是需要精心呵護的小貓小狗。

出現問題時

一旦出了問題——而且早晚肯定會出問題——我們的黃金法則就是儘可能降低對客戶造成的影響。

在出現問題時,我的第一反應就是解決問題。但事實證明,這並不是最高效的應對思路。相反,即使只是小小的問題,最高效的辦法其實是選擇回滾。返回之前能夠正常工作的狀態,這樣才能縮短客戶無法正常使用服務的時間窗口。

也只有這樣,我們才能安心查找錯誤並動手加以修復。

正如集群中的“故障”機器一樣,在嘗試判斷機器出了什麼問題之前,我們首先應該將其下線並標記為不可用。

我發現這確實是種反直覺的辦法,而且我的本能總會把自己帶離最佳解決途徑。

我覺得正是這樣的本能,逼迫我走上解決 bug 的漫長道路。有時候,引發問題的根源就是我編寫的代碼出了問題,而我會深入研究自己寫下的第一行代碼。這有點像深度優先搜索的過程。

如果最後證明是配置發生了變化,而我沒能及時調整功能本身,我就會非常生氣。因為這個錯誤太低級了,本不該發生。

從那時起,我的心得就是在深度優先搜索之前先來一輪廣度優先搜索,暫時不觸及頂級節點。我能利用自己手頭的資源確認哪些問題?

  • 機器還在運行嗎?
  • 安裝的代碼是否正確?
  • 配置是否到位?
  • 代碼是否使用到特定配置,例如代碼中的路由是否正確?
  • 架構版本是否正確?
  • 最後,再看代碼內容。

我們原本以為是 nginx 在機器上沒有正確安裝。但事實證明,只是配置文件被設置為 false。

當然,大多數情況下並不需要這麼麻煩。有時候,單靠錯誤消息就足以幫我快速找到存在問題的代碼。

當我找不出問題時,我會嘗試分步對代碼進行變更以查找可能的根源。變更的數量越少,找到真正問題的速度就越快。總之,請儘可能讓推理過程變得有跡可循,太過跳躍只會錯失線索。我現在還記得自己曾花了一個多小時解決幾個 bug:問題在哪?一般都是我忘了檢查的一些低級問題,例如設置路由、確保架構版本與服務版本匹配等等。這隻能說明我對自己使用的技術堆棧還不夠熟悉,因此需要通過犯錯誤的方式積累經驗。最終,我可以單靠直覺就判斷出為什麼代碼沒能正常運行。

戰爭故事

一邊是調整參數與查看統計數據,另一邊是修復底層問題根源。

如果沒有戰爭故事(war story,指一段令人難忘的經歷,往往涉及危險、困難或者冒險因素),這篇文章又怎麼會完整?我很喜歡回顧這類經歷,分享環節馬上開始。

這是個關於搜索與 SQLAlchemy 的故事。在 BNEF,我們需要處理大量由分析師們撰寫的研究報告。每當報告發布時,我們都會收到一條消息;在收到消息之後,我們會通過 SQLAlchemy 進入數據庫,獲取我們需要的全部信息,進行轉換,並將結果發送至 solr 實例進行索引。但這時候,我們發現了奇怪的 AF bug。

每天早上,連接數據庫的操作都會失敗,消息提示“MYSQL 服務器不存在”。有時候連下午都會出現這種狀況。由於下午時段的使用量最大,所以我首先進行了一番檢查。沒問題,機器的運行狀態一切正常。我們全天會向數據庫發出數千次請求,都沒有失敗。那麼,為什麼負載強度這麼低的情況反而會出問題呢?

哦,可能是我們在事務結束後沒有關閉會話?所以失敗其實來自同一段會話,只不過下一個請求出現在很長一段時間之後,這就引發了超時——因為此次服務器已經關閉了。快速查看代碼,我們通過上下文管理器檢查了每一次在 __exit__() 上調用 session.close() 的讀取操作。

經過一整天的排查,沒發現任何問題。在第二天早上,我又遇到了同樣的情況。錯誤發生的一秒之後,其他三項索引請求都成功了。這明顯就是會話未能正確關閉的典型表現。好了,相信大家能夠腦補出接下來的完整故事。

SQLAlchemy mysql 語言中的 Session.close() 無法關閉底層數據庫連接,除非使用 NullPool。是的,這就是修復方案。

引發這個 bug 的原因很簡單,這是因為我們不會在夜間以及午餐時段發佈研究報告。此外,我們也吸取到另一個教訓——大多數堆棧溢出問題的答案(我是從谷歌上查來的),正是 bug 本身會調整會話的超時時間,或者控制每條 SQL 語句所能發送數據量的參數。這些對我來說都沒有意義,因為它們與問題的根源無關。我檢查了查詢大小是否在限制範圍之內,而且由於會話本身正在關閉,所以也不會發生超時狀況。

我們當然可以把超時時間從 1 個小時增加到 8 個小時來快速“修復”這個 bug。但這顯然解決不了問題,到第二天早上,又會有研究報告引發的錯誤出現在我們面前。

一邊是調整參數與查看統計數據,另一邊是修復底層問題根源。這就是我們的日常生活。

監控

我之前從來沒想過監控也會歸自己管。坦白講,在接受全職編碼職位之前,我從來不管系統維護這些事。我只是構建系統,用上一個禮拜,然後再換一套系統。

現在,我日常使用的是兩套系統,其中一套擁有良好的監控機制,另一套的監管機制則比較差。通過實際體驗,我感受到了監控的重要意義。畢竟如果意識到問題,我又怎麼能解決問題呢?最差的情況,就是連客戶都發現 bug 了,我自己還矇在鼓裡。“我在做什麼?!我連自己的系統出了問題都不知道?”

我認為監控機制主要包含三大組件——日誌記錄、指標與警報。

日誌記錄以代碼的形式存在,類似於人類記錄,這是一種漸進的過程。

我們可以找到需要監控的內容,記錄這些內容,同時運行系統。隨著時間的推移,我們可能會發現自己缺少某些解決 bug 所需要的信息。這正是調整日誌記錄的好機會——我們忘了記錄哪些重要的內容?

我認為,最重要就是直觀地理解哪些內容值得進行記錄。作為我的觀察對象,他(標題中的高級軟件工程師)和我在記錄服務方面的想法有著很大的不同。我認為記錄請求 - 響應就足夠了,但他卻列出了很多指標,比如查詢執行時間、代碼中的一些特定內部調用以及何時輪換日誌等等。很明顯,如果沒有日誌記錄作為參考,我們幾乎不可能進行任何調試工作——如果我們不清楚系統的當前狀態,重建系統自然也就成了痴人說夢。

指標可以從日誌當中提取,也可以在代碼當中單獨建立。(例如將事件發送至 AWS CloudWatch 以及 Grafana)。大家可以自行設定指標,並在代碼運行時發出對應的數字。

警報則是將所有內容整合在優秀監控系統中的重要粘合劑。如果某項指標代表著當前正處於生產狀態的機器數量,那麼這個數字下降到 50% 則代表著一種嚴重警報——肯定是出了什麼大問題。失敗計數超過栽個閾值?又會有新警報給我們發出提醒。

這樣我就能安心睡覺了,因為我很清楚即使出了什麼問題,系統也會馬上提醒我~對吧……

而這中間又隱藏著另一種重要的習慣。在修復 bug 時,我們不應單純關注如何解決問題,而是為什麼我們沒能早點發現?警報有沒有及時提醒?如何更好地設置監控以防止出現類似的問題?我到現在也沒弄明白如何監控 UI。目前的組件選項還無法瞭解問題究竟來自哪裡。而且,仍有相當一部分問題是由客戶上報過來的——這裡頭肯定還有提升空間。

總結

過去一年以來,我學到了很多。在開始撰寫這篇文章時,我很高興自己接受了這份新的工作。動筆的過程中,我也深切體會到自己的成長。希望大家也能從這篇文章裡獲得一點啟發!

我非常幸運地加入了一支優秀的團隊——我們完成了大量編碼工作、我們每天都過得很開心、我們從零開始設計系統,我們也與很多其他團隊攜手協作。

今年,我身邊又多了一位高級開發人員。我很期待能學到更多重要的心得。多謝啦,我的團隊!

優秀的工程師能夠設計出更健壯且更易被他人理解的系統。這將帶來乘積效應,幫助同事們更快更可靠地構建他們的工作成果。 - 如何構建良好軟件(How to Build Good Software)

我從高級軟件工程師身上學到的那些經驗與教訓「轉」

我也不確定的那些事兒

我還沒有嘗試過對軟件工程代碼進行破解。這也提醒我,還有很多重要的知識需要學習!如果成長順利,明年的新版本應該會更長。好了,總之先進入目前的待了解問題清單:

  1. 應該立足抽象角度思考,還是立足形象角度思考?
  2. 我對於做事的方式擁有明確的見解嗎?有哪些是犯錯之後才總結出的方式?我是否完成過必須擁有這種見解才能處理的任務?
  3. 為工作流制定開發流程。如果大家因為緊急狀況或者事件而必須改變自己的工作方式,那麼這一流程是否會受到破壞?有沒有解決辦法?
  4. 什麼樣的代碼應該被放進 utils 文件夾(專門用於放置不知道該如何處理的東西)?
  5. 如何處理編碼與工作流文檔?
  6. 如何監控 UI 以發現異常狀況?
  7. 花時間設計出完美的 API/ 代碼契約,還是反覆測試加反覆迭代,從而找出哪種方法更好?
  8. 選簡單的方式,還是選正確的方式?我不相信簡單的永遠正確,這有點太樂觀了。
  9. 自己動手做事,還是教會其他不懂的同事如何處理?前者速度更快,後者則能一勞永逸地降低工作量。
  10. 重構以及防止進行大規模更新:“如果我改變了整個測試流程,那麼可能需要一下替換 52 個文件,這顯然會引起重大影響。但是,受到影響的只是代碼,測試更新一切順利。”這樣的代價,值得嗎?
  11. 進一步降低風險。有哪些策略能夠降低項目的風險?
  12. 有哪些有效的需求收集方式?
  13. 如何降低系統降級率?



原文鏈接:https://neilkakkar.com/things-I-learnt-from-a-senior-dev.html

中文譯文:https://www.infoq.cn/article/BJEejiFAe6giebc14tep


分享到:


相關文章: