chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

從AI人工智能工程師,學(xué)到了哪些重要經(jīng)驗(yàn)

倩倩 ? 來(lái)源:lq ? 作者:思考著前進(jìn) ? 2019-10-08 15:01 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

編寫(xiě)代碼如何命名

我在工作中接觸的第一項(xiàng)任務(wù)是開(kāi)發(fā)一款 React UI。當(dāng)時(shí)我們擁有一個(gè)主組件,用于容納其它所有組件。我喜歡在代碼當(dāng)中加點(diǎn)幽默元素,所以我把它命名為 GodComponent。但在代碼審查時(shí),我才意識(shí)到為什么命名工作如此重要、也如此困難。

計(jì)算機(jī)科學(xué)領(lǐng)域有兩大難題:緩存失效、命名以及緩沖溢出錯(cuò)誤。-—— Leon Bambrick

我命名的每一段代碼都包含隱藏的含義。GodComponent?這個(gè)組件的含義,就是我會(huì)把所有不知道該放在哪的組件都放在這里。它囊括一切。如果我把它命名為 LayoutComponent,后續(xù)我才會(huì)意識(shí)到它的作用就是布局分配,其中不包含任何狀態(tài)。

我發(fā)現(xiàn)的另一項(xiàng)心得在于:如果其體積過(guò)于龐大,就像是這里提到的包含大量業(yè)務(wù)邏輯的 LayoutComponent,那么我就會(huì)意識(shí)到是時(shí)候進(jìn)行重構(gòu)了,因?yàn)橥ㄟ^(guò)名稱就能看出業(yè)務(wù)邏輯并不屬于這里。但使用 GodComponent 這個(gè)名稱,我們無(wú)法判斷業(yè)務(wù)邏輯出現(xiàn)在這里是否正常。如何命名集群?最好是在運(yùn)行了服務(wù)之后再對(duì)集群進(jìn)行命名,而后根據(jù)運(yùn)行內(nèi)容的變化重新調(diào)整名稱。最終,我們用自己的團(tuán)隊(duì)名稱完成了集群命名。

函數(shù)命名的情況也是一樣。doEverything() 這個(gè)名字就不怎么樣,其會(huì)帶來(lái)嚴(yán)重的后果。如果這項(xiàng)函數(shù)能夠完成所有操作,那么我們將很難測(cè)試函數(shù)當(dāng)中的某些特定部分。而且無(wú)論這個(gè)函數(shù)有多大,我們都會(huì)覺(jué)得很正常,畢竟它的名字可是叫“everything”。所以,最好的辦法當(dāng)然是更換名稱,進(jìn)行重構(gòu)。

但是,我們?cè)诿幸惨紤]到另一類問(wèn)題。如果名稱的含義太過(guò)具體并忽略了某些細(xì)微差別,該怎么辦?例如,在 SQLAlchemy 當(dāng)中調(diào)用 session.close() 時(shí),關(guān)閉會(huì)話不會(huì)關(guān)閉基礎(chǔ)數(shù)據(jù)庫(kù)連接。(我本應(yīng)該跳出手冊(cè)限制,對(duì)這項(xiàng) bug 進(jìn)行處理,具體情況將在調(diào)試部分進(jìn)一步說(shuō)明。)在這種情況下,我們可以考慮 x, y, z 這樣的名稱,而非 count(), close(), insertIntoDB(),從而避免為其分配隱含的意義。太過(guò)具體,會(huì)迫使我們不得不在后續(xù)維護(hù)時(shí)費(fèi)力檢查這些函數(shù)到底是用來(lái)干嘛的。

最后,當(dāng)時(shí)的我從來(lái)沒(méi)想到命名會(huì)成為值得單獨(dú)一提的重要工作。

遺留代碼與下一位開(kāi)發(fā)者

大家有沒(méi)有面對(duì)一段代碼時(shí),感覺(jué)摸不著頭腦?他們?yōu)槭裁匆@么寫(xiě)?這完全說(shuō)不通啊。

我就“有幸”接手過(guò)遺留代碼庫(kù)。其中就存在類似于“跟穆罕默德確認(rèn)過(guò)情況之后,取消注釋”這類說(shuō)明。這話是誰(shuí)說(shuō)的?穆罕默德又是哪位?

在這方面,我們不妨做個(gè)角色轉(zhuǎn)換——考慮下一位接手我所編寫(xiě)代碼的開(kāi)發(fā)者。他們同樣會(huì)發(fā)現(xiàn)我的代碼非常奇怪。同行評(píng)審能夠很好地解決這個(gè)問(wèn)題。這不禁讓我想到上下文原則,即:了解團(tuán)隊(duì)開(kāi)展工作時(shí)的實(shí)際處境。

如果我跑去忙別的事,稍后又回來(lái),我可能也無(wú)法重新建立這種上下文。我坐說(shuō),“當(dāng)時(shí)我是怎么想的?這根本沒(méi)道理……哦等等,我原來(lái)是這么干的?!?/p>

正是為了實(shí)現(xiàn)這種提示作用,文檔與代碼注釋才會(huì)如此重要。

文檔與代碼注釋

文檔與代碼注釋的意義,在于保持上下文并分享知識(shí)。

正如 Li 在如何構(gòu)建良好軟件中所言,“軟件的主要價(jià)值并不在于生成的代碼,而在于生成代碼的過(guò)程中開(kāi)發(fā)者所積累下來(lái)的知識(shí)?!?/p>

“軟件的主要價(jià)值并不在于生成的代碼,而在于生成代碼的過(guò)程中開(kāi)發(fā)者所積累下來(lái)的知識(shí)。” - Li

我們當(dāng)時(shí)有一套面向 API 端點(diǎn)的隨機(jī)客戶端,好像從來(lái)就沒(méi)人用過(guò)。那么要不要把它刪除掉?畢竟這也屬于技術(shù)債務(wù)。

