日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

作者 | David Seddon

譯者 | 平川

策劃 | Tina

本文最初發(fā)布于 EuroPyhon 官方博客。

大家好,我叫 David,是 Kraken Technologies 的一名 Python/ target=_blank class=infotextkey>Python 開發(fā)人員。我從事 Kraken 開發(fā),那是一個 Python 應(yīng)用程序。據(jù)最新統(tǒng)計,它有 27,637 個模塊。是的,你沒看錯:將近 28k 個獨立的 Python 文件,這還不包括測試。我和世界各地的其他 400 名開發(fā)人員一起做這件事,不斷地合并代碼。任何人只要在 Github 上得到一個同事的批準(zhǔn),就可以做出變更,開始部署這個運行著 17 家不同的能源和公用事業(yè)公司、擁有數(shù)百萬客戶的軟件。

現(xiàn)在,你可能覺得這會很混亂。說實話,我也會這么說。但事實證明,大量的開發(fā)人員可以在一個大型的 Python 單體上有效地開展工作,至少在我們工作的領(lǐng)域是如此。這是可能的,原因有很多,很多是文化上的,而不是技術(shù)上的。但在這篇博文中,我想介紹一下代碼的組織如何幫助我們實現(xiàn)這一目標(biāo)。

代碼庫分層

如果你在某個代碼庫上做過一段時間的開發(fā),那么你肯定感受過那令人不快的復(fù)雜性。應(yīng)用程序的邏輯鏈錯綜復(fù)雜,想要獨立地考慮應(yīng)用程序的各個部分變得越來越困難。我們的代碼庫開始時也是這樣,所以我們決定采用所謂的“分層架構(gòu)”,對代碼庫層與層之間哪些部分可見做了限制。

分層是一種眾所周知的軟件架構(gòu)模式。在這種模式中,組件在概念上被組織成一個棧。棧中的組件不能依賴于上層的任何組件。

分層架構(gòu),向下依賴

如上圖所示,C 可以依賴 B 和 A,但不能依賴 D。

分層架構(gòu)的概念很廣泛:它可以用于不同類型的組件。例如,你可以將幾個可獨立部署的服務(wù)分層;或者,你的組件可以只是一組源代碼文件。

依賴的構(gòu)成也很廣泛。一般來說,如果一個組件對另一個組件有直接的了解(即使純粹是在概念層面),那么它就依賴于另一個組件。間接交互(例如,通過配置)通常不視為依賴。

Python 中的分層

在 Python 代碼庫中,最好將層視為 Python 模塊,將依賴視為 import 語句。

以下面的代碼庫為例:

myproject __init__.py payments/ __init__.py api.py vendor.py products.py shopping_cart.py

頂層模塊和子包是層的良好候選。假設(shè)我們按下面這樣的順序分層:

shopping_cart payments products

那么,在這個架構(gòu)中,shopping_cart 不能導(dǎo)入 payments 中的任何模塊。不過,它可以導(dǎo)入 products 的模塊。

層可以嵌套。因此,payments 可以像下面這樣分層:

api vendor

至于分成幾層以及各層之間的順序,并沒有一種唯一正確的方法,這是一種設(shè)計行為。但是像這樣的分層可以減少代碼庫的混亂,使其更容易理解和修改。

Kraken 是如何分層的

在我寫這篇文章時,有 17 家不同的能源和公用事業(yè)公司批準(zhǔn)了 Kraken 的使用。我們?yōu)檫@些企業(yè)客戶中的每一個運行一個單獨的實例。現(xiàn)在,Kraken 的主要特點之一是不同的實例“相同又不同”。換句話說,它們之間有很多共享的行為,但每個實例都有滿足特定客戶需求的定制代碼。在地區(qū)層面上也是如此:在英國運營的所有客戶之間存在一些共性(它們與同一能源行業(yè)相融合),但與 Octopus Energy Japan 不同。

隨著 Kraken 發(fā)展成為一個多客戶平臺,我們改進了它的分層結(jié)構(gòu)。總的來說,現(xiàn)在的情況是這樣的:

kraken/ __init__.py clients/ __init__.py oede/ oegb/ oejp/ ... territories/ __init__.py deu/ gbr/ jpn/ ... core/

客戶位于頂層。每個客戶對應(yīng)該層中的一個子包(例如,oede 對應(yīng) Octopus Energy Germany)。客戶的下面是地區(qū),實現(xiàn)特定于國家的行為,同樣,每個地區(qū)對應(yīng)一個子包。最下層是核心層,其中包含所有客戶都使用的代碼。還有一個額外的規(guī)則,即客戶子包必須是獨立的(即不能從其他客戶包導(dǎo)入),對于地區(qū)同樣如此。

像這樣把 Kraken 分層可以有效限制變更的“爆炸半徑”。由于客戶層位于頂部,所以沒有任何東西直接依賴于它。因此,要修改與特定客戶相關(guān)的內(nèi)容會比較容易,而且不會意外影響其他客戶的行為。同樣,只涉及一個地區(qū)的更改也不會影響到另一個地區(qū)的任何東西。這使得我們能夠快速獨立地跨團隊開展工作,特別是當(dāng)我們正在進行的更改僅影響少量 Kraken 實例時。

