2008/07/30

Part five: generating and testing the application

kick it on DotNetKicks.com

Hello again!

In part four of my tutorial about MDE with Olivanova I wrote a little bit about modeling the user interface.

This (last) part is about generating and testing the application. As almost nothing has to be coded by hand, this step becomes rather simple.

Creating the model took me about six hours in total, now I want to see the result as generated and working application. Of course, the application will not be totally bug-free, but my intention was rather to show you how to quickly develop a fully-functional web- and desktop-application with the Olivanova modeling system.

In order to get the application working, I need to validate the model with the Checkbox-button. As the modeler does not report any errors, I can proceed exporting the model into an xml file by clicking on the Next-button.




After choosing a location on my harddrive, the modeler exports the xml and reports no errors:

Clicking on the Next-Button again starts the application that is in charge of defining the target platform. In my case, I will generated the following:

  • C# 2.0 COM+ Server
  • C# ASP.NET 2.0 web based user interface
  • C# Winforms 2.0 desktop based user interface
  • Function Points counter

The application lets me also choose other target platforms, but because I prefer .Net I chose that one.

Now, for each target platform I need to specify code generation parameters such as if double byte support is needed, default user interface language, database system, application name, application namespace, url and so on…



It is very important to know that you can mix client and server architecture as needed. This means, that you could implement your server application on JBOSS with J2EE and connect ASP.NET 2.0 Clients running on Windows Web Servers to it. But for now, we will stick to C# and .NET.

Next, I need to define the place on my harddrive where the generated code should be placed.



When I am done with this, I just need to send the model and the transformation profile to the transformation service and a few minutes later, I receive the code.

The code structure is much to complicated to go into detail here, perhaps I will write something about the code structure in the future. For now, it is just important for you to know that the server code also contains the database scripts that are needed to create the database structure and you will get the application running within five minutes.

Below, you see a screenshot with the three projects (Server, Webclient, Desktopclient) opened. The sln and proj files are also generated during the model-to-code transformation.



You can see the running result here: http://www.c5solutions.de/TravelmanagementDemo

Most likely, using the tool will not be for free for you, so it is worth mentioning the pricing for a moment. As you hopefully noticed, I also added the Function Points Counter (FPC) in the transformation request. This service is always for free and returns a set of html files which contain detailed information about which component causes how many functions points and of course let’s you know the overall sum. If you are interested in the function points method, I would suggest you to take a look in Wikipedia.

It is very important for you to know this sum, because if you prototype an application with this tool within 4-8h, you can let your customer know the price for the finished application. Because the first prototype is usually lacking huge parts of the business logic, I usually add about 33 percent of the total function point count of the first prototype and multiply it with our price per function point. Of course, Olivanova’s business model is quite similar: if you are able to use the service, they most likely will charge you a certain amount for each function point generated (although you can also arrange a flatrate pricing with them if you plan to use the technology for many projects).

Finally, I would like you to take a look at the application and tell me how long you think it had taken you to implement this functionality with NHibernate, Lightspeed, MVC, or whatever. Furthermore I would really appreciate if you tell me what you think about this technology, the prototype and this tutorial.

Thank you very much, if you have further questions, just send me an email.

kick it on DotNetKicks.com

2008/07/18

Part four: Modeling the user interface

kick it on DotNetKicks.com

In the previous part of this tutorial, we modeled the business logic of the application. Now, we are going to define how the user interface is going to look like and which functionality and data is to be presented to the user. If you do not already know the running application prototype, I would suggest you to check it out: http://www.blogger.com/post-edit.g?blogID=2481650812860323753&postID=7311055574856183066#.

The user interface modeling is very important for the application because we all know that an application that is uncomfortable to use will never be used. So, we listen to the “customers” requirements, which are the following:

I need an interface that allows me to administer things such as departments, cost units, cost centers, cars, receipt types, travel cost groups and users. This part of the application is to be called “administration”.

The user interfaces for managing trip requests from the employees and the managers perspective should be optimized for usability as they are supposed to be the most frequently used part of the application.

All business objects should if possible be selectable in a dropdown list when processing data in forms.

