Strongly typed thank you!
This weekend I set out for doing a Rational Rose file import plugin for Modlr. I wrote the code that successfully traversed the rather strange file format that they use. Rational Rose is a pre-xml product:
1:
2: (object Petal
3: version 47
4: _written "Rose 8.0.0303.1400"
5: charSet 0)
6:
7: (object Design "Logical View"
8: is_unit TRUE
9: is_loaded TRUE
10: quid "4B7FCC8D02EF"
11: defaults (object defaults
12: rightMargin 0.250000
13: leftMargin 0.250000
14: topMargin 0.250000
15: bottomMargin 0.500000
16: pageOverlap 0.250000
17: clipIconLabels TRUE
18: autoResize TRUE
19: snapToGrid TRUE
20: gridX 0
21: gridY 0
22: defaultFont (object Font
23: size 12
24: face "Arial"
25: bold FALSE
26: italics FALSE
27: underline FALSE
28: strike FALSE
29: color 0
30: default_color TRUE)
31: showMessageNum 3
32: showClassOfObject TRUE
33: notation "Unified")
34: root_usecase_package (object Class_Category "Use Case View"
35: quid "4B7FCC8D02F1"
So when I had all that done I thought that it would an easy and quick task to wrap that information into a model designed in eco so that I could populate it with objects from the file. Once that was done I planned to write the code that transformed from that rose model to the eco modellayer model…
But I immediately got super tired when I realized that I had to create some 30-40 classes with a lot of attributes and relations all by hand in order to hold the rational rose data from the file…
It seemed silly that I would need to do stuff by hand at all. After all we are the tool making species! So I started to think that this is a common scenario – I have a description, or data adhering to a description, in one format, and I want to have that as a model so I can code towards it with strongly typed classes ( the older (and wiser?) I get, I get increasingly more allergic to scripting ).
So if this is a common problem that at least I come across from time to time maybe I should solve that first?
I asked myself what format the data I need to handle usually come in : XML.
So to avoid losing focus of my initial problem all together I used my Rational Rose File decoder logic and made it spit out the same information as XML:
1: <?xml version="1.0" encoding="utf-8"?>
2: <root>
3: <Petal>
4: <name></name>
5: <key></key>
6: <version>47</version>
7: <_written>"Rose 8.0.0303.1400"</_written>
8: </Petal>
9: <Design>
10: <name>Logical View</name>
11: <key></key>
12: <is_unit>TRUE</is_unit>
13: <is_loaded>TRUE</is_loaded>
14: <quid>"4B7FCC8D02EF"</quid>
15: <defaults>
16: <defaults>
17: <name></name>
18: <key></key>
19: <rightMargin>0.250000</rightMargin>
20: <leftMargin>0.250000</leftMargin>
21: <topMargin>0.250000</topMargin>
22: <bottomMargin>0.500000</bottomMargin>
23: <pageOverlap>0.250000</pageOverlap>
24: <clipIconLabels>TRUE</clipIconLabels>
25: <autoResize>TRUE</autoResize>
26: <snapToGrid>TRUE</snapToGrid>
27: <gridX>0</gridX>
28: <gridY>0</gridY>
29: <defaultFont>
30: <Font>
31: <name></name>
The general idea was to write a plugin that given this XML, or a similar XML, or preferably any XML, could derive a model for me, saving me from doing stuff manually.
I know that some of you are thinking “oh boy this guy is writing a plugin in order to write a plugin in order to convert a rose file?”, and yes you are correct. But one plugin will be very generic – taking almost any XML and turning it into a modlr model.
So nothing fancy:
1: XDocument xd = XDocument.Load(file);
2: foreach (XElement xe in xd.Root.Elements())
3: {
4: Analyze(xe);
5: }
And the magic of the plugin:
1: private Eco.ModelLayer.Class Analyze(XElement xe)
2: {
3: Eco.ModelLayer.Class c = EnsureClass(GetNameFromXE(xe));
4: foreach (XAttribute xa in xe.Attributes())
5: {
6: EnsureAttribute(c, xa.Name.ToString());
7: }
8: foreach (XElement subxe in xe.Elements())
9: {
10:
11: if (subxe.FirstNode is XText || subxe.FirstNode==null)
12: {
13: // treat as model attribute
14: EnsureAttribute(c, GetNameFromXE(subxe));
15: }
16: else
17: {
18: // treat as model association
19: /*
20: We treat to types of linking:
21: single link may look like this:
22: obj1
23: attr1
24: link
25: attr1
26:
27: * multilink often looks like this:
28: obj1
29: attr1
30: link
31: obj2
32: attr1
33: */
34: if (subxe.Elements().Count() > 0 &&
(subxe.Elements().First().FirstNode is XText || subxe.Elements().First().FirstNode == null))
35: {
36: Eco.ModelLayer.Class targetclass = Analyze(subxe);
37: AssociationEnd ae = EnsureAssociation(c, targetclass, GetNameFromXE(subxe));
38: if (ae!=null)
39: ae.Multiplicity = "0..1";
40: }
41: else
42: {
43: List<Eco.ModelLayer.Class> classesfoundinrelation = new List<Eco.ModelLayer.Class>();
44: foreach (XElement xeObjectInAssoc in subxe.Elements())
45: {
46: Eco.ModelLayer.Class targetclass = Analyze(xeObjectInAssoc);
47: if (classesfoundinrelation.IndexOf(targetclass) == -1)
48: classesfoundinrelation.Add(targetclass);
49: }
50:
51: if (classesfoundinrelation.Count > 0)
52: {
53: // if classesfoundinrelation.Count>1 the association is most likely
pointing to a super class of the classes found, but we dont have enough info - pick first
54: AssociationEnd ae = EnsureAssociation(c, classesfoundinrelation[0], GetNameFromXE(subxe));
55: if (ae!=null)
56: ae.Multiplicity = "0..*";
57: }
58: }
59: }
60: }
61: return c;
62: }
63:
The logic to actually create a Class, an Attribute or a Relation looks like this:
1: private AssociationEnd EnsureAssociation(Eco.ModelLayer.Class cfrom, Eco.ModelLayer.Class cto, string xName)
2: {
3:
4: if (_esp != null)
5: {
6: var res = (from x in cfrom.AssociationEnd where x.OtherEnd != null && x.OtherEnd.Name == xName select x);
7: if (res.Count() == 0)
8: {
9: AssociationEnd ae1=new AssociationEnd(_esp);
10: AssociationEnd ae2 = new AssociationEnd(_esp);
11: Association a = new Association(_esp);
12: a.AssociationEnd.Add(ae1);
13: a.AssociationEnd.Add(ae2);
14: a.Package_ = _package;
15: ae2.Name = xName;
16: ae2.IsNavigable = true;
17: cfrom.AssociationEnd.Add(ae1);
18: cto.AssociationEnd.Add(ae2);
19: return ae2;
20: }
21: return res.First().OtherEnd;
22: }
23: return null;
24: }
25:
26: private void EnsureAttribute(Eco.ModelLayer.Class c, string xName)
27: {
28: if (_esp != null)
29: {
30: foreach (ModelElement me in c.AllFeatures)
31: {
32: if (me is Eco.ModelLayer.Attribute)
33: {
34: if (xName == (me as Eco.ModelLayer.Attribute).Name)
35: {
36: return;
37: }
38: }
39: }
40: // not found
41:
42: Eco.ModelLayer.Attribute a=new Eco.ModelLayer.Attribute(_esp);
43: a.Name = xName;
44: if (_stringDataType==null)
45: _stringDataType=(from x in _esp.GetEcoService<IExtentService>().AllInstances<Datatype>()
where x.Name.ToLower()=="string" select x).First<Datatype>();
46: a.Type = _stringDataType;
47: c.Feature.Add(a);
48:
49: }
50: }
51:
52: private Eco.ModelLayer.Class EnsureClass(string xName)
53: {
54: if (_esp != null)
55: {
56: string completename = _prefix + xName;
57: var result = (from x in _esp.GetEcoService<IExtentService>().AllInstances<Eco.ModelLayer.Class>()
58: where (x.Name == completename && x.OwningPackage == _package) select x).ToArray<Eco.ModelLayer.Class>();
59: if (result.Count() == 0)
60: {
61: Eco.ModelLayer.Class c = new Eco.ModelLayer.Class(_esp);
62: c.Name = completename;
63: c.Package_=_package;
64: return c;
65: }
66: else
67: return result[0];
68: }
69: return null;
70: }
71: }
I tried the logic on several different xml files that I found in my temp folder and found some special cases. This lead me to the conclusion that I needed at least two different strategies: one where the xml element has a generic name and the real name is given in some attribute. One example of this is the EcoMdl file format:
1: <?xml version="1.0" encoding="utf-8"?>
2: <contents>
3: <object type="Diagram" href="ClassDiagram_Diagram1">
4: <doc><![CDATA[]]></doc>
5: <modlrdiagram>diagramimages/efcd3388-264f-469f-b6e2-5e0a1dc68839.jpg</modlrdiagram>
6: <attribute name="ColorOnNew">0</attribute>
7: <attribute name="Id">efcd3388-264f-469f-b6e2-5e0a1dc68839</attribute>
8: <attribute name="SnapGridSize">15</attribute>
9: <attribute name="PresentationName">Diagram1</attribute>
10: <attribute name="ShowMethodSignatures">False</attribute>
11: <attribute name="ShowAssociationNames">DimDefaults</attribute>
12: <attribute name="ShowVisibility">False</attribute>
13: <attribute name="SquareNewAssociations">False</attribute>
14: <attribute name="SquareNewGeneralizations">False</attribute>
15: <attribute name="ShowMethodReturnTypes">False</attribute>
16: <attribute name="Name">Diagram1</attribute>
17: <link name="PlacedClass">
18: <object type="PlacedClass" href="Class1">
19: <attribute name="RenderedWidth">200,8</attribute>
20: <attribute name="id">0aac4fb8-5dd6-4082-b16b-73c07565fc57</attribute>
21: <attribute name="Color">1692800256</attribute>
22: <attribute name="Size">1</attribute>
23: <attribute name="LastKnownName">Class1</attribute>
24: <attribute name="RenderedHeight">49,25</attribute>
But the more common scenario is the format where the xml elements have specific names. Like the pad format:
1: <?xml version="1.0" encoding="UTF-8"?>
2: <XML_DIZ_INFO>
3: <MASTER_PAD_VERSION_INFO>
4: <MASTER_PAD_VERSION>3.01</MASTER_PAD_VERSION>
5: <MASTER_PAD_EDITOR>PADManager 2.0.46</MASTER_PAD_EDITOR>
6: <MASTER_PAD_INFO>Portable Application Description, or PAD for short, is a data set that is used by shareware authors to disseminate information to anyone interested in their software products. To find out more go to http://www.asp-shareware.org/pad</MASTER_PAD_INFO>
7: </MASTER_PAD_VERSION_INFO>
8: <RoboSoft>
9: <Company_UIN>CMP-009701CA593</Company_UIN>
10: <Company_Description></Company_Description>
11: <Product_UIN>APP-009701FB886</Product_UIN>
12: <Publish_on_CD>FALSE</Publish_on_CD>
13: <Search_String></Search_String>
14: <Press_Release_Search_String></Press_Release_Search_String>
15: <NewsFeed_Search_String></NewsFeed_Search_String>
16: <Search_Engine_Search_String></Search_Engine_Search_String>
17: <Web_Directories_Search_String></Web_Directories_Search_String>
18: <Search_String_Unique></Search_String_Unique>
19: <Comments_For_Reviewer></Comments_For_Reviewer>
20: <Additional_Categories></Additional_Categories>
21: <Backlink></Backlink>
22: </RoboSoft>
23: <Company_Info>
24: <Company_Name>CapableObjects.com</Company_Name>
25: <Address_1>Box 1200</Address_1>
26: <Address_2>Huddinge</Address_2>
27: <City_Town>Stockholm</City_Town>
I added a window that pops up when executing the plugin, it lets you pick the xml file, choose strategy, choose target package and GO:
And it gave me this (I dragged them onto the diagram myself)
Puh, now when I have a good starting point for the rational rose object model I can back to my original task… But that will be some other day…
(the plugin is in the demos folder for the next available eco build and it is called PluginXmlToModel)
Modlr plugins
We added a plugin interface for Gaffr and ECO. We want to enable you to extend Modlr so that you can implement a special file format import, or export, or what have you.
This is how it works:
Given these two interfaces…
1: namespace Modlr.Plugins
2: {
3: public interface IModlrPlugin
4: {
5: string GetName();
6: List<IModlrPluginMenuOperation> ProvideOperations();
7: }
8:
9: public interface IModlrPluginMenuOperation
10: {
11: string GetName();
12: void CheckEnableOrExecute(IEcoServiceProvider esp, bool execute,
IEcoObject maincontext, IEcoObject subcontext,out bool enabled );
13: }
14: }
…you can implement a plugin in an assembly like this:
1: public class Class1 : IModlrPlugin
2: {
3: #region IModlrPlugin Members
4:
5: public string GetName()
6: {
7: return "Demo plugin";
8: }
9:
10:
11: public List<IModlrPluginMenuOperation> ProvideOperations()
12: {
13: List<IModlrPluginMenuOperation> ops = new List<IModlrPluginMenuOperation>();
14: ops.Add(new OperationShowDialog());
15: ops.Add(new OperationActOnClass());
16:
17: return ops;
18: }
19:
20: #endregion
21: }
22:
The code above installs two Operations; OperationShowDialog and OperationActOnClass.
Looking closer on the operation ActOnClass:
1: public class OperationActOnClass : IModlrPluginMenuOperation
2: {
3: #region IModlrPluginMenuAction Members
4:
5: public void CheckEnableOrExecute(IEcoServiceProvider esp,
bool execute, Eco.ObjectRepresentation.IEcoObject maincontext,
Eco.ObjectRepresentation.IEcoObject subcontext, out bool enabled)
6: {
7: enabled = false;
8: if (maincontext != null && maincontext.AsIObject().AsObject is Eco.ModelLayer.Class)
9: {
10: enabled = true;
11: if (execute)
12: {
13: (maincontext.AsIObject().AsObject as Eco.ModelLayer.Class).Name += "X";
14: }
15: }
16: }
17:
18: public string GetName()
19: {
20: return "Operation on class";
21: }
22:
23: #endregion
24: }
The code checks that the context is a class, and if it is the code says that the operation should be enabled. If this was an “execute” call we perform the desired logic – in this case I just add an “X” to the back of the class name.
You can do a lot of stuff in a plugin. You get access to the IEcoServerProvider for the EcoModelLayer. The Modlr application is a standard ECO-built-application so you can use the IOCLService to get to any object, of any class that builds up your model content. You can access Diagrams, PlacedClasses, StateMachines etc. You can inspect and set TaggedValues, you can run thru every Attribute and check for spelling errors. You can create reports that you share with other ECO/Gaffr users…
So even if the interface is very small and simple, it is very powerful.
When you build your Plugin you will want to reference the following assemblies (found in the eco or gaffr install directory):
Compile your plugin and put the assembly in the folder %ProgramData%/CapableObjects/Plugins
Restart Gaffr.net or VisualStudio and you will find your plugin operations in the context menu:
Simple and powerful.
ViewModels in ASP.NET
I got a couple of questions about ViewModels in ASP.NET; and my conscience has stirred me to action. I was aiming to finish the immensely cool project that we call GaffrServer and I want to use the ASP.NET viewmodels to make that happen.
Side note on what GaffrServer is: Imagine that you prototype in Gaffr.net using the upcoming Application WPF framework WECPOF (oh I just love inventing code names for our projects: WECPOF - ECO + WPF – get it?), and you want persistence. You can write to a XML file, or set up a database… But you will also be able to connect to GaffrServer – GaffrServer is cloud service that you upload your model to, then you get back an url that is the up and running server side persistence mapper with the synchronization service running – WOW! I WANT IT NOW.
Anyway the GaffrServer project is sort of dragging its feet so I am better of just showing ASP.NET ViewModels.
I wrapped up a sample that looks like this:
Notice the derived attributes on OrderItem and Order:
1: CostForRow = (self.Quantity*self.Article.Cost)+(self.Quantity*self.Article.Weight*self.Order.DeliveryType.CostPerKiloGram)
2:
3: TotalCost = self.OrderItem->Collect(a|a.CostForRow)->sum()
(Note that the TotalCost actually use the derivation in CostForRow – super cool imho)
Then I did a ViewModel:
I know some of you might initially frown at the complexity, but trust me, you just click away and use the suggested columns that are available on the context menu – I seldom have a specific plan when I start – I think and do at the same time. That is the hallmark of a tool that is helping you…
The basic idea was to fill in an order, add OrderLines, set the correct Article on the OrderLine, see the price per row, and the total price, taking into account what delivery type you use…
There you go, a neat little list of requirements so easily said – and easily implemented.
I created a ECO ASP.NET application from the ECO Solution Wizard, Added the scriptmanager and an UpdatePanel to get Ajax behavior.
Then I add the ViewModelASPNET component, hook it up to the EcoSpaceManager, and tell it to use ViewModel ViewModelOrder:
I need to write some code to get test data and to hook up the ViewModelASPNET control to an order:
1: private void Page_Load(object sender, System.EventArgs e)
2: {
3:
4: if (!Page.IsPostBack)
5: {
6: Order order;
7: if (EcoSpace.GetEcoService<IExtentService>().AllInstances<Order>().Count == 0)
8: {
9: order = InitSomeTestData();
10: }
11: else
12: order = EcoSpace.GetEcoService<IExtentService>().AllInstances<Order>()[0];
13: ViewModelASPNET1.SetObject(order);
14: }
15: }
16:
17: private Order InitSomeTestData()
18: {
19: Order order=new Order(EcoSpace);
20: order.CustomerName = "SomeName";
21: order.CustomerAddress = "SomeAddress";
22: order.DeliveryType = new DeliveryType(EcoSpace) { Name = "UPS", CostPerKiloGram = 20.5 };
23: new DeliveryType(EcoSpace) { Name = "Schenker", CostPerKiloGram = 19.5 };
24: new DeliveryType(EcoSpace) { Name = "DHL", CostPerKiloGram = 29.5 };
25:
26: new Article(EcoSpace) { Name = "Knife", Cost=127.5, Weight=0.25 };
27: new Article(EcoSpace) { Name = "Vobbler", Cost = 17.1, Weight = 0.15 };
28: new Article(EcoSpace) { Name = "Fishing rod", Cost = 527.5, Weight = 1.05 };
29:
30: EcoSpace.UpdateDatabase();
31: return order;
32:
33: }
I also must init the viewmodels before they are used:
1: protected void ScriptManager1_Init(object sender, EventArgs e)
2: {
3: ViewDefinitionsInApplication.Init(EcoSpace);
4:
5: }
Then I get something that looks like this:
Notice the crazy style on CostForRow, the style on TotalCost and on Selected orderitem – I get these by providing a css stylesheet that has styles using the names I set in the ViewModelColumns StyleRef property…
As you change deliverytype or anything else the TotalCost will be updated on the next postback.
In this demo I chose to use the setting ViewModelASPNET.PostbackOnComboboxChange="true"
I also chose to use the setting ViewModelASPNET.GridSizeFixedWithScrollbar="True"
The bits to run this is in the eco build after this date, it is in the demos called EcoASPNETWithViewModel
UML may suck, but is there anything better?
UML has been getting a lot of criticism from all sides, even from the modeling community. Sure, it has its warts:
- it is a huge language, that wants to be all things to all kinds of people (business analysts, designers, developers, users)
- it has a specification that is lengthy, hard to navigate and often vague, incomplete or inconsistent
- it is modular, but its composition mechanism (package merging) is esoteric and not well understood by most
- it is extensible, but language extensions (profiles and stereotypes) are 2nd-class citizens
- it lacks a reference implementation
- its model interchange specification is so vague that often two valid implementations won’t work with each other
- its committees work behind closed doors, there is no opportunity for non-members to provide feedback on specifications while they are in progress (membership is paid)
- <add your own grudges here>
However, even though I see a lot of room for improvement, I still don’t think there is anything better out there. The more I become familiar with the UML specification, the more impressed I am about its completeness, and how issues I had never thought about before were dealt with by its designers. And it seems that the OMG recognizes some of the issues I raised above as shortcomings and is working towards addressing them. Unfortunately, some fundamental problems are likely to remain.
In my opinion (hey, this is my blog!), for a modeling language to beat UML:
- it must be general purpose, not tailored to a specific architecture or style of software
- it must not be tailored to an implementation language
- it must be based on or compatible with the object paradigm
- it must not be limited to one of the dominant aspects of software (state, structure, behavior)
- it must be focused on executability/code generation (and thus suitable for MDD) as opposed to documentation/communication
- it must be modular, and user extensions should be 1st class citizens
- its specification should follow an open process
- it must not be owned/controlled by a single company
- it must not require royalties for adoption/implementation
My suspicion is that the next modeling language that will beat the UML as we know today is the future major release of UML. Honestly, I would rather see a new modeling language built from scratch, focused on building systems, that didn’t carry all that requirement/communication/documentation-oriented crap^H^H^H^Hbaggage that UML has (yes, I am talking about you, use case, sequence, instance and collaboration diagrams!), and developed in a more open and agile process than the OMG can possibly do. But I am not hopeful. The current divide between general purpose and domain specific modeling communities is not helping either.
So, what is your opinion? Do you think there are any better alternatives that address the shortcomings of UML without imposing any significant caveats of their own? Have your say.
Myths that give model-driven development a bad name
It seems that people that resist the idea of model-driven development (MDD) do so because they believe no tool can have the level of insight a programmer can. They are totally right about that last part. But that is far from being the point of MDD anyways. However, I think that unfortunate misconception is one of the main reasons MDD hasn’t caught on yet. Because of that, I thought it would be productive to explore this and other myths that give MDD a bad name.
Model-driven development myths
Model-driven development makes programmers redundant. MDD helps with the boring, repetitive work, leaving more time for programmers to focus on the intellectually challenging aspects. Programmers are still needed to model a solution, albeit using a more appropriate level of abstraction. And programmers are still needed to encode implementation strategies in the form of reusable code generation templates or model-driven runtime engines.
Model-driven development enables business analysts to develop software (a variation of the previous myth). The realm of business analysts is the problem space. They usually don’t have the skills required to devise a solution in software. Tools cannot bridge that gap. Unless the mapping between the problem space and solution space is really trivial (but then you wouldn’t want to do that kind of trivial job anyways, right?).
Model-driven development generates an initial version of the code that can be manually maintained from there on. That is not model-driven, it is model-started at most. Most of the benefits of MDD are missed unless models truly drive development.
Model-driven development involves round-trip engineering. In MDD, models are king, 3GL source code is object code, models are the source. The nice abstractions from the model-level map to several different implementation artifacts that capture some specific aspect of the original abstraction, combined with implementation-related aspects. That mapping is not without loss of information, so it is usually not reversible in a practical way, even less so if the codebase is manually maintained (and thus inherently inconsistent/ill-formed). More on this in this older post, pay attention to the comments as well.
Model-driven development is an all or nothing proposition. You use MDD where it is beneficial, combining with manually developed artifacts and components where appropriate. But avoid mixing manual written code with automatically generated code in the same artifact.
What is your opinion? Do you agree these are myths? Any other myths about MDD that give it a bad name that you have seen being thrown around?
Rafael
Interview at Modeling-Languages.com
Last December I had the pleasure of being interviewed by Jordi Cabot, the maintainer of Modeling-Languages.com, a web site on all things moden-driven. We talked mostly about the TextUML Toolkit project, but Jordi also asked about my opinions on more general subjects, such as modeling notations, textual modeling frameworks, DSLs, UML and trends in modeling.
Jordi has recently made a transcription of the interview available on his web site. Take a read, feel free to leave a comment, I am very keen on discussing on any of the topics covered.
Using Blend with ECO
Blend is the XAML-high-level tool. It is very powerful if you know what you are doing. Having that special designer eye that helps you to stop messing with something when it is done is probably a very useful skill when working with Blend – I do not have it, yet. But still here is my 5 minutes crash course into Microsoft Blend for ECO developers.
First: Blend is all about UI. Nothing about data. You can bind the UI to a datasource, but you cannot do anything else useful with the datasource in Blend – just use it.
Second: XAML is all about binding – in that sense it is very declarative. You do not do any imperative coding in Blend (ideally). Instead you declare rules that makes things happen for you; i.e. you declare bindings and animations.
I continued on the WPF-Hockey sample I wrote about earlier. To do anything cool in Blend you need to have an idea on what you want (that statement is sort of generic) – if that idea includes data then ECO is your best friend.
I find it useful to declare the processes in ECO, it helps me to keep my objectives clear and focused:
The SetUpGame thing I did in the previous post. Now I am going to do the “Show teams and players”.
I added LineUp and Player to the model:
And a view model that supports this model:
That was the easy part. The above steps are done quickly with Enterprise core objects. Good! More time left to spend in Blend (and boy will you need it!).
Start up Blend (I use Microsoft Expression Blend 3). File, Open, Project/Solution:
You can add UserControls just as you would have done in Visual studio:
So I did a user control looking like a hockey rink (took me forever!) ; that will come in handy. Doing stuff like this in Blend is just as complicated as in any other competent drawing tool (Photoshop or what have you). But Blend has an advantage with the split xaml view. You can fine tune stuff just by changing the xaml.
I then create a new WPF-Window and add my user control:
I add some comboboxes to show the lineups for each team. I also add some textblocks to show the players for each LineUp. I also add two images up on the ice, to show the team images. All of these controls should show data. So I need to bind…
1: //This is how I bind the Image to my ViewModel
2: <Image x:Name="imageHome" Margin="153,111,224.54,0"
3: Source="{Binding Path=Class[GameDay]/Home_Image,Mode=OneWay,Converter={StaticResource ImageBlobConverter} }"
4: Stretch="Fill" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top" Height="107">
5:
6: //This is how I bind one of the textblocks
7: <TextBlock x:Name="textBlock"
8: HorizontalAlignment="Left" VerticalAlignment="Bottom"
9: Text="{Binding Path=Class[LineUp]/CenterForward_Name}"
10: TextWrapping="Wrap" Margin="76.088,0,0,88.08" RenderTransformOrigin="0.515,0.055" Style="{DynamicResource playerstyle}">
11:
12: // And the comboboxes
13: <ComboBox DisplayMemberPath="Name"
14: IsSynchronizedWithCurrentItem="True"
15: ItemsSource="{Binding Path=Class[LineUp]}"
16: Height="23" Margin="225,0,140,110" Name="comboBox1" VerticalAlignment="Bottom" />
Ok, now I have said what I want to bind to, that is not enough, I need to get the data there as well.
1: // Add a ViewModelContent component to the resource section, tell it what your ViewModel is called, and what type your EcoSpace has:
2: <Window.Resources>
3: <ecoVM:ViewModelContent x:Key="VM1" ViewModelName="GameDay" EcoSpaceType="{x:Type ecospace:HockeyContEcoSpace}" ></ecoVM:ViewModelContent>
I now switch back to Visual Studio to actually put a “Game” into the GameDay ViewModel:
1: {
2: public WindowGameDay()
3: {
4: this.InitializeComponent();
5:
6: // Insert code required on object creation below this point.
7: }
8:
9: private EcoSpace _es;
10: internal void SetEcoSpace(EcoSpace es, Game aGame)
11: {
12: _es = es;
13: (Resources["VM1"] as Eco.ViewModel.WPF.ViewModelContent).SetEcoSpace(_es);
14: (Resources["VM1"] as Eco.ViewModel.WPF.ViewModelContent).RootObject = aGame;
15: (Resources["VM1"] as Eco.ViewModel.WPF.ViewModelContent).GetCollectionView("LineUp").MoveCurrentToFirst();
16: (Resources["VM1"] as Eco.ViewModel.WPF.ViewModelContent).GetCollectionView("LineUpVisitor").MoveCurrentToFirst();
17: LayoutRoot.DataContext = Resources["VM1"];
18:
19: }
Notice that I expect to be handed a EcoSpace and a Game for this window to display. Also I use the method GetCollectionView of the ViewModel so that I can position the LineUp combos to show the first line up when we start.
TestRun:
Ok. Now to Animations. This is how animations work: They change a value over time, from an initial value to a desired value. Animations can be grouped together into a Storyboard.
Switching back to Blend. Go to menu Window, Workspaces, Animation:
Now your Blend workspace switch and you will see this pane at the bottom of your screen:
Use the plus sign (I marked it with red) to add a new storyboard.
PAY ATTENTION TO THE LITTLE DOT MARKED WITH GREEN!!!! When this is red – recording is on, click it to turn off recording (it toggles, so you can start and stop).
When Recording is on: WHEN YOU MOVE AROUND CONTROLS, THE NEW POSITION IS THE DESIRED POSITION FOR THE TIME INDICATED BY THE YELLOW MARKER.
Animation will make a linear move from start to goal over time (you can control this if linear is not what you want).
So this is how you go about animating the Image Opacity from 100% to 0% in 3 seconds:
- Turn recording on
- Move the Yellow time line to zero
- Set Image Opacity to 100% (you use the standard panes to set the values)
- Move the yellow line to 3
- Set Image Opacity to 0%
- Turn Animation off.
You repeat this process for all the stuff you want to move around. This is a very powerful tool and you have every chance to destroy all the work you have done so far – but it is sort of fun.
The sample now animates the Players for the selection LineUp up onto the Ice, while the team images fade out and disappear:
And when you change the Line up, the names change no matter what the current position of the animation is.
I was about to create a video to show the animation, but I went for a ClickOnce install instead:
http://www.capableobjects.com/publishedsamples/Hockey/publish.htm
Define a valid Game, then click Start…
Doing away with custom UML metaclasses in TextUML
The TextUML Toolkit has since release 1.2 had a metamodel extension package (inaptly named ‘meta’). This metamodel extension package defined new metaclasses not available in UML such as:
- closure - an activity that has another activity as context
- conversion action - an action that flows an input directly as output just changing the type
- literal double - a literal value for double precision numeric values
- signature - a classifier that contained parameters, the type of a closure
- meta value specification - a value specification for meta references
- collection literals - a value specification that aggregates other value specifications
Turns out extending the UML metamodel by definining new packages and metaclasses is a bad idea. Some reasons (yes, I am feeling ‘bullety’):
- it is non-standard
- other UML tools cannot read instances of your metaclasses, some won’t read your models at all if they have *any* unknown metaclasses
- there is little documentation on how to maintain these kinds of metamodel extensions
- since it is not the mainstream approach, we are bound to encounter more issues
Because of that, release 1.6 will rely exclusively on profiles and stereotypes for extending the UML metamodel.
What to expect
For conventional users of the Toolkit, this change might possibly go unnoticed, barring any potential bugs introduced in the process.
People using the built-in base package and the base_profile will be directly affected. The elements in these models are still provided, by they are now in the new mdd_extensions profile, or one of the new mdd_types, mdd_collections and mdd_console packages.
We apologize for any inconvenience these changes might bring, but we strongly believe they are required to make the TextUML Toolkit a better product. If you have any trouble moving to 1.6 (to be released later this month), make sure to hit the user forums or report issues.
The ViewModel
In large applications with large models the UI will soon get filled with business logic that does not belong there. The logic is left there but the developer is someday going to return and clean it all up (Sure!).
Every developer knows that the degrees of freedom rapidly decrease once you fill your UI with business logic:
- You cannot easily reuse the logic placed in a UI so you copy it and increase the maintenance (BAD!)
- You forget about rules placed in UI so your system gets a life of its own (BAD!)
- Once you have logic in the UI you cannot be expected to know it all so you get afraid to make changes to your system because something will or may break (BAD!)
- You dare not give the UI to that brilliant designer because the designer will break logic for sure (BAD!)
Still I see business logic in the UI everywhere I go. When I ask about it I always get answers like: “Well this is not finished yet”, or “Well this is really special stuff, only used in one place”, or “Yea I know it sucks, I will fix that later”. But “Later” never comes, does it? It will always be just “Later”.
I am no superman for sure. I see business logic in UI I have written myself too.
If everyone or at least most of us is getting into these situations could it be that we are doing things the wrong way? Could it be that doing things the right way is just a tad bit too complicated?
These are some strategies to make developers do the correct thing and actually follow the coding guidelines:
- Automated review tools like FXCop
- Peer review (that usually will be done “later”)
- Some other strategy that will force violators (you and me) to mend our ways – even if the correct way is really complicated (maniac team leader with rabies foam in the face)
- Make it easier and faster to follow the “coding guidelines” then to be quick and dirty.
To no surprise I am in favor of making things easier. But to be able to make things easier we need to understand what cause things to go wrong in the first place: Why is the UI filling up with business logic? I think there are a couple of reasons, depending on how far you are from being model driven some of these reasons will apply:
- The UI will need to transform data (could be business logic) in order to display it according to specification.
- Actions performed in UI act on selections from UI-components, that has data in the transformed presentation format, and need to be transformed back (could be business logic) to model-scope in order to let the model work on the data (business logic). And you also need to check that the parameters sent to the model method are valid (could be business logic).
- The existing business logic may not match 100% what your action should do, you may want to call two, three of more methods to get the job done (new business logic) and you want to do some small checks based on the results of each method (could be business logic).
- Validation – your UI will do a lot of small checks to see that the data fulfills the overall rules for your application (business logic)
How do we make these reasons go away?
- We do it by offering a good and easy way to transform model-elements (or data if you will) into data elements suitable for render to match the specification.
- We do it by making it real easy to add business logic where it belongs (in the model), and make it easy to call it.
- And we offer a clean and easy way to add validation logic.
By setting the model in focus, and making it dirt simple to add methods, derived attributes and derived associations you can do everything you need for a specific UI in the model. This is sort of a good thing . The problem is that if you have a 100 UI’s your model will get filled with 100 times x derived attributes and derived links. And that does not sound like a good thing to me. It will eventually get hard to see the trees for the forest in a model like that.
And further more when a UI is dropped and deleted for some reason, will we remember to drop the derived associations and derived attributes we added to the model to accommodate it? Probably not.
A transformation layer between the UI and the Model can fix this. The transformation layer is allowed to have business logic, as long as it is unique for the context it works on. If the logic is not unique, it should go in the model ready to be re-used. We call this transformation Layer for a ViewModel.
A ViewModel transforms a piece of the model for a specific purpose. The purpose is often, but not always, to prepare the model information for interaction with a user for a specific use case – a UI. I said often but not always; it can also be for creating data transfer objects that are suitable for exposure for another application or system, or for some reporting engine or the like.
Why is it having the rules in a ViewModel is much better than having them in the UI? There are a lot of reasons:
- Testing; it is a good thing to be able to test the logic separated from the UI, because it is awkward and error prone to test and read the results back from the UI.
- ViewModel re-use ; you may have different UI’s for the exact same use case (beginner/advanced, Web-api/Rich client etc).
- Design time type checking; most UI-binding strategies rely on using strings that can only be checked at runtime (true for winforms, WPF, Silverlight and ASP.NET), whereas a good ViewModel is type checked at design or compile time.
- The designer working on the UI can harm important logic if the logic is in the UI.
- If we have dedicated designers we will not want to wait for them to release a UI file in order to fix business logic within.
- The UI may be on the other side of a network (another physical tier) so the UI cannot have access to the domain layer tier
- UI and logic have very different motivators and hence will often change for different reasons (looking good versus working correctly), mixing them up add confusion regarding the distinction between these important aspects.
- Security, designer that get access to the ViewModel cannot go beyond the ViewModel and unintentionally expose information that should not get exposed in the use case at hand.
The thing is that you do not have to use a ViewModel pattern to create a great application, it is just that is a good idea to use the ViewModel pattern when building applications that are going to be worked on for a long time, released in several versions over several iterations, and will most likely see different developers and UI-designer, and may very well be radically changed with regards to presentation framework during its lifespan. In short – it is always a good idea for successful applications to use a ViewModel pattern.
The declarative ViewModelPresented with a model that I got from Rick Weyrauch, that incidentally helps out as a Hockey Referee when he is not coding, I wanted to create a ViewModel for the use-case “Set up new Hockey game”.
The Game class has a state machine:
I took a piece of paper and draw the UI I wanted to achieve:
Now I know what the requirements are on the ViewModel since I can see from the drawing what data the ViewModel needs to hold.
And then created this ViewModel That I named GameSetup:
Notice that it is just a series of named ocl expressions. Some expressions are nested to other list definitions like Home_PickList that states that if the Game has a picked GameType, then we know what teams that can be picked – namely those teams that are associated to that GameType
I created some test data so that UI can show something:
1: private Game CreateSomeTestData()
2: {
3: // Game types
4: var gtboys15 = new GameType(_es) { Name = "15 years, Boys" };
5: var gtboys16 = new GameType(_es) { Name = "16 years, Boys" };
6: var gtgirls15 = new GameType(_es) { Name = "15 years, Girls" };
7:
8: // team types
9: var ttb15=new TeamType(_es) { Name = "Boys 15 years" };
10: var ttb16 = new TeamType(_es) { Name = "Boys 16 years" };
11: var ttg15 = new TeamType(_es) { Name = "Girls 15 years" };
12:
13: // Valid team-game combinations
14: gtgirls15.TeamTypes.Add(ttg15);
15:
16: gtboys15.TeamTypes.Add(ttb15);
17: gtboys15.TeamTypes.Add(ttg15); // girls can play in boys 15 year
18: gtboys16.TeamTypes.Add(ttb15); // 15 year boys can enter 16 year games
19: gtboys16.TeamTypes.Add(ttb16);
20: gtboys16.TeamTypes.Add(ttg15); // girls can play in boys 16 year
21:
22:
23:
24: new Team(_es) { Name = "Brynäs",Image=GetImage(imagebrynäs), TeamType=ttb15 };
25: new Team(_es) { Name = "Brynäs", Image = GetImage(imagebrynäs), TeamType = ttb16 };
26: new Team(_es) { Name = "Brynäs", Image = GetImage(imagebrynäs), TeamType = ttg15 };
27:
28: new Team(_es) { Name = "LuleĂĄ", Image = GetImage(imageluleĂĄ), TeamType = ttb15 };
29: new Team(_es) { Name = "LuleĂĄ", Image = GetImage(imageluleĂĄ), TeamType = ttb16 };
30: new Team(_es) { Name = "LuleĂĄ", Image = GetImage(imageluleĂĄ), TeamType = ttg15 };
31:
32: new Team(_es) { Name = "DjurgĂĄrden", Image = GetImage(imagedjurgĂĄrden), TeamType = ttb15 };
33: new Team(_es) { Name = "DjurgĂĄrden", Image = GetImage(imagedjurgĂĄrden), TeamType = ttb16 };
34: new Team(_es) { Name = "DjurgĂĄrden", Image = GetImage(imagedjurgĂĄrden), TeamType = ttg15 };
35:
36: return new Game(_es)
37: {
38: ScheduledDate = DateTime.Now
39: };
40:
41: }
Now I am ready to build the UI.
1: <Window x:Class="WPFBinding.Window2"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:eco="clr-namespace:Eco.WPF;assembly=Eco.WPF"
5: xmlns:ecoVM="clr-namespace:Eco.ViewModel.WPF;assembly=Eco.WPF"
6: xmlns:Controls="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
7: xmlns:local="clr-namespace:WPFBinding"
8: xmlns:ecospace="clr-namespace:WPFBinding;assembly=WPFBinding.EcoSpace"
9: Title="Window2" Height="300" Width="500" >
10: <Window.Resources>
11: <ecoVM:ViewModelContent x:Key="VM1" ViewModelName="GameSetup" EcoSpaceType="{x:Type ecospace:WPFBindingEcoSpace}" ></ecoVM:ViewModelContent>
12: <local:ImageBlobConverter x:Key="ImageBlobConverter"/>
13: </Window.Resources>
14: <Grid>
15: <Grid Name="vmrootStackPanel" DataContext="{StaticResource VM1}">
16: <Grid.ColumnDefinitions>
17: <ColumnDefinition></ColumnDefinition>
18: <ColumnDefinition></ColumnDefinition>
19: <ColumnDefinition Width="50"></ColumnDefinition>
20: </Grid.ColumnDefinitions>
21: <Grid.RowDefinitions>
22: <RowDefinition></RowDefinition>
23: <RowDefinition></RowDefinition>
24: <RowDefinition></RowDefinition>
25: <RowDefinition></RowDefinition>
26: <RowDefinition></RowDefinition>
27: <RowDefinition></RowDefinition>
28: <RowDefinition></RowDefinition>
29: <RowDefinition></RowDefinition>
30: </Grid.RowDefinitions>
31:
32: <TextBlock Grid.Row="0" Grid.Column="0" Text="GAME : " HorizontalAlignment="Right" ></TextBlock>
33: <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=Class[GameSetup]/Presentation,Mode=OneWay}"></TextBox>
34:
35: <TextBlock Grid.Row="1" Grid.Column="0" Text="Type of game : " HorizontalAlignment="Right" ></TextBlock>
36: <ComboBox Grid.Row="1" Grid.Column="1" DisplayMemberPath="Name" ItemsSource="{Binding Path=Class[GameType_PickListPresentation]}" SelectedValuePath="self" SelectedValue="{Binding Path=Class[GameSetup]/GameType}" ></ComboBox>
37:
38: <TextBlock Grid.Row="2" Grid.Column="0" Text="Home team : " HorizontalAlignment="Right" ></TextBlock>
39: <ComboBox Grid.Row="2" Grid.Column="1" DisplayMemberPath="Name" ItemsSource="{Binding Path=Class[Home_PickListPresentation]}" SelectedValuePath="self" SelectedValue="{Binding Path=Class[GameSetup]/Home}"></ComboBox>
40: <Image Grid.Row="2" Grid.Column="2" Source="{Binding Path=Class[GameSetup]/Home_Image,Mode=OneWay,Converter={StaticResource ImageBlobConverter} }"></Image>
41:
42:
43: <TextBlock Grid.Row="3" Grid.Column="0" Text="Visitor team : " HorizontalAlignment="Right" ></TextBlock>
44: <ComboBox Grid.Row="3" Grid.Column="1" DisplayMemberPath="Name" ItemsSource="{Binding Path=Class[Visitor_PickListPresentation]}" SelectedValuePath="self" SelectedValue="{Binding Path=Class[GameSetup]/Visitor}"></ComboBox>
45: <Image Grid.Row="3" Grid.Column="2" Source="{Binding Path=Class[GameSetup]/Visitor_Image,Mode=OneWay,Converter={StaticResource ImageBlobConverter} }"></Image>
46:
47: <TextBlock Grid.Row="4" Grid.Column="0" Text="Scheduled date : " HorizontalAlignment="Right" ></TextBlock>
48: <Controls:DatePicker Grid.Row="4" Grid.Column="1" ></Controls:DatePicker>
49:
50: <Button Grid.Row="5" Grid.Column="0" IsEnabled="{Binding Path=Class[GameSetup]/CanStartGame}" Click="ButtonStartGame_Click">
51: <TextBlock Text="Start Game"></TextBlock>
52: </Button>
53:
54: <Button Grid.Row="5" Grid.Column="1" IsEnabled="{Binding Path=Class[GameSetup]/CanEndGame}" >
55: <TextBlock Text="End Game" ></TextBlock>
56: </Button>
57:
58: </Grid>
59: <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
60: <Image Height="50" Name="imagebrynäs" Stretch="Fill" Width="50" Source="/WPFBinding;component/brynäs.jpg" />
61: <Image Height="50" Name="imagedjurgĂĄrden" Stretch="Fill" Width="50" Source="/WPFBinding;component/djurgĂĄrden.jpg" />
62: <Image Height="50" Name="imageluleĂĄ" Stretch="Fill" Width="50" Source="/WPFBinding;component/LuleĂĄ.jpg" />
63: </StackPanel>
64: </Grid>
65: </Window>
What happens in the xaml above is that we have a ViewModelContent component in the resource section. We initiate it to the name of the ViewModel, and we also provide the Type of the ecospace.
The ViewModelContent object, now keyed as VM1, is put in the DataContext of the Grid where I place the UI components. If a WPF Binding does not get an explicit source it will use whatever it finds in the DataContext (the datacontext is propagated down the logical tree, so for us it is everywhere).
In code behind we hook up the EcoSpace and the rootobject-property (dependencyproperty so that you bind as target and as source) to our demo Game object:
1: (Resources["VM1"] as Eco.ViewModel.WPF.ViewModelContent).SetEcoSpace(_es);
2:
3: (Resources["VM1"] as Eco.ViewModel.WPF.ViewModelContent).RootObject=CreateSomeTestData();
The UI looks like this:
Yes it looks bad; but hey, you can hand it to any WPF savvy designer in the world – the data and the rules are safe in the ViewModel.
It already shows some of the good effects of separating UI from logic. If you run the sample you will see and hopefully appreciate that:
- The PickLists for Home and Visitor are filtered based on Type of Game
- The Picklist for Home team filters away the Visitor team if set (and vice versa)
- Start game is enabled only after both home and visitor are set
- The End game button is disabled until the Game is started
These are some examples of business logic that would have easily ended up in the UI if we did not have a good place to define it.
Taking it further stillIf the cost of creating and maintaining a ViewModel is high fewer ViewModels will be created. So our mission is to reduce the cost of creating and maintaining them. Can we do more? I will argue that we can.
WPF is a declarative way to describe the UI. This mean that the same basic lookless components like TextBlock, TextBox, CheckBox, Combobox and Image etc will be used again and again and they will be given a look by an external style or template.
What if we use this fact and provide some basic rendering/placing hints for the ViewModel columns? We could then use those clues to spill out the correct lookless control in the intended relative position so we would not need to mess about with xaml every 5 minutes… I am excited… Xaml is a bit too scripty for my old strongly typed ways…
This is what the ViewModel-Editor looks like without rendering hints:
And this is the way it looks when I have checked the “Use Placing Hints” checkbox:
Given the extra fields for “Presentation”, “Column”,”Row”,”Span” etc I can work the ViewModel - preview to look like this:
Now I really need to stress this so that I do not get misunderstood: We do not mix presentation with UI, we do however allow for adding optional placing hints or clues on what you have in mind while designing the ViewModel.
Having a ViewModel with placing hints, you can add a ViewModelWPFUserControl to your form with just one row:
1: <ecoVM:ViewModelWPFUserControl Grid.Row="2" x:Name="VMU1" EcoSpaceType="{x:Type ecospace:WPFBindingEcoSpace}" ViewModelName="GameSetup" ></ecoVM:ViewModelWPFUserControl>
And the result is:
And remember that these auto layouted controls also adheres to external set styles. (Notice the datetime picker is gone? Datetime picker is in WPFToolkit so we do not use it by default. Implement ViewModelWPFUserControl.OnColumnUIOverride to add your own components to its layout engine.)
Summing it upThis has been a brief overview of the ViewModel concept. Things intentionally left out for now was Actions, Validation-rules, Variables, Master-detail (since there were no details in the sample ), Style references and Tab order.
I have written about the benefits of having a ViewModel in the first place. Then I wrote about the Modlr approach with a strictly declarative ViewModel. We looked at the sample using such a ViewModel and some of the effects it gave in separating logic from UI. Then I showed you a ViewModel with placing hints – a bit un-orthodox for sure, but efficient and easy to maintain.
Thanks goes out to everyone that has been involved in the Modlr ViewModel approach by giving feedback, and to Rick for providing the sample model – Hope I did not abuse it.
Knowing nothing, where to begin
When you are dropped by parachute deep behind enemy lines with nothing but your analytical skills – where do you start? Ok, I probably should not compare the client and their business with hostile territory filled with enemies. Sorry! But still! Where do you start if you know nothing?
You say “Hi!” to everyone, exercise your complete toolbox of people skills, follow everyone to lunch, buy the informal leaders beer etc… But that is not enough is it?
Being a developer using ECO and the strategies proposed by DDD I will know what to do once I know what “the whole thing is about”. But the client is not really equipped to tell me what I need to know spontaneously, so I need some strategy to get that information extracted from them.
This post is about that strategy. Ok, I know there must be like a million ideas on how this is done. This is the way we do it:
- Gather a representative group of people from the domain
- Set up a workshop and let them brainstorm on who is showing any interest at all in what they do. More specifically ask them: who calls you on the phone, who emails you, who comes to visit, who delivers stuff, who sends you stuff, who buys your stuff, etc. All these questions are reversible: Who do you call, Who do you email etc. Collect this information and keep it as the Triggers.
- For each unique persona from step 2 find out what the goal of this persona is; why does X email you, what is their goal? Why do you email that person, what is your goal? Collect this information and keep it as the Goals.
- Split your group into smaller groups and let them break down each non-nonsense combination of trigger and goal into some steps that are central in getting to the goal. Make them aim for 5 steps. If they have a hard time getting started, encourage them to bring up just 1 step. Example: “Trigger is Customer, Goal is Getting a loaf of bread”. One obvious step is “handing the bread to the customer”. Great! Now force your group to explain what they do before- , and what they do after that step. “Need to fetch the bread from the shelf” is before, and “Receive payment” is after. This is going great! Continue like this, and throw away the silly steps and keep the important steps. What they create here are overviews of what their business is about. Keep this information as Processes.
After you are thru these steps you will have a pretty good idea on what you are up against. You will have a set of high level processes. Document these in Gaffr.net or ECO:
Some processes that you have already found might be detailing processes for a another process. And some steps in a found process might need detailing in further steps; you should callback your domain group to help you out with that.
By arranging the processes as “detailing” a step, you build up a structure in the Modlr tree:
Do you really need to involve real domain people? Will it not suffice with reading some existing documentation and talking to some IT-guys in the company? No. It will not suffice for 2 major reasons:
- You do not know what the real issue is – it might be that the current documentation and or the current IT-crew is wrong.
- You really need to get real people involved so that they feel and know that you are on their side. After all you will be a central player when it comes to change of these peoples working environment. You need to earn trust, you need to communicate, you need to make them involved. If you do not you will have a hell of a time trying to get the real people to understand the greatness of your work once you are done. And then it is all for nothing.
When you have reach this far you need to start on the information model. Create 1 class diagram per process and associate the two:
As you focus on a specific process when creating this class diagram you get a small and readable result:
The Process diagrams indicate that they are associated to class diagrams, and you can click the Icon to jump straight to the class diagram:
Further more the Process tree gives you a good structure of diagrams:
Now you have the big picture on “What it is that happens” from the processes, you get the “What information” view from the class diagrams. All you need now is the detailed business rules that controls this process. Being totally into declarative development, I only consider for short while to actually start to write c# code to catch these. But the state diagrams are better because the documentation gets clearer and maintenance will be cheaper in that form (our point of view). You can associate these to processes as well:
Once you have reached this far you may want to take it yet another step: Declare a viewmodel per process… But I will save ViewModels for another post.
Summing it upThe process tree will give you a navigation of diagrams and artifacts. The processes will make it easier for an outsider to understand the domain. And if you are a group of people where some do client communication with process modeling and some take it further with development you can now share one tool to keep your development efforts collected.
Weather you choose to do everything in your development declarative as we do, or only part of your your work declaratively and the rest by traditional coding is entirely up to you.
Total cost of using Gaffr.netIf you control your own method and you think that Gaffr.net fits, you can even license Gaffr.net; we will stripe it so your clients see your logos and they need not to know anything about us. You will then both have a tool and method. You will be free to price the tool as you see fit and the payment models are up to discussion but very modern and flexible. Email us today: sales at capableobjects.com .
Exploring the UML Metamodel with our new free UML2 Metamodel Viewer
Hello,
if you you need to use the UML2 Metamodel in some way for your work you will have noticed, that it is not easy to develop an understanding of the Metamodel, even less to learn quickly about the classes, their attributes and their relations to other classes. Basically there are only the official specifications from the OMG which are a bit dry to read.
Enter our new, free UML2Â Metamodel Viewer!
The UML2 Metamodel Viewer is a standalone Windows application that can be used to browse the package structure of the UML2 Metamodel and explore the contained classes. In addition, it is possible to draw diagrams from these classes in a semi automatic way.
Here is a screenshot of the main window:
To create a diagram simply add a new diagram to your project and drag one or more classes from the Model Explorer to the diagram. For example, here is a diagram with the class Kernel::Classes::Class:

UML Metamodel Viewer with a diagram
One of the neat features is that the related classes (superclasses and classes that are used in relations) are automatically added to the diagram. This is an easy way to see the “context” of a given class.
The installer comes with a manual that should get you started using the UML2 Metamodel Viewer.
There is a catch: currently UML2 Metamodel Viewer relies on some third party software (namely the Graphviz package and the UmlGraph package – the latter additionally requires a Java Development Kit) that must be installed and configured so that diagrams can be created.
This is a 1.0 release, so you will surely find bugs using this software. Please report bugs and feature suggestions to support@empowertec.de. We definitely appreciate your feedback! We plan to actively support this software, which means of course fixing bugs but also implementing new features depending on demand and effort.
The software is based on the cmof-files that define the UML2 Metamodel.
Best regards,
Andreas
Catching more information in your model
Once you have started to travel the path of Model driven development you might find that the declarative approach is useful for even more things than what you thought of at first.
You may find yourself searching for a way to mark up certain classes as UserFriendly or an association as being HeavyToLoad, so that your code can see this and perform differently. Of course you can create code that checks if it used on a particular class or on a particular association, but that will eventually cost you in more maintenance.
We cannot and should not try to understand your future needs, after all you probably do not even know yourself yet. So what to do… Tag extensions…
Tag extensions definitionBrings up this dialog
You can create new extensions. In the example above there are 3 extensions, Kasper.Seeker, EcoExtensions and Kasper.
Each extension has a number of TagTypes – on the example above the Kasper extension has 4 tag types; Kasper.AutoSeekAndPick, Kasper.AllowUserNew, Kasper.UserFriendlyClass, Kasper.BusinessDeleteValue.
Each TagType is applicable to only one type of “TagExtendableItem” in the item. In the example above the Kasper.BusinessDeleteValue is active on Association end points.
A TagType can be made to act as a enumerable valueset, the example above allows for 4 values; PSCheckMustBeEmpty, MustBeEmpty, OkEvenIfNotEmpty and NoOneHasMadeADescisionForThisYet.
Tag extension usageOnce you have defined the tag extensions the property inspector is updated.
The Extensions shows up as any other properties of your modeled elements.
The values of the tag extensions are stored as tagged values and translated into .net code attributes in the generated code:
1: [UmlElement("AssociationEnd", Id="31cfadd7-2b04-493c-a5e5-399913764949", Index=Eco_LoopbackIndices.Reserverad)]
2: [UmlMetaAttribute("association", typeof(KasperPackage.LagerrorelsePrioriteringLagerrorelsePrioriteringarAnvandareReserverad), Index=1)]
3: [UmlMetaAttribute("multiplicity", "0..1")]
4: [UmlTaggedValue("Kasper.BusinessDeleteValue", "OkEvenIfNotEmpty")]
5: public Anvandare Reserverad {
6: get {
7: return ((Anvandare)(this.eco_Content.get_MemberByIndex(Eco_LoopbackIndices.Reserverad)));
8: }
9: set {
10: this.eco_Content.set_MemberByIndex(Eco_LoopbackIndices.Reserverad, ((object)(value)));
11: }
12: }
And you can access it in your code, either by using standard .net approaches to get to code attributes, or by using the extended meta information that ECO brings.
1: foreach (IStructuralFeature sf in TheObject.AsIObject().UmlClass.AllStructuralFeatures)
2: {
3: if (sf is IAssociationEnd)
4: {
5: IAssociationEnd ae = (sf as IAssociationEnd);
6: string tv = ae.TaggedValues.ValueForTag("Kasper.BusinessDeleteValue", "NoOneHasMadeADecisionForThis");
7: if (tv == "PSCheckMustBeEmpty" || tv == "NoOneHasMadeADecisionForThis" && !(ae.DeleteAction == DeleteAction.Prohibit))
8:Tag extension visualization
Even if the Tag extensions has been in ECO and Gaffr.net for some time, a new way in how they can be displayed has been added recently. A new tab on the TagExtension dialog called Symbols has been added:
In this dialog you can define symbols that are built up by a piece of xaml:
1: <Rectangle xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' Fill='Blue' Width='16' Height='16'>
2: <Rectangle.RenderTransform>
3: <RotateTransform Angle='45'/>
4: </Rectangle.RenderTransform>
5: </Rectangle>
Any stand alone xaml is valid to use here so you can define any kind of symbol you want.
You can then associate the TagTypeValues to a symbol:
And then your diagram displays the symbols when the values are set:
When hovering over a symbol, you get a tooltip that explains what tag extension it is and what the value is.
So start decorating your business models. Move stuff from your memory to Modlr for more people to see and for you to relax. Remember that development is still the hardest thing in world to truly master so accept any help you can get.
TextUML Toolkit 1.5 is out!
Release 1.5 of the TextUML Toolkit is now available from the update sites, for both Eclipse 3.5+ and 3.4. Update or install. We got a few new features in this release.
Content assist
There is now early support for content assist (contributed by Attila Bak), with initial support for stereotype applications.

Element aliasing
You can now enable aliasing by creating repository properties in the form:
mdd.aliases.<source-qualified-name>=<target-qualified-name>For instance:
mdd.aliases.base\:\:Real=mypackage\:\:MyRealNew textual notation features
There is now textual notation support for decimal literals.You might have noticed 1.4 was announced here less than a month ago. We decided to start pushing releases as often as we can, so you can expect a bunch of 1.x releases throughout 2010. If you want to see some feature in the TextUML Toolkit, ask away!
Can TextUML be implemented the generative way (with Xtext or EMFText)?
I have been trying to figure out whether the TextUML notation for action semantics can be dealt with properly by tools such as Xtext and EMFText (class models and state machines should be fine). For example, given this structural model fragment:
class Advertisement
attribute summary : String;
attribute description : String;
attribute keywords : Keyword[*];
attribute category : Category;
operation addKeyword(keywordName : String);
static operation findByCategoryName(catName : String) : Advertisement[*];
end;
association AdvertisementKeyword
role Advertisement.keywords;
role advertisement : Advertisement;
end;
class Keyword specializes Object
attribute name : String;
end;
class Category specializes Object
attribute name : String;
attribute description : String;
end;
association AdvertisementCategory
role Advertisement.category;
role ad : Advertisement[*];
end;
Notice the Advertisement class declares two operations. Their behaviour in TextUML could be written as:
operation Advertisement.addKeyword;
begin
var newKeyword : Keyword;
newKeyword := new Keyword;
newKeyword.name := keywordName;
link AdvertisementKeyword(keywords := newKeyword, advertisement := self);
end;
operation Advertisement.findByCategoryName;
begin
return Advertisement extent.select(
(a : Advertisement) : Boolean {
return a->AdvertisementCategory->category.name = catName;
}
);
end;
Note that TextUML allows the behavior to be specified inline when declaring an operation in a class, or in separate, as above (that explains the lack of parameters, modifiers etc).
In the resulting UML model, the behaviour of Advertisement.addKeyword would roughly map to this (using a textual pseudo-notation for UML activities that is hopefully more readable than raw XMI):
activity(name: "addKeyword") {
structuredActivityNode {
variable(name: "newKeyword", type: #String)
writeVariable(variable: #newKeyword, value: createObject(class: #Keyword))
writeAttribute(
attribute: #Keyword.name,
target: readVariable(variable: #newKeyword),
value: readVariable(variable: #keywordName)
)
createLink(
association: #AdvertisementKeyword,
end1: #AdvertisementKeyword.keyword,
end1Value: readVariable(variable: #newKeyword),
end2: #AdvertisementKeyword.advertisement,
end2Value: readSelf()
)
}
}
and the behaviour Advertisement.findByCategoryName would map to this:
activity(name: "findByCategoryName") {
structuredActivityNode {
// implicit variable for return value
variable(name: "@result", type: #Advertisement, upperBound: *)
// implicit variable for parameter value
variable(name: "catName", type: #String)
writeVariable(
variable: #@result,
value: callOperation(
operation: #Advertisement.select,
target: readExtent(class: #Advertisement),
filter: metaValue(#@findByCategoryName_closure1)
)
)
}
}
// a closure is an activity that has a reference to a context activity
closure(name: "@findByCategoryName_closure1") {
// implicit variable for return value
variable(name: "@result", type: #Boolean)
// implicit variable for parameter value
variable(name: "a", type: #Advertisement)
writeVariable(
variable: #@result,
value: callOperation(
operation: #Object.equals,
// variables from the context activity are available here
target: readVariable(variable: #catName)
args: readAttribute(attribute: #Category.name, target: readLink(
association: #AdvertisementCategory,
fedEnd: #Advertisement.ad,
fedEndValue: readVariable(variable: #a),
readEnd: #Advertisement.category
))
)
)
}
Note that UML does not have closures, this is an extension to the UML metamodel which I wrote about here before.
Some background on the metaclasses involved: ReadVariableAction, CreateObjectAction, CreateLinkAction, ReadExtentAction etc are all action metaclasses. Actions are the building blocks for modeling activity behaviour in UML.
The million dollar question is: can Xtext and EMFText handle more complex textual notations like this? Is this out of the happy path? Has anyone done something similar? I am under the impression I could use Xtext or EMFText better if I used them based on a intermediate metamodel for behavior that would be closer to the concrete syntax (to get all the IDE bells and whistles for free) and then transformed that to UML in a separate step.
If you have the answers for any of these questions (or even if you have comments and questions of your own), please chime in.
Eclipse Modeling Day in Toronto
Last Wednesday I attended the Eclipse Modeling Day in Toronto. Coming all the way from Victoria, I must have been the participant that came from farthest. Except, of course, those folks from SAP AG and Itemis that were presenting. But I was really glad to be there. I finally had the chance to chat and discuss about Eclipse and Modeling face to face with people like Simon Kaegi (server-side OSGi), Kenn Hussey (MDT UML2), Eike Stepper (CDO), Ed Merks and (fellow Brazilian) Marcelo Paternostro (EMF), Lynn Gayowski and Ian Skerret (Eclipse Foundation). It’s weird: I have been part of the Eclipse Modeling community since 2006 (and the larger Eclipse community since 2002), but had never actually met any of those folks before. Also amusing was that even though I worked for IBM Ottawa for quite a few years, my first time at the Toronto Lab was many years later as an ex-IBMer living on the West Coast.
The presentations I attended were in general very good. I had seen Ed Merks’ opening presentation on the web before, but this time I could ask questions. I got a better understanding of Xtext (great presentation!), CDO, and the Query, Validation and Transaction frameworks, some technologies I am considering adopting in the near future. I had a first time contact with the Papyrus 2.0 vision, which might provide an opportunity for increasing adoption of the TextUML notation by integrating the TextUML Toolkit into a larger modeling environment. And I liked the idea of a discussion panel at the end.
I had to catch a flight back home that same night, so I could not attend the Eclipse RT Day on the following day nor could I see any of the demos at the DemoCamp. Speaking of which, I did manage to stay long enough to have a beer on the Foundation (thanks!), and chat with Christopher Nagy from Dexterra/Antenna Software, who made a quick ad hoc demo to Ian and myself of their Eclipse/GEF-based tool for authoring multiplatform mobile applications. Very impressive!
As constructive criticism, I do agree with Bjorn that the format could use some tweaking. I sure had to miss some very promising presentations. Maybe with two presentation formats, a longer (for instance, 40-50 mins) and a shorter one (20-25 mins), we wouldn’t need two tracks. I am not sure presenters who came from Europe would have come had they had a shorter slot though. That being said, I was very satisfied with the event overall and am sincerely thankful to IBM Toronto for hosting the event, the Eclipse Foundation for organizing it, all the folks presenting and the companies sponsoring them. Thank you very much! As Lawrence wrote, hope we will see more events like this in the future!
Derived attributes & associations
Derived attributes has been in ECO for ages . To a SQL-guy derived attributes resemble calculated fields. Derived attributes are just like calculated fields that subscribe to all the values that it is calculated from. So whenever data, seen by the expression, is changed the derived attribute is marked as out of date. And the next time you or your UI tries to read it, the attribute is re-evaluated.
The key thing with derived attributes is that it is NOT calculated each time you access the attribute. If it were performance would suffer. It is calculated (or derived) as few times as theoretical possibly; only when read the first time after a change of anything that the derivation expression looks at.
The concept of derivation relies on the concept of subscription – everything in your domain layer has the ability to signal whenever it is changed (the publisher pattern), and subscribers subscribe to publishers to detect these changes. Although this is a different story I must mention that publishing events to catch changes is a key difference between the ECO approach to implementing a domain layer and the POCO way (plain old c#-objects) like NHibernate and some other frameworks use.
Having a model as the one above I can create a derived attribute on the Order that calculates the total shipping cost by checking the products ordered and the customer’s country in OCL:
self.OrderItems->FilterOnType(ProductThatNeedsShipping).Weight->sum
* self.Customer.Country.CostToShipHerePerKilogram
I do this by creating a new Attribute, set the AttributeMode to Derived and fill in the DerivationOCL.
Derived attributes can be used in other derivation expressions so I can make a derived TotalCost without repeating the definition of the Shipping cost:
self.OrderItems.Product.Price->Sum() + self.ShippingCost
The expression of derived attributes can be expressed with C# / VB.NET / Delphi.NET code instead of in OCL (ECO only, not Gaffr.net). You do this by setting the AttributeMode to Derived as before but leave the DerivationOCL property empty. Generate code and inspect the Order.eco.cs file. At the bottom of the file you will see these stubs:
1: /// <summary>This method is called when ShippingCost needs to be calculated</summary>
2: partial void ShippingCostDerive(ref string res);
3:
4: /// <summary>This method is called when TotalCost needs to be calculated</summary>
5: partial void TotalCostDerive(ref bool res);
You never change the files named something.eco.cs – instead you implement these partial methods in the file something.cs (or vb or delphi). So in our case we open up the Order.cs file and enter:
1: partial void ShippingCostDerive(ref double res)
2: {
3: res=0;
4: double totWeight=0;
5: foreach(OrderItem i in OrderItems)
6: {
7: if (i is ProductThatNeedsShipping)
8: {
9: totWeight += (i as ProductThatNeedsShipping).Weight;
10: }
11: }
12: if (Customer!=null && Customer.Country!=null)
13: res = totWeight * Customer.Country.CostToShipHerePerKilogram;
14: }
Prior to ECO5 you needed to explicitly explain to ECO what ECO should subscribe to in order to stay updated if anything changes. But as of the introduction of the IAutoSubscriptionService this is no longer necessary.
The IAutoSubscribeService deserves a chapter of its own but here is a brief overview:
The caller of your code derivation has a subscriber and starts an Auto subscription session. An Auto subscription session is notified about all access to the domain layer as long as the session is in effect. All access is inspected and builds up the description of what ECO needs to subscribe to in order to know when to mark the attribute out of date. The session is ended after your code derivation returns.
Conceptually this is what happens:
1: using (this.AsIObject().ServiceProvider.GetEcoService<IAutoSubscriptionService>().StartSubscribe(subscriber))
2: {
3: double res;
4: this.ShippingCostDerive(ref res)
5: }All you need to remember
All you need to remember is that derived attributes can be defined in code or in the model with OCL. Derived attributes are efficient and always return the correct up to date result. Associations can also be derived the same way as attributes.
In the example model above the Shipping cost is out of date if you add a new orderline, if you change the customer, if the customer changes country, if a already picked ProductThatNeedsShipping gets an updated weight etc – it covers every and any change that effects the calculation as long as that change is part of your domain layer.
I hope that you see the positive effect this will have on your UI implementations – Showing the ShippingCost and see it update as you change anything it depends on by one central definition far away from the UI.
Using derived attributes and associations clean up your code and consolidates central definitions to single points and thus greatly reduce maintenance costs and efforts.
TextUML Toolkit 1.4 is out!
Release 1.4 of the TextUML Toolkit is now available from the update sites, for both Eclipse 3.5+ and 3.4 (by the way, it is possible this will be the last major release targetting Eclipse 3.4, unless someone volunteers to generate and test builds for 3.4).
This is mostly a bug fix release. However, there were some minor notation changes to support stereotypes on dependencies, generalizations and interface realizations, hence the version change from 1.3.x to 1.4.x.
Thanks to Vladimir Sosnin, Attila Bak and fredlaviale for contributing with code and/or bug reports/feature requests. Keep them coming!
As usual, you can find a summary of the changes in the TextUML Toolkit Features page. If you are using the Toolkit, make sure you upgrade soon. If not, what are you waiting for? Install it already!