但如果我告訴大家,每年在特定的國(guó)家 / 地區(qū),都會(huì)有 10 名記者將新聞發(fā)送到該端點(diǎn),又該怎么辦?我們是如何測(cè)試的?如果沒(méi)有文檔(也確實(shí)沒(méi)有),我們找不到答案。因此,我們刪除了該端點(diǎn),并在對(duì)應(yīng)時(shí)間點(diǎn)上發(fā)現(xiàn)了問(wèn)題——這 10 名記者無(wú)法發(fā)送 10 份重要的報(bào)道,因?yàn)樵摱它c(diǎn)已經(jīng)不復(fù)存在。

了解產(chǎn)品的成員已經(jīng)離開(kāi)了團(tuán)隊(duì),現(xiàn)在只能靠代碼當(dāng)中的注釋來(lái)解釋該端點(diǎn)的作用。

從這件事上,我意識(shí)到文檔是每個(gè)團(tuán)隊(duì)都在努力解決、但卻難以奏效的問(wèn)題。除了代碼文檔之外,與代碼相關(guān)的流程也有類似的情況。

時(shí)至今日,我們也沒(méi)有找到完美的解決方案。

原子提交

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

在刪除垃圾代碼時(shí)要充滿信心

刪除垃圾或者過(guò)時(shí)的代碼總是讓我感覺(jué)很不舒服。我總覺(jué)得以往的工作成果有種神圣不可侵犯的意義。我那時(shí)候認(rèn)為,“在他們寫(xiě)與這些代碼時(shí),肯定是有所考量的。”這是一種傳統(tǒng)的理解方式,而且與第一性原則有所沖突。出于類似的理由,我在每年進(jìn)行代碼審查與清理時(shí)也是困難重重。這樣的糟糕習(xí)慣,讓我吃了不少苦頭。

我曾經(jīng)嘗試調(diào)整代碼問(wèn)題,也有些老成員習(xí)慣于繞過(guò)這些代碼。但刪除,刪除聽(tīng)起來(lái)更嚴(yán)重正經(jīng)。一個(gè)永遠(yuǎn)用不上的 if 語(yǔ)句、一個(gè)永遠(yuǎn)用不上的函數(shù),會(huì)在我的一聲令下徹底消失,這樣不好。因此,我更多是把自己的函數(shù)覆蓋在上面。但這并沒(méi)有減少技術(shù)債務(wù),只是增加了代碼的復(fù)雜性與誤導(dǎo)性。如此一來(lái),后繼者將更難把這些片段以有意義的方式拼湊起來(lái)。

我現(xiàn)在采取的方式是:總會(huì)存在我們無(wú)法理解的代碼,也總會(huì)存在我們永遠(yuǎn)不會(huì)使用的代碼。刪除這些永遠(yuǎn)不會(huì)使用的代碼,但對(duì)無(wú)法理解的代碼保持謹(jǐn)慎的態(tài)度。

代碼審查

代碼審查是學(xué)習(xí)中的重要組成部分。審查的過(guò)程,就是從編寫(xiě)代碼、到了解如何更好地編寫(xiě)代碼的反饋循環(huán)。我們自己的編碼思路,跟其他人的編碼思路有何不同?我在每一次代碼審查時(shí)都會(huì)問(wèn)自己:“他們?yōu)槭裁匆@樣做?”如果實(shí)在找不到合理的答案,我就會(huì)跟他們當(dāng)面聊聊。在第一個(gè)月的過(guò)渡期結(jié)束之后,我開(kāi)始瘋狂地從同事的代碼當(dāng)中查找錯(cuò)誤(當(dāng)然,他們也不會(huì)放過(guò)我)。真的很瘋狂,這也讓評(píng)審工作變成一項(xiàng)有趣的調(diào)劑——或者說(shuō)像是一種游戲,能夠改善我們編碼水平的小游戲。

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

測(cè) 試

我特別喜歡測(cè)試這項(xiàng)工作,事實(shí)上如果不加測(cè)試,我根本就不愿意直接在代碼庫(kù)中編寫(xiě)代碼。

如果您的整個(gè)應(yīng)用程序只需要執(zhí)行一項(xiàng)任務(wù)(我在學(xué)校里的實(shí)驗(yàn)性項(xiàng)目就是這樣),那么手動(dòng)測(cè)試即可解決問(wèn)題,我以前也一直習(xí)慣于這種方式。但是,當(dāng)應(yīng)用程序當(dāng)中包含上百種功能,情況又會(huì)如何?我不想拿出大量時(shí)間挨個(gè)測(cè)試,而且我也知道自己肯定會(huì)忘掉某些需要測(cè)試的部分。這絕對(duì)會(huì)是一場(chǎng)噩夢(mèng)。

這時(shí)候,我們就該請(qǐng)出測(cè)試自動(dòng)化方案了。

在我看來(lái),測(cè)試跟記錄文檔差不多。測(cè)試的過(guò)程,就是記錄我對(duì)于代碼的假設(shè)是否正確的過(guò)程。測(cè)試會(huì)告訴我,我自己(或者是當(dāng)初寫(xiě)下代碼的開(kāi)發(fā))當(dāng)時(shí)希望代碼如何運(yùn)行,以及認(rèn)為哪里有可能出問(wèn)題。

因此,現(xiàn)在再編寫(xiě)測(cè)試時(shí),我會(huì)牢記以下兩點(diǎn):

演示如何使用我正在測(cè)試的類 / 函數(shù) / 系統(tǒng)。

展示我認(rèn)為可能出問(wèn)題的部分。

第一條相信很多朋友都能理解,畢竟在大多數(shù)情況下,我們需要測(cè)試的其實(shí)是行為,而非實(shí)現(xiàn)。但我個(gè)人總會(huì)忽略第 2 條,即 bug 可能出現(xiàn)在哪里。

因此,每當(dāng)我發(fā)現(xiàn) bug 時(shí),我都會(huì)確保代碼修復(fù)程序在相應(yīng)的測(cè)試(也就是回歸測(cè)試)當(dāng)中記錄下其它有可能引發(fā)錯(cuò)誤的方式。

當(dāng)然,編寫(xiě)這類測(cè)試本身并不能提供代碼質(zhì)量,只有真正編寫(xiě)代碼才會(huì)真正影響質(zhì)量。不過(guò)我從閱讀測(cè)試結(jié)果當(dāng)中獲得的見(jiàn)解,確實(shí)能夠幫助自己編寫(xiě)出更好的代碼。

