Design by contract and CQS
This paper is published under the terms and conditions in the footnote.
In the OOP world, Bertrand Meyer proposed two patterns for object-oriented program design.
Neither pattern applies well to a world of coarse-grained loosely-coupled components in client-server and distributed systems.
Meyer proposed software should be written using this principle, meaning that:
· Every operation that can be invoked is defined by a contract, including the preconditions for its success.
· Every component that invokes an operation will guarantee the preconditions of that operation.
This is OK where components are tightly-coupled, as is normal within a single program, running on one machine.
But the trend for decades has been towards increasingly loosely-coupled (client-server and distributed) computing.
Design by contract is unrealistic in this world, since client components cannot guarantee all preconditions required for operations on remote components.
And server-side components, designed for reuse, cannot trust all clients (sending inputs through different channels) will check the same preconditions.
So, the opposite "defensive design" approach is taken.
This means that a server component tests that the preconditions for an operation hold true.
· test some conditions by inspecting the values of fields in the input Command message, then
· test other conditions by accessing the system state
Typically, the former conditions are tested on the client side before invocation, and the latter on the server side.
In most business applications, code on the client device checks data entry fields for
· missing values,
· out of range checks (age < 0)
· mismatches with pre-defined enumerated values (Mr, Mrs, Dr…)
· mismatches with pre-defined regular expressions.
The UI does not send a Command message to the server-side unless and until the message passes basic checks.
The top-most tier on the server side usually repeats some or all of the tests made by clients, including security checks.
Then, server-side components perform the required business logic, accessing stored data as need be.
During this process, further preconditions may be found not to hold, meaning the server-side processing cannot proceed to a successful conclusion.
If a server-side component cannot succeed, it usually replies (directly or indirectly) to the client with a suitable error message.
Sometimes, invalid Commands get past a defensive design, and stored data is left in a state that is inconsistent with business rules.
Consider a requirement for usernames in new registrations on a website to be unique.
The application that processes the Commands cannot (without impractical database locking) prevent duplicate usernames being registered.
In such a case, validation can be done later, and a compensating transaction can fix up that rare situation where duplicate usernames are registered at the same time.
Meyer proposed one operation (on an object) should either change/write some data or get/read some data or but not do both at the same time.
The idea was that this should make systems easier to program, to test and understand.
Using the Design by Contract pattern, a server component has no reason to reject a Command, and no need to reply with a failure message.
Structured design methods (c1980) distinguished database update transactions from database queries.
· The queries contain nothing but read operations.
· The updates are transactions that apply business rules and maintain the integrity/consistency of stored data.
That separation appears similar to the Command/Query Separation pattern, but is different.
An update transaction is a coarse-grained operation; it may invoke read-only operations to access data it does not update.
E.g. The Place Order transaction may invoke operations that read the customer’s credit limit and the product stock balance.
And it may return the retrieved values to the Command sender, along with a success or failure error message.
A Command-triggered transaction usually reports its success or failure, with appropriate error messages, whether to its client or another party.
There is a relationship between Meyer’s Design by Contract and Command/Query Separation patterns.
Design by Contract means a server component has no reason to reject a Command or reply with a failure message.
So, if a client wants to know what effect a Command has produced, then it must follow up by sending a Query.
But neither of Meyer’s two patterns applies well to a world of loosely-coupled client-server and distributed computing.
Server-side components must be designed to defend themselves against being sent Command messages that are incorrectly formatted.
And update transactions triggered by Command messages sent to the server-side will often not only change data, but also read data and return data.
Footnote: Creative Commons Attribution-No Derivative Works Licence 2.0 20/04/2015 16:27
Attribution: You may copy, distribute and display this copyrighted work only if you clearly credit “Avancier Limited: http://avancier.website” before the start and include this footnote at the end.
No Derivative Works: You may copy, distribute, display only complete and verbatim copies of this page, not derivative works based upon it.
For more information about the licence, see http://creativecommons.org