Azure DevOps in Action - 專案的相依性管理與套件的使用


近代軟體開發大多以套件或框架為基礎,不管你採用哪一個語言。最近這五年,我們在專案的相依性管理上已經有了很大的成熟度和改變。如果你回憶十幾年前的軟體開發,可能常常看到專案中有底下這樣充滿相依性的設計:

說明一下,在上圖中,WebBMI.sln內共有三個專案,HealthMgr(上圖A)它是一個類別庫(Class Library),而HealthMrgTests是該類別庫的UnitTest,WebBMI則是Web UI的主程式(上圖B)。

由於主程式中使用到了HealthMgr,因此它是相依於HealthMgr的,也就是說,主程式在建置時,必須要參考到HealthMgr內的一些類別與方法。

如果你開啟Visual Studio來看會更清楚:

Visual Studio 2019本身有著很好的相依性檢視工具,你可以看到主程式WebBMI相依於同一個.sln中的HealthMgr,而且是以專案形式相依,這點是我們不喜歡的。

目前,WebBMI以『加入參考』的方式:

把同一個.sln中的HealthMgr給加入到WebBMI當中:

這雖然讓WebBMI可以輕鬆的使用到撰寫於HealthMgr內的類別和方法,但這是很古典的作法,不能說不好(如果把HealthMgr內的類別直接全寫在WebBMI主程式中可能更不好),但最近幾年我們已經不再鼓勵開發人員這樣作了。

最主要的原因有幾點:

第一, 這使得WebBMI這個Project在Build的時候,非得跟HealthMrg專案綁在一起,兩者無法分割,形成高相依性。兩三個專案你看起來還好,但我就看過.sln的solutions中有近百個專案的。

第二, 如果HealthMrg專案又被另一個B專案所參考使用,未來很可能造成潛在的版本衝突。例如,當WebBMI專案因為某些理由,必須修改HealthMrg專案中某個類別的運算邏輯,但因為除了WebBMI專案之外,B專案同時也在使用HealthMrg中同一個類別,導致若修改了HealthMrg就會與B專案不相容,不改又不符合WebBMI新的需求,進入兩難的狀況。

砍斷針對專案的相依

因為前述的原因,近代在我們作軟體開發時,幾乎都已經不會再如同過去這樣,直接對某一個專案作參考(reference),造成專案之間的潛在相依性衝突,而是改為針對套件(Package)的相依。

砍斷對專案的相依,改成對套件相依有許多好處,我們可以把前面講到的HealthMrg專案,建立成一個副檔名為HealthMrg.nupkg這樣的套件,然後把主程式(WebBMI.csproj)對HealthMgr專案的參考,改為對HealthMrg.nupkg套件的參考。

由於HealthMrg.nupkg套件本身可以有多重的版本機制(例如HealthMrg.1.0.1.nupkg , HealthMrg.1.0.2.nupkg這樣),每一次當套件需要修改,我們只需要增加版號即可。

如此一來,就算同時有多個專案參考到同一個套件,因為套件有版本可以區分差異,所以無須擔心A, B兩個專案同時參考了HealthMrg這個套件後,HealthMrg需要更新時該怎麼辦的問題。

也因此,近代軟體設計中,只要可能被其他專案參考使用的類別,我們幾乎都會設計成套件的形式,這也讓套件庫這樣的機制開始盛行,Node.js開發有NPM、python有pip、.net開發則是Nuget。

為了確保使用到套件的應用程式可以正確執行,所有的套件都必須維持恆定性,也就是套件一但上架後是不能修改、不能刪除(只能下架隱藏)的,如果有修改,就必須對套件作版號上的增添。這也是你會看到套件都有這樣的版號的原因:

HealthMrg.1.0.1.nupkg

HealthMrg.1.0.2.nupkg

HealthMrg.2.1.1.nupkg

HealthMrg.2.2.1.nupkg

一般來說,版號會遵循著業界的規則。

例如,HealthMrg.3.2.5.nupkg這個套件其中的3是Major, 2是Minor, 5是Patch:

舉凡Major版號有所變更,例如從2升到3,大多表示新版(3.x.x)將與舊版(2.x.x)有相當大(大到不相容)的改變。因此,當我們看到自己專案中所採用到的套件升級了Major版號的時候,一般也意味著必須留意升級後相容性的議題。

而Minor版號的變更,則大多是在維持相容性的前提下,所作的套件功能擴充或修改。而Patch則多是bug fix,或是某些與新功能無關的套件修正或調整。

這個版號是業界對於套件建立與開發的習慣,遵循這樣的版號機制,可以讓套件的開發者與使用者在同一個基礎上順暢的合作。

在.net core專案中建立nuget套件

對於套件有一定的認識之後,我們就實際來建立一個套件。打開Visual Studio 2019建立一個.net core的類別庫:

或乾脆使用我在Azure DevOps上公開的Repo,其Clone位置如下:

https://mytestaz400@dev.azure.com/mytestaz400/SampleCode/_git/dotNetCoreBMISample

你可以直接建立一個Azure DevOps專案,然後在repo中Clone上面這個現有的Project。

開啟後,你會發現,其中有一個HealthMrg專案:

這個類別有一個Calculate方法(上圖A)我們會在WebBMI的主程式中使用到:

參考上圖A,你會看到這是以.net core的razor page所撰寫的主程式,其中呼叫到了HealthMgr類別中的Calculate方法,用來計算BMI。這是因為在這個主專案中我們透過『加入參考』的方式,參考了同一個.sln方案中的HealthMgr專案,之前說過,這是傳統的作法,而現在我們要改成以Nuget Package的方式參考。

我們來到了HealthMgr專案的屬性視窗:

你會發現,在.net core/.net standard的類別庫(Class Library)專案上,想要讓某一個類別庫專案建置為nuget套件非常、非常容易,只需要在上圖的畫面中打一個勾即可。

當專案勾選了『建置Nuget套件』後,在Build這個類別庫時,就會自動建置出該組件(.dll)的nuget套件。

若你開啟產生出的nuget套件,可以看到:

包含該.dll的nuget套件就這樣被自動的建立出來了。

將套件上傳到Nuget.Org

建立好Nuget套件之後,我們得讓原本主程式WebBMI改為對套件參考,而非對專案參考。因此,我們必須先把建置好的套件發佈到套件庫裡面。

套件內的程式碼常常會被視為企業資產的一部分,所以一般來說,企業應該要針對自己開發的套件作為一個Private的套件庫,而非上傳到開放存取的Nuget.Org[1],以避免全世界都來共享你的開發成果。

要建立一個Private Nuget也不是太難,但更方便的是Azure DevOps裡面已經具有內建的套件庫,位於Artifacts:

不過,我們後面再來談這個部分。我們先來看,如果要把套件上傳到Public的Nuget.org該如何作?

開發人員只需要具有Microsoft Account,就可以透過Single Sign On的方式,登入Nuget.org(人人可開發套件的概念):

登入後,最簡單的方式,是透過Upload Package選單來上傳你開發好的套件:

在右上角登入的個人選單底下,選取Upload Package(上圖A),就可以進入上傳畫面,然後選取你要上傳的組件直接Upload即可。

不過要請留意,你的套件ID不能跟其他人的相同,且每一個套件的同一個版本,也只能上傳一次,否則就會出現底下的錯誤訊息(下圖A):

所以,如果你是Clone本文中前面提到的專案,你必須修改套件名稱和版號,才能夠上傳的上去nuget。由於我是HealthMgr這個套件的作者,因此我可以上傳id為HealthMgr的套件,只需要修改版號即可:

在上圖中我們把版號改成1.1.10,Visual Studio會自動建置出名稱為『HealthMgr.1.1.10.nupkg』的套件。

取得套件後我們將其上傳:

上傳後你會看到該套件會先被自動檢查,並且nuget會為其建置索引,一段時間後(大概十幾分鐘到一小時),該套件的狀態(Status)就會變成Listed,這意味著剛才我們上傳的套件已經上架,這時候你在開發工具中,就能夠使用該套件了。

改為針對套件的相依

在套件上架後,我們可以透過Visual Studio的方案總管,先移除WebBMI主專案原本對HealthMrg專案的相依。

您可以在專案名稱上按下滑鼠右鍵,選擇加入參考,就會出現底下畫面。然後直接把原本打勾的HealthMgr勾選取消:

移除後,你會發現,方案總管中相依性的部分也看不到『專案』了。

接著,我們再對主專案加入Nuget套件:

我們可以透過專案的『管理nuget套件』選單,開啟Nuget套件管理員,接著選擇『瀏覽』頁標籤,透過關鍵字搜尋套件名稱。

你會發現我們剛才上傳的套件果然有列在清單中,點選該套件選擇『安裝』即可:

成功安裝後,你可以建置(Build)主專案,你會發現主專案由於使用了這個套件,既便沒有直接對HealthMrg專案的相依,依舊是可以建置與執行的:

就是這樣,我們將主專案中針對Project的相依,改成針對Package的相依,過程並非相當困難,但對於系統相依性的管理則大大的提升了便利性。


[1] 當然,如果企業覺得該套件沒有敏感性,也沒有商業考量,想要上傳到nuget.org和全世界一起分享也並無不可。

---------------------------
相關課程:http://www.studyhost.tw/NewCourses/ALM
節錄自『Azure DevOps敏捷開發與專案管理實戰

留言

這個網誌中的熱門文章

使用 Airtable 在小型需求上取代傳統資料庫

在POC或迷你專案中使用 LiteDB

專業的價值...

精彩(且驚人)的Semantic Kernel入門範例

周末讀書會 - 一如既往