這就是測(cè)試的宏觀意義。

除此之外,測(cè)試還肩負(fù)著另一項(xiàng)重要使命:確定部署環(huán)境。

大家可能擁有完美的單元測(cè)試,但如果沒(méi)有進(jìn)行系統(tǒng)測(cè)試,就有可能發(fā)生以下情況:

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

對(duì)于經(jīng)過(guò)良好測(cè)試的代碼也是如此:如果您的機(jī)器上沒(méi)有其需要的庫(kù),代碼就會(huì)崩潰。

您開(kāi)發(fā)所在的機(jī)器環(huán)境。(「一切都能在我的機(jī)器上正常運(yùn)行!」)

您測(cè)試所在的機(jī)器環(huán)境。(可能就是您開(kāi)發(fā)所使用的那臺(tái)機(jī)器。)

最后,您部署所在的機(jī)器環(huán)境。(請(qǐng)一定換一臺(tái)別的機(jī)器。)

如果測(cè)試與部署機(jī)器間的環(huán)境不匹配,那一般都會(huì)出點(diǎn)問(wèn)題。而這,正是部署環(huán)境的意義所在。我們?cè)谧约旱臋C(jī)器上使用 docker 構(gòu)建本地開(kāi)發(fā)環(huán)境。

在這套開(kāi)發(fā)環(huán)境當(dāng)中安裝有一組庫(kù)(及開(kāi)發(fā)工具),我們則以此為基礎(chǔ)安裝已經(jīng)編寫(xiě)完成的代碼。所有與其它依賴系統(tǒng)相關(guān)的測(cè)試,都在這里完成。

然后是 beta 測(cè)試 / 分段環(huán)境,其與生產(chǎn)環(huán)境完全一致。

最后是生產(chǎn)環(huán)境,也就是負(fù)責(zé)運(yùn)行代碼并為實(shí)際客戶提供服務(wù)的機(jī)器。

我們的基本思路是努力捕捉那些不會(huì)在單元與系統(tǒng)測(cè)試中出現(xiàn)的錯(cuò)誤。例如,請(qǐng)求與響應(yīng)系統(tǒng)之間的 API 不匹配問(wèn)題。

我猜個(gè)人項(xiàng)目或者小型企業(yè)的情況可能有所不同,畢竟并不是每個(gè)人都有資源來(lái)設(shè)置自己的一套基礎(chǔ)設(shè)施。但是,如果大家愿意使用 AWS 以及 Azure 等云服務(wù),這里提到的方法仍然適合各位。大家可以為開(kāi)發(fā)以及生產(chǎn)環(huán)境設(shè)置單獨(dú)的集群。AWS ECS 利用 docker 鏡像進(jìn)行部署,因此各環(huán)境之間相對(duì)一致。比較棘手的部分,就是如果與其它 AWS 服務(wù)順利整合。例如,我們是否從正確的環(huán)境中調(diào)用了正確的端點(diǎn)?

大家甚至可以更進(jìn)一步:為其它 AWS 服務(wù)下載備用容器鏡像,并利用 docker-compose 命令設(shè)置完整的本地環(huán)境。這樣能夠加速反饋循環(huán)。

如此一來(lái),當(dāng)我的附帶項(xiàng)目啟動(dòng)并開(kāi)始運(yùn)行之后,我就能積累到更多經(jīng)驗(yàn)心得。

消除風(fēng)險(xiǎn)

所謂消除風(fēng)險(xiǎn),就是在部署代碼的過(guò)程中盡可能降低風(fēng)險(xiǎn)水平的一種藝術(shù)。

那么,我們可以采取哪些措施來(lái)消除災(zāi)難性后果?

如果我們希望推出的一項(xiàng)突破性的變更,那么一旦出現(xiàn)問(wèn)題,如果確保業(yè)務(wù)盡可能不受?chē)?yán)重影響?

“我們不需要對(duì)所有的新變化進(jìn)行全系統(tǒng)部署!”哦,是嗎……抱歉,我沒(méi)想到。

設(shè) 計(jì)

很多朋友可能會(huì)問(wèn),我為什么要把設(shè)計(jì)放在編寫(xiě)代碼與完成測(cè)試之后?好吧,設(shè)計(jì)在實(shí)際流程中可能比較靠前,但如果沒(méi)有在當(dāng)前環(huán)境中進(jìn)行編碼與測(cè)試,我個(gè)人很難設(shè)計(jì)出一套能夠與特定環(huán)境完美適配的系統(tǒng)。在設(shè)計(jì)系統(tǒng)時(shí),我們需要考慮很多問(wèn)題,包括:

資源使用量是多少?

存在多少用戶?預(yù)計(jì)用戶會(huì)以怎樣的速度增長(zhǎng)?(這將直接決定未來(lái)存在多少數(shù)據(jù)庫(kù)行)

未來(lái)可能出現(xiàn)的陷阱是什么?

我需要把這些轉(zhuǎn)化成一份名為“要求匯總”的清單。目前我還沒(méi)有積累到充分的相關(guān)經(jīng)驗(yàn),根據(jù)計(jì)劃,明年我的工作內(nèi)容就是著力解決這方面問(wèn)題。

這個(gè)過(guò)程有點(diǎn)違背敏捷原則——在開(kāi)始實(shí)施之前,我們能夠做出多少設(shè)計(jì)判斷?這是個(gè)權(quán)衡問(wèn)題,我們需要選擇在怎樣的時(shí)間點(diǎn)上做什么。我們什么時(shí)候該深入剖析,又該在什么時(shí)候退后一步進(jìn)行規(guī)劃?

當(dāng)然,這里收集到的要求不需要也不可能真正全面。我認(rèn)為把開(kāi)發(fā)的過(guò)程納入設(shè)計(jì)考量也是完全可行的,例如:

本地開(kāi)發(fā)將如何運(yùn)作?

我們?nèi)绾未虬安渴穑?/p>

我們?nèi)绾芜M(jìn)行端到端測(cè)試?

