Tôi không biết khẳng định rằng "nó không và thường không thể thực hiện phân tích tĩnh" đến từ đâu. Phần đầu tiên của khẳng định là sai rõ ràng. Cái thứ hai phụ thuộc vào ý của bạn là "thường". Tôi muốn nói rằng thường xuyên , nó thực hiện phân tích tĩnh, và hiếm khi, nó thất bại ở đó. Trong ứng dụng kinh doanh thông thường, hiếm khi trở nên gần gũi hơn bao giờ hết .
Vì vậy, ở đây nó đến, lợi ích đầu tiên:
Lợi ích 1: phân tích tĩnh
Các xác nhận thông thường và kiểm tra đối số có một nhược điểm: chúng bị hoãn cho đến khi mã được thực thi. Mặt khác, các hợp đồng mã biểu hiện ở mức độ sớm hơn nhiều, ở bước mã hóa hoặc trong khi biên dịch ứng dụng. Bạn càng bắt lỗi sớm thì càng ít tốn kém để sửa nó.
Lợi ích 2: loại tài liệu luôn cập nhật
Hợp đồng mã cũng cung cấp một loại tài liệu luôn cập nhật. Nếu nhận xét XML của phương thức SetProductPrice(int newPrice)
cho biết newPrice
nên vượt trội hoặc bằng 0, bạn có thể hy vọng rằng tài liệu này được cập nhật, nhưng bạn cũng có thể phát hiện ra rằng ai đó đã thay đổi phương thức để newPrice = 0
ném ArgumentOutOfRangeException
, nhưng không bao giờ thay đổi tài liệu tương ứng. Dựa vào mối tương quan giữa các hợp đồng mã và chính mã, bạn không gặp phải vấn đề tài liệu không đồng bộ.
Loại tài liệu được cung cấp bởi các hợp đồng mã cũng rất quý theo cách mà thông thường, các nhận xét XML không giải thích tốt các giá trị chấp nhận được. Đã bao nhiêu lần là tôi tự hỏi nếu null
hay string.Empty
hoặc \r\n
là một giá trị được uỷ quyền cho một phương pháp, và ý kiến XML đã im lặng về điều đó!
Tóm lại, không có hợp đồng mã, rất nhiều đoạn mã giống như vậy:
Tôi sẽ chấp nhận một số giá trị nhưng không phải giá trị khác, nhưng bạn sẽ phải đoán hoặc đọc tài liệu, nếu có. Trên thực tế, đừng đọc tài liệu: nó đã lỗi thời. Đơn giản chỉ cần lặp qua tất cả các giá trị và bạn sẽ thấy những giá trị khiến tôi ném ngoại lệ. Bạn cũng phải đoán phạm vi của các giá trị có thể được trả về, bởi vì ngay cả khi tôi sẽ nói thêm một chút với bạn về chúng, điều đó có thể không đúng, với hàng trăm thay đổi được thực hiện cho tôi trong những năm qua.
Với các hợp đồng mã, nó trở thành:
Đối số tiêu đề có thể là một chuỗi không null có độ dài 0..500. Số nguyên theo sau là một giá trị dương, chỉ có thể bằng 0 khi chuỗi trống. Cuối cùng, tôi sẽ trả lại một IDefinition
đối tượng, không bao giờ null.
Lợi ích 3: hợp đồng giao diện
Một lợi ích thứ ba là các hợp đồng mã trao quyền cho các giao diện. Hãy nói rằng bạn có một cái gì đó như:
public interface ICommittable
{
public ICollection<AtomicChange> PendingChanges { get; }
public void CommitChanges();
...
}
Làm thế nào bạn, chỉ sử dụng các xác nhận và ngoại lệ, đảm bảo chỉ CommitChanges
có thể được gọi khi PendingChanges
không trống? Làm thế nào bạn sẽ đảm bảo rằng PendingChanges
không bao giờ null
?
Lợi ích 4: thực thi các kết quả của một phương pháp
Cuối cùng, lợi ích thứ tư là có thể đạt Contract.Ensure
được kết quả. Điều gì sẽ xảy ra nếu, khi viết một phương thức trả về một số nguyên, tôi muốn chắc chắn rằng giá trị không bao giờ thấp hơn hoặc bằng 0? Bao gồm năm năm sau, sau khi chịu nhiều thay đổi từ nhiều nhà phát triển? Ngay khi một phương thức có nhiều điểm trả về, Assert
s trở thành cơn ác mộng bảo trì cho điều đó.
Xem xét các hợp đồng mã không chỉ là một phương tiện chính xác cho mã của bạn, mà còn là một cách chặt chẽ hơn để viết mã. Theo cách tương tự, một người sử dụng các ngôn ngữ động độc quyền có thể hỏi tại sao bạn sẽ thực thi các loại ở cấp ngôn ngữ, trong khi bạn có thể làm điều tương tự trong các xác nhận khi cần. Bạn có thể, nhưng gõ tĩnh dễ sử dụng hơn, ít bị lỗi hơn so với một loạt các xác nhận và tự ghi lại tài liệu.
Sự khác biệt giữa gõ động và gõ tĩnh là cực kỳ gần với sự khác biệt giữa lập trình thông thường và lập trình theo hợp đồng.