large scale 的應用通常意味著:
目錄較多, 層次較深
依賴較多, 構建指令碼依賴的第三方ant task, 專案依賴的第三方庫等
測試較多, 構建時間反饋週期較長
需要在不同作業系統上執行
需要在不同團隊成員的機器上執行
由於以上原因, 導致ant指令碼較長
通常有兩種風格的解決方案
一是使用ant-contrib中的來遍歷子目錄並依次呼叫其中的構建指令碼, 一般是預設的target
另外一種是用ant自身的命令來搜尋構建指令碼並呼叫特定的target
第一種方案可看作深度優先, 不同的子目錄通常是系統的不同元件, 這種方式是把單個元件全部構建完再構建另外的元件
第二種方案可看作廣度優先, 類似於模板方法, 要求每個子系統的構建指令碼都要定義特定的約定的target, root構建指令碼會先呼叫所有構建指令碼的某個target, 再呼叫另外的target
當然也可以用來實現第二種風格
明確區分構建指令碼的依賴和你的專案的依賴. 那些第三方的ant task通常你只會在構建過程中用到它們, 而不會在產品中用到, 如 checkstyle, emma 等, 把它們放在單獨的目錄中, 打包時不要理會它們. 關於區分不同依賴的經驗, 參考<>
使用 ivy 來管理你專案的依賴
清理不必要的依賴或干擾:
總是提供 target, 並借助工具保證在需要的時刻總是能夠得到執行, 參見後面的章節定義單獨的目錄來存放專案所有的輸出, 通常是頂級目錄下的名字叫做 target或者build或者dist之類的目錄, 其內部的層次結構應該與原始檔的目錄結構一致
構建過程中拷貝需要的資源到上面定義的輸出目錄中, 而不是直接對資源操作
一般你不會希望直到構建過程的末尾某個任務才失敗, 這樣你修正後不得不從頭再跑一遍來校驗, 有幾種方式來來縮短反饋時間
一種是先執行最可能失敗的任務, 利用前面提到的或
一種是為每個任務都定義單獨的target, 或用"property"來選擇或忽略特定的target. 參見 target 的 if/unless 屬性, 及 condition 元素. 如用property來控制執行所有測試還是某個測試:
if="testcase"/>
unless="testcase">
另外你希望一次構建能夠發現盡可能多的問題, 而不是出現第乙個問題後構建就停止, 這樣的話可以批量修復它們然後再重新執行一次構建, 而不是一遍一遍的執行構建來逐個找出錯誤
可以用一些任務提供的 haltonerror, haltonfailure, errorproperty 等來控制構建結束的時機和最後的結果, 如:
haltοnerrοr="false" haltonfailure="false" errorproperty="test.failed" failureproperty="test.failed"...>
if="test.failed">tests failed. check log or reports for details
利用 的 os 或 osfamily 屬性來控制不同作業系統上的行為
路徑分隔符統一使用 "/"
其實這是配置管理的問題, 專案的所有文件和依賴, 甚至包括ant本身都應該包含在乙個單根目錄下, 並且check in到版本控制系統中. 裡面所有涉及路徑的地方都使用相對路徑. 這樣專案就可以即拷即用
但總有一些對外部環境的依賴, 這是就要借助 ant 強大而合理的 immutable property 體系
所有可能變化的地方都使用 property 來引用
優先使用 jvm 的系統屬性, 而不是環境變數
使用 user.properties 檔案定義環境相關的property, 並在構建指令碼中最先引入 <
property
file
="$/user.properties" />
在引入 user.properties 之後, 為所有屬性定義合理的預設值, 以處理 user.properties 不存在不完整的情況
後面兩步也可以用 來代替
乙個應用就是可以在命令列傳入使用者名稱和密碼而不是把它們寫在指令碼中, 這樣就避免了安全和隱私問題
其它的例子包括用 property 來定義 test filter, 或者來定義碰到第一次錯誤是退出還是繼續執行構建等
關於目錄的處理
為根目錄定義屬性, 以此為起點定義子目錄的屬性
總是使用$作為相對路徑的字首. 這樣可以保證即使 ant 的工作路徑不同, 只要傳遞了正確的 basedir 屬性, 所有的相對路徑還是正確的.
使用location定義路徑, 而不是 value. ant會將 location 展開為絕對路徑, 這樣即使傳遞到另外的 ant project 中, 它的值也不會變
ant不是script language, 你更應該像編寫產品**一樣認真對待它的編寫風格
前面說過通過命令列引數控制執行的target, 引數多了, 就要有 usage, help
模組化構建指令碼, 使用 等
抽取可復用的 macrodef 或 target 到單獨的指令碼中, 並在其它指令碼中 import 這個可復用的檔案, 這樣有助於分離關注點, 使指令碼更易維護
缺乏異常處理機制, 任何 buildexception 都會終止 ant 的執行, 而任何 task 都可能出現異常, 這樣有些清理操作就得不到執行. 解決方案:
a. ant-contrib的
b. cruisecontrol 的 antpublisher. cruisecontrol定義了構建結束後的操作, 參見 <>
缺乏依賴管理機制
前面已經提到, 借助 ivy 來管理, ivy 已經成為了 ant 的子專案
define tasks, datatypes, and properties before targets.
order attributes logically and consistently.
separate words intarget nameswith ahyphen.
separate words with adot (.)character inproperty names.
include an "all" target that builds it all.
define reusable paths.
use explicit classpaths wherever possible.
provide visual and xml test results. use , and .
用以連字元(-)開頭的target名字來定義無法從命令列呼叫的"內部"target
與使用者互動, 這在持續整合環境中應該不多:
併發執行: , 通常用來執行在後台執行的任務
遞迴的property定義. ant 預設並不支援 property 的遞迴展開, 如 $.$}. 但任何事情都可以用乙個額外的中間層解決, 這裡可以借用的機制是
這樣就可以動態的定義屬性
spawn, 不要使用spawn=true, 使用前面的
預設spawn等於false, 這種情況下ant退出時會把所有fork的程序都殺掉. 把spawn設定成true可以令程序壽命長於ant, 從而可以不堵塞ant的執行而用來執行後台程式. 但會帶來很多不好的地方,比如不能即時在console看到資訊等. 並且壽命長於 ant 在某些情況下不是我們期待的, 比如在 cruisecontrol 的環境中執行 ant, 如果ant fork的程序沒有隨著ant退出而退出, 那麼cruisecontrol會認為ant程序還沒有結束, 從而一直在那裡等待而不是執行後面的 publishers.
用的來執行後台程式
unix上的萬用字元 (windows上沒問題): on unix-like systems, wildcards are understood by shell intepreters, not by individual binary executables as /usr/bin/ls or shell scripts.
幾個沒在 jdk 文件中說明的系統屬性? -duser.country=en -duser.language=us
大規模應用安全
在團隊,產品,業務部門之間使用同伴壓力和計分卡 通過競爭提高更好的應用程式安全性 正如我們稍後了解到的,思科是組織計分業務單元和產品以推動軟體安全計畫改進的組織之一 編寫好的,可用的安全框架和庫,並在預設情況下將安全性內建到主要的應用程式框架中 不幸的是,在廣泛採用之前,我們不知道哪種框架會被廣泛採...
白話去哪兒 RN 大規模應用實踐方案
去哪兒 ymfe,作為一支國內比較早期實踐 react native 的年輕團隊,我們從 2016 年 3 月上線了第乙個基於 rn 的頁面,截止目前已經有超過 30 個的 rn 專案。在 rn 專案實踐中,我們是如何抹平 android ios 平台化差異的?如何設計熱更新系統?如何對rn的 痛點...
雲安全是雲計算大規模應用前提
上週雲儲存服務商dropbox遭遇了一次嚴重的安全問題,任何使用者的帳號不用密碼就可以直接訪問。問題與程式 有關,dropbox在當天更新了 結果引進了乙個影響認證系統的bug 直至4小時後他們才發現問題,並立即進行了修正。官方部落格證實,已經向在此期待登入的帳號傳送了電子郵件通知,dropbox公...