我們?nèi)绾螌?duì)這項(xiàng)新服務(wù)進(jìn)行壓力測(cè)試?

我們?nèi)绾喂芾肀C苄畔ⅲ?/p>

我們?nèi)绾螌?shí)現(xiàn) CI/CD 集成?

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

那么,為什么把保密信息引入生產(chǎn)環(huán)境可能引發(fā)問(wèn)題?

我們不能將其直接添加到代碼當(dāng)中,否則任何人都能夠直接查看。

是否應(yīng)該將其作為環(huán)境變量,如同 12 因素應(yīng)用所要求的那樣?這確實(shí)是個(gè)好辦法,但我們?cè)撊绾螌?shí)現(xiàn)?(在每次機(jī)器啟動(dòng)時(shí)都訪問(wèn)生產(chǎn)設(shè)備以填充環(huán)境變量,絕對(duì)是個(gè)痛苦的過(guò)程。)

將其部署為保密文件?那么該文件來(lái)自哪里?又該如何填充?

最后,整個(gè)過(guò)程當(dāng)然不可能手動(dòng)實(shí)現(xiàn)。

總而言之,我們使用了具有角色訪問(wèn)控制機(jī)制的數(shù)據(jù)庫(kù)(只有我們的機(jī)器以及我們自己能夠與該數(shù)據(jù)庫(kù)通信)。我們的代碼會(huì)在啟動(dòng)時(shí)從該數(shù)據(jù)庫(kù)處獲取保密信息。這部分信息能夠在開(kāi)發(fā)、beta 測(cè)試以及生產(chǎn)環(huán)境之間順暢復(fù)制,且各自保留在對(duì)應(yīng)的數(shù)據(jù)庫(kù)當(dāng)中。

這里要再提一句,AWS 等各家云服務(wù)供應(yīng)商提供的具體方案可能有所區(qū)別。大家不用為保密信息費(fèi)多少心。獲取角色賬戶、在 UI 當(dāng)中輸入保密信息,而后即可確保代碼在需要時(shí)獲取其內(nèi)容。這些服務(wù)能夠顯著簡(jiǎn)化整個(gè)流程,但之前的探索也并沒(méi)有白費(fèi)——我很高興自己能夠真正理解并欣賞這種簡(jiǎn)潔的解決方案。

在設(shè)計(jì)當(dāng)中考慮維護(hù)要求

設(shè)計(jì)系統(tǒng)令人興奮,但維護(hù)呢?恐怕就沒(méi)什么成就感可言了。

在維護(hù)系統(tǒng)的過(guò)程中,我想到了這樣一個(gè)問(wèn)題:我們?yōu)槭裁匆M(jìn)行系統(tǒng)降級(jí),又該如何實(shí)現(xiàn)系統(tǒng)降級(jí)?

第一部分的答案是,因?yàn)榭傆腥瞬粣?ài)丟棄陳舊的部分,而是添加新的部分。厚古而薄今,至少我自己就有這樣的毛病。

至于第二部分,答案是我們?cè)谶M(jìn)行系統(tǒng)設(shè)計(jì)時(shí)提出的終極目標(biāo),后續(xù)可能不再適用。在系統(tǒng)的發(fā)展當(dāng)中,其很可能會(huì)以與設(shè)計(jì)假設(shè)相沖突的方式進(jìn)行使用,這意味著我們當(dāng)初做出的一切預(yù)期需求都不再有效。這時(shí)候我們就需要后退一步,層層剝離那些不再適用的部分。

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

保證業(yè)務(wù)邏輯與基礎(chǔ)設(shè)施彼此分離:一般來(lái)說(shuō),需要降級(jí)的往往基礎(chǔ)設(shè)施部分——例如使用量增加、框架過(guò)時(shí)、出現(xiàn)零日漏洞等等。

圍繞維護(hù)需求設(shè)計(jì)流程。對(duì)新代碼與舊代碼采用同樣的更新手段,從而防止新舊之間出現(xiàn)差異,確保代碼整體保持“現(xiàn)代”特性。

始終堅(jiān)持去掉一切不需要的 / 陳舊的代碼。

部 署

我更傾向于把功能捆綁在一起,還是逐一進(jìn)行部署?

這要取決于現(xiàn)有流程,但如果答案是捆綁部署,那么很可能會(huì)引發(fā)后續(xù)問(wèn)題。

這里我們需要回答的問(wèn)題是,我們?yōu)槭裁匆压δ芾壠饋?lái)加以部署?

是因?yàn)椴渴鹦枰馁M(fèi)太多時(shí)間嗎?

是因?yàn)榇a審查比較困難嗎?

無(wú)論是因?yàn)槭裁丛?,我們都需要解決瓶頸本身,而不是在部署方法上做出遷就。捆綁方式至少會(huì)帶來(lái)以下兩大弊端。

如果其中一項(xiàng)功能出了錯(cuò)誤,就會(huì)阻止另一功能的執(zhí)行。

這會(huì)提高風(fēng)險(xiǎn)水平,或者說(shuō)導(dǎo)致發(fā)生問(wèn)題的機(jī)率上升。

接下來(lái),無(wú)論大家選擇哪一種部署流程,各位肯定是希望自己的機(jī)器能像耕牛一樣勤勤懇懇,而不是像寵物那樣動(dòng)不動(dòng)耍脾氣。機(jī)器必須吃苦耐勞,我們知道每臺(tái)機(jī)器上運(yùn)行的是什么,在宕機(jī)時(shí)又該如何恢復(fù)。一旦發(fā)生宕機(jī),我們不會(huì)感到沮喪——啟動(dòng)一臺(tái)新的就行。這些設(shè)備應(yīng)該像放養(yǎng)的牛羊,而不是需要精心呵護(hù)的小貓小狗。

出現(xiàn)問(wèn)題時(shí)

一旦出了問(wèn)題——而且早晚肯定會(huì)出問(wèn)題——我們的黃金法則就是盡可能降低對(duì)客戶造成的影響。