利用 Import Linter 強制分層

當(dāng)我們引入分層時,我們很快就發(fā)現(xiàn),僅僅討論分層是不夠的。開發(fā)人員經(jīng)常會不小心違反分層結(jié)構(gòu)。我們需要以某種方式強制執(zhí)行,為此,我們使用了 Import Linter。

Import Linter 是一個開源工具,可以檢查你是否遵守了分層架構(gòu)。首先,在 INI 文件中定義一個契約,用于描述分層,像下面這樣:

[importlinter:contract:top-level]

name = Top level layerstype = layerslayers =kraken.clientskraken.territoriesKraken.core

我們也可以另外添加兩個契約(‘independence’契約),強制保持不同客戶和地區(qū)的獨立性:

[importlinter:contract:client-independence]name = Client independencetype = independencelayers =kraken.clients.oedekraken.clients.oegbkraken.clients.oejp...

[importlinter:contract:territory-independence]name = Territory independencetype = independencelayers =kraken.territories.deukraken.territories.gbrkraken.territories.jpn...

然后,你可以在命令行上運行 lint-imports,它會告訴你是否有任何導(dǎo)入違反了契約。每次有 pull 請求時都會自動執(zhí)行這個命令進行檢查,所以如果有人引入了非法導(dǎo)入,就無法通過檢查,也就無法完成合并。

契約不只這些。團隊可以在應(yīng)用程序中添加更深的分層:例如,kraken.territories.jpn 本身就是分層的。目前,我們有 40 多個契約。

減少技術(shù)債務(wù)

在引入分層架構(gòu)時,我們沒法從第一天開始就嚴格遵守。所以我們使用了 Import Linter 的一個特性,在檢查契約之前忽略某些導(dǎo)入。

[importlinter:contract:my-layers-contract]name = My contracttype = layerslayers =kraken.clientskraken.territorieskraken.coreignore_imports =kraken.core.customers ->kraken.territories.gbr.customers.viewskraken.territories.jpn.payments -> kraken.utils.urls(and so on...)

然后,我們使用被忽略導(dǎo)入的數(shù)量作為跟蹤技術(shù)債務(wù)的指標(biāo)。這使我們能夠了解改進情況,以及改進速度。

自 2022 年 5 月 1 日起被忽略導(dǎo)入的數(shù)量

上圖是在過去一年左右的時間里,被忽略導(dǎo)入的數(shù)量變化情況。我定期向人們進行分享和展示,鼓勵他們朝著完全遵守依賴原則的方向努力。我們在其他幾個技術(shù)債務(wù)指標(biāo)中也使用了這種燃盡方法。

缺點,缺點總是不可避免

局部復(fù)雜性

在采用分層架構(gòu)之后的某個時刻,你可能會遇到需要打破分層的情況。實際情況會非常復(fù)雜,到處都是相互依賴,比如,你會發(fā)現(xiàn)自己想要調(diào)用一個更高層的函數(shù)。

幸運的是,辦法總比問題多。我們可以利用控制反轉(zhuǎn),那在 Python 中很容易實現(xiàn),所需的只是理念的轉(zhuǎn)變。但它確實會增加“局部”的復(fù)雜性(如代碼庫的一小部分)。然而,為了使系統(tǒng)總體上更簡單,付出這樣的代價是值得的。

較高的層上代碼過多

層越高,越容易更改。我們是有意為之的,讓針對特定客戶或地區(qū)的代碼更容易更改。其他所有的層都要依賴于核心代碼,對其進行修改的成本和風(fēng)險也都更高。

因此,我們面臨的設(shè)計壓力部分是由我們選擇的分層結(jié)構(gòu)帶來的,我們需要編寫更多特定于客戶和地區(qū)的代碼,而不是在核心代碼中引入更深的層次和更多可供全局使用的代碼。因此,較高的層所擁有的代碼超出了我們的預(yù)期。我們?nèi)栽谘芯咳绾谓鉀Q這個問題。

我們還沒有完成

還記得那些被忽略的導(dǎo)入嗎?好吧,幾年過去了,我們還是有一些!據(jù)最新統(tǒng)計,有 15 個。最后幾項導(dǎo)入是最棘手、讓人最糾結(jié)的。

回顧性地對代碼庫進行分層可能需要付出很大的努力。但這件事你做得越早,需要解決的問題就越少。

小 結(jié)

Kraken 的分層架構(gòu)使我們這個非常龐大的代碼庫得以保持健康,并且相對比較容易使用,尤其是在這么個規(guī)模下。如果不對這成千上萬的模塊之間的關(guān)系施加約束,我們的代碼庫可能就會變成一大盤意大利面。但是,我們選擇的這個大規(guī)模結(jié)構(gòu)——并且隨著業(yè)務(wù)的發(fā)展而發(fā)展——幫助我們在單個 Python 代碼庫上做了大量的工作。這似乎是不可能的,但我們確實做到了!

如果你正在處理大型 Python 代碼庫(甚至是相對比較小的代碼庫),不妨試一下分層。這事越早做越簡單。

原文鏈接:

https://blog.europython.eu/kraken-technologies-how-we-organize-our-very-large-pythonmonolith/

分享到:
標(biāo)簽:Python
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定