Dienstag, 10. August 2010

From Control Theory to CQS

The term observable state steems from control theory, which is about state-systems. The observable state is the state of a system which can be observed (queried) from the outside world, while the controllable state of a system the state is, which may be changed.

Thinking in the concepts of encapsulation, observability enables it to find something out about the system. In OO, this would mean that all properties of a type which are observable must be public (or protected) queries on the object.
Controllability, on the other hand, defines operation on a system. Ideally, a system (or object) cannot change. In that case, it offers only observable properties and is stateless (immutable).

However, any kind of program needs to modify some state - otherwise, its just a "black box that getters hotter" (google this). For classical OO, I'd like to add a further definition exclusively for programming: Two systems (objects) can be considered to be equal at a given state, if all of their observable properties are also equal (recursively by this definition).

Taking these three approaches: Controllability, Observability and the Equality Definition, it's very easy to define referential transparency as well: All observations which are done with the same parameters on the same observer method at the same system's state must yield an equal observation result. After each control operation, all observer methods might have changed their result (but do not need to), but a guarantee is given that their result will once again be constant until the next control opreation arises.

Quite obviously, this is only true as long the system does not introduce side effects, which would modifiy the observable state internally without external control. Now, we're coming to next and last two definitions:
A system without malicious side effects and just with observations is a functional pure system.

However, there are few programming languages which model this definition, since the referential transparency cannot always be guaranteed: Simply think about external resources which are needed for in- and output by the program, for example. If these would be used in queries, then even for the same parameters (connection settings, file names), the same results could never be guaranteed. Therefore, imperative languages allow it, besides writing pure functions, to introduce invisible side effects as well - usually these are the resource for countless bugs and hard-to-read code.

And now up to the last step: A good approach in these impure languages could be the command and query pattern for system building: Queries are functional pure and referential transparent observations of the system, Commands will change the state of the system.
After a command has been executed, all queries on a single object are no longer guaranteed to yield the same results. Furthermore, all other objects which directly or indirectly depend on the queries on this object might have also changed their state as well.

Whats the point behind all these definitions? To show how different concepts in system building can be used to define and program software that is easy to understand and tries to avoid side-effects in imperative languages.

In my opionion, the problems of all imperative approaches are not that important as long as the command / query pattern is used massively and commands are tried to be reduced to those which are really needed, falling back to immutables in all other cases.

Under these circumstances, and given that the types have a low cohesion, so that commands on one object cannot influence the queries on another, an imperative system should avoid all of the common problems with the uncontrollable side-effects.

Note, however, that i am not yet fully aware on how systems would look like if the concept would be consequently applied on a large project. Maybe I should ask Betrand Meyer, the genius how proposed most of these OO-Concepts, esp. CQS, long ago....

Keine Kommentare:

Kommentar veröffentlichen