<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 讓開發自動化: 持續集成反模式 _通過避免反模式輕松實現持續集成_ 盡管持續集成(Continuous Integration,CI)可以非常有效地減少項目的風險,但是它對與編程相關的日常活動提出了很高的要求。在這一期 [_讓開發自動化_](http://www.ibm.com/developerworks/cn/java/j-ap/)中,自動化專家和 [_Continuous Integration: Improving Software Quality and Reducing Risk_](http://www.amazon.com/gp/product/0321336380/?tag=integratecom-20)的作者之一 Paul Duvall 列舉了一系列 CI 反模式并解釋了如何避免它們。 在我的職業生涯中經常發現,通過了解在特定情況下 _不應該_做什么,可以學到更多知識。例如,在我職業生涯的早期,由于需要快速發布軟件,我省略了單元測試,因為我認為不值得做這些工作。幸運的是,我已經學到 _絕不應該_將未經測試的代碼投入生產;因此開始堅持編寫單元測試。 整個 IT 行業似乎都主要采用這種學習方式;實際上,我們甚至專門創建了 _反模式(anti-pattern)_這個詞,表示在特定環境中不應該采用的做法。反模式是看起來似乎有好處,但是最終可能產生嚴重影響的解決方案。 ## 看似真實的假象 遺憾的是,我發現當缺少經驗的團隊試圖采用 CI 時,他們很可能錯誤地采用許多反模式,這最終導致他們不但沒有獲得預期的好處,反而遇到一大堆麻煩。不幸的是,在這種情況下,團隊常常將麻煩歸罪于 CI 本身。因此,我常常聽到 “CI 不適合大項目” 或 “我們的項目 _太特殊_,不適合采用 CI” 這樣的說法,實際上 CI 根本不是問題的原因 —是某些做法的不恰當應用或者缺少某些方法導致了這些麻煩。 ## 關于本系列 作為開發人員,我們的工作就是為終端用戶實現過程自動化;然而,很多開發人員卻忽略了將自己的開發過程自動化的機會。為此,我編寫了 [_讓開發自動化_](http://www.ibm.com/developerworks/cn/java/j-ap/)這個系列的文章,專門探討軟件開發過程自動化的實際應用,并教您 _何時_以及 _如何_成功地應用自動化。 在本文中,我要描述與 CI 相關的六個反模式: * **簽入不夠頻繁**,這會導致集成被延遲 * **破碎的構建**,這使團隊無法轉而執行其他任務 * **反饋太少**,這使開發人員無法采取糾正措施 * 接收 **垃圾反饋**,這使開發人員忽視反饋消息 * 所擁有的 **機器緩慢**,這導致延遲反饋 * 依賴于 **膨脹的構建**,這會降低反饋速度 如果您采用 CI 的時間足夠長,那么幾乎肯定體驗過這些反模式的效果。這沒關系,但是如果它們發生得太頻繁,就會大大限制 CI 的好處。因此,如果您希望避免這些反模式并控制它們的負面影響,那么本文正適合您。 * * * ## 由于簽入不夠頻繁導致的延遲集成 **名稱:**簽入不夠頻繁 **反模式:**由于所需的修改太多,源代碼長時間簽出存儲庫。 **解決方案:**頻繁地提交比較小的代碼塊。 實施 CI 的前提是團隊可以快速獲得關于當前開發的代碼的反饋;而且,與傳統的集成相比,這種頻繁的軟件集成風格會減少集成花費的時間(和麻煩)。但是,有效的 CI 假設修改會頻繁地發生(所以可以頻繁地執行構建!)。如果代碼長期留在開發人員的桌面(而不是存儲庫)中,那么就會出現糟糕的情況,因為在系統的不同部分中會出現其他修改。 ## 每天提交一次,成功實現集成 一條常用的經驗規則是 _至少_每天簽入一次代碼。我使用一種有效的技術:如果我覺得需要把工作停一下,就會先看看目前是否可以運行本地構建,然后提交代碼。然后我才會暫停工作。 從本質上說,如果不頻繁地提交修改,集成就會延遲;延遲越長,消除其嚴重影響就越困難(比如其他人的修改可能會影響您的代碼)。對于使用 CI 的項目,我建議開發人員 _至少_每天簽入一次代碼,但是我相信最好是每天簽入多次。 ### 任務越小,工作越輕松 我常常聽到一些開發人員抱怨說,他們要忙于修改那么多文件,哪有精力每天簽入代碼。實際上,這正是我要說的要點 —為了每天提交源代碼修改,需要將任務劃分得更小。實際上,需要將編程任務劃分成小塊,這樣修改也會更小。 不要在一個大任務中實現一個業務對象上的所有特性,例如編寫 `read()`、`write()`、`update()`和 `delete()`方法的原型;而是應該首先編寫 `read()`方法(以及對應的測試),然后簽入這個類,從而與整個代碼基集成。接下來,可以實現另一個方法,再次執行簽入,直到完成整個任務。這樣的話,就可以讓 CI 的好處最大化,而且會讓您確信自己的代碼可以與 _別人的代碼_相互配合。 請記住,即使您和您的團隊正確地執行許多 CI 實踐,如果團隊成員不堅持至少每天簽入一次源代碼修改,那么 CI 的好處會大打折扣。這常常會讓人誤以為 CI 是無效的,這種想法實在大錯特錯。 * * * ## 破碎的構建減慢了開發的節奏 **名稱:**破碎的構建 **反模式:**構建長時間破碎,導致開發人員無法簽出可運行的代碼。 **解決方案:**在構建破碎時立即通知開發人員,并以最高優先級盡快修復破碎的構建。 無論您信不信,構建破碎的時間越長,就越麻煩。這是因為文件、修改和依賴項越多,隔離缺陷就越困難。因此,當通知某人構建破碎時(通過電子郵件、RSS 或其他機制),他應該優先解決這個問題;否則,構建破碎的時間越長(尤其是對于頻繁修改代碼的團隊),就越難糾正。 破碎的構建不總是壞事。實際上,破碎的構建會讓您迅速地意識到軟件出了問題。當構建 _頻繁地_破碎或長時間破碎時,破碎的構建就會成為問題。在構建破碎的情況下,絕不應該置之不理。 ## 不存在永不破碎的構建 我曾經聽到一些開發人員說,“永遠不要出現破碎的構建!” 這是個糟糕的建議。我們希望避免許多常見的構建錯誤,比如缺少文件或破碎的測試;但是,不破碎的構建也可能反映一些問題。構建可能只做少量工作(可能只是執行一個編譯和幾個單元測試)。我稱之為 “持續忽視(Continuous Ignorance)”,這種情況有時候比頻繁的破碎構建更糟糕。 ### 用私有構建減少破碎的構建 防止破碎構建的有效技術之一是,在將代碼提交到存儲庫之前,運行 _私有構建(private build)_。執行私有構建的步驟如下: 1. 從存儲庫簽出代碼。 2. 在本地修改代碼。 3. 用存儲庫執行更新,從而集成其他開發人員所做的修改。 4. 運行本地構建。 5. 構建成功之后,將修改提交到存儲庫。 圖 1 說明了這種做法。注意,這個工作流強調頻繁地與存儲庫執行同步,從而保證定期簽入并限制破碎的構建 —這真是一舉兩得! ##### 圖 1\. 運行私有構建減少破碎的集成構建 ![](https://box.kancloud.cn/2016-05-11_5733315e6a970.gif) 通過在簽入源代碼之前執行私有構建(當然是頻繁地執行),可以避免許多導致構建破碎的典型錯誤;因此,可以節省時間和減少麻煩。 * * * ## 由于反饋太少,無法采取糾正措施 **名稱:**反饋太少 **反模式:**團隊沒有把構建狀態通知發送給團隊成員;因此,開發人員不知道構建已失敗。 **解決方案:**使用各種反饋機制傳播構建狀態信息。 在設置 CI 系統時,團隊常常認為接收電子郵件是浪費時間;因此,他們決定不發布通知。但是,如果沒有對構建的反饋,就無法采取糾正措施。實際上,反饋是 CI 最重要的方面之一;因此,反饋是否 _有效_也非常關鍵。 如果希望擴展將構建狀態信息發布給團隊成員的機制,那么使用視覺和聲音設備可能很有幫助,對于集中工作的團隊尤其如此。Ambient Orb 這樣的設備可以幾乎實時地反映構建的狀態。例如,當構建失敗時,orb 可以顯示紅色;當構建通過時,orb 顯示綠色。另外,orb 還可以傳播其他信息,例如通過改變顏色表示代碼庫的復雜性是增長還是下降(比如綠色表示良好,黃色表示糟糕)。 ### 發揮創造力 設置 Ambient Orb 非常容易。清單 1 演示如何使用 Quality Lab 的開放源碼軟件 `OrbTask`在 Ant 中設置 Ambient Orb: ##### 清單 1\. 使用 Ambient Orb Ant 任務 ``` <target name="notifyOrb" > <taskdef classname="org.qualitylabs.ambientorb.ant.OrbTask" name="orb" classpathref="orb.class.path"/> <orb query="http://myambient.com:8080/java/my_devices/submitdata.jsp" deviceId="AAA-9A9-AA9" colorPass="green" colorFail="red" commentFail="Code+Duplication+Threshold+Exceeded" /> </target> ``` 清單 1 中的任務對于通過狀態將 orb 改為綠色,對于失敗狀態顯示紅色。圖 2 顯示綠色的 orb,這表示最近的構建狀態是成功: ##### 圖 2\. 成功的構建! ![](https://box.kancloud.cn/2016-05-11_5733315e7a43f.gif) 團隊可以創造性地使用各種反饋機制,讓團隊成員不會忽視構建狀態消息。另外,這些技術也會讓 CI 變得生動有趣,讓人們更容易注意到需要采取措施的問題。 其他通知機制包括: * RSS feed * 任務欄監視器,比如 CCTray(用于 CruiseControl) * X10 設備(比如 LavaLamps) * 通過 Jabber 等發送的即時消息 * SMS(Text Messages) 警告:需要在信息過多和信息過少之間找到一個平衡點。反饋機制應該隨著工作環境定期調整。例如,對于集中工作的團隊,聲音提示可能是有效的(比如在構建失敗時發出火災警報);但是,其他團隊可能更喜歡 Ambient Orb(它不會在您陷入沉思時嚇著您)。 * * * ## 垃圾反饋 **名稱:**垃圾反饋 **反模式:**團隊成員很快被構建狀態消息淹沒(成功、失敗或界于這兩者之間的各種消息),所以開始忽視這些消息。 **解決方案:**反饋要目標明確,使人們不會收到無關的信息。 與 “反饋太少” 反模式相反,我常常發現團隊天真地認為,當 CI 服務器做任何事情時,_每個人_都應該接到反饋(比如電子郵件)。信息一旦泛濫,人們就會忽視它們;如果反饋太多,團隊很快就會將 CI 反饋看做垃圾。所以,當發生真正嚴重的問題(比如構建真的破碎了)時,可能無法引起注意。 ### 通過精確地確定反饋的目標,盡可能減少垃圾反饋 清單 2 給出一個 CruiseControl 配置文件示例,演示如何有效地使用電子郵件通知。在這個示例中,無論構建是成功還是失敗,技術主管都會收到電子郵件,項目經理只在構建失敗時收到電子郵件,最近向存儲庫提交源代碼修改的開發人員也會收到通知。 ##### 清單 2\. 使用 CruiseControl 發送電子郵件通知 ``` <project name="brewery"> ... <publishers> <htmlemail css="./webapps/cruisecontrol/css/cruisecontrol.css" mailhost="localhost" xsldir="./webapps/cruisecontrol/xsl" returnaddress="cruisecontrol@localhost" buildresultsurl="http://localhost:8080" mailport="25" defaultsuffix="@localhost" spamwhilebroken="false"> <always address="techlead@localhost"/> <failure address="pm@localhost" reportWhenFixed="true"/> </htmlemail> </publishers> ... ``` 反饋是 CI 系統最重要的方面之一,值得好好討論一下。_反饋太少_和 _垃圾反饋_是兩個極端,要在它們之間找到一個適當的平衡點。當構建破碎時,必須及時地將反饋發送給適當的人,而且必須提供采取糾正措施所需的信息。如果構建是成功的,那么應該只向少數人發送反饋,包括最近提交修改的開發人員以及希望掌握最新情況的技術領導。如果不加區分地把所有狀態消息發送給所有人,肯定會大大損害 CI 過程的效果。 * * * ## 不要讓緩慢的機器導致反饋延遲 **名稱:**緩慢的機器 **反模式:**用一臺資源有限的工作站執行構建,導致構建時間太長。 **解決方案:**增加構建機器的磁盤速度、處理器和 RAM 資源,從而提高構建速度。 幾年前,我參與了一個相當大的項目,它有超過一百萬行代碼,編譯需要花兩個小時以上。當我們試圖更頻繁地執行集成時,等待持續管理團隊執行集成的時間越來越長,讓人很不耐煩。當然,兩個小時其實是最好的情況,因為構建常常失敗,所以這個過程常常要花幾 _天_(真是痛苦啊!)。這種情況持續幾周之后,解決方案就非常明確了:必須購買一臺更強大的機器,它的磁盤空間必須足以容納所有要簽出的文件和構建生成的文件,它的處理器速度更快,可以處理許多指令,RAM 數量要足以運行測試和其他需要大量內存的進程。 ### 您覺得需要提高速度嗎? 有了這臺強大的機器,我們將構建時間從兩個小時降低到了 30 分鐘;所以,通過花費額外資金購買最新的機器,我們節省了大量時間和金錢,而且最終能夠更快地集成軟件(這意味著更快地發現問題!)。 用更強大的工作站執行集成構建總是沒錯的;但是,這個故事的要旨在于,如果發現構建機器在速度、內存或硬盤方面無法讓人滿意,就應該認真考慮進行升級;加快構建可以幫助我們更快地獲得反饋,快速糾正問題,更快地轉到下一個開發任務。 * * * ## 膨脹的構建導致反饋延遲 **名稱:**膨脹的構建 **反模式:**把太多的任務添加到提交構建過程中,比如運行各種自動檢查工具或運行負載測試,從而導致反饋被延遲。 **解決方案:**一個構建 _管道(pipeline)_可以運行不同類型的構建。 一些開發團隊喜歡把能添加的所有過程都添加到自動構建中,但是他們忘了執行這些操作是要花 _時間_的。還記得嗎?我遇到的那個項目的編譯要花兩個小時。想像一下,如果把執行測試添加到構建過程中,會怎么樣呢?對于一百萬行代碼,您認為運行靜態分析工具要花多長時間?如果您認為耗時八小時的構建過程是難以令人置信的,那么再想想吧。我經常遇到這種情況。 為了向團隊成員提供更多的構建信息,團隊往往會逐漸增加構建過程的內容。要向開發團隊提供快速反饋,還要從 CI 構建過程提供有用的信息,必須在這兩個目標之間取得平衡。 ### 通過構建管道提高效率 如果發現構建過程耗時太長,而且已經實現了其他改進技術(比如改用更快的機器)并優化了測試執行時間,那么就有必要考慮創建所謂的 _構建管道(build pipeline)_。構建管道的用途是異步地執行長時間運行的過程,這樣的話,開發人員簽入代碼之后,不需要長時間等待反饋。 例如,如果執行一個構建過程要花 10 分鐘以上,那么可以創建一個構建管道,在某人將代碼提交到存儲庫之后,它會運行一個初步的輕型構建。這個 “提交” 構建由編譯和運行快速單元測試等輕型過程組成。如果這個初步構建成功了,就可以運行第二個構建,它執行長時間運行的測試、軟件檢查,甚至包括部署到應用服務器上。 例如,在清單 3 中,讓 CruiseControl 檢查存儲庫中的修改。當發現修改時,CruiseControl 運行一個所謂的 _委派(delegating)_構建,它調用項目的主構建文件(在使用 Ant 時是 build.xml)。但是,特殊之處是 CruiseControl 執行另一個目標,這個目標執行一些輕型過程,比如編譯和細粒度的單元測試。 ##### 清單 3\. 檢查修改的 CruiseControl 配置 ``` <project name="brewery-commit"> ... <modificationset quietperiod="120"> <svn RepositoryLocation="http://brewery-ci.googlecode.com/svn/trunk"/> </modificationset ... ``` 在清單 4 中,CruiseControl 檢查對 `brewery-commit`項目的修改(這個項目不在存儲庫中 —它實際上查看一個日志文件)。當發現修改時,CruiseControl 運行另一個委派構建。這個構建調用相同的構建文件,但是執行另一個目標。這個目標可能執行長時間運行的過程,比如功能測試、軟件檢查等等。 ##### 清單 4\. 執行長時間運行的構建的 CruiseControl 配置 ``` <project name="brewery-secondary"> ... <modificationset quietperiod="120"> <buildstatus logdir="logs/brewery-commit"/> </modificationset> ... ``` _膨脹的構建_反模式是導致 CI 無法實施的最常見原因。但是,正如您看到的,使用構建管道可以避免這種情況。有效的構建管道應該充分利用 “80/20” 規則:百分之 20 的構建時間花費在導致百分之 80 的構建錯誤(比如缺少文件、破碎的編譯和測試失敗)的部分上。完成這個過程之后,開發人員接到反饋,然后運行第二個構建過程,這個過程的運行時間比較長,但是只產生百分之 20 的構建錯誤。 * * * ## 反模式是可以糾正的 CI 反模式會妨礙團隊從持續集成實踐中獲得最大的收益;但是,本文描述的技術有助于限制這些反模式發生的頻率。這些技術包括: * 經常提交代碼,可以防止集成變得復雜。 * 在提交源代碼之前運行私有構建,可以避免許多破碎的構建。 * 使用各種反饋機制避免開發人員忽視構建狀態信息。 * 有針對性地向可以采取措施的人發送反饋,這是將構建問題通知團隊成員的好方法。 * 花費額外資金購買更強大的構建機器,從而加快向團隊成員提供反饋的速度。 * 創建構建管道來緩解構建膨脹。 本文描述了我最常遇到的一些反模式,但是還有其他反模式,包括: * **持續忽視(Continuous Ignorance)**,也就是構建過程只包含很少的過程,導致構建總是成功。 * 構建 **只在您的機器上執行**,這會延長引入缺陷和糾正缺陷之間的時間。 * **瓶頸提交(Bottleneck Commits)**,這會導致破碎的構建,讓團隊成員無法回家。 * 運行 **間歇構建(intermittent build)**,這使反饋延遲。 明年我會討論其他影響持續集成效果的 CI 反模式,請保持關注。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看