項目源碼與項目構建產物的版本管理

前言

工作中雜事比較多,或許沒有哪個公司會去給你專門的寫技術博客的時間吧。我想說的是,也許會擠時間的人能夠在工作間隙抽空寫出自己對技術的感悟,一有某方面看法,立馬能夠捕捉當時想法記錄下來,至少也方便後來的整理成文,而且能夠用這種方式說服更多人認可他的觀點。而對於我,事實上我沒有寫博客的習慣,但是我確實想寫,記錄出來,我只能說自己比較懶吧,可是我對我做的項目,對於我工作中遇到的諸多問題其實都有自己的想法,我時常有很多想要去改善的衝動,無奈,我目前做的項目有很多的問題,改動了一點小問題也不能拯救一個地球,地震呢還是會出現。因爲我們一直相信的所謂的不要影響太大,只能讓我們每一個項目成員束手束腳,始終不能解決根本問題!!像開頭說的,我暫時只有在晚上努力絞盡腦汁去想工作中出現了哪些問題,如何有秩序的分析這些問題,併合理整理成文,剖析項目的根本管理問題。
其實我應該用一個富文本去寫這些內容,但是我確實很少寫博客,暫時只能在手機上先用這種筆記本的方式記下來,文中大部分都是文字的描述,我儘可能寫的讓大家看懂,明白我,理解我,贊同我!!!
介於項目問題比較多,代碼規範問題,版本管理問題等。我今天就挑出項目根本的問題來談!!!

正文

這個最根本的問題就是項目的版本管理問題。而我今天的話題是項目的代碼版本管理與部署後的項目版本管理。
首先我強調的是前者關注的是源碼,包括項目所有的java源代碼、用到的jar庫、用到的資源、所有爲初始轉化和編譯而存在的編譯腳本。而後者實際上是已經編譯並且組裝成符合webapp規範的目錄的產物。即後者是前者轉化過來的,當然更多的是編譯過程,而編譯後還要對資源和編譯產物進行組裝成最終web服務器能識別的標準產物,這個標準產物有它規範的目錄,這話我又說了一遍,不懂的就百度java web應用部署的目錄規範。所以我就抽象叫這個過程是一種轉化過程,轉化的過程可能複雜,也許你認爲簡單,說複雜是因爲我們的源碼目錄事實上是可以很隨意的,只要我們定製我們的編譯腳本,按照我們自己的目錄邏輯去構建項目,最終還是生成標準的Archive,即可部署的web app。
說了大半天,你可能還沒理解我說這些幹嘛。我想說的是我們沒必要去關心構建過程最終生成產物與源碼的區別,他們唯一的區別就是源碼給我們看,產物給計算機看,我們是高級動物,我們當然看高級語言,我們知道這個源碼經過那個構建腳本編譯成最終產物扔給服務器就行了,我們無論任何時候都不要傻瓜蛋去對編譯產物進行搬磚的動作。我們只要明白一點,源碼只要固定在一個版本,經過我們已經定製的構建規則,它的產物永遠不會變,而且是二進制的不變,結論就是源碼與構建產物是一一對應的,就像如果你是男的就不用生孩子這樣一一對應的因果關係,當然那些所謂男的也能生孩子的例外就不要跟我說了。

