契約式設計（，縮寫為 DbC），一種設計計算機軟體的方法。這種方法要求軟體設計者為軟體元件定義正式的，精確的並且可驗證的介面，這樣，為傳統的抽象資料型別又增加了先驗條件、後驗條件和不變式。這種方法的名字裡用到的 契約 或者說 契約 是一種比喻，因為它和商業契約的情況有點類似。 因為 Design by Contract 是屬於 Eiffel Software 的註冊商標，很多開發人員用契約式程式設計（Programming by Contract），契約程式設計（Contract Programming），或者契約優先式開發（ContractFirst development）來指代這種方法。微軟也採用這種設計方法，稱為程式碼合約（Code Contracts）。 歷史 這個術語最早由伯特蘭邁耶於 1986 年提出。他設計了 Eiffel 程式語言來實現這種程式設計方法，在《物件導向軟體建構》（ObjectOriented Software Construction）一書中，又提出兩個後繼版本。2003 年，由伯特蘭邁耶建立的 Eiffel software 公司，申請將 Design by Contract 作為商標，於 2004 年透過。 契約式設計應用了形式驗證、與霍爾邏輯的理論。 描述 DbC 的核心思想是對軟體系統中的元素之間相互合作以及 責任 與 權利 的比喻。這種比喻從商業活動中 客戶 與 供應商 達成 契約 而得來。例如： 供應商必須提供某種產品（責任），並且他有權期望客戶已經付款（權利）。 客戶必須付款（責任），並且有權得到產品（權利）。 契約雙方必須履行那些對所有契約都有效的責任，如法律和規定等。 同樣的，如果在面向物件程式設計中一個類的函式提供了某種功能，那麼它要： 期望所有呼叫它的客戶模組都保證一定的進入條件：這就是函式的先決條件 客戶的義務和供應商的權利，這樣它就不用去處理不滿足先驗條件的情況。 保證退出時給出特定的屬性：這就是函式的後置條件 供應商的義務，顯然也是客戶的權利。 在進入時假定，並在退出時保持一些特定的屬性：不變條件。 契約就是這些權利和義務的正式形式。我們可以用 三個問題 來總結 DbC，並且作為設計者要經常問： 它期望的是什麼？ 它要保證的是什麼？ 它要保持的是什麼？ 很多程式語言都有對這種斷言的支援。然而 DbC 認為這些契約對於軟體的正確性至關重要，它們應當是設計過程的一部分。實際上，DbC 提倡首先寫斷言。 契約的概念擴充套件到了方法 過程的級別。對於一個方法的契約通常包含下面這些資訊： 可接受和不可接受的值或型別，以及它們的含義 返回的值或型別，以及它們的含義 可能出現的錯誤以及異常情況的值和型別，以及它們的含義 副作用 先驗條件 後置條件 不變條件 （不太常見）效能上的保證，如所用的時間和空間 繼承中的子型別可以弱化先驗條件（但不可以加強它們），並且可以加強後驗條件和不變式（但不能弱化它們）。這些原則很接近 Liskov 代換原則。 所有類之間的關係就是客戶與供應商的關係。一個客戶在呼叫供應商的功能時有義務不去違反供應商所需的狀態。相應的，供應商也有義務為客戶提供它所需的狀態和資料。例如，供應商的 delete 功能要求客戶在 data buffer 當中有資料存在。相應的，供應商要保證當 delete 功能完成後，data buffer 中的資料已被刪除。其它的設計契約還有不變式。不變式保證類的狀態在任何功能被執行後都保持在一個可接受的狀態。 當使用契約時，供應商不應對契約條件是否被滿足進行校驗。大體的思想是，利用契約條件校驗為保護網，在契約被違反的情況下程式碼會 硬性失敗（fail hard）。DbC 的 硬性失敗 概念讓對契約行為的除錯變簡單，因為每個過程的行為意圖被定義得很清楚。它和一種叫作防禦性程式設計的方法明顯不同，在那種方法裡，供應商要負責解決先驗條件不滿足的情況。相對通常的情況下，在 DbC 和防禦性程式設計中，如果客戶違反了先驗條件供應商都會丟擲異常 由客戶來負責解決這種情況。DbC 讓供應商的工作更簡單。 DbC 同時也定義了軟體模組的正確性條件： 如果對一個供應商的呼叫之前類的不變式和先驗條件是真，那麼在呼叫後不變式和後驗條件也為真。 當呼叫供應商時，軟體模組應保證不違反供應商的先驗條件。 因為契約條件在程式執行中不應被違反，它們可以只作為除錯程式碼，或者在釋出版本中被移除從而得到更好的效能。 DbC 也能幫助程式碼重用，因為每段程式碼的契約都被很好的文件化了。模組的契約可以被當做軟體文件來描述模組的行為。 語言支援 原生支援語言 貫徹契約式設計特徵最多的語言包含： Ada 2012 Clojure D Eiffel Kotlin Mercury （曾叫做 Chrome 和 Delphi Prism） RacketFindler Felleisen Contracts for HigherOrder Functions ScalaStrong typing as another contract enforcing in Scala see discussion at scalalangorg SPARK（經過 Ada 程式的靜態分析） Vala 透過第三方支援的語言 Ada，透過 GNAT 的先決條件和後置條件的 pragma。 C 和 C BoostContract DBC for C 預處理器 GNU Nana eCv 和 eCv 形式驗證工具 C 編譯器，透過 C 的 CTESK 擴充套件。 Loki 庫，提供叫做 ContractChecker 的機制用來驗證一個類服從契約設計。 DBC CDBC C Design by contract for C C（和其他NET 語言），透過 Code Contracts Groovy，透過 GContracts。 Go，透過 dbc 或 gocontracts Java OValOVal，經由。 Contracts for Java（Cofoja） （JML） （只有先決條件和後置條件） valid4j JavaScript，透過 AspectJS（特別是 AJS_Validator）、Cernyjs、ecmaDebug、jsContract、dbccodecontracts 或 jscategory。 Common Lisp，透過宏設施或 CLOS 元物件協議。 Nemerle，透過宏。 Nim，透過宏。 Perl，透過 CPAN 模組 ClassContract（出自）或 CarpDatum（出自 Raphael Manfredi）。 PHP，透過 PhpDeal、或 Stuart Herbert 的 ContractLib。 Python，使用包如 deal、icontract、PyContracts、Decontractors、dpcontracts、zopeinterface、PyDBC 或 Contracts for Python。 Ruby，透過 Brian McCallister 的 DesignByContract、Ruby DBC rubycontract 或 contractsruby。 Rust，透過 contracts crate。 Tcl，透過面向物件擴充套件。 參考文獻 外部連結 The Power of Design by Contract TM A toplevel description of DbC with links to additional resources Building bugfree OO software An introduction to Design by Contract TM Older material on DbC Benefits and drawbacks implementation in RPSObix Bertrand Meyer Applying Design by Contract IEEE Computer October 1992 Using Code Contracts for Safer Code Category 軟體設計 Category 程式設計典範