在出現(xiàn)問(wèn)題時(shí),我的第一反應(yīng)就是解決問(wèn)題。但事實(shí)證明,這并不是最高效的應(yīng)對(duì)思路。相反,即使只是小小的問(wèn)題,最高效的辦法其實(shí)是選擇回滾。返回之前能夠正常工作的狀態(tài),這樣才能縮短客戶無(wú)法正常使用服務(wù)的時(shí)間窗口。

也只有這樣,我們才能安心查找錯(cuò)誤并動(dòng)手加以修復(fù)。

正如集群中的“故障”機(jī)器一樣,在嘗試判斷機(jī)器出了什么問(wèn)題之前,我們首先應(yīng)該將其下線并標(biāo)記為不可用。

我發(fā)現(xiàn)這確實(shí)是種反直覺(jué)的辦法,而且我的本能總會(huì)把自己帶離最佳解決途徑。

我覺(jué)得正是這樣的本能,逼迫我走上解決 bug 的漫長(zhǎng)道路。有時(shí)候,引發(fā)問(wèn)題的根源就是我編寫(xiě)的代碼出了問(wèn)題,而我會(huì)深入研究自己寫(xiě)下的第一行代碼。這有點(diǎn)像深度優(yōu)先搜索的過(guò)程。

如果最后證明是配置發(fā)生了變化,而我沒(méi)能及時(shí)調(diào)整功能本身,我就會(huì)非常生氣。因?yàn)檫@個(gè)錯(cuò)誤太低級(jí)了,本不該發(fā)生。

從那時(shí)起,我的心得就是在深度優(yōu)先搜索之前先來(lái)一輪廣度優(yōu)先搜索,暫時(shí)不觸及頂級(jí)節(jié)點(diǎn)。我能利用自己手頭的資源確認(rèn)哪些問(wèn)題?

機(jī)器還在運(yùn)行嗎?

安裝的代碼是否正確?

配置是否到位?

代碼是否使用到特定配置,例如代碼中的路由是否正確?

架構(gòu)版本是否正確?

最后,再看代碼內(nèi)容。

我們?cè)疽詾槭?nginx 在機(jī)器上沒(méi)有正確安裝。但事實(shí)證明,只是配置文件被設(shè)置為 false。*

當(dāng)然,大多數(shù)情況下并不需要這么麻煩。有時(shí)候,單靠錯(cuò)誤消息就足以幫我快速找到存在問(wèn)題的代碼。

當(dāng)我找不出問(wèn)題時(shí),我會(huì)嘗試分步對(duì)代碼進(jìn)行變更以查找可能的根源。變更的數(shù)量越少,找到真正問(wèn)題的速度就越快??傊?,請(qǐng)盡可能讓推理過(guò)程變得有跡可循,太過(guò)跳躍只會(huì)錯(cuò)失線索。我現(xiàn)在還記得自己曾花了一個(gè)多小時(shí)解決幾個(gè) bug:?jiǎn)栴}在哪?一般都是我忘了檢查的一些低級(jí)問(wèn)題,例如設(shè)置路由、確保架構(gòu)版本與服務(wù)版本匹配等等。這只能說(shuō)明我對(duì)自己使用的技術(shù)堆棧還不夠熟悉,因此需要通過(guò)犯錯(cuò)誤的方式積累經(jīng)驗(yàn)。最終,我可以單靠直覺(jué)就判斷出為什么代碼沒(méi)能正常運(yùn)行。

戰(zhàn)爭(zhēng)故事

一邊是調(diào)整參數(shù)與查看統(tǒng)計(jì)數(shù)據(jù),另一邊是修復(fù)底層問(wèn)題根源。

如果沒(méi)有戰(zhàn)爭(zhēng)故事(war story,指一段令人難忘的經(jīng)歷,往往涉及危險(xiǎn)、困難或者冒險(xiǎn)因素),這篇文章又怎么會(huì)完整?我很喜歡回顧這類經(jīng)歷,分享環(huán)節(jié)馬上開(kāi)始。

這是個(gè)關(guān)于搜索與 SQLAlchemy 的故事。在 BNEF,我們需要處理大量由分析師們撰寫(xiě)的研究報(bào)告。每當(dāng)報(bào)告發(fā)布時(shí),我們都會(huì)收到一條消息;在收到消息之后,我們會(huì)通過(guò) SQLAlchemy 進(jìn)入數(shù)據(jù)庫(kù),獲取我們需要的全部信息,進(jìn)行轉(zhuǎn)換,并將結(jié)果發(fā)送至 solr 實(shí)例進(jìn)行索引。但這時(shí)候,我們發(fā)現(xiàn)了奇怪的 AF bug。

每天早上,連接數(shù)據(jù)庫(kù)的操作都會(huì)失敗,消息提示“MYSQL 服務(wù)器不存在”。有時(shí)候連下午都會(huì)出現(xiàn)這種狀況。由于下午時(shí)段的使用量最大,所以我首先進(jìn)行了一番檢查。沒(méi)問(wèn)題,機(jī)器的運(yùn)行狀態(tài)一切正常。我們?nèi)鞎?huì)向數(shù)據(jù)庫(kù)發(fā)出數(shù)千次請(qǐng)求,都沒(méi)有失敗。那么,為什么負(fù)載強(qiáng)度這么低的情況反而會(huì)出問(wèn)題呢?

哦,可能是我們?cè)谑聞?wù)結(jié)束后沒(méi)有關(guān)閉會(huì)話?所以失敗其實(shí)來(lái)自同一段會(huì)話,只不過(guò)下一個(gè)請(qǐng)求出現(xiàn)在很長(zhǎng)一段時(shí)間之后,這就引發(fā)了超時(shí)——因?yàn)榇舜畏?wù)器已經(jīng)關(guān)閉了??焖俨榭创a,我們通過(guò)上下文管理器檢查了每一次在 exit() 上調(diào)用 session.close() 的讀取操作。

經(jīng)過(guò)一整天的排查,沒(méi)發(fā)現(xiàn)任何問(wèn)題。在第二天早上,我又遇到了同樣的情況。錯(cuò)誤發(fā)生的一秒之后,其他三項(xiàng)索引請(qǐng)求都成功了。這明顯就是會(huì)話未能正確關(guān)閉的典型表現(xiàn)。好了,相信大家能夠腦補(bǔ)出接下來(lái)的完整故事。