The administration part of the application needs to provide the functionality to create, edit and delete the mentioned business objects as already (partially) specified. If nothing else is mentioned, a business object can only be deleted from the database, if it is not referenced anywhere else. So, for example, if a Car is used for a trip, the car cannot be deleted unless the trip request is also deleted.

You might think now that this requirement is strange as it does not match the needs of a real-world application. The reason why I chose the requirement to be like this is because this is just a demonstration of the application, although this can be further developed in the future. Just in case, I will specify another more complex exception from the rule above:

If a receipt type is to be deleted, the administrator should get the possibility to define another, previously defined receipt type that is going to replace the receipt type that is to be deleted for all referencing trip requests. The new receipt type should be selectable by a dropdown list and that input parameter has to be mandatory. Of course, the dropdown list must not contain the receipt type to be deleted. If, however, there is no trip request referencing the receipt type the user wants to delete, the administrator is not required to specify a new receipt type and the input parameter in the user interface is disabled.

If it is possible to implement this feature for the class ReceiptType, it should also be obvious that the same feature could be implemented for any other comparative class, with almost arbitrary complex logic.

When creating a new trip request ("travel application"), the application should ask the employee whether he or she wants to enter receipts for the trip request just created. If so, the application should display the form for adding a receipt to the trip request. If creating the receipt succeeded, the application should ask the user if he or she wants to enter another receipt or if he or she wants to return to the trip request overview form.

Let's move on from specifying and start to model those (and all other) requirements concerning the user interface.

The user interface can be modeled when clicking on the eye-button on the modeler toolbar. The following dialog window pops up and gives us the option to define views and services, navigations, filters and so on.




As you can see, each class modeled in the class diagram is listed underneath the so-called “Conceptual Schema”. For starters we need to define a list view on the administrator objects and need to provide a way to access the services create_instance and delete_instance of the class Administrator.

I will briefly explain the concepts you see on this screen. For each class, you can specify default patterns that are used in the user interface if you do not specify explicitly an interaction pattern. Currently, there are three default interaction patterns that we can define:

  • Instance IU is a interaction unit that displays data from a single object, you can define which attributes of the object (or associated unary objects).
  • Population IU represents a list view of a set of objects of the selected class. Here, you can specify filters on that class, the attributes to display, order criteria and so on. We will come back to this later.
  • Supplementary Information: sometimes, it is useful to display additional information to the user when he just selected an object in a subform. The Supplementary Information pattern defines which attributes are displayed to the user in this case.

Of course, there are a few more presentation concepts, but for now, we will create a Population IU in order to provide a view to display and control the available administrators of the system. If I click on the + button beneath the dropdown that says “(void)”, the following window pops up and lets me specify presentation patterns specifically for this view:



So, here you can see several input fields. The name needs to be unique for the model, the alias is the text that is displayed in the user interface whenever the Population IU is used in the application. “Nr. Instances” is the default value for the number of instances to be displayed when loading the data into the view.

Moving on to the second tab: definition. This is by far more interesting, as you can define which attributes should be displayed in the view, which order criteria should be offered and which filters upon data should be offered to execute.



As a first step, we leave the displayset (Auto) as it is because the class administrator has only one attribute and so we do not need to create an additional displayset.
Next, we define a simple order criteria by clicking on the + button on the right border of the order criteria section. I defined the order criteria shown in the screenshot to sort the instances alphabetically by the attribute id.

I will explain the Filters in a more complex example for you later on.

The third tab lets us specify additional patterns for the view. I will not dive any further into details but want to tell you that you can specify which services can be accessed from the view, which related objects can be navigated to and which service should be directly attached to the data view in order to edit data faster.

I could document dozens of further features but as I have limited time for this tutorial, I just modeled the following features in 1.5h:

  • Defining the menu navigation
  • Creating the wizard-like interaction dialog that allows the user to quickly decide whether to add receipts to a travel or to return to the overview screen
  • Adding grid-inline-editing features for Population and Instance IUs
  • Providing other filters on data, including a administrative filter on receipts that has (amongst other controls) two dropdown input fields: one lets the user choose a department and the other lets the user choose an employee – but if you try out the application, you’ll notice, that I also implemented a dependency between those two dropdown lists. The list of employees is automatically repopulated when the selection in the department dropdownlist has been changed
  • Defined additional order criterias
  • Grouped service input fields
  • etc.


