定期面對面
2024 年 2 月 27 日
通訊技術的進步讓越來越多團隊採用 遠距優先 的工作方式,而這股趨勢在新冠肺炎疫情的強制隔離下更加蓬勃發展。不過,遠距工作的團隊仍然受益於面對面的聚會,而且應該每隔幾個月就舉辦一次。
遠距優先團隊的每個人都在不同的地點,完全透過電子郵件、聊天、視訊和其他通訊工具進行溝通。這種方式確實有其優點:團隊可以招募來自世界各地的成員,而且我們可以讓有照顧責任的人參與其中。浪費在通勤上的無聊時光可以轉化為生產力或休養時間。
不過,無論個人遠距工作的技能有多高,現代協作工具有多麼靈巧,都比不上與團隊其他成員身處同一個地方。當人們面對面互動時,人際互動總是更加豐富。視訊通話很容易變成交易式的,幾乎沒有時間閒聊,而閒聊正是建立良好人際關係的基礎。少了這些深厚的連結,誤解會演變成嚴重的關係問題,而團隊可能會陷入一些狀況,如果大家能夠親自交談,就能有效解決這些狀況。
我從那些在遠距工作中表現出色的人身上看到一個規律的模式,就是他們確保定期舉行面對面的會議。在這些會議中,他們安排那些一起完成效果較好的工作元素。遠距工作對於需要單獨專注的任務來說更有效率,而現代化的工具可以讓遠距配對變得可行。但是,需要許多人提供大量意見且需要快速回饋的任務,當所有人都在同一個房間時會更容易完成。沒有任何視訊會議系統可以創造出這種深度互動,盯著電腦螢幕看其他人正在做什麼會讓人筋疲力盡,而且沒有機會一起出去喝杯咖啡來暫停工作。關於產品策略的辯論、系統架構的探討、新領域的探索——這些都是團隊集結時常見的任務。
為了讓人們有效地合作,他們需要彼此信任,了解他們可以相互依賴的程度。在線上建立信任很困難,因為沒有我們在同一個房間時會出現的社交暗示。因此,面對面聚會最有價值的部分不是預定的工作,而是買咖啡時閒聊,以及午餐時的歡樂時光。非正式的對話,大多與工作無關,可以建立人與人之間的聯繫,讓工作互動更有效率。
這些準則建議面對面聚會的內容是什麼。合作本身就有價值,而且是團隊凝聚力中很重要的一部分。因此,我們應該設定一整天的工作時間,專注於那些受益於面對面低延遲溝通的任務。然後,我們應該加入感覺上過多的休息時間、非正式聊天時間,以及走出辦公室的機會。我會避免任何人工的「團隊建設」練習,僅僅是因為我有多麼討厭它們。那些舉辦這種聚會的人強調,事後每個人都充滿活力,因此在接下來的幾週內可以更有效率。
遠端團隊可以遠距離組成,成員之間相隔數小時的車程是很常見的。對於這樣的團隊,我建議的經驗法則是在每兩或三個月聚會一次,每次一週。團隊成熟後,他們可能會決定減少聚會頻率,但如果一個團隊一年沒有至少兩次面對面的會議,我會感到擔心。如果一個團隊都在同一個城市,但使用遠端優先的風格來減少通勤,那麼他們可以組織較短的聚會,並更頻繁地進行。
這種聚會可能會導致重新思考如何配置辦公空間。自從疫情爆發以來,辦公室的使用率大幅下降,這一點已經被廣泛討論。辦公室很可能會減少作為日常工作空間,而更多地成為這些不定期團隊聚會的地點。這導致了對靈活舒適的團隊聚會空間的需求。
一些組織可能會對這種團隊聚會的差旅和住宿費用望而卻步,但他們應該把它視為對團隊效能的一項投資。忽視這些面對面的聚會會導致團隊陷入困境、朝著錯誤的方向前進、飽受衝突困擾,以及人員失去動力。與此相比,在飛機和酒店上省錢是一種虛假的經濟。
進一步閱讀
遠端優先是遠端工作的形式之一,我在 遠端與共同定位工作 中探討了不同的遠端工作風格及其利弊。
在 Thoughtworks,當我們在近二十年前首次啟動我們的離岸開發中心時,我們了解到定期面對面聚會對遠端團隊的重要性。這些聚會產生了我所描述的實務,詳見 使用敏捷軟體流程進行離岸開發。
遠端工作,特別是跨越時區時,更重視非同步協作模式。我的同事 Sumeet Moghe 是一位產品經理,他在他的書 非同步優先手冊 中深入探討了如何做到這一點。
軟體產品公司 Atlassian 最近已全面轉為遠距工作,並發表了一份經驗報告。他們發現,團隊每年大約見面三次是明智的。Claire Lew 在 2018 年調查了遠距優先團隊,並指出四分之一的受訪者「每年多次」舉辦工作坊。37Signals 已作為遠距優先公司經營了近二十年,並每年安排兩次聚會。
致謝
Alejandro Batanero、Andrew Thal、Chris Ford、Heiko Gerin、Kief Morris、Kuldeep Singh、Matt Newman、Michael Chaffee、Naval Prabhakar、Rafael Detoni 和 Ramki Sitaraman 在我們的內部郵寄清單中討論了這篇文章的草稿。
傳統 Seam
2024 年 1 月 4 日
在使用傳統系統時,找出並建立 Seam 非常有價值:我們可以在其中變更系統的行為,而不編輯原始碼。一旦找到 Seam,我們就可以使用它來中斷相依關係以簡化測試、插入探測以獲得可觀察性,以及將程式流程重新導向到新模組,作為傳統取代的一部分。
Michael Feathers 在其著作與傳統程式碼有效率地工作中,在傳統系統的脈絡中創造了「Seam」一詞。他的定義:「Seam 是您可以在不編輯該處的情況下變更程式行為的地方」。
以下是一個 Seam 會派上用場的範例。想像一些計算訂單價格的程式碼。
// TypeScript
export async function calculatePrice(order:Order) {
const itemPrices = order.items.map(i => calculateItemPrice(i))
const basePrice = itemPrices.reduce((acc, i) => acc + i.price, 0)
const discount = calculateDiscount(order)
const shipping = await calculateShipping(order)
const adjustedShipping = applyShippingDiscounts(order, shipping)
return basePrice + discount + adjustedShipping
}
函式 calculateShipping
會連線到外部服務,而該服務很慢(而且昂貴),因此我們不希望在測試時連線到它。相反地,我們想要引入一個替身,以便我們可以為每個測試情境提供罐頭且確定性的回應。不同的測試可能需要函式提供不同的回應,但我們無法在測試中編輯 calculatePrice
的程式碼。因此,我們需要在呼叫 calculateShipping
的周圍引入一個 Seam,這將允許我們的測試將呼叫重新導向到替身。
執行此操作的方法之一是將 calculateShipping
的函式作為參數傳遞
export async function calculatePrice(order:Order, shippingFn: (o:Order) => Promise<number>) { const itemPrices = order.items.map(i => calculateItemPrice(i)) const basePrice = itemPrices.reduce((acc, i) => acc + i.price, 0) const discount = calculateDiscount(order) const shipping = await shippingFn(order) const adjustedShipping = applyShippingDiscounts(order, shipping) return basePrice + discount + adjustedShipping }
此函式的單元測試接著可以替換一個簡單的替身。
const shippingFn = async (o:Order) => 113 expect(await calculatePrice(sampleOrder, shippingFn)).toStrictEqual(153)
每個接縫都附帶一個啟用點:「一個可以讓你決定使用一種或另一種行為的地方」[WELC]。將函式作為參數傳遞會在 calculateShipping
的呼叫方中開啟一個啟用點。
這讓測試變得容易許多,我們可以放入不同的運費成本值,並檢查 applyShippingDiscounts
是否正確回應。儘管我們必須變更原始原始碼才能引入接縫,但對該函式的任何進一步變更都不需要我們變更該程式碼,所有變更都發生在啟用點,而啟用點位於測試程式碼中。
傳遞函式作為參數並非我們可以引入接縫的唯一方式。畢竟,變更 calculateShipping
的簽章可能是充滿風險的,而且我們可能不希望透過生產程式碼中的舊式呼叫堆疊來執行運送函式參數。在這種情況下,查詢可能是更好的方法,例如使用服務定位器。
export async function calculatePrice(order:Order) {
const itemPrices = order.items.map(i => calculateItemPrice(i))
const basePrice = itemPrices.reduce((acc, i) => acc + i.price, 0)
const discount = calculateDiscount(order)
const shipping = await ShippingServices.calculateShipping(order)
const adjustedShipping = applyShippingDiscounts(order, shipping)
return basePrice + discount + adjustedShipping
}
class ShippingServices { static #soleInstance: ShippingServices static init(arg?:ShippingServices) { this.#soleInstance = arg || new ShippingServices() } static async calculateShipping(o:Order) {return this.#soleInstance.calculateShipping(o)} async calculateShipping(o:Order) {return legacy_calcuateShipping(o)} // ... more services
定位器允許我們透過定義子類別來覆寫行為。
class ShippingServicesStub extends ShippingServices { calculateShippingFn: typeof ShippingServices.calculateShipping = (o) => {throw new Error("no stub provided")} async calculateShipping(o:Order) {return this.calculateShippingFn(o)} // more services
然後我們可以在測試中使用啟用點
const stub = new ShippingServicesStub() stub.calculateShippingFn = async (o:Order) => 113 ShippingServices.init(stub) expect(await calculatePrice(sampleOrder)).toStrictEqual(153)
這種服務定位器是一種傳統的面向物件方式,可透過函式查詢來設定接縫,我這裡顯示的是為了指出我可能在其他語言中使用的途徑類型,但我不會在 TypeScript 或 JavaScript 中使用這種途徑。相反地,我會將類似這樣的內容放入模組中。
export let calculateShipping = legacy_calculateShipping export function reset_calculateShipping(fn?: typeof legacy_calculateShipping) { calculateShipping = fn || legacy_calculateShipping }
然後我們可以在測試中使用以下程式碼
const shippingFn = async (o:Order) => 113 reset_calculateShipping(shippingFn) expect(await calculatePrice(sampleOrder)).toStrictEqual(153)
正如最後一個範例所建議的,用於接縫的最佳機制在很大程度上取決於語言、可用的架構,當然還有舊有系統的樣式。控制舊有系統意味著學習如何將各種接縫引入程式碼,以提供正確類型的啟用點,同時將對舊有軟體的干擾降至最低。雖然函式呼叫是引入此類接縫的簡單範例,但它們在實務上可以複雜得多。一個團隊可能需要花幾個月的時間才能找出如何將接縫引入一個使用多年的舊有系統。將接縫新增到舊有系統的最佳機制可能與我們在全新系統中為類似彈性所做的不同。
Feathers 的書籍主要著重於讓舊系統接受測試,因為這通常是能夠以合理的方式使用舊系統的關鍵。但接縫還有更多用途。一旦我們有了接縫,我們就能夠將探針置入舊系統,讓我們增加系統的可觀察性。我們可能想要監控對 calculateShipping
的呼叫,找出我們使用它的頻率,並擷取其結果以進行個別分析。
但接縫最有價值的用途可能是它們允許我們將行為從舊系統中遷移出去。接縫可能會將高價值客戶重新導向到不同的運費計算器。有效的舊系統取代建立在將接縫引入舊系統,並使用它們逐漸將行為移到更現代的環境中。
接縫也是我們在撰寫新軟體時需要考慮的事情,畢竟每個新系統遲早都會變成舊系統。我的許多設計建議都是關於建置具有適當放置接縫的軟體,這樣我們就能夠輕鬆地測試、觀察和增強它。如果我們在撰寫軟體時考慮到測試,我們往往會得到一組良好的接縫,這就是 測試驅動開發 如此有用的技術的原因。
軟體與工程
2023 年 12 月 13 日
在我的整個職業生涯中,人們將軟體開發與「傳統」工程進行比較,通常是以一種責罵軟體開發人員沒有做好工作的語氣。作為一個電子工程學位畢業的人,這在我職業生涯的早期引起了我的共鳴。但這種思考方式是有缺陷的,因為大多數人對工程在實務中的運作方式有錯誤的印象。
Glenn Vanderburg 花了很多時間探討這些誤解,我強烈建議任何想要將軟體開發與工程進行比較的人觀看他的演講 真正的軟體工程。也值得聽聽 他在 Oddly Influenced 播客上的訪談。遺憾的是,我無法說服他將這些資料寫下來 - 這會是一篇很棒的文章。
另一個對這種關係有深入思考的人是 Hillel Wayne。他採訪了一群「跨界者」 - 既在傳統工程領域又曾在軟體領域工作過的人。他將所學寫成了一系列文章,從 我們真的是工程師嗎? 開始。
測試驅動開發
2023 年 12 月 11 日
測試驅動開發 (TDD) 是一種透過撰寫測試來引導軟體開發的軟體建置技術。它是由 Kent Beck 在 1990 年代後期開發,作為極限編程的一部分。我們基本上會重複執行以下三個簡單步驟
- 為您想要新增的下一個功能性撰寫測試。
- 撰寫功能性程式碼,直到測試通過。
- 重構新舊程式碼,使其結構良好。

儘管這三個步驟通常總結為「紅燈 - 綠燈 - 重構」,是此流程的核心,但還有一個重要的初始步驟,我們會先寫出測試案例清單。然後我們會挑選其中一個測試,對其套用紅燈 - 綠燈 - 重構,完成後再挑選下一個。正確排序測試是一項技能,我們希望挑選能快速引導我們找出設計中顯著重點的測試。在流程中,我們應該將想到的更多測試新增到清單中。
先撰寫測試,也就是 XPE2 所稱的測試優先編程,提供了兩個主要優點。最明顯的是,這是一種取得 SelfTestingCode 的方式,因為我們只能在讓測試通過後撰寫一些功能性程式碼。第二個優點是,先思考測試會迫使我們先思考程式碼的介面。這種對介面和如何使用類別的關注,有助於我們將介面與實作分開,這是許多程式設計師難以掌握的良好設計關鍵要素。
我聽過最常見的搞砸 TDD 的方式,就是忽略第三個步驟。重構程式碼以保持其乾淨是流程中的關鍵部分,否則我們最終只會得到一團混亂的程式碼片段。(至少這些會有測試,所以這比大多數設計失敗的結果不那麼痛苦。)
進一步閱讀
Kent 對於 執行 TDD 的標準方式 的總結是關鍵的線上總結。
如需更深入的資訊,請參閱 Kent Beck 的著作 測試驅動開發。
James Shore 的 敏捷開發的藝術 一書中的相關章節是另一個精闢的描述,它也將其與其他有效的敏捷開發聯繫起來。James 還撰寫了一系列名為 讓我們玩 TDD 的螢幕錄製。
修訂
我最初發布此頁面的時間為 2005-03-05。受到 Kent 的經典文章啟發,我在 2023-12-11 更新了它
Diff 除錯
2023 年 12 月 4 日
回歸錯誤是軟體功能中新出現的錯誤,這些功能已經存在了一段時間。在追蹤它們時,找出軟體中哪個變更導致它們出現通常很有價值。查看該變更可以提供關於錯誤位置和如何消除錯誤的寶貴線索。這種調查形式沒有廣為人知的術語,但我稱之為 Diff 除錯。
Diff 除錯僅在我們將程式碼放入版本控制中時才有效,但幸運的是,現在這已成為常態。但還有一些事情需要讓它有效運作。我們需要 可重現的建置,以便我們可以輕鬆執行軟體的舊版本。由於 高頻率整合,因此擁有小的提交非常有幫助。這樣,當我們找到有問題的提交時,我們可以更容易地縮小發生的事情範圍。
要找到產生錯誤的提交,我們首先找到任何沒有錯誤的過去版本。將其標記為最後良好版本,並將當前版本標記為最早不良。然後找到介於兩者之間的提交,看看錯誤是否在那裡。如果是,則此提交變為最早不良,否則它變為最後良好。重複此過程(這是「半區間」或「二進制」搜尋),直到我們找到有問題的提交。
如果我們使用 git,那麼 git bisect 命令將為我們自動執行大部分操作。如果我們可以撰寫一個測試來顯示錯誤的存在,那麼 git bisect 也可以使用它,自動執行查找有問題提交的整個過程。
我經常發現 Diff 除錯在編程階段很有用。如果我有一些需要幾分鐘才能執行的慢測試,我可能會編寫半小時的程式,只執行一小部分最相關的測試。只要我在每次綠色測試執行後提交,如果其中一個較慢的測試失敗,我就可以使用 Diff 除錯。即使它們很小,以至於我認為最好將它們壓縮以供長期歷史記錄,但頻繁提交的價值也是如此。一些 IDE 會自動保留比版本控制提交更精細的本地歷史記錄,從而簡化了這項工作。
修訂
我最初於 2004-06-01 發布此頁面。在其原始形式中,它更像是一個休閒的經驗報告。我在 2023-12-04 重新撰寫它,使其更像是一個術語定義。Diff 除錯並不是一個在業界中流行的術語,但我沒有看到另一個通常用於描述它的術語。
團隊拓撲
2023 年 7 月 25 日
任何大型軟體專案,例如大型公司的軟體資產,都需要大量人力,而當你擁有大量人力時,你必須找出如何將他們分組成有效率的團隊。組成以業務能力為中心的團隊有助於軟體專案回應客戶需求,但所需的技能範圍通常會讓此類團隊不堪負荷。團隊拓撲是描述軟體開發團隊組織的一種模型,由馬修·史凱爾頓和曼紐爾·派斯開發。它定義了四種形式的團隊和三種模式的團隊互動。此模型鼓勵健康的互動,讓以業務能力為中心的團隊在提供穩定且有價值的軟體任務中蓬勃發展。
此架構中的主要團隊類型是串流對齊團隊,一個以業務能力為中心的團隊,負責單一業務能力的軟體。這些是長期運作的團隊,將他們的努力視為提供軟體產品以增強業務能力。
每個串流對齊團隊都是全堆疊且全生命週期的:負責前端、後端、資料庫、業務分析、功能優先順序、使用者體驗、測試、部署、監控,也就是軟體開發的全部。它們是以成果為導向的,專注於業務成果,而不是以活動為導向的團隊,專注於業務分析、測試或資料庫等功能。但它們也不應該太大,理想情況下,每個團隊都是兩披薩團隊。大型組織將有許多這樣的團隊,儘管他們有不同的業務能力需要支援,但他們有共同的需求,例如資料儲存、網路通訊和可觀察性。
像這樣的小團隊需要設法降低認知負擔,才能專注於支援業務需求,而不是(例如)資料儲存問題。這樣做的一個重要部分是建立一個平台來處理這些非重點的顧慮。對許多團隊來說,一個平台可以是一個廣泛可用的第三方平台,例如用於資料庫後端網路應用的 Ruby on Rails。但對許多產品來說,沒有單一的現成平台可以使用,團隊必須找到並整合多個平台。在較大的組織中,他們必須存取一系列內部服務並遵循公司標準。
這個問題可以透過為組織建立內部平台來解決。這樣的平台可以整合第三方服務、近乎完整的平台和內部服務。團隊拓撲將建立此平台的團隊(沒有想像力但很明智)分類為平台團隊。
較小的組織可以使用單一平台團隊,在外部提供的產品集上產生一層薄層。然而,較大的平台需要比兩個披薩所能餵飽的人員更多。因此,作者轉而描述許多平台團隊的平台群組。
平台的一個重要特徵是,它的設計目的是以大多數自助服務的方式使用。與串流對齊的團隊仍然負責其產品的營運,並直接使用平台,而不會期待與平台團隊進行精密的協作。在團隊拓撲架構中,這種互動模式稱為X 即服務模式,平台對與串流對齊的團隊充當服務。
然而,平台團隊需要將其服務建置為產品本身,並深入了解客戶的需求。這通常需要他們在建置該服務時使用不同的互動模式,也就是協作模式。協作模式是一種更密集的互動夥伴關係形式,應視為一種暫時性方法,直到平台成熟到足以轉移到 X 即服務模式為止。
到目前為止,此模型並未代表任何特別創新的事物。將組織分解為與業務對齊和技術支援團隊是與企業軟體一樣古老的方法。近年來,許多作家表達了讓這些業務能力團隊負責全堆疊和全生命週期的重要性。對我來說,團隊拓撲的亮點見解著重於業務對齊團隊全堆疊和全生命週期所帶來的問題,表示他們經常面臨過度的認知負擔,這與小型、反應靈敏團隊的願景相違背。平台的主要好處在於它降低了這個認知負擔。
團隊拓撲的一個關鍵見解是,平台的主要好處是降低與串流對齊團隊的認知負擔
這個見解具有深遠的影響。首先,它改變了平台團隊應如何思考平台的方式。降低客戶團隊的認知負擔會導致不同的設計決策和產品路線圖,以用於主要用於標準化或降低成本的平台。除了平台之外,這個見解引導團隊拓撲透過識別另外兩種團隊類型來進一步發展其模型。
有些能力需要專家,他們可以投入大量時間和精力來掌握對許多與串流對齊的團隊很重要的主題。安全專家可能會花更多時間研究安全問題並與更廣泛的安全社群互動,這在成為與串流對齊團隊的成員時是不可能的。這些人聚集在支援團隊中,其角色是在其他團隊內培養相關技能,以便這些團隊可以保持獨立,並更好地擁有和發展其服務。為了達成此目標,支援團隊主要使用團隊拓撲中的第三個也是最後一個互動模式。促進模式涉及教練角色,其中支援團隊不在於撰寫和確保符合標準,而是教育和指導其同事,以便與串流對齊的團隊變得更自主。
與串流對齊的團隊負責為其客戶提供整個價值串流,但偶爾我們會發現與串流對齊團隊工作中需要專門小組專注於的方面,導致第四個也是最後一個團隊類型:複雜子系統團隊。複雜子系統團隊的目標是降低使用該複雜子系統的與串流對齊團隊的認知負擔。即使該子系統只有一個客戶團隊,這也是一個有價值的區分。大多數複雜子系統團隊努力使用 X 即服務模式與其客戶互動,但需要在短時間內使用協作模式。
團隊拓撲的設計明確承認康威定律的影響。它鼓勵的團隊組織考慮了人類和軟體組織之間的相互作用。團隊拓撲的倡導者希望其團隊結構能塑造軟體架構未來的發展,使其成為響應式且解耦的元件,並與業務需求保持一致。
喬治·博克斯巧妙地說:「所有模型都是錯誤的,但有些是有用的。」因此,團隊拓撲是錯誤的:複雜的組織無法簡單地分解為僅四種類型的團隊和三種類型的互動。但像這樣的限制正是讓模型有用的原因。團隊拓撲是一個工具,促使人們將其組織演變為更有效的運作方式,讓與流程一致的團隊透過減輕認知負擔來最大化其流程。
致謝
安德魯·塔爾、安迪·伯茲、克里斯·福特、迪帕克·帕拉馬西瓦姆、海科·格林、基夫·莫里斯、馬特奧·瓦卡里、馬修·福斯特、帕夫洛·克雷斯特、彼得·吉拉德-莫斯、普拉尚特·拉馬克里希南和桑迪普·賈格塔普在我們的內部郵寄清單上討論了這篇文章的草稿,並提供了寶貴的回饋。
馬修·史凱爾頓和曼努埃爾·佩斯親切地對這篇文章提供了詳細的評論,包括分享他們自出書以來的一些最新想法。
進一步閱讀
團隊拓撲架構的最佳處理方式是同名書籍,於 2019 年出版。作者還維護團隊拓撲網站,並提供教育和培訓服務。他們最近關於團隊互動建模的文章很好地介紹了如何使用團隊拓撲(元)模型來建立和演進組織模型。[1]
團隊拓撲的很大一部分基於認知負擔的概念。作者在 Tech Beacon 中探討了認知負擔。喬·皮爾斯進一步說明了認知負擔如何應用於軟體開發。
團隊拓撲中的模型與我在此網站上發表的許多關於軟體團隊組織的想法產生了共鳴。您可以在團隊組織標籤中找到這些想法的彙整。
註解
1: 如果要更嚴格地使用我的建模術語,我會說團隊拓撲通常充當元模型。如果我使用團隊拓撲來建立航空公司軟體開發組織的模型,那麼該模型會顯示根據團隊拓撲術語對航空公司的團隊進行分類。然後我會說團隊拓撲模型是我的航空公司模型的元模型。
兩披薩團隊
2023 年 7 月 25 日
兩披薩團隊是一個小團隊,完全支援特定業務能力的軟體。這個術語之所以流行,是因為它用來描述亞馬遜如何組織其軟體人員。
這個名稱暗示了此類團隊最明顯的特徵,即它們的規模。這個名稱來自於團隊規模不應大於兩披薩所能餵飽的原則。(儘管我們這裡討論的是美式披薩,當我第一次在這裡遇到它們時,它們顯得非常巨大。)保持團隊規模小巧可以讓團隊保持凝聚力,形成緊密的合作關係。我通常聽說這意味著此類團隊約有 5-8 人,儘管我的經驗表明上限約為 15 人。
儘管這個名稱僅關注規模,但團隊的重點同樣重要。兩披薩團隊應具備向其使用者傳遞有價值軟體所需的所有功能,並儘量減少與其他團隊的交接和依賴。他們可以找出客戶的需求,並快速將其轉化為可用的軟體,隨著客戶需求的變化,能夠對該軟體進行試驗和演進。
兩披薩團隊是以結果為導向的,而不是以活動為導向的。他們不是按技能(資料庫、測試、運作)組織的,而是承擔支援客戶所需的所有責任。這可以最大限度地減少功能流向客戶時團隊間的交接,從而讓他們減少週期時間(將功能構想轉化為在生產中執行的程式碼所需的時間)。這種以結果為導向也意味著他們將程式碼部署到生產環境中並在那裡監控其使用情況,對任何生產中斷負責(通常意味著他們負責非工作時間的支援)——這項原則稱為「你建構它,你執行它」。
專注於像這樣的客戶需求意味著團隊是長期的,以業務能力為中心的團隊,只要該能力處於活動狀態,他們就會支援該業務能力。與專案導向團隊(在軟體「完成」時解散)不同,他們認為自己是在啟用和增強長期的產品。這個特點通常導致他們被稱為產品團隊。
一個雙披薩團隊需要支援其產品的廣泛技能和責任,表示儘管此類團隊可能是團隊組織的主要方法,但他們需要一個結構良好的軟體平台支援。對於小型組織,這可能是一個商業平台,例如現代雲端服務。較大型的組織將會建立自己的內部平台,讓他們的雙披薩團隊更容易合作,而不會產生困難的交接。 團隊拓撲 提供了一個很好的方式來思考支援雙披薩團隊所需的不同類型的團隊和互動(團隊拓撲稱它們為串流對齊團隊)。
為了讓以業務能力為中心的團隊發揮效用,他們需要利用彼此的能力。因此,團隊需要透過經過周密設計的 API,向其同儕提供其能力。此類團隊提供服務給同儕的責任通常會被忽略,如果沒有發生,將會導致僵化的資訊孤島。
像這樣以業務能力為中心來組織人員,會對組織軟體的結構方式產生深遠的影響,這是由於 康威定律 的影響。由雙披薩團隊建置的軟體元件需要與其同儕有良好的互動控制,並在它們之間有明確的 API。這種思考方式導致了 微服務 的發展,但這不是唯一的方法,單體執行時間內結構良好的元件通常是更好的途徑。