每個(gè)開發(fā)者都應(yīng)該知道的10件事
我是一個(gè) Python + Go 開發(fā)者,過去幾年一直從事于全球范圍內(nèi)的應(yīng)用開發(fā)。我和我的團(tuán)隊(duì)每天要應(yīng)對(duì)大約 200 萬的客戶,處理這種規(guī)模級(jí)別的事務(wù)其實(shí)是不太容易的,所以,我想分享一下過去幾年我的一些經(jīng)驗(yàn)和技巧。
安全問題絕不能是馬后炮
應(yīng)用的安全問題絕不應(yīng)該是馬后炮或者降級(jí)成為“稍后再考慮的事兒”。我們需要從應(yīng)用開發(fā)的第一天起,就將強(qiáng)有力的安全性考量貫穿到每次討論和開發(fā)流程中去,而不是開發(fā)到第 300 天才開始考慮。將安全問題放到最后考慮,反而會(huì)增加開發(fā)的時(shí)間,需要回爐重構(gòu)以適應(yīng)安全問題。更糟的情況是,你沒有足夠的時(shí)間來解決任何漏洞,最終只能交付易受攻擊的代碼。可以去了解下雅虎(Yahoo)這樣的公司,他們是如何做到這一點(diǎn)的。
應(yīng)用不同,需求也不同。按需為應(yīng)用做技術(shù)選型,而不是迫于行政壓力或市場(chǎng)熱度
每個(gè)應(yīng)用都不盡相同,這一點(diǎn)其實(shí)無須贅述。沒有任何一套神圣的準(zhǔn)則可以應(yīng)用于所有應(yīng)用(當(dāng)然也包含本條)。當(dāng)開始開發(fā)一個(gè)新的應(yīng)用時(shí),是應(yīng)用本身及其架構(gòu)決定了它要使用哪種技術(shù)或者基于哪個(gè)平臺(tái)。在思考“我的應(yīng)用需要什么?”這個(gè)問題之前,就決定使用 gRPC 或者Kubernetes 只會(huì)造成一種后果:在你開始動(dòng)手寫代碼之前,就為以后設(shè)置了路障,這也是為什么我們會(huì)陷入像 Canonical 這樣公司會(huì)為物聯(lián)網(wǎng)設(shè)備提供 Kubernetes 服務(wù)的可笑境地。引用 Jeff Goldblum 的話,“你們的科學(xué)家如此醉心于他們能夠干什么,卻不會(huì)停下來想一想是否應(yīng)該這樣做”
你可能不需要微服務(wù)
我知道,微服務(wù)很迷人。能夠在應(yīng)用程序中獨(dú)立地伸縮各種組件是令人興奮的,這也合理化了基于特定代碼庫(kù)的持續(xù)工作。但如果誠(chéng)實(shí)地想一想,你可能沒有必要“微服務(wù)化”,像諸如此類的原因,“我想將 X 功能和 Y 功能解耦”,“避免壞代碼污染應(yīng)用的其他部分”,亦或是 “應(yīng)用程序崩潰時(shí),最小化受影響的半徑”,這些都不是微服務(wù)化的借口,反而是壞的開發(fā)實(shí)踐(保持你現(xiàn)在,需要時(shí)再去觸及),code review 標(biāo)準(zhǔn)需要更加嚴(yán)格(不滿足要求的代碼暫時(shí)不要 merge),缺乏細(xì)粒度的安全控制的表現(xiàn)。
你真的需要獨(dú)立伸縮應(yīng)用的不同部分,并且目前有能力解決一個(gè)或更多的組件問題(如登錄流程)嗎?
你的應(yīng)用是運(yùn)行在基于虛擬服務(wù)器的架構(gòu)上并且想要縮減開支嗎?那么你不應(yīng)該去探索微服務(wù)。
在最好的情況下,你能做到收支相抵。在最壞的情況下,需要啟動(dòng)額外的實(shí)例。假設(shè)你有一個(gè)包含五個(gè)服務(wù)的整體應(yīng)用,然后你將其分解為多個(gè)微服務(wù)。現(xiàn)在,你有5個(gè)應(yīng)用程序,要么a)為其啟動(dòng)專用實(shí)例,使初始內(nèi)存占用增加5倍,要么b)使用現(xiàn)有內(nèi)存占用,只需增加管理它的操作成本。
擁有標(biāo)準(zhǔn)的開發(fā)環(huán)境
當(dāng)你與多個(gè)開發(fā)者協(xié)作時(shí),其中一件最有裨益的事情就是在團(tuán)隊(duì)中標(biāo)準(zhǔn)化開發(fā)環(huán)境。這其實(shí)并不意味著非得一起使用基于容器,虛擬化開發(fā)環(huán)境的“巫術(shù)”。當(dāng)然了,如果你想這么做也可以。但像使用相同版本的開發(fā)語(yǔ)言這種簡(jiǎn)單的標(biāo)準(zhǔn),有時(shí)就會(huì)在團(tuán)隊(duì)中創(chuàng)造奇跡。當(dāng)同事基于 Go 1.11 版本開發(fā)時(shí),你去嘗試基于 Go 1.12 版本去定位 bug 時(shí),你會(huì)哭的。在協(xié)作中升級(jí)版本是有難度的,但如果操作正確升級(jí)也可以很順滑。
配置比看起來要困難,按需計(jì)劃
與一些熱門網(wǎng)站所說的相反,配置其實(shí)要比“把所有東西扔進(jìn)環(huán)境變量”復(fù)雜的多。在我看來,配置一個(gè)應(yīng)用程序應(yīng)該至少有四種方式:
- 代碼中的默認(rèn)配置
- 本地配置文件
- 命令行標(biāo)記
- 環(huán)境變量
- 遠(yuǎn)端配置源(如 Hashicorp 的 Consul)
我將遠(yuǎn)端配置當(dāng)做是可選的,但其他四種是必要的。
開發(fā)過程中,將依賴的 27 個(gè)配置值扔到環(huán)境變量中,僅僅是為了在本地運(yùn)行應(yīng)用程序,這一點(diǎn)至少是令人沮喪的?;蛘吣憧赡苄枰玫淖詣?dòng)化以及一個(gè) Makefile?可以提供一種方式如一個(gè)application.yaml文件來訪問本地配置源,允許你設(shè)置默認(rèn)的 “dev” 配置。另外,代碼中的默認(rèn)配置意思是你只需要設(shè)置需要修改的默認(rèn)配置。當(dāng)通過像 systemd 這樣的初始系統(tǒng)運(yùn)行應(yīng)用時(shí),命令行標(biāo)記會(huì)非常有用,因?yàn)樗梢栽谧粉欉M(jìn)程時(shí),更加容易的看到配置信息。當(dāng)應(yīng)用運(yùn)行在容器中時(shí),環(huán)境變量會(huì)非常實(shí)用,但像秘鑰這種配置不適合放在環(huán)境變量中。
絕不要將秘鑰如密碼、認(rèn)證token、證書等一些你不想泄露出去的東西放到環(huán)境變量中,因?yàn)檫@樣很不安全,有可能被宿主機(jī)上的任何進(jìn)程讀到。你應(yīng)該總是使用秘鑰管理器來管理秘鑰,我個(gè)人的選擇是Vault by Hashicorp,你可以選擇最適合你的。
按需使用包管理,而不是僅僅因?yàn)槟苡?/strong>
我們都知道 “left-pad” 事件,一個(gè)只有 11 行代碼的 NPM 包從倉(cāng)庫(kù)中移除,為何給全網(wǎng)造成了影響?我們不要這樣做。有合理的導(dǎo)包需求時(shí),才應(yīng)該使用 package,如特定供應(yīng)商的SDK(例如 AWS 的 SDK),是一組非常詳細(xì)的標(biāo)準(zhǔn)庫(kù)的抽象(這就是為什么大家喜歡用 Python 的 Requests 庫(kù)而不使用 urllib),或者導(dǎo)入被廣泛使用的框架如 Go 語(yǔ)言的 Echo HTTP server 或者 Python 語(yǔ)言的 Flask WSGI server。一些方便的庫(kù)也可以,比如 JavaScript 的 Lodash,它提供了一些標(biāo)準(zhǔn)庫(kù)中沒有的公共功能和附加功能。這些外部依賴應(yīng)該讓開發(fā)更容易,并且不需要手工編寫樣板或集成代碼 -- 這些是包管理的益處,但是,像 left-pad 這種,很容易陷入這種陷阱--“這正好有一個(gè)能解決問題的庫(kù),直接用舊行了”。每一個(gè)你導(dǎo)入的依賴,都會(huì)增加不穩(wěn)定、不安全或者僅僅不可維護(hù)的風(fēng)險(xiǎn)。
每導(dǎo)入一個(gè)包,新的依賴項(xiàng)本身的風(fēng)險(xiǎn)就會(huì)增加——這也稱為傳遞依賴項(xiàng)。如果你導(dǎo)入一個(gè)單獨(dú)的包,而這個(gè)包又導(dǎo)入了五個(gè)包,那么你現(xiàn)在就繼承了這五個(gè)依賴項(xiàng)以及它們所帶來的所有風(fēng)險(xiǎn)和危險(xiǎn)。我和很多業(yè)內(nèi)人士都認(rèn)為包不應(yīng)該引入傳遞依賴關(guān)系,但這是不現(xiàn)實(shí)的,至少包應(yīng)該盡可能精簡(jiǎn),如果需要更強(qiáng)大的功能,則為用戶提供顯式擴(kuò)展它的方法。
我現(xiàn)在遵循的一個(gè)簡(jiǎn)單原則是,如果導(dǎo)入的庫(kù),我自己可以在 10-15 分鐘實(shí)現(xiàn),就自己實(shí)現(xiàn)。否則,如果有可用的外部庫(kù),我就使用外部庫(kù)。開發(fā)過程中謹(jǐn)記這個(gè)規(guī)則可以讓你避免導(dǎo)入一些不必要的包。如果你不希望每次都從頭開始編寫新的 HTTP 服務(wù)器來提供 API,那么這種方法就足了。
如無必要,無需抽象
一個(gè)極易陷入的大陷阱就是“抽象所有”的黑洞。“這個(gè)我后面可能會(huì)復(fù)用”的想法可能會(huì)使你誤入一些黑暗和可怕的面向?qū)ο笃缤?,我弄清了其中的個(gè)中緣由,DRY 原則已經(jīng)深入人心且理由充分。但是你花太多時(shí)間去抽象反而沒有足夠的時(shí)間寫邏輯。只需安心編寫代碼,如果你發(fā)現(xiàn)需要實(shí)現(xiàn)一個(gè)與之前完成的其他工作類似的方法或函數(shù),那么你可以返回并抽象它——但同樣要有節(jié)制。我個(gè)人傾向于遵循的原則是,如果在抽象之前它是一個(gè)簡(jiǎn)單的三行函數(shù),那么最好保持不變,然后重復(fù)它。如果只是 3 行代碼,也許可以自問,它是否需要變成一個(gè)函數(shù)?
你應(yīng)該時(shí)不時(shí)地“涅槃”你的項(xiàng)目
本條準(zhǔn)則是最可怕的,它讓管理者緊張,讓產(chǎn)品經(jīng)理氣急敗壞,讓開發(fā)者憤怒,但是你絕對(duì)需要它。
每隔一段時(shí)間就從頭開始是一件好事,它允許你代碼中刪除垃圾,實(shí)現(xiàn)新的想法,而不需要改造現(xiàn)有的代碼庫(kù),并迫使每個(gè)人重新評(píng)估項(xiàng)目。
把項(xiàng)目想象成森林,每一行代碼都是綿延數(shù)英里的大森林中的一棵巨大松樹。隨著森林的演化,灌木叢、丟棄的松針、松果、枯死的樹枝和其他雜物散布于森林之中。這是你厭惡的東西,你的技術(shù)債。它會(huì)一直不斷堆積,直到某些巨變發(fā)生。對(duì)于森林而言,這種變化是以野火的形式出現(xiàn)。大火橫掃森林,燒毀了堆積起來的無用垃圾。樹皮足夠厚的樹會(huì)留下來,未成熟或未發(fā)育完全的樹會(huì)在火災(zāi)中被燒毀。雖然這看起來是森林的盡頭,但它隱藏了一個(gè)巨大的秘密:森林一直在等待這場(chǎng)火。耐心地,年復(fù)一年地,森林一直在期待這場(chǎng)大火來凈化自己,并帶來變化。因?yàn)楫?dāng)大火在樹冠下肆虐時(shí),下一代的參天大樹正在松果中發(fā)芽。當(dāng)大火蔓延到森林地面時(shí),脆弱的幼樹就會(huì)冒出來,與被大火熏黑的幸存者為伴。這也是你的應(yīng)用程序該有的樣子:有彈性的、在清除過程中,編寫良好的部分幸存下來,而其他部分則為新思想和新代碼讓路——就像鳳凰涅槃一樣。
你不是 Google
除非你是 Google,但如果你真的是 Google,為何你還在讀這篇文章呢?關(guān)鍵是你大概率不是 Google,不是 Microsoft,不是 Amazon,不是 Twitter,不是 Facebook。你不需要在全世界 17 個(gè)不同的數(shù)據(jù)中心的 10,000 個(gè)裸機(jī)服務(wù)器上編排 150,000 個(gè)容器。你的問題通常不會(huì)對(duì)世界上每一個(gè)人造成很大的影響。我們?yōu)槭裁匆懻撨@個(gè)?因?yàn)槟愕囊?guī)模決定了你的操作平臺(tái)。如果你正在運(yùn)行幾百個(gè)容器,那么你真的需要 Kubernetes 嗎?你真的需要自己運(yùn)行 Kubernetes,還是只是想把它添加到你的簡(jiǎn)歷中?HashiCorp Nomad 之類的工具非常適合解決中小型問題:它易配置,幾乎不需要維護(hù),有良好的文檔,并且非常容易就可以把應(yīng)用程序遷移過去,因?yàn)樗梢耘c容器、系統(tǒng)進(jìn)程和 JVM 應(yīng)用程序一起工作。如果你真的想使用 Kubernetes,為什么不基于把繁雜細(xì)節(jié)都抽象好的 Rancher 來管理呢?運(yùn)行 Kubernetes 這樣的復(fù)雜系統(tǒng)(它是為谷歌這樣的公司設(shè)計(jì)的)所帶來的麻煩和開銷對(duì)于一個(gè)團(tuán)隊(duì)來說是難以承受的。我甚至?xí)苯亓水?dāng)?shù)卣f,初創(chuàng)公司應(yīng)該不惜一切代價(jià)避免使用它,除非他們的產(chǎn)品是專門針對(duì) Kubernetes 的。需要注意的是,要使用 Google、Amazon 和 Microsoft 在各自的云產(chǎn)品中提供的托管服務(wù)。因?yàn)樗麄児芾碇械某舐臇|西,很多管理費(fèi)用并不是由你來承擔(dān)的。但千萬別讓我抓到你在物聯(lián)網(wǎng)設(shè)備上使用 Kubernetes,千萬不要。
不要照搬網(wǎng)上陌生人的開發(fā)哲學(xué)
對(duì)于開發(fā)風(fēng)格和要遵循的原則,你應(yīng)該形成自己的想法。即使是上面的 10 條建議也只是僅供討論,我只是網(wǎng)上的過客。