I have some confusion with applying Larman's system operation contracts (OO Analysis from book Applying UML and Patterns) on CRUD-like operations. More precisely, I'm confused with postcondition part.
For example, if I have CRUD system operations looking as follows:
createEmployee(employee:Employee),
readEmployee(employeeId:int),
updateEmployee(employee:Employee),
deleteEmployee(employeeId:int)
what would be postcondition on, for example, readEmployee
system operation, or some other operation like searchEmployees
etc?
For example: for read operation, system needs to read record from database, instantiate domain object, set attribute values on domain object (set relations also) and that's it. Does it means that postconditions are above mentioned - instance creation, changes on attributes, etc. Or, read operation does not have any postcondition. None of this does sound logical to me.
My confusion is about relation between domain model (state) and database (state). I just don't get implications which above operations will have on domain model. I always think in way that the database is a place that preserves the state of the system. After I create employee, its object's state will be persisted in database... But what happens with domain model state?
The post-condition defines what the state of your application (or object, depending on the level of abstraction) should be after the operation for it to be considered as successful. For the
readEmployee
operation, for example, the post-condition would be that:Employee
instance is created.Employee
instance contains attributes matching the database values.I like to think of "pre-condition" and "post-condition" as the "state of mind" of your application before and after an operation has executed, respectively. As you can imagine, it's more a thought process than a coding exercise when you do DbC.
(If you do unit-testing, states make it clear what needs to be covered by your tests. Basically, you end up testing the "state of mind" of your application.)
Interestingly, if you consider the reverse of DbC, you realise that to identify what operations your application (or object) should expose, it is simply a matter of listing what states it can have and how it transitions between these states. The actions that you need to take to make these transitions then become your operations, and you do not have to bother with implementing operations that do not lead to any desired states. So, for example, you probably want the following states for your application.
The following state transitions are possible.
Based on the above, you can write your operations in such a way that only valid transitions are allowed, with anything else giving rise to errors.
Impossible state transitions:
State modeling is probably the most important part of designing objects, so you're asking the right questions. If you want a good resource on state modeling, get Object Lifecycles Modeling the World in States from Sally Shlaer / Stephen Mellor. It is quite an old book and costs almost nothing on Amazon, but the principles it introduces form the basis of modern UML -- incidentally, the notation used in the book looks nothing like UML.
I realise I did not touch on database state, but at the conceptual level, the database layer is just another system of states and the same principles apply.
I hope this was useful.