The Object Constraint Language: Getting Your Models Ready for MDA (2nd Edition)
When implementing constraints, you must decide when to check them and what to do when a constraint fails. 4.6.1 When to Check Constraints
Invariants are defined as being true at any moment in time, but in a runtime system they cannot be checked continuously. One solution to this problem is to check the invariants on an object immediately after any value in the object has changed. For example, when the value of an attribute changes, all invariants that refer to the attribute would be checked. Of course, this might include invariants on objects other than the object that is being changed, and checking could prove to be expensive. How often and when to check an invariant depends on how serious the error could be. Invariants on objects in a customer relationship management system might be checked once a week or whenever the object is used, whereas the aforementioned expensive solution might be the right one to check objects in a crucial process-control system. You need to find a solution that balances complete checking with runtime efficiency in a way that is right for your situation. Preconditions should be checked each time the operation is called. However, depending on the complexity of the precondition and the performance requirements, the cost of this technique might be prohibitive. In circumstances where the software is used as a component, offering services to other unknown components , it is wise to always check preconditions ”to avoid incorrect use and potential disaster as a result of it. If the software is used as part of a closed, well-defined system, precondition checking should be turned on during testing, but might be turned off during production. Postconditions are naturally checked at the end of the execution of an operation. Practice has shown that precondition checking is much more important than postcondition checking. Therefore, if the possibility for checking is limited, preconditions are the best candidates to check. This leads to another question: whether you want constraints ”invariants as well as pre- and postconditions ”to be checked during deployment. Practice has shown that during system development, checking is very useful. When the system is deployed, checking might take too much processor time, making the system slower than necessary. In that case, an assert mechanism that can be switched on and off is very useful. For instance, in systems built with the Eiffel language, preconditions are often checked during development, testing, and debugging, but not checked (or only partially checked) when the application is operational. The Java language also includes an assertion mechanism, although it can only be controlled in a rather coarse-grained fashion. Whether constraints need to be checked during deployment depends on the type of system you are dealing with. In an average database system, it is not unusual to have corrupted data. Unless the percentage of corrupted data grows too large, it is no problem. In such a case, the database administrator might run a check of all invariants every couple of weeks, and clean the database based on the results. If the correctness of the data is (much) more important, the invariants could be checked upon every change of value. A broken constraint can lead to a rollback of the transaction in which the failure occurs. The same argument holds for precondition checking. Only when the precondition represents a vital aspect of the system does it need to be checked each time the operation is called. In other circumstances, far less checking is necessary. 4.6.2 What to Do When a Constraint Fails
Another issue is how one should react when a constraint is broken; in other words, what action has to be taken when the restrictions laid on the objects are no longer met? Consider three different approaches to broken constraints. The simplest one is to print an error message each time a constraint is broken. Although this might seem a very low-level approach, it still is a very effective one, especially when constraints are checked only during development of the system, and not during deployment. Constraint checking during development is a way to continuously test the software. Some people argue that breaking a constraint should throw some kind of exception, or at least that such behavior should be an option. In Eiffel, assertions are used both as a debugging tool and as an exception facility; this means that when the assertion (or, in our terms, the constraint) is broken, an exception is thrown. In Java, which incorporates the concept of assertions, this approach is used as well. Others argue that the breaking of a constraint is a trigger for an operation to be executed. For instance, in Soma, the analysis and design method defined by Ian Graham [Graham95], rules can be triggers to actions that the system must undertake. An example of a possible action in a transaction environment is to roll back the transaction. |