Stay tuned for the last part of this tutorial that will show you how to generate the code from this small and simple model!

kick it on DotNetKicks.com

2008/07/08

Part three: Modeling the business logic

kick it on DotNetKicks.com

In the second part of the tutorial we have been modeling the class diagram of the web application that can be tested using the url http://www.blogger.com/post-edit.g?blogID=2481650812860323753&postID=6027216049265152531# . In this third part, Iwill show you how easy it is to define real business logic on top of the class diagram that we created.

Now we are going to implement the business logic in the model on top of the classes, attributes and relationships that we have just defined. The OlivaNova modeler enables us to define almost the entire logics in a formal language called OASIS. It looks a little bit similar to SQL but also allows us to make method calls and so on. Instead of explaining the theory behind that language, I will first show you an example.

In the screenshot below, I have defined a precondition for the method that creates an instance of the class TravelApplication. This method is used whenever an instance of TravelApplication needs to be created – even if the method is wrapped into another method. So, here is how we define a precondition with a simple OASIS-statement:



I think the statement defined in the formula is self-explanatory. If the method is executed, the system checks if the statement is true, and if it is not, it displays the error message to the user.
Now, we are going to add another precondition. This time, we want to make sure that the end time is greater than the start time if the start date is the same as the end date:



This editor window appears if you click on the magnifying glass right beneath the formula text field. The following screenshot shows two preconditions. Please note that we cannot yet check attributes in our preconditions but only parameters. This is due to the fact that the object does not exist when the precondition is executed (because the precondition is defined for a method that is just about to create the object).



If you enter a syntactically incorrect statement, and want to save that precondition using the “+” button, the modeler fails validating the statement and will tell you so.
In order to show you a slightly more complex sample of a precondition. If an administrator needs to delete a receipt type, he can use the transaction TDELETE in the class ReceiptType. If there isn’t any receipt that uses the receipt type that the administrator is about to delete, we are done. But what should happen, if there are already receipts associated with that receipt type? In this case, the transaction TDELETE enables the administrator to specify another receipt type that is going to be assigned instead of the receipt type that he is about to delete. So, we must be sure that either there are no receipts associated with the receipt type or that the user specifies a new receipt type to use. Of course, the receipt type must not be the same as the receipt type to be deleted.
Therefore, I added two preconditions to the transaction TDELETE in class ReceiptType:



The first one checks if the inbound argument specified does not equal to THIS (= to the receipt type the user is about to delete). The second precondition checks that there are either no associated receipts OR the user chose a receipt type as inbound argument that is different from NULL.

This way, you can define almost all constraints defined in the specification.

This leads us to the next big issue: methods. The concept of methods is very similar to what you probably know from your programming experience, but there are some important differences. Methods are called “Services” in the Olivanova System, and there are three kinds of “services”:

  • Events: … are not what you might think. In the context of OlivaNova, events are primitive data processing actions that run in a transactional context (in terms of database transactionality)
  • Transactions: … is logics defined in OASIS that can also call other events and transactions. They are executed as a whole or – if an error occurs – rolled back.
  • Operations: … are just like transactions but do not provide transactionality. This, on one hand can make your database logically inconsistent (if it fails during execution) but on the other hand no transaction log has to be made and thus, operations are somewhat faster in execution than transactions are (especially for massive calculations on data).

The following screenshot shows the dialog that allows the definition of those methods (input parameters, output parameters, preconditions …).



So far, everything besides the preconditions of the event create_instance has been automatically generated by the modeler. The Ins* and Del* events are events for establishing and deleting relationships at runtime between objects as defined in the class diagram.
The interface might irritate you a little bit because it is not so intuitive, but once you are used to work with the modeler it is quite okay.

So, back to the service editing form … on the left you see all methods (“services”) defined until now, and on the right side, you can see all input arguments defined for the selected service on the left side. Because I do not want most services to be directly accessible to the end user through the interface, I set many of the services to be for “Internal use”. This means, that those services can only be accessed through internal logics.
For now you can forget about the rest of all those buttons etc.

