OCL Editor, system prototyper and ViewModel
No edit summary
(Automatically adding template at the end of the page.)
 
(14 intermediate revisions by 3 users not shown)
Line 1: Line 1:


<html>  
<html>


<h4> Continue on introducing the MDriven Designer as a UML modelling tool that allows you to capture enough details to cover every aspect of a software system. From this series you will find out how to work with New OCL Debugger editor, system prototyper and View Model editor. We will re-create the model of "lifecycle" of a house from planning to demolition, also structure the concept of the "House" class and make it possible to work with the user interface.
<h4> We continue to introduce the MDriven Designer as a UML modeling tool that allows you to capture enough details to cover every
  aspect of a software system. From this series, you will discover how to work with the new OCL Debugger editor, system prototyper,
  and View Model editor. We will re-create the model of the "lifecycle" of a house from planning to demolition, also structure
  the concept of the "House" class, and make it possible to work with the user interface.
</h4>
</h4>


<p class="warn">
<p class="video-warn">
<em>To make your experience more comfortable, we set the main tags mentioned in the video to the right bar menu of this mini player. Choose the interesting subtitle on the list and immediately get to the exact theme timeplace in the video. Now you can pick any topic to be instructed without watching the whole video.</em> </p>
  <em>To make your experience smooth, we set the main tags mentioned in the video to the right bar menu of this mini-player. Choose an interesting subtitle on the list and immediately get to the exact theme navigation item place in the video. Now you can pick any topic to be instructed on without watching the whole video.</em>
<style type="text/css">
</p>
p.warn {
    opacity: 0.7;
    text-align: justify;
    width: 90%
}
#video12 {
  position: relative;
  padding-bottom: 10px;
}
#video12::after {
  content: "";
  display: table;
  clear: both;
}
#video12 iframe {
  width: 100%;
  min-width: 200px;
  max-width: 740px;
  height: 500px;
  float: left;
}


@media (max-width: 767px) {
<div class="video">
  #video12 iframe {
   <div class="video__wrapper">
    height: 180px;
    <iframe src="https://www.youtube.com/embed/KQerwRGgmE4?rel=0&autoplay=0" frameborder="0" allowfullscreen></iframe>
  }
   </div>
}
  <div class="video__navigation">
 
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="21" tabindex="0"> Additional diagram</span>
#video12 div {
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="130" tabindex="0"> Nullable types</span>
  float: left;
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="193" tabindex="0"> State Machine</span>
  padding-left: 10px;
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="375" tabindex="0"> Guards and triggers</span>
overflow-y: auto;
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="585" tabindex="0"> OCL Editor</span>
height: 500px;
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="668" tabindex="0"> Methods on the class</span>
}
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="650" tabindex="0"> System prototyper</span>
span.time {
    display:block;
  padding: 2px 10px 2px 10px;
    padding-bottom: 0.5em;
    padding-top: 0.5em;
   opacity: 0.7;
}
span.time:hover {
  color: #0000FF;
  cursor: pointer;
}
span.time:focus {
  color: blue;
}
</style>
 
<br>
<div id="video12">
<iframe width="740" height="500" src="https://www.youtube.com/embed/KQerwRGgmE4?rel=0&autoplay=0" frameborder="0" allowfullscreen></iframe>  
   <div>
     <span class="time" data-video="KQerwRGgmE4" data-start="337" tabindex="0">Additional diagram</span>
     <span class="time" data-video="KQerwRGgmE4" data-start="446" tabindex="0">Nullable types</span>
     <span class="time" data-video="KQerwRGgmE4" data-start="509" tabindex="0">State Machine</span>
     <span class="time" data-video="KQerwRGgmE4" data-start="691" tabindex="0">Guards and triggers</span>
     <span class="time" data-video="KQerwRGgmE4" data-start="901" tabindex="0">OCL Editor</span>
     <span class="time" data-video="KQerwRGgmE4" data-start="984" tabindex="0">Methods on the class</span>
     <span class="time" data-video="KQerwRGgmE4" data-start="966" tabindex="0">System prototyper</span>
     <strong>New OCL Debugger</strong>
     <strong>New OCL Debugger</strong>
     <span class="time" data-video="KQerwRGgmE4" data-start="1346" tabindex="0"> • Introduction </span>
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="714" tabindex="0"> • Introduction </span>
     <span class="time" data-video="KQerwRGgmE4" data-start="1605" tabindex="0"> • Using “memory”, M1, M2, M3 </span>
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="1289" tabindex="0"> • Using “memory”, M1, M2, M3 </span>
     <span class="time" data-video="KQerwRGgmE4" data-start="2648" tabindex="0"> • XML persistence </span>
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="2332" tabindex="0"> • XML persistence </span>
     <span class="time" data-video="KQerwRGgmE4" data-start="2877" tabindex="0"> • SQL persistence </span>
     <span class="navigation-item" data-video="KQerwRGgmE4" data-start="2516" tabindex="0"> • SQL persistence </span>
      <span class="time" data-video="KQerwRGgmE4" data-start="2933" tabindex="0"> • MDriven server </span>
    <span class="navigation-item" data-video="KQerwRGgmE4" data-start="2617" tabindex="0"> • MDriven server </span>
    <span class="time" data-video="KQerwRGgmE4" data-start="3004" tabindex="0">View Model Editor</span>
    <span class="navigation-item" data-video="KQerwRGgmE4" data-start="2688" tabindex="0"> View Model Editor</span>
<span class="time" data-video="KQerwRGgmE4" data-start="3595" tabindex="0">"ModelView" and "ViewModel" patterns</span>
    <span class="navigation-item" data-video="KQerwRGgmE4" data-start="3280" tabindex="0"> "ModelView" and "ViewModel" patterns</span>
 
   </div>
   </div>
</div>
</div>


<script>
var IMG = document.querySelectorAll('#video12 span'),
    IFRAME = document.querySelector('#video12 iframe');
for (var i = 0; i < IMG.length; i++) {
  IMG[i].onclick = function() {
    IFRAME.src = 'https://www.youtube.com/embed/' + this.dataset.video + '?rel=0&autoplay=1';
    if(this.dataset.end) IFRAME.src = IFRAME.src.replace(/([\s\S]*)/g, '$1&end=' + this.dataset.end);
    if(this.dataset.start) IFRAME.src = IFRAME.src.replace(/([\s\S]*)/g, '$1&start=' + this.dataset.start);
    this.style.backgroundColor='rgba(0,0,0,.2)';
  }
}
</script>
</html>
</html>


'''Text guidance of video'''
'''Textual Guidance to the Video'''


Continuing on the types of diagrams, we will talk about the additional one. Which we start working with by double clicking beside the name of the class, otherwise, choosing he actual name, we enter the edit state. This type of diagram is an automatically generated display of the class, its attributes and its relations. Withal it serves as a navigation tool for the other existing classes, that it has relations to associations. So this is another way to walk around your complete model. As you can observe each element in the repository and you are not able to hide anything from view.
Continuing on the types of diagrams, we will talk about the additional one. We start working by double-clicking beside the name of the class and by choosing the actual name, we enter the edit state. This type of diagram is an automatically generated display of the class, its attributes, and its relations. Withal it serves as a navigation tool for the other existing classes - it has relations to associations. This is another way to walk around your complete model as you can observe each element in the repository and are unable to hide anything from view.


Explaining the default repository graphical display, coordination works in the way that if you select the relation, you get the properties, if you choose the class, you get the properties as well. Whenever you select the class in the circle around the centre class, it will navigate to that one and clicking an attribute, get its properties.
To explain the default repository graphical display, coordination works in this way: if you select the relation, you get the properties; if you choose the class, you get the properties as well. Whenever you select the class in the circle around the centre class, it will navigate to that class, and by clicking an attribute, you get its properties.


