MML 4: Precise Models
At MML 4 the specification of the software is written down in one or more models. Natural language can still be used to explain the background and motivation of the models, but it takes on the same role as comments in source code. If a number of models are used, the relationships between these models are clearly defined. For instance, a developer would know which models would be affected when he or she removes an operation/method from a UML class diagram.
At this level the models are precise enough to have a direct link with the actual code. For instance, a UML operation becomes a method in the code, with exactly the specified parameters and return type, and a UML attribute becomes a field with its get
methods. Because of this direct link between models and code, it is possible to generate large portions of the code automatically. This is the level at which the OMG's MDA or Model Driven Architecture is targeted.
Changes to the system are done in the models, after which the code is regenerated. In effect the models become part of the source code. This means that it is easy to keep models and code up-to-date. Furthermore, the direct translation from model to code facilitates agile, iterative, and incremental development.
The model is more than just code in pictures. The model contains abstractions that are equivalent to many lines of generated code. For instance, an association in a UML class diagram may have the multiplicity many ('0..*', '*', '1..n', or '0..n'). In the code this means that the field that implements this association will not only have the normal getter
methods but also add
methods. In fact, the simple diagram
we showed at MML 2 implies that the generated code for the class Person has the following set of methods (we use the UML convention to write the type after the method and its parameters).
- getMessages(): Set(Message)
- setMessages(newMessages : Set(Message) ) : void
- addMessage(newMessage: Message) : void
- addMessages(newMessages : Set(Message) ) : void
- removeMessage(newMessage: Message) : void
- removeMessages(newMessages : Set(Message) ) : void
Furthermore, because the association is bidirectional, the generated code for the class Message will have a field representing this link, probably something like: private myPerson: Person
. The implementation of the above methods will ensure that this field is set to the right value for all messages involved.
It is clear that this type of model is more difficult to develop, but the added value is that much of the code can be generated. And if there is no code generator available for your programming language, or for whatever reason, the developer will at least be able to work very fast, because it is so clear what needs to be done.
|Figure 5. The MML 4 Specification of the Mailer: This is the specification at MML 3 enhanced with precise information. Pre- and post-conditions are added to the different operations, to specify exactly what the operation must do. Use cases have pre- and post-conditions attached to them. The class diagram contains additional constraints to clarify what a correct model looks like.|
The MML 4 specification of the Mailer is the specification at MML 3 enhanced with precise information. Pre- and post-conditions are added to the different operations, to specify exactly what the operation must do. Use cases have pre- and post-conditions attached to them. The class diagram contains additional constraints to clarify what a correct model looks like (see Figure 5
In addition to this, several OCL expressions are used to make the class model more precise. We will explain OCL at length in a future DevX article.
context Mailbox::receive(m : Message)
post : messages->includes(m)
context Mailbox::remove(m : Message)
post : not messages->includes(m)
context Mailbox::readMessage(m : Message)
post : m.isNew = false
context Mailbox::findMessage(from : String) : Set(Message)
body: message->select(m | m.fromName = from)
context PostOffice::findMailBox(name : String)
body: boxes->select(b : b.owner.name = name)->any()
context PostOffice::createFailedMessage(from : String)
post : result.isNew = true and
result.toName = from and
result.fromName = 'PostOffice' and
result.content = 'Cannot deliver message, addressee unknown'
init : true
Also at MML 4, the use case description is enhanced with pre- and post-conditions (see Figure 6
|Figure 6. Use Case Description: The use case description is enhanced with pre- and post-conditions.|
The sequence diagram is enhanced with the PostOffice class.
MML 5: Models Only
|Figure 7. The Sequence Diagram: The sequence diagram is enhanced with the PostOffice class.|
At MML 5 the models are precise and detailed enough to allow complete code generation. The code generators at this level have become as trustworthy as compilers, therefore no developer needs to even look at the generated code. It is as invisible as assembler code is today. In other words, the MML 5 is the modeling Valhalla.
Unfortunately, there are no modeling languages in which we can write MML 5 models. We cannot work at this levelyet. Currently we still need to hand code a lot of nitty gritty details. This is the reason why we do not give an example here. Only within specific and limited application domains there are languages and tools that can achieve this. Most notably different vendors selling their versions of 'Executable UML' provide solutions in the realtime domain.
The challenge for all of us working in this field is to reach this level. And we will, eventually, because the people who commission our software will become more and more demanding, until the point that we will not be able to hand code software. No matter how many people we put on the project and no matter how much time we have, the software of the future will be too complex. We can only battle this by taking software development to the next level of abstraction: models only.