A few lines above, I explained to you how preconditions work. Now, I am going to use the sample above again (ReceiptType.TDELETE) in order to give you an idea of how transactions look like in OASIS.

The Transaction code of the transaction mentioned above looks like this:



I will explain those lines briefly:

{ia_newReceiptType <> NULL}
FOR ALL Receipt DO Receipt.TCHANGERECEIPTTYPE(Receipt, ia_newReceiptType).

delete_instance(THIS)

{ia_newReceiptType <> NULL} are so-called “guards”. Actually, they are nothing else than if-statements without the else-statement. So, the statement checks if the inbound argument ia_newReceiptType is not null and if it is not null, the line below is executed.

FOR ALL Receipt DO Receipt.TCHANGERECEIPTTYPE(Receipt, ia_newReceiptType).

This line is more interesting. FOR ALL belongs to the group of collection operators, that means, that they operate on a collection of objects and give you the ability to do something on those objects. In this case, the code iterates over all associated receipts with the receipt type the administrator selected to delete, and executes the transaction TCHANGERECEIPTTYPE in the class Receipt. The first argument of the transaction is the receipt object on which the transaction is executed and the second argument is the new receipt type to use when the current one has been deleted.

After this transaction has been executed (it just deletes the association from the receipe to the receipt-type to delete and creates an association to the new receipt type), the event

delete_instance(THIS)

is executed, which causes the THIS object to be deleted permanently.

To get an overview about what is going on in the whole transaction (which of course can span various classes), it is a good idea to click on the blue tree symbol on the right border of the dialog. The following window pops up and shows the whole execution workflow:



This way, almost any business functionality can be implemented.

Data visibility

Of course, we need to ensure that any employee or manager using the application is able to see and edit only the data he or she is allowed to see. Therefore, Olivanova provides several concepts, and you will know about them within a few moments.

First of all, we need to make sure, that a manager sees only the travel applications of the employees in his or her department. Because a manager is also an employee, he or she do also have a department assigned. If we try to formalize our security requirement, we could say that a travel application is visible to the current manager user when the employee that created the travel application is assigned to the same department as the current manager is.
In OASIS, this statement looks like this (assuming that we are starting at a TravelApplication object):

Employee.Department = AGENT.Department

AGENT means the currently logged in manager in this context. You may wonder how the system knows which role we are actually talking about, but if you take a look at the following screenshot, it becomes clear:



The “Server class” is the class whose services, attributes and roles (=associations) are displayed on the left side and can be moved to the right side in order to make them accessible to an interactive user of class Manager (bottom). On the left bottom of the screenshot you see a section “Formula” which contains the formula we just defined. Because the formula is valid only for managers that try to access TravelApplication objects, the keyword AGENT is unambiguous. Furthermore, there are other concepts in the modeler that allow you to specify the evaluation of expressions for a certain role only, so – for example – you could specify that a certain precondition only applies to employees but not to managers.

Next, we need to specify which TravelApplications an employee can see and what he or she can do with TravelApplication. We want the employee to create and edit his or her own travel applications, see all fields but do not allow him or her to approve or reject a travel application.



As you can see, each agent of type Employee is allowed to execute all services except for reject and TAPPROVE, and he or she is allowed to see all attributes and associated of the TravelApplication provided the fact that the Employee of the TravelApplication is the currently logged in user.

So, after doing some modeling cosmetiques, I want to know if I have any serious bugs in my model. Therefore, I click on the Checkbox-symbol on the modeler toolbar and the following window pops up to show me the model validation output. The model validation checks the whole model for errors and only if there are not any errors in the model, I am able to send the model file to the transformation service.



There is one warning in the above picture we do not have to care about right now. Since there are no errors, we could get a working application right now. But we are not yet satisfied because there are some more improvements we can do for our customer.

Check out the next part to see how we are going to model the user interface.

kick it on DotNetKicks.com

2008/07/03

Part two: Modeling the class diagram

kick it on DotNetKicks.com