SQLAlchemy mysql 語(yǔ)言中的 Session.close() 無(wú)法關(guān)閉底層數(shù)據(jù)庫(kù)連接,除非使用 NullPool。是的,這就是修復(fù)方案。

引發(fā)這個(gè) bug 的原因很簡(jiǎn)單,這是因?yàn)槲覀儾粫?huì)在夜間以及午餐時(shí)段發(fā)布研究報(bào)告。此外,我們也吸取到另一個(gè)教訓(xùn)——大多數(shù)堆棧溢出問(wèn)題的答案(我是從谷歌上查來(lái)的),正是 bug 本身會(huì)調(diào)整會(huì)話的超時(shí)時(shí)間,或者控制每條 SQL 語(yǔ)句所能發(fā)送數(shù)據(jù)量的參數(shù)。這些對(duì)我來(lái)說(shuō)都沒(méi)有意義,因?yàn)樗鼈兣c問(wèn)題的根源無(wú)關(guān)。我檢查了查詢大小是否在限制范圍之內(nèi),而且由于會(huì)話本身正在關(guān)閉,所以也不會(huì)發(fā)生超時(shí)狀況。

我們當(dāng)然可以把超時(shí)時(shí)間從 1 個(gè)小時(shí)增加到 8 個(gè)小時(shí)來(lái)快速“修復(fù)”這個(gè) bug。但這顯然解決不了問(wèn)題,到第二天早上,又會(huì)有研究報(bào)告引發(fā)的錯(cuò)誤出現(xiàn)在我們面前。

一邊是調(diào)整參數(shù)與查看統(tǒng)計(jì)數(shù)據(jù),另一邊是修復(fù)底層問(wèn)題根源。這就是我們的日常生活。

監(jiān) 控

我之前從來(lái)沒(méi)想過(guò)監(jiān)控也會(huì)歸自己管。坦白講,在接受全職編碼職位之前,我從來(lái)不管系統(tǒng)維護(hù)這些事。我只是構(gòu)建系統(tǒng),用上一個(gè)禮拜,然后再換一套系統(tǒng)。

現(xiàn)在,我日常使用的是兩套系統(tǒng),其中一套擁有良好的監(jiān)控機(jī)制,另一套的監(jiān)管機(jī)制則比較差。通過(guò)實(shí)際體驗(yàn),我感受到了監(jiān)控的重要意義。畢竟如果意識(shí)到問(wèn)題,我又怎么能解決問(wèn)題呢?最差的情況,就是連客戶都發(fā)現(xiàn) bug 了,我自己還蒙在鼓里?!拔以谧鍪裁??!我連自己的系統(tǒng)出了問(wèn)題都不知道?”

我認(rèn)為監(jiān)控機(jī)制主要包含三大組件——日志記錄、指標(biāo)與警報(bào)。

日志記錄以代碼的形式存在,類似于人類記錄,這是一種漸進(jìn)的過(guò)程。

我們可以找到需要監(jiān)控的內(nèi)容,記錄這些內(nèi)容,同時(shí)運(yùn)行系統(tǒng)。隨著時(shí)間的推移,我們可能會(huì)發(fā)現(xiàn)自己缺少某些解決 bug 所需要的信息。這正是調(diào)整日志記錄的好機(jī)會(huì)——我們忘了記錄哪些重要的內(nèi)容?

我認(rèn)為,最重要就是直觀地理解哪些內(nèi)容值得進(jìn)行記錄。作為我的觀察對(duì)象,他(標(biāo)題中的高級(jí)軟件工程師)和我在記錄服務(wù)方面的想法有著很大的不同。我認(rèn)為記錄請(qǐng)求 - 響應(yīng)就足夠了,但他卻列出了很多指標(biāo),比如查詢執(zhí)行時(shí)間、代碼中的一些特定內(nèi)部調(diào)用以及何時(shí)輪換日志等等。很明顯,如果沒(méi)有日志記錄作為參考,我們幾乎不可能進(jìn)行任何調(diào)試工作——如果我們不清楚系統(tǒng)的當(dāng)前狀態(tài),重建系統(tǒng)自然也就成了癡人說(shuō)夢(mèng)。

指標(biāo)可以從日志當(dāng)中提取,也可以在代碼當(dāng)中單獨(dú)建立。(例如將事件發(fā)送至 AWS CloudWatch 以及 Grafana)。大家可以自行設(shè)定指標(biāo),并在代碼運(yùn)行時(shí)發(fā)出對(duì)應(yīng)的數(shù)字。

警報(bào)則是將所有內(nèi)容整合在優(yōu)秀監(jiān)控系統(tǒng)中的重要粘合劑。如果某項(xiàng)指標(biāo)代表著當(dāng)前正處于生產(chǎn)狀態(tài)的機(jī)器數(shù)量,那么這個(gè)數(shù)字下降到 50% 則代表著一種嚴(yán)重警報(bào)——肯定是出了什么大問(wèn)題。失敗計(jì)數(shù)超過(guò)栽個(gè)閾值?又會(huì)有新警報(bào)給我們發(fā)出提醒。

這樣我就能安心睡覺(jué)了,因?yàn)槲液芮宄词钩隽耸裁磫?wèn)題,系統(tǒng)也會(huì)馬上提醒我~對(duì)吧……

而這中間又隱藏著另一種重要的習(xí)慣。在修復(fù) bug 時(shí),我們不應(yīng)單純關(guān)注如何解決問(wèn)題,而是為什么我們沒(méi)能早點(diǎn)發(fā)現(xiàn)?警報(bào)有沒(méi)有及時(shí)提醒?如何更好地設(shè)置監(jiān)控以防止出現(xiàn)類似的問(wèn)題?我到現(xiàn)在也沒(méi)弄明白如何監(jiān)控 UI。目前的組件選項(xiàng)還無(wú)法了解問(wèn)題究竟來(lái)自哪里。而且,仍有相當(dāng)一部分問(wèn)題是由客戶上報(bào)過(guò)來(lái)的——這里頭肯定還有提升空間。

