發(fā)布于:2020-12-24 16:05:07
0
121
0
那是2011年,我們Toopher正在構(gòu)建一個(gè)復(fù)雜的身份驗(yàn)證API。我們的小型創(chuàng)業(yè)公司基于創(chuàng)始人Evan Grim的研究生項(xiàng)目,而認(rèn)證API是我們的唯一產(chǎn)品。作為一家初創(chuàng)公司,我們專注于創(chuàng)造價(jià)值,因此我們利用現(xiàn)有工具,而不是從頭開始構(gòu)建一切。
我們用Django編寫了整個(gè)產(chǎn)品,這是一個(gè)成熟的,包含電池的開源Python Web框架,致力于快速的應(yīng)用程序開發(fā)(正是我們當(dāng)時(shí)的工作?。?。我們使用了Piston框架來處理API創(chuàng)建。這是一個(gè)不錯(cuò)的框架,沒有什么可以滿足我們的需求了。但是Piston最終被放棄為一個(gè)項(xiàng)目,迫使我們提出了自己的解決方案,我們做到了,我們稱之為django-declarative-apis。
到這個(gè)時(shí)候,我們的小公司已經(jīng)被Salesforce收購。實(shí)際上,Salesforce Authenticator應(yīng)用程序是作為我們復(fù)雜的身份驗(yàn)證API的前端而構(gòu)建的。我們意識到django-declarative-apis框架填補(bǔ)了Django生態(tài)系統(tǒng)中的空白,并希望將其開源,但遇到了兩個(gè)問題。
首先,新框架已深深地嵌入到我們創(chuàng)建的自動(dòng)兩因素身份驗(yàn)證API中,并且將其發(fā)布到一個(gè)可以公開發(fā)布的單獨(dú)程序包中將是一個(gè)挑戰(zhàn)。
其次,盡管Salesforce制定了支持員工從事開源項(xiàng)目的政策,但當(dāng)時(shí)并沒有將先前專有代碼轉(zhuǎn)換為開源代碼的流程。
我們想分享我們學(xué)到的東西,我們學(xué)到了兩件事。首先,我們學(xué)習(xí)了如何為Django設(shè)計(jì)這樣的庫,以及如何將其與許多早已嵌入到應(yīng)用程序中的意大利細(xì)面條邏輯解耦,以進(jìn)行公共開源發(fā)行。其次,我們學(xué)習(xí)了如何通過Salesforce推出這樣的開源版本,這是一個(gè)動(dòng)態(tài)的地方,但也是一個(gè)很大的地方-您不僅可以獲取專有代碼,然后將其扔到GitHub上,然后再調(diào)用它。首先,讓我們討論一下技術(shù)挑戰(zhàn)以及我們?nèi)绾螒?yīng)對這些挑戰(zhàn)。
反對意大利面條的邏輯
原始的API框架是一個(gè)非常程序化的解決方案。您從一個(gè)請求開始,然后提取參數(shù)并執(zhí)行您需要做的事情,以一種方法形成響應(yīng)。我們必須不斷地使用新功能,而又不會(huì)破壞任何東西,最后我們得到了一堆令我們感到羞恥的意大利面條邏輯處理程序。對于單個(gè)處理程序,那里有一個(gè)非常多毛的500行方法。
它變得非常脆弱,每次不得不修改它時(shí),我們都會(huì)感到難過。不同的行為集將基于輸入?yún)?shù)運(yùn)行,并且存在很多相互依賴關(guān)系。但是我們需要繼續(xù)支持所有這種行為,因?yàn)槲覀冇幸蕾囉谒拿總€(gè)方面的客戶。
關(guān)于版本2的想法已經(jīng)出現(xiàn)了一段時(shí)間。最大的目標(biāo)是使所有API處理程序都以聲明方式進(jìn)行編碼。也就是說,可以根據(jù)代碼確定處理程序的行為。您可以對代碼進(jìn)行靜態(tài)分析,并了解所有需要了解的信息:如何調(diào)用處理程序,獲得什么樣的響應(yīng)以及它在中間執(zhí)行什么操作。
我們還希望從處理程序中的業(yè)務(wù)邏輯中抽象出HTTP請求-響應(yīng)周期。在這一點(diǎn)上,現(xiàn)有的選擇相當(dāng)嚴(yán)格。對于任何處理程序,您都必須處理請求對象,并在處理程序方法中進(jìn)行所需的任何數(shù)據(jù)轉(zhuǎn)換,并使用與該代碼的業(yè)務(wù)功能沒有直接聯(lián)系的邏輯對其進(jìn)行污染。
我們想出了愿望清單界面。 Evan想出了一種更具進(jìn)取性的前瞻性方法來編寫我們的API,這啟發(fā)了我們立即放棄我們考慮過的所有其他方法并全力以赴。這與我們之前看到的API處理程序的任何方式都不同。
使它與眾不同的是,處理程序代碼完全不知道HTTP接口。標(biāo)頭,編碼,URL參數(shù),所有這些東西都是通過一個(gè)類來處理的,該類將請求參數(shù)自動(dòng)映射到該類中的字段。該類可能包含將請求數(shù)據(jù)轉(zhuǎn)換為處理程序方法可用的數(shù)據(jù)的方法,從而確保處理程序代碼僅包含業(yè)務(wù)邏輯。根據(jù)該請求,它可以提取必要的數(shù)據(jù),收集所有依賴關(guān)系并準(zhǔn)備響應(yīng)對象。
如果請求引起任何副作用,例如發(fā)送電子郵件,則可以將其隔離到單獨(dú)的任務(wù)方法中,同時(shí)保持該處理程序方法的清潔。使用附加的裝飾器,可以使該task方法自動(dòng)推遲運(yùn)行,直到處理程序返回響應(yīng)為止。通過分離所有此類內(nèi)容,我們使處理程序變得更加易于維護(hù)。
框架一旦實(shí)現(xiàn),就需要證明它是完整的功能。為此,我們在其中重新實(shí)現(xiàn)了超級多毛的500行處理程序。因?yàn)槿绻覀兡軌蚴乖撘矮F在此框架中工作,那么我們將非常有信心它具有將所有API移植到該框架所需的全部功能。在快速完成一半的API(以及笨拙的野獸)之后,整個(gè)移植過程大約花費(fèi)了一年的時(shí)間。
雖然最初的項(xiàng)目是作為身份驗(yàn)證器API和應(yīng)用程序的一部分創(chuàng)建的(您可以在Apple和Google應(yīng)用商店中以Salesforce Authenticator的身份看到它),但該框架是如此有用,我們決定將其拆開并使其成為一個(gè)單獨(dú)的庫。
第一步是將其復(fù)制并粘貼到主項(xiàng)目(其自己的頂級目錄)中的干凈模塊中。雜亂無章,但是將這段代碼移到其自己的模塊中暴露了耦合,并向我們展示了我們需要解開哪些類型的結(jié)。我們在這個(gè)新模塊中重構(gòu)了所有破壞的依賴關(guān)系,然后返回到原始API并對其進(jìn)行了重構(gòu)以與新的修補(bǔ)程序一起使用。此時(shí),我們在兩個(gè)項(xiàng)目中都有相同的模塊,因此我們可以從原始API中刪除框架代碼。最后一步是使新框架可用于Salesforce中的項(xiàng)目安裝-一個(gè)真正的庫,而不僅僅是一個(gè)子模塊。
分享您引以為豪的東西
我們一直有野心要開源我們創(chuàng)建的框架。當(dāng)您創(chuàng)建引以為傲的新穎解決方案時(shí),讓其他人使用和貢獻(xiàn)它只能對整個(gè)軟件社區(qū)有所幫助。另外,通過開源,我們可以使用一些一流的工具,例如Travis CI,并且可以更輕松地將這個(gè)框架整合到Salesforce的項(xiàng)目中。
但這仍然是我們待辦事項(xiàng)列表中的低優(yōu)先級項(xiàng)目。至少直到Demian Brecht加入該團(tuán)隊(duì)為止。他是我們的開源倡導(dǎo)者,他不僅相信以個(gè)人身份參與開源社區(qū),而且相信回饋開源社區(qū)的公司的有形和無形利益。他活躍于Salesforce內(nèi)部和外部的許多開源項(xiàng)目。到目前為止,django-declarative-apis已經(jīng)是一個(gè)子模塊,在Salesforce的許多項(xiàng)目中都被大量使用。我們很自然地將其開源。
但是,當(dāng)我們與團(tuán)隊(duì)中的人們交談時(shí),一個(gè)共同的主題是他們喜歡開源軟件,但以前從未對此做出過貢獻(xiàn),并且對此感到有些害羞。我們希望給他們這種機(jī)會(huì),并幫助他們開始以有意義的方式為開源項(xiàng)目做出貢獻(xiàn)。他們會(huì)與我們的客戶或休閑愛好者(任何想使用和塑造它的人)一起公開開發(fā)該庫。
這樣,您的團(tuán)隊(duì)可以公開開發(fā)代碼,這將為您帶來巨大的好處;因?yàn)槿魏稳硕伎梢钥吹侥拇a,將其添加到項(xiàng)目中并評論您的拉取請求,所以您有更多的責(zé)任來考慮您所做的更改。您會(huì)收到有關(guān)更周到的更改的更好的提交消息,這使您的開發(fā)過程具有自記錄功能。
工程團(tuán)隊(duì)正在考慮將框架開源,然后我們需要與法律部門合作以實(shí)現(xiàn)該框架。對于他們來說,這是一個(gè)全新的情況。他們建立了一個(gè)矩陣,用于以開源形式啟動(dòng)一個(gè)新項(xiàng)目或在現(xiàn)有的開源項(xiàng)目上工作,但沒有采取從安全相關(guān)產(chǎn)品中提取框架并公開發(fā)布代碼的方式。
因?yàn)槲覀冋陂_拓新的天地,所以我們必須確保我們的i點(diǎn)綴成點(diǎn),而t的點(diǎn)綴在各處。我們需要仔細(xì)檢查所有代碼,以確保沒有任何值得我們放棄的專利。我們讓產(chǎn)品安全人員確保我們不會(huì)無意間泄露一些簡單的方法來入侵我們。這是同類項(xiàng)目中的第一個(gè)項(xiàng)目,所以花了大約六個(gè)月的時(shí)間,但是由于我們經(jīng)歷了整個(gè)項(xiàng)目并弄清了問題,因此,Salesforce的現(xiàn)有項(xiàng)目的開源采購現(xiàn)在變得更加精簡(而且很平常)。這些天來,我們有一個(gè)正式的開源采購流程,該流程有時(shí)是即時(shí)的,但很少需要4-6周以上的時(shí)間!因此,我們現(xiàn)在每年在公司范圍內(nèi)公開采購數(shù)十個(gè)項(xiàng)目。
對于我們而言,將其開源是有實(shí)際好處的,而與社區(qū)相關(guān)或外部無關(guān)。內(nèi)在的好處圍繞著我們的部署流程而展開。我們在Heroku上部署了我們的API,這使安裝開源和公共存儲(chǔ)庫中的依賴關(guān)系變得容易。作為Salesforce內(nèi)部的一個(gè)封閉庫,我們不得不跳很多圈來向項(xiàng)目添加django-declarative-api。箍之一的一個(gè)示例是提供依賴關(guān)系,即將庫的整個(gè)源樹鏡像到依賴項(xiàng)目中,而不是簡單地在配置文件中指定依賴關(guān)系和版本。當(dāng)它變成開源時(shí),突然之間,我們不再需要消耗封閉源代碼依賴項(xiàng),也沒有其他任何障礙。
除了使我們的工作流程更容易之外,使項(xiàng)目開源還使我們能夠使用某些最佳工具,例如Travis CI。這些工具周圍有龐大的社區(qū),因?yàn)樗鼈儽旧砭褪情_源的。能夠參與這些社區(qū)并為社區(qū)做出貢獻(xiàn)真是太好了。如果開源,意味著我們可以在django-declarative-apis周圍找到一些社區(qū),那就太好了。但是,沒有任何這些都是值得的。
我們?yōu)檫@個(gè)圖書館感到驕傲,并很高興能夠與社區(qū)分享。當(dāng)您在django-declarative-apis中實(shí)現(xiàn)具有相當(dāng)程度的復(fù)雜性的新端點(diǎn)時(shí),您會(huì)非常感謝它在很大程度上保護(hù)了您免于編寫不良代碼。我們接受復(fù)雜性作為我們的權(quán)衡;但是如果它允許我們在每天實(shí)施的處理程序中表達(dá)更多的簡單性,我們愿意接受框架中的更多復(fù)雜性。
最后,這兩個(gè)部分都是學(xué)習(xí)經(jīng)驗(yàn)。我們造成了很多技術(shù)債務(wù),與嘗試進(jìn)行零散維修相比,重新開始比以前更能解決問題。我們還發(fā)現(xiàn),Salesforce的同僚很高興地解釋了為何存在法律法規(guī),這很有幫助。開源過程花費(fèi)了更長的時(shí)間。
作者介紹