This is part two of my five-part tutorial about implementing a web-based database application with the OlivaNova Modeler (check out the running application: http://www.blogger.com/post-edit.g?blogID=2481650812860323753&postID=4842178084421971171#). In this part, we are going to discuss a rather simple task, the creation of classes, attributes, associations and inheritance. If you are interested, you might want to check out Part one: introduction and specification.

First of all, let’s start with the "static" model. Here, we are going to define classes and their relationships to each other quite similar to the way you are used to doing in UML.
We are going to define the following classes: Administrator, Employee, Manager, Car, Receipt, TravelApplication (=trip request), Department, TravelCostGroup, ReceiptType, CostCenter, CostUnit.




In the next step, we are going to specify the classes’ attributes. For simplicity sake, let’s start with Employee.

Defining class attributes

We double-click on the class Employee and the following dialog pops up:



I already entered the attributes according to the current specification (the final model contains some more calculated attributes for statistical purposes according to the specification). I highlighted the attribute EmployeeID for demonstration purposes.


  • The name must not start with a number and must not contain white spaces or special characters.
  • Attribute type can be Constant, Variable or Derived. “Constant” means, that the value cannot be changed after the object has been created. Variable means the opposite. “Derived” means that the attribute value is calculated through a formula. In this case, the EmployeeID won’t change (its supposed to be the AD login domain\username).
  • As the EmployeeID is in domain\username format, its datatype has to be String.
  • Id:0 means that the attribute is part of the objects primary key. I really don’t know why the guys who implemented the modeller made such a crappy feature , nevertheless it works just fine.
  • Size means (as you might already have guessed) the maximum length of the string attribute value that can be entered, processed and stored.
  • Optionally you can define a default value that is used if the user doesn’t change it.
  • Null allowed is self-explanatory.
  • Request upon creation means, that the method that is used for object creation contains this attribute as an argument.
  • The alias is a string that represents a more end-user friendly name for the attribute and can also contain white spaces and special characters etc.

Finally, you can enter a help message for the attribute and a comment for the analyst who is going to maintain the model. If you add help messages, the text will be displayed as a tooltip text in the generated user interface in service forms.
In this same way, all other classes get their attributes, but again because I don’t want to bore you, I skip this section and we go straight to doing something more interesting.

Establishing relationships and inheritance

Now that we have defined our classes, we need to define relationships between those classes. Remember, we didn’t define the car license number as a primitive datatype (although we could) because we know the cars in our car pool and want to be able to manage them and want to eliminate typos when entering the same car license number over and over again. That is why we have created a class Car which we can use as a dropdown data source.



Relationships work almost in the same way as in UML. However, there is one annotation you probably don’t already know: each relationship is labeled with it's cardinality and the letter “D” or “S”. “D” means, that you can change the number of associated objects after an object creation while “S” means just the opposite.

So, if you read the association between Receipt and ReceiptType, it means that a Receipt needs to have exactly one ReceiptType and the ReceiptType cannot be changed after the creation of an object of type Receipt. A ReceiptType object may have zero or more Receipts associated and those associations can change at any time during the lifetime of the object.

So, this was rather easy, wasn't it? And you might ask yourself where and how the functionality is modeled or if I programmed those requirements secretly by hand.

In part three of my tutorial you'll find out how the business logic is being implemented in the modeler.

Stay tuned :-)

kick it on DotNetKicks.com

2008/07/01

That's cool MDE - Introduction

kick it on DotNetKicks.com

This tutorial is about creating a (almost) fully functional web-based database application within 8 hours of work with a great MDE tool we're using since several years now. The tool is called “OlivaNova – The Programming Machine”.

For those of you who are as impatient as I am,click on http://www.c5solutions.de/TravelmanagementDemo to see and try out the running web application prototype (or take a look at the screenshot below).

I would like to show you how to implement a rock-solid, multi-tier, scalable, AJAXified C# ASP.NET client/server-application with ease. The tutorial consists of five parts:
  • 1. The specification
  • 2. Modeling the class diagram
  • 3. Modeling business logic
  • 4. Modeling the user interface
  • 5. Generating and using the application

Modeling, generating and testing took me around eight hours.
Of course, this prototype isn't perfect, but you should be able to get an idea of the possibilities you get with that tool. Throughout the entire code, I coded only as much as four (!) lines of c# code by hand (whereas two of them are only quick-and-dirty hacks to prevent demo users from deleting other users). I encourage you to show me another tool or method that’s so powerful. You'll love it.