總 結(jié)

過(guò)去一年以來(lái),我學(xué)到了很多。在開(kāi)始撰寫(xiě)這篇文章時(shí),我很高興自己接受了這份新的工作。動(dòng)筆的過(guò)程中,我也深切體會(huì)到自己的成長(zhǎng)。希望大家也能從這篇文章里獲得一點(diǎn)啟發(fā)!

我非常幸運(yùn)地加入了一支優(yōu)秀的團(tuán)隊(duì)——我們完成了大量編碼工作、我們每天都過(guò)得很開(kāi)心、我們從零開(kāi)始設(shè)計(jì)系統(tǒng),我們也與很多其他團(tuán)隊(duì)攜手協(xié)作。

今年,我身邊又多了一位高級(jí)開(kāi)發(fā)人員。我很期待能學(xué)到更多重要的心得。多謝啦,我的團(tuán)隊(duì)!

優(yōu)秀的工程師能夠設(shè)計(jì)出更健壯且更易被他人理解的系統(tǒng)。這將帶來(lái)乘積效應(yīng),幫助同事們更快更可靠地構(gòu)建他們的工作成果。- *如何構(gòu)建良好軟件(How to Build Good Software)

我也不確定的那些事兒

我還沒(méi)有嘗試過(guò)對(duì)軟件工程代碼進(jìn)行破解。這也提醒我,還有很多重要的知識(shí)需要學(xué)習(xí)!如果成長(zhǎng)順利,明年的新版本應(yīng)該會(huì)更長(zhǎng)。好了,總之先進(jìn)入目前的待了解問(wèn)題清單:

應(yīng)該立足抽象角度思考,還是立足形象角度思考?

我對(duì)于做事的方式擁有明確的見(jiàn)解嗎?有哪些是犯錯(cuò)之后才總結(jié)出的方式?我是否完成過(guò)必須擁有這種見(jiàn)解才能處理的任務(wù)?

為工作流制定開(kāi)發(fā)流程。如果大家因?yàn)榫o急狀況或者事件而必須改變自己的工作方式,那么這一流程是否會(huì)受到破壞?有沒(méi)有解決辦法?

什么樣的代碼應(yīng)該被放進(jìn) utils 文件夾(專門(mén)用于放置不知道該如何處理的東西)?

如何處理編碼與工作流文檔?

如何監(jiān)控 UI 以發(fā)現(xiàn)異常狀況?

花時(shí)間設(shè)計(jì)出完美的 API/ 代碼契約,還是反復(fù)測(cè)試加反復(fù)迭代,從而找出哪種方法更好?

選簡(jiǎn)單的方式,還是選正確的方式?我不相信簡(jiǎn)單的永遠(yuǎn)正確,這有點(diǎn)太樂(lè)觀了。

自己動(dòng)手做事,還是教會(huì)其他不懂的同事如何處理?前者速度更快,后者則能一勞永逸地降低工作量。

重構(gòu)以及防止進(jìn)行大規(guī)模更新:“如果我改變了整個(gè)測(cè)試流程,那么可能需要一下替換 52 個(gè)文件,這顯然會(huì)引起重大影響。但是,受到影響的只是代碼,測(cè)試更新一切順利。”這樣的代價(jià),值得嗎?

進(jìn)一步降低風(fēng)險(xiǎn)。有哪些策略能夠降低項(xiàng)目的風(fēng)險(xiǎn)?

有哪些有效的需求收集方式?