Properties should have a type, but the “?” behind it is the C# syntax to denote nullability - able to have a "null" value. In MDriven we call this '''"Allow NULL"'''. For instance, this property is "True" and it is randomed as a "String?", if we were to change this to "False" the "?" would disappear.
Properties should have a type, but the “?” behind it is the C# syntax to denote nullability - able to have a "null" value. In MDriven, we call this '''"Allow NULL"'''. For instance, this property is "True" and it is randomized as a "String?"; if we were to change this to "False", the "?" would disappear.


The “State” attribute having the “S” icon on it, so let's go back to the "state diagram", clicking the dialog box. Once reaching the "State diagram", on the Property Inspector dialog, we see that "State attribute" is "State”, in the ”House.State". Here we are able to change its name, give the category and "ColorOnNew" states.  
The “State” attribute has the “S” icon on it. Let's go back to the "state diagram" by clicking the dialog box. Once reaching the "State diagram", on the Property Inspector dialog, we see that the "State attribute" is "State”, in the ”House.State". We are able to change its name and give the category and "ColorOnNew" states.  


Depending on what dynamics you would like for your Class, you can describe them in a state machine. A state diagram for a e.g. "House" would be the "Plan" to build a "House". Evidently, "Construction" will be the next step followed by the "Maintenance" phase. Finally in this "State Machine"  might be a "Demolition" phase. Obviously, during the "Construction" phase, there might be additional sub states, in this case we appear with a "Region" to the "Construction" phase. Continue with states in this Region named "GroundWork" and "Building". In this way, whenever the "House" created, it will start with the e.g. Initial State. Since there are no “guards” stopping it from going further, it will end up in "Plan". But we will need a "trigger" to take it forward called "StartConstruction".
Depending on what dynamics you would like for your Class, you can describe them in a state machine. A state diagram for an e.g. "House" would be the "Plan" to build a "House". Evidently, "Construction" will be the next step followed by the "Maintenance" phase. Finally, in this "State Machine"  might be a "Demolition" phase. Obviously, during the "Construction" phase, there might be additional sub-states. In this case, we appear with a "Region" to the "Construction" phase. Continue with states in this Region named "GroundWork" and "Building". In this way, whenever the "House" is created, it will start with the e.g. Initial State. Since there are no “guards” stopping it from going further, it will end up in "Plan". However, we will need a "trigger" to take it forward called "StartConstruction".


Whenever we enter "Construction", charge "GroundWork” as the initial step. Whereupon that, by creating a trigger "StartBulding”, we are able go on "Building" a "House".  Creating "ConstructionDone" trigger we move to the next “Maintenance” step. Final “Demolish" can be triggered with the “Demolish” as well.
Whenever we enter "Construction", charge "GroundWork” as the initial step. Whereupon, by creating a trigger "StartBulding”, we are able to go on "Building" a "House".  Creating a "ConstructionDone" trigger, we move to the next “Maintenance” step. The final “Demolish" can be triggered with the “Demolish” as well.


You can compose these state machines as complex or simple as you need. Whether you need another acts before "Construction", or there's a domain rule that should be fulfilled, we can have these in "Guards".   
You can compose these state machines as simple or as complex as needed. Whether you need other acts before "Construction", or there's a domain rule that should be fulfilled, we can have these in "Guards".   


The language we will use throughout defining our model is '''[[OCL Expressions|OCL (object constraint language)]]'''. In order to start “Construction”, with its help we can create "Address" for our “House”, distinct from "NULL”. The great thing about OCL is that it really uses the language from our model a lot and just add a few operators to work on the information that we have to define in the model. It means that if we take care of quality model and design everything according to expectations when we speak about these things. The rules get really easy to read, so in this case, the "Address" should not be "NULL", in order to be able to start "Construction".  
The language we will use throughout defining our model is '''[[OCL Expressions|OCL (object constraint language)]]'''. In order to start “Construction”, with its help we can create "Address" for our “House”, distinct from "NULL”. OCL is beneficial because it constantly uses the language from our model and merely adds a few operators to work on the information that we have to define in the model. We can take care of our quality model and design everything according to expectations when we speak about these things. The rules become easier to read; in this case, the "Address" should not be "NULL", in order to be able to start "Construction".  


Heading back to the "House" class, the triggers that we added has been added as "Methods" on the "House". This is one application mode of methods on the class, but we could just as easily add another method, that isn't a trigger, the symbol "tr" for the trigger is absent. And we could implement this saying that it should have a “ReturnType” of type "String". Setting the parameters for trigger:  
Heading back to the "House" class, the triggers that we added have been added as "Methods" on the "House". This is one application mode of methods on the class, but we could just as easily add another method, that isn't a trigger, the symbol "tr" for the trigger is absent. And we could implement this by saying that it should have a “ReturnType” of type "String". Setting the parameters for the trigger:  