Right now, we're going to start with part 1) the specification. I'll write and publish the following parts of the article within the next few days.


Part One: the specification

The customer wants to have a travel expense and management system. The system has to be implemented as web-application for employees, managers and administrators as it has to be accessible from the internet (after authentication). An Employee requests a and depending on the estimated costs the system automatically approves the trip request or forwards the request to the employee’s manager for approval. Employees are assigned to a travel cost group which defines the cost limit that reasons an automatic approval (per trip and also total costs within x days). The travel cost group can be changed at any time in general as the change of the travel cost group doesn’t affect trip requests in the past but only in the future. The trip request status has to be visible to both the employee that requested the trip and his or her manager. Of course, each employee must see only his or her own trip requests and each manager will be able to see only the request of his or her employees (a manager is responsible for the employees within the same department he works in). Trip requests can also be rejected by the manager; a trip request approval status can have the following values: new, automatically approved, manually approved, rejected.

Once the employee’s trip has finished, the employee must enter the actual costs by entering all receipts he paid throughout the trip. If the actual travel costs regularly (trips within x days, as specified in the travel cost group) exceed the travel cost group limit by more than 20 percent, the employee’s manager should get a notification about that fact.

As an optional feature, employee and manager records can also be disabled, so the person cannot log on to the system anymore. Eventually the user administration (employee, manager) is going to be synchronized with the corporate’s AD.

All data views have to exportable to Microsoft Excel.

Please note: I mixed up the words "travel application " and "trip request" somehow because I modeled the application before my colleague corrected me and I'm too lazy to change the model and re-generate the application. I hope you understand this.

Specification of the employee’s data:

First name, last name, salutation, birthdate, department, travel cost group, email address,
ratio in percent of actual costs and estimated costs regarding the last travel,
ratio in percent of actual cots and estimated costs regarding the travels within the last n days as defined in the assigned travel cost group,
ratio in percent of actual costs and n days cost limit as defined in the assigned travel cost group,
boolean value that indicates whether the previously mentioned value exceeds the n days cost limit by more than 20%.

Specification of the manager’s data:


Manager is also an employee; responsible for department (for simplicity, this is the department he also works in)

Specification of the department’s data:


Department ID, name short, name long

Specification of the Travel application data:


TravelApplicationID,
start date (must be less or equal to end date),
end date (must be greater or equal to the start date),
start time (if travel end date on same days as start, start time must be lesser than the end time), end time (analogue to start time),
estimated costs (>=0),
currentCostLimit (calculated when entering the application),
abroad (yes/no),
connection (yes/no),
departure location, destination location, intermediate location, purpose, cost center, cost unit,
car license number (dropdown, if no value chosen, cartype must be private; if value chosen, cartype must be company),
cartype (company/private; see car license number)
business Mileage (>=0),
private Mileage (>=0),
receipts, real costs (calculated based on the receipts net sum)
approvedBy ("SYSTEM" if travel cost limit not exceeded; the login of the manager that approved the application),
application status (0=new; 1=automatically approved, 2=manually approved; 3=rejected)

Specification of receipt data:


receiptID, Receipt type (dropdown), bill date, bill time, travelApplicationID, cost Net, tax%
Specification of receipt type data:

Receipt type name (ID)

Specification of car data:


License number (ID)

Specification of cost center:


Cost center ID

Specification of cost unit:


Cost unit ID

Specification of Travel cost group data:

Travel Cost Group ID (autonumeric),
cost limit (decides whether the travel application is automatically approved or not),
cost limit for travels within the last n days,
number of n days for the cost limit mentioned above


Because I don’t want to bore you, I’ll stop specifying any further and just implement the requirements in the model because the effort of directly modeling the features of smaller applications like this one is nearly identical to specifying features in a normal textual representation.


In the next part, I'll show you how classes and attributes are being modeled. Most likely, you'll already know the idea behind it as this modeling language is based on OMT, a predecessor of UML (http://en.wikipedia.org/wiki/Object-modeling_technique).

kick it on DotNetKicks.com