所以我總結一下,我們管理源碼版本就是等於管理構建產物的版本。這裏就只說源碼版本,就可以解決所有問題了,可是我開篇的標題好像在扯什麼犢子,說什麼管理產物的版本,好像與管理源碼的版本是分開的。
我在裏只想說我前面說那麼多都是在做鋪墊,且往後看。。。
這裏我就要談到我們目前項目版本管理的現狀,因爲我們沒有做到真正的版本管理,因爲我們硬性的把這種一一對應的關係通過我們來搬運構建產物而分開的,我們自豪的認爲我們改了某個java文件,我們就把那個java生成的class文件也就是所謂的產物替換掉原來的即可。我們欣然的認爲這樣還做到了所謂的打補丁功效。
首先這種思路咋一看起來似乎蠻合理的,那麼下面我就推到它。
首先我們管理源碼的版本就是基於文件系統版本管理。我們先拋開構建產物這一環節。什麼是所謂基於文件系統的版本管理,其實所有的版本控制工具都是對一個目錄下所有的實際文件的版本管理,如果某個文件改動了,你覺得它會影響其它文件嗎?我們說的不是後期業務上的影響,比如有兩個txt文檔,你改動其中一個txt文檔,另一個txt文檔會變化嗎?如果變化了,我覺得你孫子開掛了。那麼我們改動其中一個文件,提交後,到了版本2,而線上的版本,注意我這裏提的是線上的源碼版本,它還仍處於版本1,那麼我們要想更新到2就相當於拿剛纔改動的那個文件去替換就ok了,任何只談文件系統的版本管理,就是這麼簡單,改動什麼文件,我們就替換哪些,不用全盤拷貝,就是這麼簡單,這就是版本控制工具遵循的很簡單的原則,當然像git可以對文本文件做到控制內容的打補丁,更能優化它的管理。
而我想說的你涉及到構建產物的版本管理時,你覺得你改動了某個java文件,你也學着版本管理工具所謂的原則,去替換構建產物的對應文件,啊,但是構建產物編譯了,成class字節碼文件了,吼吼吼,簡單啊,老子替換字節碼不就ok了。這裏我要糾正一個誤區,誠然很多情況下,我們改動一個java文本文件,對應的class文件基本上會變,那麼對應的構建後的產物全局來說也基本上就只有這個文件會變,這個文件就是那個產出的字節碼class文件。所以我們這時按照版本控制器的原則也確實只有它改變了,我們做一回手動替換那個改變的產物文件,整個項目系統確實達到了一定的版本管理。
但是有意外情況啊,兄弟。舉例,java編譯規則有一條,就是一個java類A如果引用了另一個java類B中的一個常量配置參數,所謂的常量就是final加static修飾的,在整個系統運作過程中這個變量也不會變化,所以編譯期間類A就直接把類B那個常量的值拿過來,記住是值,java這樣做,是有它的原因的,因爲編譯期間就靜態確定這些東西,還有一些固定大小內存分配的確定等等,就比如基本類型的出現就是這個原因,這樣在編譯期間就靜態確定了,運行時就不用動態去檢索可以優化java運行。OK,這樣情況下,有一個需求我們要調下這個參數,那麼我們就去修改類B的這個常量值,想當然的,我們很happy,我們覺得我們只改動了類B,也就是所謂版本控制器遵循的最基本的原則,改什麼替換什麼嘛,我們編譯類B後,把字節碼替換到產物目錄中對應的舊的類B的字節碼文件。
這樣完事了嗎?哥們?你可以測試下,如果類A是輸出那個類B那個常量值,我相信,它絕對輸出的是舊的常量值。原因就是剛纔那條編譯規則,你確實替換了類B的常量值,但是你整體編譯項目,類B引用的常量值事實上也變了,因爲它是靜態寫入值的,所以,當時你改變了類B,類A其實也變化了,而你只替換了類B。你還敢這樣做嗎?你還好意思亂用這種原則嗎?我只能答到你是用錯地方了,因爲你是起初改動的是源碼,而你替換是產物。你又不是直接的去改動class,再直接的去替換class,那麼直接的去改動class,你覺得可能嗎,我們操作的是高級語言,面向我們的只能是文本文件,中間你尚且不知道還有個構建的轉化過程嗎?構建是整體的,java類是各相邏輯關聯的,你可以理解java的編譯就是做了一個邏輯外掛處理,它對任何java文件的編譯都有潛在的與底層jdk或第三方jar或自己編寫的其它需要引用的類有着編譯規則層面上的邏輯關聯,這實質上就告訴我們編譯是對應的一套整體代碼和平臺,我們不能把對源碼的修改按照文件系統修改的原則聯動到產出物應該的變化,我們也無需把精力用在關心這個變化上,我們更應該只關心源碼層面上的版本,通過一套構建體系來產出我們最終要的發佈版本。而對於任何一套系統或者說一個軟件類項目,我們也更應該明白要以源碼爲基本版本管理來創作研發,因爲我們做的都是上層應用級別的項目,讀源碼也就是讀這個項目的邏輯運作,高級文本語言的修改最終構建後也會翻譯成底層的計算指令,從而實現需求的增加以及bug的修復。再者來說,java雖然有所謂java與class對應關係,誠然這樣,也不是一對一的。一個java內如果有匿名內部類,還可能生成多個字節碼文件。打個比方,如果有一天java構建規則大改變,編譯出來是個整體的某種類型的單個文件,你還怎麼去一對一,改動,然後替換?似乎行不通吧?!
總結:說了這麼多,不知道大家有沒有明白這其中真正的規範。既然用版本控制工具可以很方便自動化的管理我們的文件系統,即項目源碼,方便它的源碼版本的回退與控制,爲何還要多一事去操心構建產物的手動操作搬運,前面已經說了源碼與構建產物是一一對應的的,中間經過構建腳本的構建即可,一切是多麼自動化可控制化。
即便你想要弄出打補丁的方式,不想整體替換,你也得遵循原則。只要你不覺得麻煩,你也可以拿出兩個版本的源碼,各自構建後,再對構建產物做兩相二進制對比,做手動替換也可呀,而不應該用上面說的方式去做。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章