Signature      Method1 (''"param1:integer, param2:integer):String''
Signature      Method1 (''"param1:integer, param2:integer):String''


Using the Action Editor Body, now we can implement, what the logic in the method should be. Here we call OCL as an "action language" because while using the methods, we are allowed side effects, to be more flexible with changing data.
Using the Action Editor Body, we can implement what the logic in the method should be. We refer to OCL as an "action language" because while using the methods, we are allowed side effects to be more flexible with changing data.


For instance, this method should just take
For instance, this method should just take:
  ''"param1"+”param2”''
  ''"param1"+”param2”''
It displays the “WrongExpectedType, as the "param1" and "param2" return "Int32" as an integer, although the required type as we define our method was "String". We could take the result from this and state it should be "asstring" instead.
It displays the “WrongExpectedType, as the "param1" and "param2" return "Int32" as an integer, although the required type as we define our method was "String". We could take the result from this and state it should be "asstring" instead.
Line 130: Line 71:
What if we have typed something excessive?  
What if we have typed something excessive?  
  ''"param1"+”param2x”''
  ''"param1"+”param2x”''
Respond is "wrong" and if we were to save this model we see that we have an error in <blockquote>''"Method:House.Method1:7: “param2x" is not a type name''</blockquote>It's unrecognizable, having fixed that and saved, we don't have any errors.
The response is "wrong". If we were to save this model, we see that we have an error in the: <blockquote>''"Method:House.Method1:7: “param2x" is not a type name''</blockquote>It's unrecognizable. Having fixed and saved that, we don't have any errors.
 
This is one way to add logic to the definition of your model. Without executing anything of this subject, just defining and assigning it. Switching back to a diagram, we can see that the trigger methods, that were created as well as "Method1" were added. This way, we demonstrate the definition, and how to navigate around designing the model.


That is one way to add logic to the definition of your model. Without executing anything of this subject, just defining and assigning it. Switching back to a diagram, we can see that the trigger methods, that were created as well as "Method1" were added. This way, we demonstrate the definition, and how to navigate around designing of the model.
''What if we use the “Play” option to bring up a '''"System prototyper"''' dialogue?''


''What if we use “Play” option  to bring up a '''"System prototyper"''' dialogue.''
The first step is that we should "Select persistence". "Persistence" is where data is stored.


The first step is that we should "Select persistence". "Persistence" is where data is stored
'''Step1''' Choosing persistence ''"None"'' →


'''Step1''' Choosing persistence ''"None"'' → '''Step 2''' there's no persistence configuration for this →
'''Step 2''' There's no persistence configuration for this →


'''Step 3''' is actually start a system running our model, so we will press “Start System”.
'''Step 3''' is to start a system running our model, so we will press “Start System”.


Then we have a few options, implementing "New Debugger" to execute the definition that we have in the model and launching '''“OCLExecuteandDebug”''' window.
Then we have a few options, implementing "New Debugger" to execute the definition that we have in the model and launching '''“OCLExecuteandDebug”''' window.


Afterwards,we can't actually get to the “design surface”, however the "Prototyper" is the model we can close t and still have the “Debugger” available. “OCLExecuteandDebug” is operated with OCL expressions, in case, going to "edit", we will get the same "OCL Editor" as we've seen before. For instance, we pick the class "House" and there we should find and create some "operators". There is no "create operator" in OCL, as it does not have side effects nor the ability to change data.
Afterward, we can't actually get to the “design surface”; however, the "Prototyper" is the model we can close it with and still have the “Debugger” available. “OCLExecuteandDebug” is operated with OCL expressions, in case, by going to "edit", we will get the same "OCL Editor" as we've seen before. For instance, we pick the class "House" and there we should find and create some "operators". There is no "create operator" in OCL, as it does not have side effects nor the ability to change data.


Another operator that's common in use in OCL is to bring up all the instances of the type "House":<blockquote>        ''House.allinstances''   →   "Execute"</blockquote>Here we get a result list of all the "House" class attributes, which is empty. This way we need to be able to execute some action language
Another operator that's common in use in OCL is to bring up all the instances of the type "House":<blockquote>        ''House.allinstances''   →   "Execute"</blockquote>Here we get a result list of all the "House" class attributes, which is empty. This way we need to be able to execute some action language
Line 150: Line 93:
''"Prefix a row with ocl:, action:, oclps: (ocl:default)''
''"Prefix a row with ocl:, action:, oclps: (ocl:default)''
* ž      "''action:''"  is actually to state that the expression should be action language instead of OCL
* ž      "''action:''"  is actually to state that the expression should be action language instead of OCL
<u>How does the debugger works?</u>  
<u>How does the debugger work?</u>  


As long as there is an empty line between expressions, the debugger will think of it as separated expression. So "execute" will be applied to the item that we are pointing at only.
As long as there is an empty line between expressions, the debugger will think of it as a separated expression. So "execute" will be applied to the item that we are pointing at only.


Entering "Edit" again we get into the “'''Action Editor Execute and Debug'''”, where "Create" is an operator:
Entering "Edit" again, we get into the “'''Action Editor Execute and Debug'''”, where "Create" is an operator:
  ''“House.Create”''
  ''“House.Create”''
''Whenever in the Action Editor pressing "Ctrl+Enter", we reach a code completion type list, pick the one to quicken my typing.''
''When in the Action Editor, by pressing "Ctrl+Enter", we reach a code completion type list, picking the one to quicken my typing.''


In case we were to  execute ''“House.Create”'' nothing much happens except, there is a new row in "Result" set, which shows all instances. In the new "House" we see that the state is "Plan". Thus according to our "State machine", it should go to "Plan" initially.
In case we were to execute ''“House.Create”'' nothing much happens except, there is a new row in the "Result" set, which shows all instances. In the new "House" we see that the state is "Plan". Thus according to our "State machine", it should go to "Plan" initially.


Let's get a handle to make a "House". On the “OCLExecuteandDebug”, we see a list of "Available variables" of M1, so there's a quick way to access '''M1, M2, and M3'''. Which stands for "memory one", "memory two" and "memory three" like on a calculator.  
Let's get a handle to make a "House". On the “OCLExecuteandDebug”, we see a list of "Available variables" of M1, so there's a quick way to access '''M1, M2, and M3'''. Which stands for "memory one", "memory two" and "memory three" like on a calculator.  
Line 165: Line 108:
{| class="wikitable"
{| class="wikitable"
|''M1:     Collection(House) = (1 item)''     
|''M1:     Collection(House) = (1 item)''     
|"M1" at the “Available Variables”, that is a collection of "House" and it has one item
|"M1" at the “Available Variables”, is a collection of "House" and it has one item
|}
|}
Performing a trigger on the M1:
Performing a trigger on the M1:


''action:''<blockquote>''M1''   → “Edit”</blockquote>M1 is a collection, so we want to reduce it to the first object. And then we will complete the operation. According to State Machine, it is "StartConstruction".<blockquote>''M1 → first.StartConstruction''</blockquote>Executing this now we shouldn't be able to get to the “Construction” phase, as the guard <blockquote>''“StartConstraction” [sel.Adress.notnull]''  isn't fulfilled</blockquote>At this point we need to check  
''action:''
''M1''   → “Edit”
M1 is a collection, so we want to reduce it to the first object. And then we will complete the operation. According to State Machine, it is "StartConstruction".
''M1 → first.StartConstruction''
Executing this now we shouldn't be able to get to the “Construction” phase, as the guard  
''“StartConstraction” [sel.Adress.notnull]''  isn't fulfilled
At this point, we need to check  


''action:''<blockquote>''"M1 → first.address.isnull"'' → "Execute"</blockquote><blockquote>''"M1 → first.address.notnull'' → "Execute"</blockquote>The "Address" field even if it was knowledgeable, it was not "null" performing apparently as an empty string. Which is very similar to "null", but it's not "null". So maybe we should change our "null" to be "Address".
''action:''
''"M1 → first.address.isnull"'' → "Execute"


There's an operator from C# - "IsNullOrEmpty", checking strings in condition of “null” or “empty”<blockquote>''self.Address → IsNullOrEmpty''</blockquote>In order to make sure that it isn't, we add a "not" in front of the "boolean" result<blockquote>'''''not''''' ''self.Address → IsNullOrEmpty''</blockquote>But our rule stayed the same, instead. That doesn't really help much here, because this works on the model, that we had when having started the "Debugger".  Starting everything over with "re-read the model”, it will work on the current model, so if we execute the
''"M1 → first.address.notnull'' → "Execute"
The "Address" field even if it was knowledgeable, was not "null" performing apparently as an empty string. Which is very similar to "null", but it's not "null". So maybe we should change our "null" to "Address".


''"House.allinstances"'' – we have no "houses" in the “Result List”, that's because their persistence, that we chose to use was “none” -  it remembers nothing while starting over.
There's an operator from C# - "IsNullOrEmpty", checking strings in the condition of “null” or “empty”
''self.Address → IsNullOrEmpty''
In order to make sure that it isn't, we add a "not" in front of the "boolean" result:
'''''not''''' ''self.Address → IsNullOrEmpty''
Our rule stayed the same, instead. That doesn't help much here, because this works on the model we had when we started the "Debugger". Starting everything over with "re-read the model” will work on the current model, so if we execute the ''"House.allinstances"'' – we have no "Houses" in the “Result List”, that's because of their persistence, which we chose to use, was “none” -  it remembers nothing while starting over.  


That's easily fixed by creating the "House" again
This is easily fixed by creating the "House" again


''action:''<blockquote>''House.Create''   →  “Execute”</blockquote>Now we have planned “House” to "StartConstruction". Initializing M1 selected as "House", we execute<blockquote>''M1 → first.StartConstruction''</blockquote>In case it says "Unable to find a transition for triggers "Start Construction" from state "Plan", while it should state "unable to find a valid transition". We need to ask the system if it is allowed to use a trigger?"<blockquote>''M1 → first.StartConstruction?''</blockquote>For each of these transitions there is also a check, that is denominated with the "?" behind it.
''action:''
''House.Create''   →  “Execute”
Now we have planned “House” to "StartConstruction". Initializing M1 selected as "House", we execute
''M1 → first.StartConstruction''
In case it says "Unable to find a transition for triggers "Start Construction" from state "Plan", while it should state "unable to find a valid transition". We need to ask the system if it is allowed to use a trigger.
''M1 → first.StartConstruction?''
For each of these transitions, there is also a check, that is denominated with the "?" behind it.


Here it returns an empty box, not checked, which denotes "false", so we are not allowed to walk this way in the state machine, the business rule prohibits it.
Here it returns an empty box, not checked, which denotes "false", so we are not allowed to walk this way in the state machine - the business rule prohibits it.


Another question about the ability to update or set the "Address".  As setting a value is a side effect, we need to be in the action language.  
Another question about the ability to update or set the "Address".  As setting a value is a side effect, we need to be in the action language.  
Line 187: Line 148:
How to assign a value in the action language?
How to assign a value in the action language?


Displaying the “Action Editor Execute and Debug”, there is an operator starting with a ":=" <blockquote>''M1  →    first.Address''':='''''</blockquote>For those who acknowledged with the Pascal or Delphi it will recognizable as the assignment operator ":=". Separating it from a simple "=", which is just equals. As this is assignment and we want to assign it to a "string". It should not be empty, filled with an actual address. <blockquote>''M1  →    first.Address:="youraddress"  →''  “Execute”</blockquote>This way, by executing the valid expression, we are allowed to "StartConstruction". Working on the "House" and "StartConstruction" state we immediately enter into the "Construction" outer state. As it forced to the "Start" state for the "Region1" and there is no guard on the way from the hinitial point of the inner region, it will end up in "Construction.GroundWork".<blockquote>"StartConstruction"'''→''' "Construction" outer state → "Start" state for the "Region1" → "Construction.GroundWork"</blockquote>We have learnt how to define rules and a model to work on, create data according to this model. following these rules. Thus the engine that runs this "Debugger" is the mechanism for any MDriven system in the end. Run time part of the MDriven framework for turnkey is situated on the web server. As a fat wpf client or a thin client on Android, you will have the same engine that is mainly your model. And make sure that you follow every rule that you have defined in the model.
Displaying the “Action Editor Execute and Debug”, there is an operator starting with a ":="  
''M1  →    first.Address''':='''''
For those who acknowledged using Pascal or Delphi, it will be recognizable as the assignment operator ":=". Separating it from a simple "=", which is just equals. As this is an assignment and we want to assign it to a "string", it should not be empty, filled with an actual address.  
''M1  →    first.Address:="youraddress"  →''  “Execute”
This way, by executing the valid expression, we are allowed to "StartConstruction". Working on the "House" and "StartConstruction" state, we immediately enter into the "Construction" outer state. As it is forced to the "Start" state for "Region1" and there is no guard on the way from the initial point of the inner region, it will end up in "Construction.GroundWork".
"StartConstruction"'''→''' "Construction" outer state → "Start" state for the "Region1" → "Construction.GroundWork"
We have learned how to define rules and to create a model to work on and create data according to this model following these rules. Thus the engine that runs this "Debugger" is the mechanism for any MDriven system in the end. The run time part of the MDriven framework for turnkey is situated on the web server. As a fat WPF client or a thin client on Android, you will have the same engine that is mainly your model. Make sure you follow every rule that you have defined in the model.


It brings us to the main idea that defines what the MDriven catalog of products do, compared to other uml designers. We have the engine that actually executes the model. By implementing the model, you do not need following ordinary program code. Instead, the engine will follow this in runtime and never gets wrong. Since it just follows the model exactly, you can create anything and I want to stress this! Sometimes people say that "well, you can't model everything", but that is a misconception, - you can. And you should! However, you should only model things that are important to your business. As modelling is all about doing a model of reality, not doing reality. It helps you to understand and cope with reality, not replace it. So keep that in mind that you need to have a clear goal, with what you want to achieve, in order to be able to model. Otherwise, it will be hard to know what is important for your model.
It brings us to the main idea that defines what the MDriven catalog of products does, compared to other UML designers. We have the engine that actually executes the model. By implementing the model, you do not need to follow ordinary program code. Instead, the engine will follow this in runtime and never gets it wrong. Since it follows the model exactly, you can create anything - I want to stress this! Sometimes people say that "Well, you can't model everything", but that is a misconception - you can! And you should! However, you should only model things that are important to your business. As modeling is all about creating a model of reality, not actual reality, it helps you understand and cope with reality, not replace it. Keep in mind that you need to have a clear goal of what you want to achieve in order to be able to model. Otherwise, it will be hard to know what is important for your model.


What we have shown here is that it forced to jump between the engine that executes the model and the actual model. In his way, it helps you get the model right. This Auto generated diagram also has cross-references. Thus, we have an option to find all the diagrams, where the "House" class is available.
What we have shown here is that it forced us to jump between the engine that executes the model and the actual model. In this way, it helps you get the model right. This auto-generated diagram also has cross-references. Thus, we have the option to find all the diagrams, where the "House" class is available.


For instance, we go to "Class1" finding out, that it is only available on “DiagramMyFirst". Deleting its attributes, they disappear from the repository as well. Save that, and going to the “OCLExecuteandDebug” window, we “re-read” the model and execute “allinstances”. As a result - the attributes are gone. This is a quick way to verify the ideas in your model that actually can be followed in real life.  
For instance, we go to "Class1" and find that it is only available on “DiagramMyFirst". When you delete its attributes, they disappear from the repository as well. Save and go to the “OCLExecuteandDebug” window. We “re-read” the model and execute “allinstances”. As a result, the attributes are gone. This is a quick way to verify the ideas in your model that can actually be followed in real life.  


Another simple way to execute the model is the engine will allow you variety of options. Engine that we have here is like a software developer made of software, so this software developer gets your complete uml model specification. Following it by the letter, never deviating one millimeter, doing everything exactly as you want. At this point, there is no need to hold back, while designing something complex. You can be very explicit, because there is no penalty in implementation - it is all about design. As an architect of the system, you own the model and be assured that the engine will handle whatever you can express in the model. There is no limits on giving your best shot and really expressing yourself with this tool. What is more, the engine will handle it in a matter of seconds.
Another simple way to execute the model is the realization that the engine will allow you a variety of options. The engine is like a software developer, made of software that gets your complete UML model specification, following it to the letter, never deviating one millimeter, and doing everything exactly as you want it to be. At this point, there is no need to hold back while designing something complex. You can be very explicit because there is no penalty in implementation - it is all about design. As an architect of the system, you own the model; rest assured that the engine will handle whatever you can express in the model. There are no limits to giving your best shot and really expressing yourself with this tool. What is more, the engine will handle it in a matter of seconds.


By all means, this changes the scene for software development, when it comes to standard systems. Which is really a standard model - something that anyone can do, notion, that is not interesting any longer. The most efficient way is really coming close to a specific business, thriving and reducing bottlenecks.
By all means, this changes the scene for software development when it comes to standard systems. Standard systems are standard models - something that anyone can do - a notion that is now uninteresting. The most efficient way is to come close to a specific business, thrive, and reduce the bottlenecks.


Pressing the play button brings up the "System prototype" that enables the "Debugger". Here we can see different kinds of persistence  
Pressing the play button brings up the "System prototype" that enables the "Debugger". Here we can see different kinds of persistence


'''XML''' is just to persist your data in a xml file that you choose on your hard drive. That's a simple way to keep your data ''c:\temp\mydata.xml.'' Starting system with xml persistence, we bring up a new instance of the "Debugger". In case we create
'''XML''' is just to persist your data in an XML file that you choose on your hard drive. There's a simple way to keep your data ''c:\temp\mydata.xml.'' Starting the system with XML persistence, we bring up a new instance of the "Debugger". In case we create


House" in  “OCLExecuteandDebug”<blockquote>''action:''</blockquote><blockquote>''House.Create'' →”Execute”</blockquote>We get the yellow “Save” button, as the engine has detected having not saved objects and that we are in a persisted environment. In case we select all the instances<blockquote>''House.allinstances''    →   "Execute" * 3 times</blockquote>Got three verifiable houses. So the engine is working on model and we are able to undo the actions that have been completed as well as save or cancel the edits all together. That stands for “Save”, “Undo”, “Redo” or “Cancel” options.
House" in  “OCLExecuteandDebug”<blockquote>''action:''</blockquote><blockquote>''House.Create'' →”Execute”</blockquote>We get the yellow “Save” button, as the engine has detected unsaved objects and that we are in a "persisted" environment. In case we select all the instances<blockquote>''House.allinstances''    →   "Execute" * 3 times</blockquote>We get three verifiable houses. The engine is working on the model and we are able to undo the actions that have been completed as well as save or cancel the edits altogether - that stands for the “Save”, “Undo”, “Redo” or “Cancel” options.


Setting "M1" to the first “Plan” for a new house from the resulting list, we might be allowed then to “Start Construction”. However only to the extent that the house has an actual address. <blockquote>''M1  →    first.Address'':="youraddress"  →  ''“Execute”''</blockquote>Finally, to engage the mechanism and lead it to the "Construction.GroundWork", the execution of “Start Construction” stage is necessary.  <blockquote>''M1  →  first.StartConstruction'' → “Execute” →  "Save”</blockquote>If we now make changes to the model, deleting some attributes e.g. and apply "re-read", the system will restart. Though, executing "House.allinstances" we do get data back, but it has trimmed the things from the file that doesn't exist anymore.
Setting "M1" to the first “Plan” for a new house from the resulting list, we might be allowed then to “Start Construction” - however, only to the extent that the house has an actual address. <blockquote>''M1  →    first.Address'':="youraddress"  →  ''“Execute”''</blockquote>Finally, to engage the mechanism and lead it to the "Construction.GroundWork", the execution of the “Start Construction” stage is necessary.  <blockquote>''M1  →  first.StartConstruction'' → “Execute” →  "Save”</blockquote>If we now make changes to the model, deleting some attributes e.g., and applying "re-read", the system will restart. Though by executing "House.allinstances" we do get data back, it has trimmed the things from the file that don't exist anymore.


As we deep further into this we see, that there is also a "'''''SQL'''''" option for the persistence then the configuration. That is more complex in order to define the connection string to a database. We need to be able to create the database. In case, keeping and advancing data with changing model, we would press "EvolveDatabase" to save the script, that is slightly more advanced option. The most considerable option is "MDriven Server". Once we have this running server or a turnkey site we can easily hook the "Debugger" up to that one and observe our data with the cloud.
As we dip further into this, we see that there is also an "'''''SQL'''''" option for the persistence and the configuration for that is more complex in order to define the connection string to a database. We need to be able to create the database. In any case, to keep and advance the data with changing models, we would press "EvolveDatabase" to save the script, which is a slightly more advanced option. The most considerable option is the "MDriven Server". Once we have this running server or a turnkey site, we can easily hook the "Debugger" up to it and observe our data with the cloud.


A very important piece to get further with our designs is to collect data in different views that  belongs together.
A very important piece to enable us to get further with our designs is to collect data from different views that belong together.
* ž  how should a user look at information?
* How should a user look at information?
* ž  how should it be consumed?
* How should it be consumed?
'''Let's make a short introduction of the "View model" concept.'''


Pressing the button to display "'''View Model"- editor''', we add new one called "ViewModel1". It should be rooted in the class. For example in "House" class it would make sense to be named "HouseView". As a result, the "HouseView” appears in the repository, under the "ViewModel"s node as well.  
== '''A Short Introduction to the "View Model" Concept.''' ==
Pressing the button to display the "'''View Model" Editor''', we add a new one called "ViewModel1". It should be rooted in the class. For example, in "House" class, it would make sense to name it "HouseView". As a result, the "HouseView” appears in the repository, under the "ViewModel"s node as well.  


"HouseView” has a few properties, which easily changeable with the "ViewModel"- editor. Here we define what information should be kept together for a specific use case.  Commonly we will be using the placing hints, but just to prove a point we are to remove them for now. Think of the context of the "House", as if we had a house instance and our goal is to collect the information about it.
"HouseView” has a few properties, which are easily changeable within the "ViewModel" Editor. We can define what information should be kept together for a specific use case. Usually, we would use the placing hints, but to prove a point, we will remove them for now. Think of the context of the "House", as if we had a house instance and our goal is to collect information about it.


Let’s say that the "Address" field is important <blockquote>(HouseView:House) Add column→ Address: String</blockquote>It also has navigation to “The street”, so we could add a column for “The Street.Position”<blockquote>Add column → TheStreet → TheStreet.Position: String</blockquote>These were guided additions to the "ViewModel" that really helped, as we were in the context of the "House". However the "generic column" could be added as well.  And this “New Column” doesn't have an OCL expression.
Let’s say that the "Address" field is important: <blockquote>(HouseView:House) Add column→ Address: String</blockquote>It also has navigation to “The street”, so we could add a column for “The Street.Position”<blockquote>Add column → TheStreet → TheStreet.Position: String</blockquote>These were guided additions to the "ViewModel" that really helped, as we were in the context of the "House". However the "generic column" could be added as well.  This “New Column” doesn't have an OCL expression.


For instance, in the OCL editor have the "Address" as a property<blockquote>''self.Address''   where OCL "''self''" equals to the C# “''this''”</blockquote>In the "HouseView" we will call this column "Address", eliminating the duplicated one. As well as rename “The Street.Position” to “Position”.
For instance, in the OCL editor, we have the "Address" as a property<blockquote>''self.Address''   where OCL "''self''" equals to the C# “''this''”</blockquote>In the "HouseView", we will call this column "Address", eliminating the duplicated one and renaming “The Street.Position” to “Position”.


At this point, it gets apparent that this isn't really going to cut it I want something more maybe I don't even want to "Address" on the "House" as a property, because I had the "Street". This is what happens all the time when you model, in one moment you think you got it and another - you don't.
At this point, it is apparent that this isn't going to cut it - I want something more - maybe I don't even want to have an "Address" on the "House" as a property because I have the "Street". This is what happens all the time when you model. If at one moment you think you got it, you soon realize you don't.


With the overview screen, in condition that "TheStreet" has the name instead <blockquote>''Name: String?''</blockquote>and "House" has a "StreetNumber" only that is also integer<blockquote>StreetNumber: integer</blockquote>Checking the whole model, there are a few errors, as the "DefaultStringRepresentation" for a "House" was set. This isn't valid any longer and instead, using OCL editor we should go from "''self.Address''" to "''TheStreet''" and take the “name” as the attribute.<blockquote>''self.TheStreet.Name''</blockquote>What might be a better for "DefaultStringRepresentation" in a "House"
With the overview screen in, we add a condition that "TheStreet" has the name instead <blockquote>''Name: String?''</blockquote>and "House" has a "StreetNumber" that is also an integer:<blockquote>StreetNumber: integer</blockquote>Checking the whole model, there are a few errors, as the "DefaultStringRepresentation" for a "House" was set. This is no longer valid. Instead, using the OCL editor, we should go from "''self.Address''" to "''TheStreet''" and take the “name” as the attribute.<blockquote>''self.TheStreet.Name''</blockquote>What might be better for "DefaultStringRepresentation" in a "House":
  ''self.TheStreet.Name+” “+self.StreetNumber.asstring''
  ''self.TheStreet.Name+” “+self.StreetNumber.asstring''
as "self.StreetNumber" is an integer, needs to be treaed as a string.
as "self.StreetNumber" is an integer, it needs to be treated as a string.


We still have a couple of more error "Invalid Expression in Address self.Address 5: Address is not a member of "House" in the "HouseView". Going for it, we get into the "HouseView" and have the "Address" with the same problem.  
We still have a couple more errors. "Invalid Expression in Address self.Address 5: Address is not a member of "House" in the "HouseView". We get into the "HouseView" and discover the "Address" with the same problem.  
  ''self.TheStreet.Name''
  ''self.TheStreet.Name''
We had some errors left in the guard, in the state machine, “House state transition guard Plan -> Construction 9: Address” is not a member of the “House”. Able to eliminate it with the same OCL expression editing. Instead, we do "TheStreet" that's a relation in this case and it should not be empty.<blockquote>''not self.TheStreet  →  NotEmpty''</blockquote>Here is what it means to be strongly typed that whenever you break something, you get full information on what are the side effects.
We had some errors left in the guard, in the state machine, “House state transition guard Plan -> Construction 9: Address” is not a member of the “House” to enable us to eliminate it with the same OCL expression editing. Instead, we do "TheStreet" which is a relation in this case and should not be empty.<blockquote>''not self.TheStreet  →  NotEmpty''</blockquote>This is what it means to be strongly typed. Whenever you break something, you get full information on what the side effects are.
 
Starting collecting the use cases to actually think about what the data should be used for, it's really easy to see wherever you haven't given a careful thought to your model. So this might be one use case, where you get the "Position" and the "Address". Adding "TheStreetNumber"  to the HouseView as well we can find it automatically <blockquote>Add column  → TheStreetNumber → TheStreetNumber: Integer</blockquote>You might have heard a discussion about the "ModelView" and "ViewModel" patterns and that's a good separation of concerns keeping your business rules to the model. The only section pieces of information for consuming is about certain use cases. Therefore, you can view it, as each use case should have a specific view model. That way you ensure, that you don't overexpose the information. As you expose a class, it is often a case that happens to come along with some other information, just of its convenience. At this point, you get a lot of information and possibilities, but if you have really thought about use case you have redacted the available things from the class as well as followed a few associations to other important details. 
 
Since this is so centric to building views we have that "Why is it centric?"


The data in the view needs a “ViewModel” to fulfill itss presentation. Thus theviewmodell goes hand-in-hand with a use case that for its part goes along with the view in most systems. So making this even easier, we could add the "placing hints" to "ViewModel".  
When you start collecting the use cases to think about what the data should be used for, it is easy to see where you lack careful thoughts for your model. This might be one use case, where you get the "Position" and the "Address". By adding "TheStreetNumber"  to the HouseView, we can find it automatically <blockquote>Add column  → TheStreetNumber → TheStreetNumber: Integer</blockquote>You might have had a discussion about the "ModelView" and "ViewModel" patents and that's a good separation of concerns for keeping your business rules to the model and only section pieces of information for consuming certain use cases. Therefore, you can view it as each use case should have a specific view model to ensure that you don't overexpose information as is often the case when you expose a class. At this point, you get a lot of information and possibilities, but if you have really thought about the use case, you have redacted the available things from the class and followed a few associations to other important details. 


Pointing out the "placing hints", expose the matrix that provides some metadata about each view model column. It states where it should be positioned in the grid. "Show the gridlines" option stands for displaying a little grid that demonstrates how the engine interpreting our view model and metadata for the placing hints. We can go about drawing this, making it easier to design a few more details about the UI. This isn't actually the UI that will be executed, it's just the definition of a way to collect data.
Since this is so centric to building views, we ask this question: "Why is it centric?" The data in the view needs a “ViewModel” to fulfill its presentation. Thus the ViewModel goes hand-in-hand with a use case that for its part, goes along with the view in most systems. We could add the "placing hints" to "ViewModel" to make this even easier.


Having model re-read, we select the "House"s and use “Result as root ViewModel tree” option to show me the data available according to the view. I could also have the engine construct a UI “Result as root ViewModel UI”,  based on my “ViewModel” definition and on the placing hints. This would be another way to set the value.  
Pointing out the "placing hints", expose the matrix that provides some metadata about each view model column, which states where it should be positioned in the grid. The "Show the gridlines" option displays a little grid that demonstrates how the engine interprets our view model and metadata for placing hints. We can go about drawing this, making it easy to design a few more details about the UI. This is not the actual UI that will be executed - it is just the definition of a way to collect data.


Heading way back to the "ViewModel" editor state, there's an action to construct "TheStreet". Next step will be adding a column prepared for Action
We re-read the model and select the "House"s and use the “Result as root ViewModel tree” option to show the data available according to the view. We could also have the engine construct a UI “Result as root ViewModel UI” based on the “ViewModel” definition and on the placing hints. This would be another way to set the value.


Add column è Add a column prepared for Action
Head back to the "ViewModel" editor state - there's an action to construct "TheStreet". The next step will be adding a column prepared for Action.


and now we get the action language. Using the expression for assigning the creation of a new street
Add column è. Add a column prepared for Action and now we get the action language. Using the expression for assigning the creation of a new street,
  ''self.TheStreet:=Street.Create''
  ''self.TheStreet:=Street.Create''
that way the street object would be available to write in the action called e.g. "CreateStreet".
the street object would be available to write in the action called e.g. "CreateStreet".


Now we can return to the "Debugger" and re-read the model, but first of all,  need to have the changes saved. Selecting the "House"s again → "Result as root ViewModel UI" and now I can create the street.  At this point, we will be able to set the address and the position, finally saving it. Thus, taking a look at "Street.allinstances" we see that there are two streets that we created.
We can now return to the "Debugger" and re-read the model, but first, we save the changes. Select the "House" again → "Result as root ViewModel UI" and create the street.  We will be able to set the address and the position, finally saving it. Thus, looking at "Street.allinstances", we see that we created two streets.
[[Category:MDriven Designer]]
[[Category:MDriven Designer]]
[[Category:OCL]]
[[Category:OCL]]
[[Category:OCL Editor]]
[[Category:OCL Editor]]
[[Category:View Model]]
[[Category:View Model]]
{{Edited|July|12|2024}}

Latest revision as of 15:43, 10 February 2024

We continue to introduce the MDriven Designer as a UML modeling tool that allows you to capture enough details to cover every aspect of a software system. From this series, you will discover how to work with the new OCL Debugger editor, system prototyper, and View Model editor. We will re-create the model of the "lifecycle" of a house from planning to demolition, also structure the concept of the "House" class, and make it possible to work with the user interface.

To make your experience smooth, we set the main tags mentioned in the video to the right bar menu of this mini-player. Choose an interesting subtitle on the list and immediately get to the exact theme navigation item place in the video. Now you can pick any topic to be instructed on without watching the whole video.

Additional diagram Nullable types State Machine Guards and triggers OCL Editor Methods on the class System prototyper New OCL Debugger • Introduction • Using “memory”, M1, M2, M3 • XML persistence • SQL persistence • MDriven server View Model Editor "ModelView" and "ViewModel" patterns

Textual Guidance to the Video

Continuing on the types of diagrams, we will talk about the additional one. We start working by double-clicking beside the name of the class and by choosing the actual name, we enter the edit state. This type of diagram is an automatically generated display of the class, its attributes, and its relations. Withal it serves as a navigation tool for the other existing classes - it has relations to associations. This is another way to walk around your complete model as you can observe each element in the repository and are unable to hide anything from view.

To explain the default repository graphical display, coordination works in this way: if you select the relation, you get the properties; if you choose the class, you get the properties as well. Whenever you select the class in the circle around the centre class, it will navigate to that class, and by clicking an attribute, you get its properties.

Properties should have a type, but the “?” behind it is the C# syntax to denote nullability - able to have a "null" value. In MDriven, we call this "Allow NULL". For instance, this property is "True" and it is randomized as a "String?"; if we were to change this to "False", the "?" would disappear.

The “State” attribute has the “S” icon on it. Let's go back to the "state diagram" by clicking the dialog box. Once reaching the "State diagram", on the Property Inspector dialog, we see that the "State attribute" is "State”, in the ”House.State". We are able to change its name and give the category and "ColorOnNew" states.

Depending on what dynamics you would like for your Class, you can describe them in a state machine. A state diagram for an e.g. "House" would be the "Plan" to build a "House". Evidently, "Construction" will be the next step followed by the "Maintenance" phase. Finally, in this "State Machine"  might be a "Demolition" phase. Obviously, during the "Construction" phase, there might be additional sub-states. In this case, we appear with a "Region" to the "Construction" phase. Continue with states in this Region named "GroundWork" and "Building". In this way, whenever the "House" is created, it will start with the e.g. Initial State. Since there are no “guards” stopping it from going further, it will end up in "Plan". However, we will need a "trigger" to take it forward called "StartConstruction".

Whenever we enter "Construction", charge "GroundWork” as the initial step. Whereupon, by creating a trigger "StartBulding”, we are able to go on "Building" a "House".  Creating a "ConstructionDone" trigger, we move to the next “Maintenance” step. The final “Demolish" can be triggered with the “Demolish” as well.

You can compose these state machines as simple or as complex as needed. Whether you need other acts before "Construction", or there's a domain rule that should be fulfilled, we can have these in "Guards". 

The language we will use throughout defining our model is OCL (object constraint language). In order to start “Construction”, with its help we can create "Address" for our “House”, distinct from "NULL”. OCL is beneficial because it constantly uses the language from our model and merely adds a few operators to work on the information that we have to define in the model. We can take care of our quality model and design everything according to expectations when we speak about these things. The rules become easier to read; in this case, the "Address" should not be "NULL", in order to be able to start "Construction".

Heading back to the "House" class, the triggers that we added have been added as "Methods" on the "House". This is one application mode of methods on the class, but we could just as easily add another method, that isn't a trigger, the symbol "tr" for the trigger is absent. And we could implement this by saying that it should have a “ReturnType” of type "String". Setting the parameters for the trigger:

Signature      Method1 ("param1:integer, param2:integer):String

Using the Action Editor Body, we can implement what the logic in the method should be. We refer to OCL as an "action language" because while using the methods, we are allowed side effects to be more flexible with changing data.

For instance, this method should just take:

"param1"+”param2”

It displays the “WrongExpectedType, as the "param1" and "param2" return "Int32" as an integer, although the required type as we define our method was "String". We could take the result from this and state it should be "asstring" instead.

so then we get a green light

("param1"+”param2”).asstring

Considering another case, we will instead change the “Return type” to an integer at the Properties Inspector. Checking that, we see that it’s green and this "System.Int32"  is the return type and the expected "Required return type:" "System.Int32".

What if we have typed something excessive?

"param1"+”param2x”

The response is "wrong". If we were to save this model, we see that we have an error in the:

"Method:House.Method1:7: “param2x" is not a type name

It's unrecognizable. Having fixed and saved that, we don't have any errors.

This is one way to add logic to the definition of your model. Without executing anything of this subject, just defining and assigning it. Switching back to a diagram, we can see that the trigger methods, that were created as well as "Method1" were added. This way, we demonstrate the definition, and how to navigate around designing the model.

What if we use the “Play” option to bring up a "System prototyper" dialogue?

The first step is that we should "Select persistence". "Persistence" is where data is stored.

Step1 Choosing persistence "None"

Step 2 There's no persistence configuration for this →

Step 3 is to start a system running our model, so we will press “Start System”.

Then we have a few options, implementing "New Debugger" to execute the definition that we have in the model and launching “OCLExecuteandDebug” window.

Afterward, we can't actually get to the “design surface”; however, the "Prototyper" is the model we can close it with and still have the “Debugger” available. “OCLExecuteandDebug” is operated with OCL expressions, in case, by going to "edit", we will get the same "OCL Editor" as we've seen before. For instance, we pick the class "House" and there we should find and create some "operators". There is no "create operator" in OCL, as it does not have side effects nor the ability to change data.

Another operator that's common in use in OCL is to bring up all the instances of the type "House":

House.allinstances   →   "Execute"

Here we get a result list of all the "House" class attributes, which is empty. This way we need to be able to execute some action language

"Prefix a row with ocl:, action:, oclps: (ocl:default)

  • ž   "action:"  is actually to state that the expression should be action language instead of OCL

How does the debugger work?

As long as there is an empty line between expressions, the debugger will think of it as a separated expression. So "execute" will be applied to the item that we are pointing at only.

Entering "Edit" again, we get into the “Action Editor Execute and Debug”, where "Create" is an operator:

“House.Create”

When in the Action Editor, by pressing "Ctrl+Enter", we reach a code completion type list, picking the one to quicken my typing.

In case we were to execute “House.Create” nothing much happens except, there is a new row in the "Result" set, which shows all instances. In the new "House" we see that the state is "Plan". Thus according to our "State machine", it should go to "Plan" initially.

Let's get a handle to make a "House". On the “OCLExecuteandDebug”, we see a list of "Available variables" of M1, so there's a quick way to access M1, M2, and M3. Which stands for "memory one", "memory two" and "memory three" like on a calculator.

Having marked a row and chosen "Selected to M1":

M1:     Collection(House) = (1 item)      "M1" at the “Available Variables”, is a collection of "House" and it has one item

Performing a trigger on the M1:

action:

M1   → “Edit”

M1 is a collection, so we want to reduce it to the first object. And then we will complete the operation. According to State Machine, it is "StartConstruction".

M1 → first.StartConstruction

Executing this now we shouldn't be able to get to the “Construction” phase, as the guard

“StartConstraction” [sel.Adress.notnull]  isn't fulfilled

At this point, we need to check

action:

"M1 → first.address.isnull" → "Execute"
"M1 → first.address.notnull → "Execute"

The "Address" field even if it was knowledgeable, was not "null" performing apparently as an empty string. Which is very similar to "null", but it's not "null". So maybe we should change our "null" to "Address".

There's an operator from C# - "IsNullOrEmpty", checking strings in the condition of “null” or “empty”

self.Address → IsNullOrEmpty

In order to make sure that it isn't, we add a "not" in front of the "boolean" result:

not self.Address → IsNullOrEmpty

Our rule stayed the same, instead. That doesn't help much here, because this works on the model we had when we started the "Debugger". Starting everything over with "re-read the model” will work on the current model, so if we execute the "House.allinstances" – we have no "Houses" in the “Result List”, that's because of their persistence, which we chose to use, was “none” -  it remembers nothing while starting over.

This is easily fixed by creating the "House" again

action:

House.Create   →  “Execute”

Now we have planned “House” to "StartConstruction". Initializing M1 selected as "House", we execute

M1 → first.StartConstruction

In case it says "Unable to find a transition for triggers "Start Construction" from state "Plan", while it should state "unable to find a valid transition". We need to ask the system if it is allowed to use a trigger.

M1 → first.StartConstruction?

For each of these transitions, there is also a check, that is denominated with the "?" behind it.

Here it returns an empty box, not checked, which denotes "false", so we are not allowed to walk this way in the state machine - the business rule prohibits it.

Another question about the ability to update or set the "Address".  As setting a value is a side effect, we need to be in the action language.

How to assign a value in the action language?

Displaying the “Action Editor Execute and Debug”, there is an operator starting with a ":="

M1  →    first.Address:=

For those who acknowledged using Pascal or Delphi, it will be recognizable as the assignment operator ":=". Separating it from a simple "=", which is just equals. As this is an assignment and we want to assign it to a "string", it should not be empty, filled with an actual address.

M1   →     first.Address:="youraddress"  →  “Execute”

This way, by executing the valid expression, we are allowed to "StartConstruction". Working on the "House" and "StartConstruction" state, we immediately enter into the "Construction" outer state. As it is forced to the "Start" state for "Region1" and there is no guard on the way from the initial point of the inner region, it will end up in "Construction.GroundWork".

"StartConstruction" "Construction" outer state → "Start" state for the "Region1" → "Construction.GroundWork"

We have learned how to define rules and to create a model to work on and create data according to this model following these rules. Thus the engine that runs this "Debugger" is the mechanism for any MDriven system in the end. The run time part of the MDriven framework for turnkey is situated on the web server. As a fat WPF client or a thin client on Android, you will have the same engine that is mainly your model. Make sure you follow every rule that you have defined in the model.

It brings us to the main idea that defines what the MDriven catalog of products does, compared to other UML designers. We have the engine that actually executes the model. By implementing the model, you do not need to follow ordinary program code. Instead, the engine will follow this in runtime and never gets it wrong. Since it follows the model exactly, you can create anything - I want to stress this! Sometimes people say that "Well, you can't model everything", but that is a misconception - you can! And you should! However, you should only model things that are important to your business. As modeling is all about creating a model of reality, not actual reality, it helps you understand and cope with reality, not replace it. Keep in mind that you need to have a clear goal of what you want to achieve in order to be able to model. Otherwise, it will be hard to know what is important for your model.

What we have shown here is that it forced us to jump between the engine that executes the model and the actual model. In this way, it helps you get the model right. This auto-generated diagram also has cross-references. Thus, we have the option to find all the diagrams, where the "House" class is available.

For instance, we go to "Class1" and find that it is only available on “DiagramMyFirst". When you delete its attributes, they disappear from the repository as well. Save and go to the “OCLExecuteandDebug” window. We “re-read” the model and execute “allinstances”. As a result, the attributes are gone. This is a quick way to verify the ideas in your model that can actually be followed in real life.

Another simple way to execute the model is the realization that the engine will allow you a variety of options. The engine is like a software developer, made of software that gets your complete UML model specification, following it to the letter, never deviating one millimeter, and doing everything exactly as you want it to be. At this point, there is no need to hold back while designing something complex. You can be very explicit because there is no penalty in implementation - it is all about design. As an architect of the system, you own the model; rest assured that the engine will handle whatever you can express in the model. There are no limits to giving your best shot and really expressing yourself with this tool. What is more, the engine will handle it in a matter of seconds.

By all means, this changes the scene for software development when it comes to standard systems. Standard systems are standard models - something that anyone can do - a notion that is now uninteresting. The most efficient way is to come close to a specific business, thrive, and reduce the bottlenecks.

Pressing the play button brings up the "System prototype" that enables the "Debugger". Here we can see different kinds of persistence.

XML is just to persist your data in an XML file that you choose on your hard drive. There's a simple way to keep your data c:\temp\mydata.xml. Starting the system with XML persistence, we bring up a new instance of the "Debugger". In case we create

House" in  “OCLExecuteandDebug”

action:

House.Create →”Execute”

We get the yellow “Save” button, as the engine has detected unsaved objects and that we are in a "persisted" environment. In case we select all the instances

House.allinstances    →   "Execute" * 3 times

We get three verifiable houses. The engine is working on the model and we are able to undo the actions that have been completed as well as save or cancel the edits altogether - that stands for the “Save”, “Undo”, “Redo” or “Cancel” options. Setting "M1" to the first “Plan” for a new house from the resulting list, we might be allowed then to “Start Construction” - however, only to the extent that the house has an actual address.

M1 → first.Address:="youraddress" → “Execute”

Finally, to engage the mechanism and lead it to the "Construction.GroundWork", the execution of the “Start Construction” stage is necessary. 

M1 → first.StartConstruction → “Execute” → "Save”

If we now make changes to the model, deleting some attributes e.g., and applying "re-read", the system will restart. Though by executing "House.allinstances" we do get data back, it has trimmed the things from the file that don't exist anymore.

As we dip further into this, we see that there is also an "SQL" option for the persistence and the configuration for that is more complex in order to define the connection string to a database. We need to be able to create the database. In any case, to keep and advance the data with changing models, we would press "EvolveDatabase" to save the script, which is a slightly more advanced option. The most considerable option is the "MDriven Server". Once we have this running server or a turnkey site, we can easily hook the "Debugger" up to it and observe our data with the cloud.

A very important piece to enable us to get further with our designs is to collect data from different views that belong together.

  • How should a user look at information?
  • How should it be consumed?

A Short Introduction to the "View Model" Concept.

Pressing the button to display the "View Model" Editor, we add a new one called "ViewModel1". It should be rooted in the class. For example, in "House" class, it would make sense to name it "HouseView". As a result, the "HouseView” appears in the repository, under the "ViewModel"s node as well.

"HouseView” has a few properties, which are easily changeable within the "ViewModel" Editor. We can define what information should be kept together for a specific use case. Usually, we would use the placing hints, but to prove a point, we will remove them for now. Think of the context of the "House", as if we had a house instance and our goal is to collect information about it.

Let’s say that the "Address" field is important:

(HouseView:House) Add column→ Address: String

It also has navigation to “The street”, so we could add a column for “The Street.Position”

Add column → TheStreet → TheStreet.Position: String

These were guided additions to the "ViewModel" that really helped, as we were in the context of the "House". However the "generic column" could be added as well.  This “New Column” doesn't have an OCL expression. For instance, in the OCL editor, we have the "Address" as a property

self.Address   where OCL "self" equals to the C# “this

In the "HouseView", we will call this column "Address", eliminating the duplicated one and renaming “The Street.Position” to “Position”.

At this point, it is apparent that this isn't going to cut it - I want something more - maybe I don't even want to have an "Address" on the "House" as a property because I have the "Street". This is what happens all the time when you model. If at one moment you think you got it, you soon realize you don't.

With the overview screen in, we add a condition that "TheStreet" has the name instead

Name: String?

and "House" has a "StreetNumber" that is also an integer:

StreetNumber: integer

Checking the whole model, there are a few errors, as the "DefaultStringRepresentation" for a "House" was set. This is no longer valid. Instead, using the OCL editor, we should go from "self.Address" to "TheStreet" and take the “name” as the attribute.

self.TheStreet.Name

What might be better for "DefaultStringRepresentation" in a "House":

self.TheStreet.Name+” “+self.StreetNumber.asstring

as "self.StreetNumber" is an integer, it needs to be treated as a string.

We still have a couple more errors. "Invalid Expression in Address self.Address 5: Address is not a member of "House" in the "HouseView". We get into the "HouseView" and discover the "Address" with the same problem.

self.TheStreet.Name

We had some errors left in the guard, in the state machine, “House state transition guard Plan -> Construction 9: Address” is not a member of the “House” to enable us to eliminate it with the same OCL expression editing. Instead, we do "TheStreet" which is a relation in this case and should not be empty.

not self.TheStreet → NotEmpty

This is what it means to be strongly typed. Whenever you break something, you get full information on what the side effects are. When you start collecting the use cases to think about what the data should be used for, it is easy to see where you lack careful thoughts for your model. This might be one use case, where you get the "Position" and the "Address". By adding "TheStreetNumber"  to the HouseView, we can find it automatically

Add column → TheStreetNumber → TheStreetNumber: Integer

You might have had a discussion about the "ModelView" and "ViewModel" patents and that's a good separation of concerns for keeping your business rules to the model and only section pieces of information for consuming certain use cases. Therefore, you can view it as each use case should have a specific view model to ensure that you don't overexpose information as is often the case when you expose a class. At this point, you get a lot of information and possibilities, but if you have really thought about the use case, you have redacted the available things from the class and followed a few associations to other important details. 

Since this is so centric to building views, we ask this question: "Why is it centric?" The data in the view needs a “ViewModel” to fulfill its presentation. Thus the ViewModel goes hand-in-hand with a use case that for its part, goes along with the view in most systems. We could add the "placing hints" to "ViewModel" to make this even easier.

Pointing out the "placing hints", expose the matrix that provides some metadata about each view model column, which states where it should be positioned in the grid. The "Show the gridlines" option displays a little grid that demonstrates how the engine interprets our view model and metadata for placing hints. We can go about drawing this, making it easy to design a few more details about the UI. This is not the actual UI that will be executed - it is just the definition of a way to collect data.

We re-read the model and select the "House"s and use the “Result as root ViewModel tree” option to show the data available according to the view. We could also have the engine construct a UI “Result as root ViewModel UI” based on the “ViewModel” definition and on the placing hints. This would be another way to set the value.

Head back to the "ViewModel" editor state - there's an action to construct "TheStreet". The next step will be adding a column prepared for Action.

Add column è. Add a column prepared for Action and now we get the action language. Using the expression for assigning the creation of a new street,

self.TheStreet:=Street.Create

the street object would be available to write in the action called e.g. "CreateStreet".

We can now return to the "Debugger" and re-read the model, but first, we save the changes. Select the "House" again → "Result as root ViewModel UI" and create the street.  We will be able to set the address and the position, finally saving it. Thus, looking at "Street.allinstances", we see that we created two streets.

This page was edited 101 days ago on 02/10/2024. What links here