如何降低系統(tǒng)降級(jí)率?

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 機(jī)器
    +關(guān)注

    關(guān)注

    0

    文章

    795

    瀏覽量

    41687
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4922

    瀏覽量

    72258
  • 計(jì)算機(jī)科學(xué)

    關(guān)注

    1

    文章

    144

    瀏覽量

    11750
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    招鑲?cè)胧?b class='flag-5'>工程師1個(gè),硬件工程師一個(gè),

    東莞市研生科技有限公司是一家藍(lán)牙方案公司,主營(yíng)藍(lán)牙方案的設(shè)計(jì)開(kāi)發(fā),產(chǎn)品包括藍(lán)牙BLE/4G透?jìng)?AI智能體方案開(kāi)發(fā),因公司發(fā)展需要需對(duì)外招聘嵌入式軟件開(kāi)發(fā)工程師,對(duì)藍(lán)牙音頻/BLE以及智能
    發(fā)表于 08-29 02:14

    電子發(fā)燒友工程師看!電子領(lǐng)域評(píng)職稱,技術(shù)之路更扎實(shí)

    電子發(fā)燒友的各位工程師、硬件開(kāi)發(fā)者們,咱們每天在平臺(tái)查芯片手冊(cè)、討論電路設(shè)計(jì)難題、分享嵌入式項(xiàng)目經(jīng)驗(yàn)調(diào)試 PCB 板到開(kāi)發(fā) AIoT 系統(tǒng),靠的都是過(guò)硬的技術(shù)實(shí)力 —— 而電子領(lǐng)域的職稱評(píng)審
    發(fā)表于 08-20 13:53

    AI 芯片浪潮下,職場(chǎng)晉升新契機(jī)?

    芯片設(shè)計(jì)為例,最初的架構(gòu)選型,到算法適配、性能優(yōu)化,每個(gè)環(huán)節(jié)都考驗(yàn)著工程師的專業(yè)素養(yǎng)。在設(shè)計(jì)一款面向智能安防領(lǐng)域的 AI 芯片時(shí),需要深入研究安防場(chǎng)景下圖像識(shí)別算法的特點(diǎn),針對(duì)性地
    發(fā)表于 08-19 08:58

    挖到寶了!人工智能綜合實(shí)驗(yàn)箱,高校新工科的寶藏神器

    ,技術(shù)自主可控 在如今這個(gè)科技競(jìng)爭(zhēng)激烈的時(shí)代,國(guó)產(chǎn)化硬件的重要性不言而喻。比鄰星人工智能綜合實(shí)驗(yàn)箱就做到了這一點(diǎn),采用國(guó)產(chǎn)化硬件,積極推進(jìn)全行業(yè)產(chǎn)業(yè)鏈上下游環(huán)節(jié)的國(guó)產(chǎn)化進(jìn)程,把國(guó)產(chǎn)自主可控的軟硬件平臺(tái)
    發(fā)表于 08-07 14:30

    挖到寶了!比鄰星人工智能綜合實(shí)驗(yàn)箱,高校新工科的寶藏神器!

    ,技術(shù)自主可控 在如今這個(gè)科技競(jìng)爭(zhēng)激烈的時(shí)代,國(guó)產(chǎn)化硬件的重要性不言而喻。比鄰星人工智能綜合實(shí)驗(yàn)箱就做到了這一點(diǎn),采用國(guó)產(chǎn)化硬件,積極推進(jìn)全行業(yè)產(chǎn)業(yè)鏈上下游環(huán)節(jié)的國(guó)產(chǎn)化進(jìn)程,把國(guó)產(chǎn)自主可控的軟硬件平臺(tái)
    發(fā)表于 08-07 14:23

    迅為RK3588開(kāi)發(fā)板Linux安卓麒麟瑞芯微國(guó)產(chǎn)工業(yè)AI人工智能

    迅為RK3588開(kāi)發(fā)板Linux安卓麒麟瑞芯微國(guó)產(chǎn)工業(yè)AI人工智能
    發(fā)表于 07-14 11:23

    最新人工智能硬件培訓(xùn)AI 基礎(chǔ)入門(mén)學(xué)習(xí)課程參考2025版(大模型篇)

    人工智能大模型重塑教育與社會(huì)發(fā)展的當(dāng)下,無(wú)論是探索未來(lái)職業(yè)方向,還是更新技術(shù)儲(chǔ)備,掌握大模型知識(shí)都已成為新時(shí)代的必修課。職場(chǎng)上輔助工作的智能助手,到課堂用于學(xué)術(shù)研究的智能工具,大模
    發(fā)表于 07-04 11:10

    一招拿捏電子工程師#被AI拿捏了 #電子工程師 #電子電工

    電子工程師
    安泰小課堂
    發(fā)布于 :2025年03月25日 17:30:51

    嵌入式軟件工程師就業(yè)好不好?

    嵌入式軟件工程師就業(yè)好不好?會(huì)不會(huì)越老越吃香?今天一起來(lái)看看。 首先看下市場(chǎng)需求。 隨著物聯(lián)網(wǎng)、人工智能、5G等前沿技術(shù)的快速發(fā)展,嵌入式系統(tǒng)的應(yīng)用領(lǐng)域不斷擴(kuò)大,智能家居、汽車(chē)電子到
    發(fā)表于 02-20 10:19

    【入門(mén)必看】人工智能就該這樣學(xué)!一文盤(pán)點(diǎn)人工智能全棧工程師學(xué)習(xí)路徑

    隨著人工智能技術(shù)的不斷發(fā)展,人工智能應(yīng)用場(chǎng)景越來(lái)越多,企業(yè)人才需求也越來(lái)越大。很多人都想進(jìn)入AI這個(gè)高薪領(lǐng)域,包括理工科背景的學(xué)生、程序員、工程師、甚至是非科班跨領(lǐng)域的從業(yè)人員等等。但
    的頭像 發(fā)表于 02-14 16:33 ?1467次閱讀
    【入門(mén)必看】<b class='flag-5'>人工智能</b>就該這樣學(xué)!一文盤(pán)點(diǎn)<b class='flag-5'>人工智能</b>全棧<b class='flag-5'>工程師</b>學(xué)習(xí)路徑

    電子工程師的PCB設(shè)計(jì)經(jīng)驗(yàn)

    本文分享了電子工程師在PCB設(shè)計(jì)方面的經(jīng)驗(yàn),包括PCB布局、布線、電磁兼容性優(yōu)化等內(nèi)容,旨在幫助初學(xué)者掌握PCB設(shè)計(jì)的關(guān)鍵技術(shù)。
    的頭像 發(fā)表于 01-21 15:15 ?2010次閱讀

    電子工程師的電源設(shè)計(jì)經(jīng)驗(yàn)

    本文分享了電子工程師在電源設(shè)計(jì)方面的經(jīng)驗(yàn),包括電源電路的設(shè)計(jì)要點(diǎn)、電源管理芯片的選擇、電源完整性優(yōu)化等內(nèi)容,旨在幫助初學(xué)者掌握電源設(shè)計(jì)的關(guān)鍵技術(shù)。
    的頭像 發(fā)表于 01-21 15:14 ?727次閱讀

    電子工程師的電路設(shè)計(jì)經(jīng)驗(yàn)分享

    本文分享了電子工程師在電路設(shè)計(jì)方面的豐富經(jīng)驗(yàn),包括項(xiàng)目開(kāi)發(fā)步驟、電路設(shè)計(jì)核心思想、元器件選擇與優(yōu)化等內(nèi)容,旨在幫助初學(xué)者快速提升電路設(shè)計(jì)能力。
    的頭像 發(fā)表于 01-21 15:13 ?1005次閱讀

    電子工程師經(jīng)驗(yàn)分享

    電子工程師在實(shí)際工作中積累了豐富的經(jīng)驗(yàn),這些經(jīng)驗(yàn)對(duì)于新手工程師和電子專業(yè)的學(xué)生具有重要的參考價(jià)值。 一、電路設(shè)計(jì)
    的頭像 發(fā)表于 01-14 10:14 ?922次閱讀

    嵌入式和人工智能究竟是什么關(guān)系?

    人工智能的結(jié)合,無(wú)疑是科技發(fā)展中的一場(chǎng)革命。在人工智能硬件加速中,嵌入式系統(tǒng)以其獨(dú)特的優(yōu)勢(shì)和重要性,發(fā)揮著不可或缺的作用。通過(guò)深度學(xué)習(xí)和神經(jīng)網(wǎng)絡(luò)等算法,嵌入式系統(tǒng)能夠高效地處理大量數(shù)據(jù),從而實(shí)現(xiàn)
    發(fā)表于 11-14 16:39