Archief voor categorie technical

Threading made easy in .Net 4.0 (2/2)

Threading made Easy (2/2)

This blog is part two of a little example I wrote to test the new threading stuff in .Net 4.0. To read part 1 follow this link.

Short recap from part 1 first. This is what I wrote:
The thing I have to do is get some data from the web in the following pseudo manner:

foreach subject from the list
search for the last 100 tweets on this subject

The part left over was to show some results from the threaded calls from part 1. It so happens to be that, somewhere near the end, I showed the following call as the most nicest and clean threading mechanism:

public static void GetParallel()
{
    Parallel.ForEach(UrlList, url =>
        {
            Get(url);
        }
    );
}

Threadsafe collections

From the example it shows we’re not doing anything useful with the result which is returned by Twitter. A byte array is returned and the thing I want to do is to store the byte array in a collection of byte arrays. Pretty simple huh? Well almost because a potential threading problem is kickin’ in. The standard collections in .Net are not threadsafe. We used to write code with a locking object and lock the piece of code which makes changes to the collection. The new .Net 4.0 has a more smooth solution to this problem: System.Collections.Concurrent.BlockingCollection. And the code above is changed in:

// use a thread safe collection for all threads
BlockingCollection<byte[]> data = new BlockingCollection<byte[]>();
 
Parallel.ForEach(UrlList, url =>
{
    data.Add(Get(url));
}
);
 
// return an ordinary collection (non thread safe) to the outside world
return data.ToList<byte[]>();

So each thread use a thread safe collection to store its results and when we’re ready with all threads the non-threadsafe counterpart is returned because when processing the result we don’t need any multithreaded handling.

Twitter data structure

Twitter returns its data in JSON format. The search API returns the data in the following structure (see also the Twitter API documentation), here is an example:

{
  "results":
  [
    {
      "text":"@twitterapi  http:\/\/tinyurl.com\/ctrefg",
      "to_user_id":396524,
      "to_user":"TwitterAPI",
      "from_user":"jkoum",
       "metadata":
      {
        "result_type":"popular",
        "recent_retweets": 109
      },
      "id":1478555574,
      "from_user_id":1833773,
      "iso_language_code":"nl",
      "source":"<a href="http:\/\/twitter.com\/">twitter<\/a>",
      "profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/118412707\/2522215727_a5f07da155_b_normal.jpg",
      "created_at":"Wed, 08 Apr 2009 19:22:10 +0000"
      },
      ... truncated ...
  ],
  "since_id":0,
  "max_id":1480307926,
  "refresh_url":"?since_id=1480307926&q=%40twitterapi",
  "results_per_page":15,
  "next_page":"?page=2&max_id=1480307926&q=%40twitterapi",
  "completed_in":0.031704,
  "page":1,
  "query":"%40twitterapi"
}

The list of byte arrays we have is a list of bytes in JSON format. Each byte array represents the results of a query and consists of some meta data describing the query and a list with references to all tweets returned by the search query. Each of these byte arrays needs to be transformed in something more meaningful and useful. Here JSON comes to the rescue, it is not only blazingly fast it is also simple. All we have to do is just define the interesting elements in the structure and the serialization will do its work, silently and fast. The structure in a .Net understandable format is:

[DataContract]
public class TwitterSearchResultList
{
    [DataMember]
    public TwitterSearchResult[] results { get; set; }
    [DataMember]
    public string query { get; set; }
    [DataMember]
    public double completed_in { get; set; }
}
 
[DataContract]
public class TwitterSearchResult
{
     [DataMember]
     public string from_user { get; set; }
     [DataMember]
     public string text { get; set; }
     [DataMember]
     public string profile_image_url { get; set; }
}

Transforming one byte array with twitter results is now as easy as:

List<TwitterSearchResultList> tweets = new List<TwitterSearchResultList>();
 
foreach (byte[] tweetlist in allTweetLists)
{
        MemoryStream tweetStream = new MemoryStream(tweetlist);
        DataContractJsonSerializer serializer = 
                new DataContractJsonSerializer(typeof(TwitterSearchResultList));
        TwitterSearchResultList tsrl = 
                (TwitterSearchResultList)serializer.ReadObject(tweetStream);
}

Rendering to html

To render the TwitterSearchReturnList to a presentable format I generated some html. This can be done much cleaner and nicer with XSLT and/or CSS but for the sake of the example I just coded the bare minimum. It looks like:

StringBuilder = new StringBuilder();
stringBuilder.Append("<TABLE>");
foreach (TwitterSearchResult tweet in list.results)
{
     stringBuilder.Append("<TR>");
 
     // the tweeters' avatar
     stringBuilder.AppendFormat("<TD><IMG src=\"{0}\" width=\"48\" heigth=\"48\" /></TD>", tweet.profile_image_url);
     // tweeters' name
     stringBuilder.AppendFormat("<TD>{0}</TD>", tweet.from_user);
     // tweet text; with all urls as an href
     stringBuilder.AppendFormat("<TD>{0}</TD>", Regex.Replace(tweet.text, "(http:/[\\S/]*)", "<a href=\"$1\">$1</A>"));
 
    stringBuilder.Append("</TR>");
}
 
stringBuilder.Append("</TABLE>");

Resulting in the following output:
ThreadingTestOutput

Source code

The full source code for this example can be downloaded here.
Thank you for reading, questions will be answered, suggestions are more than welcome!
have fun,
florisz

Nog geen reacties

MetaEdit+ 4.5 Review

MetaEdit+MetaEdit+ DSM Environment by company MetaCase is a commercial language workbench that in contrast to inflexible CASE tools, enables users to build their own modeling and code generation tools (aka DSM tools). It comes in two main product components:

  • MetaEdit+ Modeler provides customizable DSM functionality for multiple users, multiple projects, running on all major platforms.
  • MetaEdit+ Workbench i) allows building custom modeling languages (DSLs), and text generators and 2) includes the functionality of MetaEdit+ Modeler and MetaEdit+ API (the latter is not reviewed in this document).

This review is written from the MDE perspective and will cover major MDE functionally related to specification of modeling languages. For a complete picture of MetaEdit+, readers are advised to consider other aspects (e.g. collaboration, versioning, etc…) as well.

This review covers MetaEdit+ Workbench version 4.5.

Language Specification

AMetaEdit+ supports graph-like visual languages represented as diagrams, matrixes or tables. There is a limited support for spatial languages: touch and containment relationships are derived from canvas coordinates of modeling elements. There is no actual tool support to preserve these relationships: for example, as a modeller moves a “container” element, contained elements do not move along as expected, but remain at old coordinates.

In MetaEdit+, languages are specified with a set of specialized tools. In the following, we describe the tools per each aspect of the visual language definition: abstract syntax, concrete syntax, static and dynamic semantics.

Abstract Syntax

This aspect is defined with GOPPRR metatypes. GOPPRR is an acronym for metatypes Graph, Object, Property, Port, Role and Relationship. For each metatype, there is a form-based tool, e.g. Object tool allows specification of object types  and Graph tool allows assembling types produced with the other tools into a specification of abstract syntax. GOPPRR tools support single inheritance.

Graph tool also allows linking DSL objects to graphs of other DSLs through decomposition and explosion structures. Furthermore, through sharing language concepts (of any OPPRR metatype) among graphs, DSLs can be integrated so that changes in one model can be automatically reflected in models based on different languages.

An alternative to these form-based tools for abstract syntax specification is a visual metamodeling DSL. However, this functionality is best used as easy start-up leading to automated generation of barebone GOPPRR metamodels. Once a language developer changes a GOPPRR metamodel (which is inevitable), visual metamodeling is best discontinued to avoid manual round-trip between the two metamodels.

Concrete Syntax

By default, MetaEdit+ provides generic symbols. However, language developers are free to specify custom symbols for objects, roles and relationships. These symbols are either defined with a WYSIWYG vector drawing tool or imported from vector graphics (SVG) or bitmap files. Symbols can display text, property values and dynamic outputs produced by text generators (more on generators in section M2T Transformation). Moreover, symbols or their parts can be conditionally displayed. Finally, symbols can be reused among different DSLs via a symbol library.

MetaEdit+ does not directly support multiple concrete syntaxes per language, which (the lack of such support) is still a common practice among language workbenches. However, its capability to display symbols based on conditions allows to work around this limitation.

Static Semantics

This aspect covers constraints and business rules. The purpose of these rules is to ensure a consistent and valid model.

In general, DSM tools should verify a model against the static semantics of its DSL at different times. These times can be classified as ‘live’ (i.e. when a user is modelling) and ‘batch’ (i.e. invoked on events caused by actions such as user demand, model saving or transformation). Furthermore, tool actions following violation of a constraint can be classified as prevention (i.e. a violating action is canceled and a warning message is displayed) or merely informative (i.e. a violating action is allowed, but model will display clues about invalid constructions until the effect of the action is corrected).

MetaEdit’s Constraint tool (available from the Graph tool) allows ‘live’ checks against constraints and preventive protection of models (‘live’ and ‘preventive’ in the terms of the above classifications). The tool is very expressive and easy to use, but covers only limited number of types of constraints, namely:

  • object connectivity in a relationship
  • object occurrence in a model
  • ports involved in a relationship
  • property uniqueness

More advanced constraints have to rely on MERL generator (see section M2T Transformation), which can inform users about invalid constructions during modeling (‘live’ and ‘informative’ in the terms of the above classifications). MERL generator can also be used for ‘batch informative’ and ‘batch preventive’ checks: a checking report can be run on demand or included as preventive check before any other transformation is carried out.

Dynamic Semantics

MetaEdit+ can define dynamic semantics through a process of translating DSL concepts to concepts in another target domain with defined dynamic semantics. Examples of target domains in code generation applications are e.g. C++ or Java. A major benefit of language workbenches is that they are capable of automating this and other useful kinds of processes.

PROCESS AUTOMATION

MDE applications need capabilities to automate processes in which models are inputs and outputs. MetaEdit+ provides various levels of support for model-to-model (M2M), model-to-text (M2T) (e.g. in code generation applications) and text-to-model (T2M) (import of legacy code, data type definitions, etc. into models) types of transformations. (The latter transformation type is not reviewed.)

M2T Transformation

Text (and more specifically code) generation is accomplished with Generator tool that can efficiently navigate models, filter and access information, and output text into external files, Generator Output tool and DSL symbols.  All these tasks are specified with imperative language MERL. While MERL is very concise and efficient for most of these tasks, I think that navigation and access tasks are better accomplished in a declarative way.

MERL generators are defined per graph type (i.e. per DSL) and can be acquired from supertypes of a given graph type via an inheritance hierarchy. If a generator has to be used for different graph types, then the generator should be defined for the common parent graph type. On the other hand, DSL developer can define new or redefine generators already provided by parent graph types.

Finally, MERL provides support for modularization by allowing includes of generators in other generators. Making modular generators pays off well, as there are many reuse opportunities in MetaEdit+: generators can be reused not only for text generation but also in concrete syntax (symbols) and validation/reporting purposes (symbols, generator output tool).

M2M Transformation

Models can be transformed 1) programmatically via the SOAP and WebServices-based API of MetaEdit+ (this option requires product component MetaEdit+ API) or 2) through code generation of an intermediate external representation (in the XML format) and consequent import thereof as new model.

These two options amount to a generic support at a minimum level that is commonly provided nearly by all language workbenches. Moreover, code generation of an intermediate representation cannot implement in-place M2M transformations, of which application examples are: model optimization, model layout, model interpretation, model weaving and any repeatable model manipulation in general.

OTHER

  • DSL evolution: MetaEdit+ updates existing models instantly yet non-destructively to reflect changes in DSLs.  The update policy ensures that models created with the older DSL versions are not broken and remain usable with existing generators. Instant update is also very useful when fine-tuning a DSL with end users.
  • According to MetaCase, a MetaEdit+ project can hold over 4 billion objects. A typical project would contain about 40-100 models (graphs).
  • In the multi-user version, users can simultaneously access and share all models within a Repository. Locking is made at the object-level, so several users could collaboratively work on the same model at the same time.
  • Multi-user collaboration in MetaEdit+, product line analysis of commonality and variability and proper separation of concerns reduce the need for version control as it is known in software engineering. Therefore MetaEdit+ does not provide its own versioning system. Best practices for versioning with MetaEdit+ can be found here.
  • Model interoperability: by default, all models and DSLs can be exported in an XML format. The schemas are very simple, which make it easy to post-process such files if needed. Moreover, the M2T transformation capabilities of MetaEdit+ enable DSL developers to easily create custom export generators.

CONCLUSION

MetaEdit+ is a versatile language workbench that enables building high quality visual DSLs for any kind of domain, be it technical or business. Another key quality of MetaEdit+ is efficient DSL/GOPPRR tools, which allow light-weight, agile and fast DSL development and evolution. A testament to this quality is the fact that MetaCase is one of few language workbench makers that routinely designs and builds DSLs in improvisation with audience at conferences, workshops, etc. In my opinion, this impressive productivity is possible because GOPPRR tools are based on paradigms that are optimum for DSL development (DSM for DSM so to speak).

Highlights of MetaEdit+ are:

  • Proper level of abstraction: DSL developers are completely shielded from details of how DSM-tools are implemented. DSL development tools focus on essential abstractions for specification of languages and generators.
  • High-levels of automation: DSM-tools are completely and automatically generated from abstract language specifications.
  • High quality of tools: each DSL development task has its own dedicated tool.
  • Numerous enhancements: high integration of tools, non-destructive evolution of languages, inheritance mechanism, reuse opportunities for types, symbols and generators, visual metamodeling, etc.
  • Very cheap introductory license.

Naturally, there are a few drawbacks as well:

  • No specific support for model-to-model transformation.
  • Somewhat limited constraints support.
  • Limited support for spatial relations.
  • Uncommon user interface.
  • Form-based GOPPRR tools prevent a global overview of a metamodel.
  • Expensive  standard licenses.

Code generation applications are the oldest tradition in MDE and this is where MetaEdit+ excels. As MDE discovers new applications, my experience is that the code generation specialization becomes restrictive. Admittedly, it is possible to implement some types of M2M transformations with code generation (via intermediate representation). However, the problem with this workaround is that it introduces accidental complexity both to MDE developers and more importantly to end users (that have to keep repeating the generate/import routine, sometimes complicated by model merge).

That said, in my opinion MetaEdit+ gets the big things right. Whether its shortcomings are little things is a subjective matter that is best evaluated in the context of a concrete problem domain.

, , , , , , , , , , , , , ,

Nog geen reacties

DSL Design Tutorial at PPL2010

Photo from Inception (2010)In MDD explicit knowledge of the domain is crucial for successful development of domain-specific modeling languages (DSML). Yet many starting DSL developers are missing the skill of domain knowledge conceptualization. The main symptoms are difficulty to come up with good language concepts and struggling with levels of abstractions.

While language design remains an art, there are a number of paradigms, techniques and guidelines that can make creation of DSLs easier. These helping means are the core of the DSL design tutorial developed at Luminis Software Development.

The tutorial was given for the first time during the PPL2010 conference that took place on November 17 & 18 at Océ R&D, Venlo, NL. A small group of participants learned basics of domain analysis, participated in domain definition and implemented a simple metamodel of their own. The general feedback was very positive.

The slides for the tutorial can be downloaded here from the Bits&Chips website.

, , , , , ,

Nog geen reacties

Introduction to AIR for mobile

A couple of weeks ago, Adobe released a preview of the new Flash Builder and SDK. One of the new features is support for mobile devices using AIR. For now, only Android 2.2 is capable of running mobile AIR applications, but since Steve has changed the rules again, AIR on iOS is nearby, according to Adobe. Time to take a test drive with a tutorial.

Goal

We will create a simple RSS reader. Not a very exciting example, but already shows some nice features of AIR for mobile. I’ll assume you have experience with Flex or AIR, but I think you will manage with some level of programming experience. If not, feel free to leave a reply if you have any questions or take a look at the full source.

Setup

Empty project contents

Download and install the preview release of Flash Builder called Burrito It provides a wizard to start an empty mobile application. By default the wizard creates two mxml files containing a MobileApplication and a View component.

The MobileApplication class is inherited from the Application class used for desktop AIR. The mobile version provides, among other things, an action bar and a navigator. Furthermore its firstView property points to the empty view component. The view component is a normal group, but optimized for mobile use as well.

Article list

Open the main view component (called <projectName>Home.mxml). Create a List component in the main view. Provide positioning constraints to let it occupy the whole screen.

<s:List left="0" top="0" bottom="0" right="0" />

To retrieve the feed, create an HTTPService pointing to the RSS feed in the declaration section of the view. Add a resultHandler function to parse the feed-data. Parsing xml data is quite simple. You can just navigate to the DOM-tree as it were a normal ActionScript object. Use the data property of the view to store the articles locally. Using this property will provide some benefits with navigation, which will become clear in a bit.

<fx:Script>
  <![CDATA[
    import mx.rpc.events.ResultEvent;
 
    protected function service_resultHandler(event:ResultEvent):void {
      data = event.result.rss.channel.item;
    }
  ]]>
</fx:Script>
<fx:Declarations>
  <s:HTTPService
    id="service"
    url="http://lsd.luminis.nl/feed/"
    result="service_resultHandler(event)" />
</fx:Declarations>

Now there are only a couple of things left to do. Invoke the server and provide the list with the articles and instructions to show them.

Both are quite simple. The feeds are retrieved by invoking the send() method of the service. To automatically retrieve them, this method should be invoked when the view is created so we will use the creationComplete handler.

<s:View
  xmlns:fx="http://ns.adobe.com/mxml/2009" 
  xmlns:s="library://ns.adobe.com/flex/spark"
  title="Home"
  creationComplete="service.send()">

Finally, bind the data property to the dataProvider of the list and set its labelField attribute to ‘title’.

<s:List
  dataProvider="{data}"
  labelField="title"
  left="0" top="0" bottom="0" right="0" />

Your view will probably look something like this.

<?xml version="1.0" encoding="utf-8"?>
<s:View
  xmlns:fx="http://ns.adobe.com/mxml/2009" 
  xmlns:s="library://ns.adobe.com/flex/spark"
  title="Home"
  creationComplete="service.send()">
 
  <fx:Script>
    <![CDATA[
      import mx.rpc.events.ResultEvent;
 
      protected function service_resultHandler(event:ResultEvent):void {
        data = event.result.rss.channel.item;
      }
 
    ]]>
  </fx:Script>
 
  <fx:Declarations>
    <s:HTTPService
      id="service"
      url="http://lsd.luminis.nl/feed/"
      result="service_resultHandler(event)" />
  </fx:Declarations>
 
  <s:List
    dataProvider="{data}"
    labelField="title"
    left="0" top="0" bottom="0" right="0" />
 
</s:View>

Emulator

Emulate hardware buttons

Emulate hardware buttons


Now it is time to run a first test. Click the Run button and select ‘On Desktop’ as launch method in run configuration dialog. Also choose a device to simulate and run the application.

When the emulator is launched it shows a list of articles after a couple of seconds. Now you can select Rotate Right from the Device menu to display the landscape view. You will also notice the list is able to scroll up and down when dragging your mouse pointer (Which of course is the emulated equivalent of a one-finger swipe)

Article details

Next is to create a detailed view showing the full content of an article. Close the emulator and return to Flash Builder. In the views package, create a new component and call it DetailView. Bind the title attribute to data.title. Add a label as well and bind the text property to data.description. Don’t forget to specify the positioning constraints.

<s:View
  xmlns:fx="http://ns.adobe.com/mxml/2009" 
  xmlns:s="library://ns.adobe.com/flex/spark"
  title="{data.title}">
 
  <s:Label
    text="{data.description}"
    left="20" right="20" bottom="20" top="20" />
</s:View>

All view components provide a navigator object. We will use this in the change event handler of the article list. This event is fired when the user selects an article from the list. It looks as follows:

import spark.events.IndexChangeEvent;
 
protected function articleList_changeHandler(event:IndexChangeEvent):void {
  navigator.pushView(DetailView, data[event.newIndex]);
}

It simply instructs the navigator to create a new DetailView and push it on top of of the navigation stack. Furthermore the selected item from the article list is passed on to the data property of the DetailView.

Add the change handler and assign it to the change event of the article list:

<s:List
  dataProvider="{data}"
  labelField="title"
  change="articleList_changeHandler(event)"
  left="0" top="0" bottom="0" right="0" />

Article list inside the emulator

Article list inside the emulator

For performance optimization, AIR destroys the view when a user navigates away and recreates it when he returns. Only the contents of the data property is saved and passed into a recreated view of the same type. This is why we used it to store the articles. Otherwise the user has to wait for a reload when he returns to the main view.

When you launch the new version in the emulator, you will notice the application slides to the detail view when an article is selected. Click Back from the Device menu to simulate a click on the hardware back button.

Last but not least: action buttons

One thing our application is missing, is a button to go to the original webpage showing the full article. This button is placed inside the header of our detail view, next to the title.
To achieve this, add the button inside the actionContent of the detail view. Give the button an icon (I used one from the Tango project) and set the click handler to open the url of the article.

<s:actionContent>
  <s:Button
    click="{navigateToURL(new URLRequest(data.link))}"
    icon="@Embed('/assets/internet-web-browser.png')"/>
</s:actionContent>

Of course you might want an additional button to return to the article list instead of using the ‘hardware button’. Place this button inside the navigationContent. This will place the back button at the upper left corner. The click event of this button will invoke the navigation.popView() method to remove the current view from the stack and return to the previous one.

<s:navigationContent>
  <s:Button
    click="navigator.popView()"
    icon="@Embed('/assets/go-previous.png')"/>		
</s:navigationContent>
Action and navigator buttons

Action and navigator buttons

If you launch the application you will notice the buttons are nicely aligned at the top of the screen.

What’s next?

The next step will be to package the application to an apk file so you could install it on an Android device. This is done by the Export Release build wizard inside the Project menu of Flash Builder. It includes the ability to sign your application to allow distribution through the Android Market.

Another nice feature which I will not discuss in detail is to add gesture based navigation. Take a look at this article from Adobe to find out more. The approach discussed should be working for mobile AIR applications as well.

Unfortunately the most interesting benefit of using AIR for mobile didn’t become clear with this tutorial. It would be nice to deploy our application on other mobile plastforms as well. However the cross compiler for iOS isn’t available yet and the same goes for AIR on Windows Phone, BlackBerry or Symbian. We will just have to wait when Adobe is ready so we can fully benefit from the “Write once, run anywhere” promise.

, , , ,

3 reacties

The thin line between embracing change and being critical

The thin line between embracing change and being critical

Blogging: never before have so many people with so little to say said so much to so few
Do you recognise the following? Suddenly there’s a lot of buzz about a new hype, everybody is talking about it and if you haven’t tried it yet, you are definately lagging behind.
Now you have to decide: will you hop onboard and give $hip_new_tech a try or are you skeptical and wait it out?

Sometimes a new technology has obvious advantages, which makes it easy to accept. Other things need some time to show their merits, or need a certain user base to become useful.

Following are some examples, I only have experience with some of them, so feel free to comment or add your own!

VCS vs. DVCS

In the recent years, several distributed source control systems, such as Git, Mercurial and Bazaar, have emerged. Centralised systems are mostly common practice at most projects and a lot of (mostly open source) projects have already switched to or are thinking about switching to a distributed one.
The distributed systems have some nice perks, everybody has the whole repository (i.e., better offline support), sharing commits without submitting them to the central server, local branches and more. On the other hand, they require learning the new tool, which can take a lot of time, especially with the less tech-savvy coworkers.
I’ve been using Git for a few years now. For a previous project, we were able to fully switch to Git with our team. This was my idea and it meant I had to take up some Git support work every now and then, but it was fun and provided the abovementioned advantages. In the projects that followed, the main repository was Subversion, but there is a Subversion connector for Git, which works fine for daily use. It has a few inconveniences, like not committing the removal of directories to Subversion, so someone else has to clean them up. For the rest, it’s great.

The cloud

Another hip thing is ‘the cloud’, which allows you to host web sites, run applications and store stuff somewhere in a giant network. It sounds really scalable, you only pay what you use and most of the management is done by the cloud provider. There are some risks: you might need to modify the application to make it work, security and encryption could become more of an issue and there are new tools to get used to (e.g., for deployment and configuration).

NoSQL vs. RDBMS

The NoSQL-movement has gained a lot of momentum, known implementations include CouchDB, Jackrabbit, Cassandra and BigTable. It advocates that most data can be treated a lot less strict than old-style databases do. Think foreign keys, strict data types and designated master/slave servers. When true, this improves performance, flexibility and scalability, but you need to think through your decision, as some data really needs to have a restricted format.

Social networking: blogs, Twitter, LinkedIn

Internet has enabled new forms of communication, and every few years, a new one is invented.
First came blogs, then Twitter and LinkedIn. Now most sites have an array of icons to submit the current article to one of many networking sites.
Twitter has brought news reporting to everyone, blogs allow even me to say stuff to the world, networking sites help you to find people with common areas of interest.
They do however cost a lot of time and effort, which might intervene with other activities. Anybody wants to comment on this? Do you feel your real social life profits from this, or does it get in the way of it?

tl;dr

These are some things I could think of, do you have some other examples of hypes you aren’t sure about?
What do you usually do in these situations? Are you an early adopter or not so much?

, , , , , , , , ,

Nog geen reacties

Model Interpretation for Weighbridge domain

Model interpretation approach is grasping attention of the model driven community. Industrial experiences of company Mendix has shown some very promising results. A recent post at a popular “model-minded” blog triggered a discussion about code generation versus model interpretation.

Model interpretation in itself is not a new concept and there exist well known interpreters for generic and mainstream domains (e.g., Ptolemy and Simulink). The novelty in model interpretation today is that model driven methods provide efficiency and flexibility, which enable application of this concept to arbitrary problem domains.

In a series of blogs we will illustrate this novel aspect and provide an example of model interpretation. Specifically this article will illustrate 1) how a custom modeling language (DSL) is developed for an arbitrary problem domain and 2) how a system behavior can be specified with the DSL and directly interpreted without any intermediate transformation steps. In a followup article we will show how a custom model interpreter can be efficiently built using a model driven method.

Model Interpretation As System

Traditional generative approaches like Model Driven Architecture (MDA) prescribe an (automated) code generation process that takes a system model as input and eventually produces code that implements the specified system. The system comes to existence when the code is executed.

Alternatively, the code generation process can be skipped and a system model be executed directly.  Model Interpretation achieves such direct execution by means of a model interpreter. In this case the system comes to existence when the model is being interpreted. Thereby system behavior is completely defined by the model being interpreted.

Fig. 1 illustrates a possible approach to model interpretation of event-driven systems.  An event-driven system exhibits behavior by generating (external) events in reaction to incoming external events. Therefore, the interpreter should support two-way event communication with the context. An example of an incoming external event is arrival of a positive signal from a motion sensor for an automated door. An outgoing external event could be a command to an actuator to open the door.

Screen shot 2010-10-04 at 9.07.01 PM

Figure 1: An approach to system as model interpretation

In the figure, entities are shown as boxes and their roles w.r.t.  each other are shown in italic. Given that a domain-specific language (DSL) and an interpreter already exist, a domain expert uses the DSL to specify a system and its events at development time. Moving to the run-time, the same model (system configuration) represents the system and its events. During model execution, the interpreter reads system state from the model and interprets system events according to the semantics of the events. Interpretation may change the state of the system by changing the system configuration at run time, and communicate external events to the system’s context.

Typically a sequence of external events is provided by the context of the system. Alternatively, these events can be specified in the system model and consequently generated by the interpreter itself (in this case, system behavior is simulated).

Domain

Today model interpretation can be applied to an arbitrary problem domain. To reflect this freedom, we chose a minor and uncommon weighbridge domain, whose purpose is to measure weight of vehicles.

The following is a typical weighbridge scenario: One or more delivery vans arriving (at a factory) must pass over a weighbridge on entry. A weighbridge accepts one van at a time and each weighing operation takes a certain amount of time. If the weighbridge is busy, arriving vans join the waiting queue to the bridge. When the weighbridge becomes available again, the first van in the waiting queue drives over the bridge.

This domain is characterized by a number of inherent variations, such as number of weighbridges, weighbridge capacity, weighing operation duration, number of arriving vans, arrival times of vans, etc.. The result is that a multitude of weighbridge system configurations are possible and per configuration a multitude of dynamic van arrival and weighing scenarios can play out.

A weighbridge system modeled in a DSL

Figure 2: A weighbridge system modeled in a DSL

Figure 2 shows a simplified weighbridge system configuration, originally described by Birtwistle and Tofts [1]. Yellow boxes are vans. The large blue box is a weighbridge and green entities are a van arrival queue (EL) at the factory and a van waiting queue (Delay) at a weighbridge. As you can see the factory’s configuration has a single weighbridge W, which is free at this time. Finally, three delivery vans V1, V2 and Main have arrived (external events). An execution of this model is illustrated further in the article. An AToM3 implementation of a DSL for the domain is briefly described next.

Weighbridge DSL

The earlier mentioned freedom of application depends on flexibility and efficient adaptation of model interpreters to new domains. Model driven methods achieve this flexibility through metamodeling. If you are not familiar with metamodeling, you can skip this section as it is not required for understanding the demo.

A DSL is defined with abstract syntax, concrete syntax, static semantics and dynamic semantics. (Such a definition is known as metamodel.) Behind every DSL is a modeling paradigm that gives fundamental guidelines for metamodeling. In case of the weighbridge domain, a proper modeling paradigm is Process Interaction [2].

PI Metamodel

Figure 3: PI Metamodel

For the purposes of this demo, a PI modeling language will suffice  and we will reuse and extend a PI metamodel developed by Juan de Lara [3]. We just have to keep in mind that Process and Resource in Juan’s metamodel correspond to van and weighbridge concepts in the demo domain. The abstract syntax of the PI DSL is illustrated in Figure 3. The concrete syntax of this DSL is illustrated in Figure 2. We skip static semantics (in other words, business rules) as the focus of the domain is interpretation, not domain modeling. The following is a brief description of the key PI concepts:

Resource is a synonym for the Weighbridge concept. A weighbridge has the following attributes:

Name is a unique identifier of Weighbridge: String

State denotes availability of Weighbridge: Enum{idle, busy}

Tproc is typical duration of weighing service: Time (used in simulated execution)

Capacity denotes capability to weigh multiple vans at the same time: [1..N]

Load denotes weighbridge’s capacity occupied with served vans: [0..Capacity]

Process is a synonym of the Van concept. A van has the following attributes:

Name is a unique identifier of Van: String

Tcreation is time-stamp of Van’s arrival event: Time

Tinitproc is the start time of weighing operation: Time

Tendproc is the end time of weighing operation: Time

Body is a sequence of tasks: sequence{task} (tasks examples are bridge access, van weighing, bridge exit, etc.)

EVnext is the iterator for tasks in body: [0..N]

For simulation purposes, additional concepts are defined:

Time is a clock for simulated time.

ProcIntGenerator specifies time intervals between van arrivals.

Finally, to assist visualization of system state, the original metamodel was extended with additional relationship:

manageElement specifies an operation (append, insert or remove) on an element (target end of this relationship) of a sequence (source end of this relationship).

The final touch of DSL definition is dynamic semantics (meaning of DSL concepts). In the model interpretation approach, such semantics is defined in an interpreter. In case of a DSL and a pure interpretive approach there is a good chance that an interpreter exactly matching the DSL will need to be developed. More so if the interpreter has to meet additional specific requirements. In our case, such requirements were run-time visualization of system behavior and interpreter integration with the factory context (not covered in this article). In a followup article we will show how a custom model interpreter can be developed. Incidentally our development approach is also based on model interpretation.

Run Time Example

A picture is worth a thousand words. With that in mind an illustration of model interpretation is best done with a video. The following screencast shows execution of the weighbridge system configuration introduced earlier (see Figure 2). For the sake of visualization, execution is carried out in the step-by-step mode and displays how the state of the weighbridge configuration changes in response to events.

Conclusions

In our experience model interpretation is characterized by very fast development times. In fact it did not even feel like development at all as domain experts are completely shielded from all incidental technical details.  I believe that Birtwistle and Tofts, the scientists that coined the weighbridge benchmark, would feel at home with the demonstrated DSL and the interpreter in no time. With incidental complexity out of the equation and direct involvement of domain experts, I think we’ve come very close to the essential complexity of the domain and development times cannot be drastically improved any more. That said, I feel that those interested in this approach should be aware of run-time performance penalty due to interpreter indirection. Whether this will pose a problem, depends on the application domain.

What are your experiences with model interpretation? What is your domain?

References

[1] Graham Birtwistle and Chris Tofts. An operational semantics of process-oriented simulation languages: Part 1 πDemos. ACM Transactions on Modeling and Computer Simulation, 10(4):299–333, December 1994.

[2] Jerry Banks, editor. Handbook Of Simulation. Principles, Methodology, Advances, Applications, and Practice, pages 813 – 833. Wiley-Interscience Publication, New York, September 1998.

[3] Juan de Lara. Simulacio ́n educativa mediante meta-modelado y grama ́ticas de grafos. Revista de Ensen ̃anza y Tecnolog ́ıa, 23, Mayo-Agosto 2002.

, ,

4 reacties

Being a .NET developer in a Mac OSX world: serializing XmlDates

I blogged before on differences in implementation between the Mono and the Microsoft implementation of the .NET framework. In this post I investigate a difference in XmlSerialization.

Dates in XSD

When you write an XSD you have (at least) 3 options to use dates and/or times:

Most of the time you probably choose the “dateTime”, since that maps nicely to the DateTime type in .NET. But you might choose “date” for a birthday for example, and you might even choose “time” for uh, well for a time of some sort…

For his post I’ll use the following XSD. It’s a bit contrived but I like this better than “MyDate” and “ADateTimeField”:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="Book" type="BookType"></xsd:element>
 
  <xsd:complexType name="BookType">
    <xsd:sequence>
      <xsd:element name="Title" type="xsd:string"/>
      <xsd:element name="Price" type="xsd:float" nillable="true"/>
      <xsd:element name="PrintedAt" type="xsd:date"/>
      <xsd:element name="SoldAt" type="xsd:dateTime"/>
      <xsd:element name="WillReadTodayAt" type="xsd:time"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

Generate classes from your XSD

Both Mono and Microsoft have command-line tools that generate classes from your XSD. Very convenient and a good thing to do when you need simple entities. We did this in a project where we had both C# and Java code. On both sides we generated the classes from the same XSD.

The syntax of both tools is more or less the same:

xsd book.xsd /classes /namespace:BookStore.Books

will work on both systems.
The outcome of both generators is quite different. The Mono version uses public fields, the MS version use properties with back-up private fields. They both adorn the fields/properties with attributes from the XmlSerialization namespace.
For Microsoft it looks like this:

namespace BookStore.Books {
    using System.Xml.Serialization;
 
    ///
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlRootAttribute("Book", Namespace="", IsNullable=false)]
    public partial class BookType {
 
        private string titleField;
        private System.Nullable priceField;
        private System.DateTime printedAtField;
        private System.DateTime soldAtField;
        private System.DateTime willReadTodayAtField;
 
        ///
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Title {
            get {
                return this.titleField;
            }
            set {
                this.titleField = value;
            }
        }
 
        ///
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=true)]
        public System.Nullable Price {
            get {
                return this.priceField;
            }
            set {
                this.priceField = value;
            }
        }
 
        ///
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="date")]
        public System.DateTime PrintedAt {
            get {
                return this.printedAtField;
            }
            set {
                this.printedAtField = value;
            }
        }
 
        ///
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public System.DateTime SoldAt {
            get {
                return this.soldAtField;
            }
            set {
                this.soldAtField = value;
            }
        }
 
        ///
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="time")]
        public System.DateTime WillReadTodayAt {
            get {
                return this.willReadTodayAtField;
            }
            set {
                this.willReadTodayAtField = value;
            }
        }
    }
}

That could have been a bit more readable by removing all the fully-qualified namespaces (since there is a “using” at the top), the empty comments and the back-up fields (if you generate for .NET after version 3).

For Mono it is like this:

namespace BookStore.Books {
 
    ///
    [System.Xml.Serialization.XmlRootAttribute("Book", Namespace="", IsNullable=false)]
    public class BookType {
 
        ///
        public string Title;
 
        ///
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public System.Single Price;
 
        ///
        [System.Xml.Serialization.XmlElementAttribute(DataType="date")]
        public System.DateTime PrintedAt;
 
        ///
        public System.DateTime SoldAt;
 
        ///
        [System.Xml.Serialization.XmlElementAttribute(DataType="time")]
        public System.DateTime WillReadTodayAt;
    }
}

Much more concise. But with an important omission: the Price has the right XmlAttribute, but should have been defined as “Nullable”. I’ve seen some remarks on this in the mailing-list/forum for Mono, but could not find out if this was already fixed. So I use the Microsoft XSD.exe whenever my XSD changes, copy paste the result to my MonoDevelop environment and recompile. I would rather call the MonoXSD on the background whenever my XSD changes (has anyone used scripts as Custom Tools in MonoDevelop?) so that the class gets re-generated automatically. Maybe the upcoming Mono 2.8 will fix it.

It’s all a DateTime

As you can see, all the fields are generated as DateTimes. Makes sense, since there is nothing else in the framework to hold time-related information. So what happens when you read an Xml file and serialize the Xml into a Book object?

Take this Xml:

<Book>
    <Title>How to be a Mac Developer</Title>
    <PrintedAt>1965-02-16</PrintedAt>
    <SoldAt>1965-02-16</SoldAt>
    <WillReadTodayAt>11:00:01</WillReadTodayAt>
</Book>

And process it with this code:

    class MainClass
    {
        public static void Main (string[] args)
        {
            string bookXml = @"
            <Book>
                <Title>How to be a Mac Developer</Title>
                <PrintedAt>1965-02-16</PrintedAt>
                <SoldAt>1965-02-16</SoldAt>
                <WillReadTodayAt>11:00:01</WillReadTodayAt>
            </Book>
            ";
 
            BookType book = (BookType) ToObject(bookXml, typeof(BookType), Encoding.Default);
            Console.WriteLine("PrintedAt:{0}", book.PrintedAt);
            Console.WriteLine("SoldAt:{0}", book.SoldAt);
            Console.WriteLine("WillReadAt:{0}", book.WillReadTodayAt);
            Console.ReadLine();
        }
 
        public static object ToObject(string xml, Type xmlObjectType, Encoding encoding)
        {
            MemoryStream xmlStream = new MemoryStream(encoding.GetBytes(xml));
            StreamReader reader = new StreamReader(xmlStream, encoding, false);
            XmlReaderSettings readerSettings = new XmlReaderSettings();
            readerSettings.CloseInput = true;
            XmlReader xmlReader = XmlReader.Create(reader, readerSettings);
            XmlSerializer xmlSerializer = new XmlSerializer(xmlObjectType);
            return xmlSerializer.Deserialize(xmlReader);
        }
    }

Different ideas on default dates

You get this output in Windows (running the exe build by MonoDevelop directly on my VMWare-WindozeXP):
Screen shot 2010-09-21 at 11.26.27 AM

And this output on the Mac:
Screen shot 2010-09-21 at 11.30.34 AM

Interesting difference, right? Windows sets the date part of “WillReadTodayAt” to DateTime.MinValue and Mono assumes it is today. It doesn’t matter that much, since I’m going to ignore the date-part anyway for that property.
The time part of the date-olny property “PrintedAt” is set to “12:00:00AM” in Windows and “00:00:00″ in Mono. Again, I’m going to ignore the time-part, but what will happen when I compare dates for equality? I prefer the Mono setting.

Invalid time data

Take this slightly modified Xml:

<Book>
    <Title>How to be a Mac Developer</Title>
    <PrintedAt>1965-02-16</PrintedAt>
    <WillReadTodayAt>2010-09-21T11:00:01</WillReadTodayAt>
    <SoldAt>1965-02-16</SoldAt>
</Book>

Running this on Mono result in an FormatException: Screen shot 2010-09-21 at 11.41.53 AM
Fair enough, the data in the xml is not a Time, it is a DateTime. So an exception makes sense.

Wonder what Windows will do? After you have started an instance of Visual Studio to see the error, you get this:
Screen shot 2010-09-21 at 11.45.46 AM

So both platforms agree that the data is invalid. Unfortunately the position that Windows gives us is right after the offending data, at not before as I was expecting. So it took some time (way more than an hour) to realize that the problem was not in the “SoldAt”, but in the “WillReadTodayAt” just before it. Be warned.

Invalid date data

Now pass in a date-with-time on the field that expects only a date:

<Book>
    <Title>How to be a Mac Developer</Title>
    <PrintedAt>1965-02-16T08:01:03</PrintedAt>
    <WillReadTodayAt>11:00:01</WillReadTodayAt>
    <SoldAt>1965-02-16T09:00:02</SoldAt>
</Book>

Mono doesn’t like it. Same error as before, no indication on what line and what xml-tag, alas.
Windows doesn’t like it either. Same error as before, positioned right before “WillReadTodayAt”.

Conclusions

There’s a big difference in the C# classes that get generated. The Mono implementation is missing the support for nullables, the MS implementation is a bit too verbose.
The handling of incorrect date/time information is okay in both systems.
The date-part in a xsd:time gets defaulted to “1-1-1″ in MS and “today” in Mono. The time-part gets defaulted to “0:0:0″ in Mono and “12:0:0AM” in MS.

The code for this article

, , ,

Nog geen reacties

Uncle Bob in da house: how to write clean code

Gisterenavond (16 september) was Arnhem in de gelukkige omstandigheid dat Robert C. Martin de uitnodiging had aangenomen van de HAN om een verhaal te komen houden. Het onderwerp: Clean Code.

Robert Martin (die ook schrijft onder de naam Uncle Bob) is een geweldige spreker en een wereldberoemd schrijver van publicaties over software craftmanship. Hij is dermate gepassioneerd over het op een hoger niveau brengen van ons vak, dat hij zelfs voor een groepje jonge engineers die de schoolbanken nog niet hebben verlaten een vlammend betoog komt houden.

Hij raasde in een uur tijd door zijn slides over Clean Code heen, lardeerde dat met leuke verhalen en analogieën en onderbouwde zijn betoog met praktijk voorbeelden. Hieronder een greep uit de tips die we kregen over het schrijven van functies.

Leesbaarheid

Eigenlijk gaan alle onderstaande tips over de leesbaarheid van de code. Iemand die jouw code ziet (en dat kun je ook goed zelf zijn) moet met lichte verveling van boven naar beneden door je code kunnen gaan, waarbij de code steeds gedetailleerder wordt.
- “Ja”
- “Mmmh, mmh”
- “Duidelijk”
- “Ja”
- “Logisch”
Totdat de code een nivo van detaillering bereikt dat je als lezer denkt “Ja, ja, nu begrijp ik het wel. Saai”. Dan heb je het goed gedaan. Saaie code, waar niemand lang bij hoeft stilt te staan (want daar heb je gewoon geen tijd voor). Niemand zit te wachten op briljante code, behalve jouw ego. Briljante code is de eerste code die ik vervang als ik onderhoud moet doen; vervang door saaie, begrijpelijke code.

Descriptive names

Gebruik een naam voor je functie die zegt wat de functie doet. Dus niet “Process()” maar “AddOrderLineToOrder()”.

Do One Thing

Een functie moet slechts 1 ding doen. Als een functie 2 dingen doet, moet je ‘m in 2 functies opdelen. De functie “AddOrderAndCalculateTotals()” wordt dan dus “AddOrder()” en “CalculateTotalsForOrder()”.

Small functions

Functies mogen niet meer dan 4 regels lang zijn (tussen de accolades). Het liefst 2 of 3, maar als het echt moet dan kan 4 ook. Een functie moet eigenlijk niet veel meer doen dan bijvoorbeeld een test uitvoeren in een if-statement en dan een andere functie aanroepen. En de test in de if is natuurlijk ook een functie.
Hoe kom je aan kleine functies? Die kun je niet van scratch af aan maken. Je maakt eerst je bekende grote bak code van wel 20 of 30 regels, zodat je je test aan de praat kan krijgen (je weet wel “Red-Green-Refactor”). Daarna ga je je grote functie opknippen met een van de standaard Refactor-tools die jouw IDE ondersteunt, meestal “ExtractMethod” geheten. En na elke ExtractMethod draai je je tests om te weten of je niets stuk gemaakt hebt.

No error codes

Functies moeten exceptions gebruiken en try/catch blocks. Binnen een try moet bij voorkeur 1 regel code staan: de aanroep van een functie.
Return-codes zijn om iets nuttigs terug te geven aan de aanroepende code, bijvoorbeeld een Boolean als je functie “IsValidDate()” heet, maar niet om te laten weten dat er iets is mis gegaan. Error-codes leiden tot veel geneste if’s en tot out-parameters (zie verderop).

No more than 3 parameters

Een functie heeft bij voorkeur geen parameters, dat leest het makkelijkst, maar is niet zo realistisch. Als een functie meer data dan 3 parameters nodig heeft om zijn werk te kunnen doen, moet je gaan refactoren. Waarschijnlijk hoort al die data bij elkaar in één class.

No out-parameters and no boolean-parameters

Een functie heeft dingen aan de rechterkant (parameters) die erin gaan en een ding aan de linkerkant (return-value) die eruit komt. Als er dingen aan de rechterkant uitkomen verwar je de lezer enorm. Tijd voor een refactoring.
Booleans lezen helemaal moeilijk en verraden dat je eigenlijk een functie hebt die 2 dingen doet, gestuurd door de vlag die je erin stop.
Wat doet het onderstaande?

var html = GetHtmlForControl(button, true)

Zou het niet beter zijn om 2 functies te hebben die beter laten zien wat ze doen?

private string GetUnformattedHtmlForControl(button)
{ ... }
private string GetFormattedHtmlForControl(button)
{ ... }

Unit tests

Als je geen unit-test hebt kun je nooit bewijzen (voor jezelf, je teamgenoten of je baas) dat de code die je gemaakt hebt echt werkt.
Accountants controleren hun eigen werk door elke boeking 2 keer op te nemen: één keer aan de debet kant en één keer aan de credit kant. Onderaan moet dan nul staan. Je kunt nog steeds de pech hebben dat je twee fouten hebt gemaakt die elkaar precies opheffen, maar die kans is niet zo groot. In ieder geval heb je een Standard Practice toegepast.
Dat kunnen wij software-engineers minstens even goed doen. Code schrijven en tests schrijven.

Design Patterns

DesignPatternsKen je patterns. Het boek van de Gamma et al is volgens Robert Martin het belangrijkste boek dat de afgelopen 20 jaar is geschreven op het gebied van software design.

Maar daar hebben we geen tijd voor!

Je zult het zelf misschien onmiddellijke roepen als je bovenstaande hebt gelezen: “Allemaal leuk en aardig, en ja, ik wil goeie code schrijven, maar het moet af, ik heb hier echt geen tijd voor”.
Fout. Als je het op bovenstaande manier doet, houd je tijd over. Om de simpele reden dat iedereen gedurende het project zijn bestaande code moet uitbreiden, aanpassen, verbeteren of overdragen. Als je clean-code schrijft dan kost dat wroeten in je eigen code je veel minder tijd dan wanneer je de gebruikelijke bak spaghetti heb geschreven. En omdat je unit-tests hebt, weet je ook dat je aanpassing niets stuk gemaakt heeft.

Robert Martin haalde het voorbeeld aan van Hongaarse arts Ignaz Semmelweis die ontdekte dat het aantal vrouwen dat overleed in het kraambed van 8 op de 10 zakte naar 1 op de 100 als je eerst je handen waste nadat je een autopsie had gedaan. Hij begreep niet waarom, maar stelde onomstotelijk vast dat het werkte. Desalniettemin duurde het tot vele jaren na zijn dood voordat deze activiteit tot het standaard repertoire van de arts ging behoren.

Zou jij tegen je chirurg zeggen vlak voordat je de operatiekamer ingereden werd “Laat dat handen wassen maar achterwegen hoor, daar heb je helemaal geen tijd voor”? Vast niet. En omgekeerd? Als jouw patiënt dat zou zeggen, zou je dan naar hem luisteren?
In jouw vak ben jij de chirurg en is je opdrachtgever degene die onder het mes gaat.

Word een professional

Wij zijn geen loonwerkers, ons werk is niet te vergelijken met het op elkaar stapelen van stenen. En onze verantwoordelijkheid gaat verder dan “maar hij heeft gezegd dat dat zo moest”. Als professional heb je de plicht om tegen je opdrachtgever/klant/baas “nee” te zeggen als hij/zij vraagt om iets slechts af te leveren.
- “Kun je het niet zonder tests?”
- “Nee”
- “Maar daar hebben we geen tijd voor!”
- “Dus er mogen bugs zitten in mijn werk?”
- “Uh, nou ja, het hoeft niet perfect te zijn”
- “Als er bugs in mogen zitten, dan ben ik klaar wanneer je wilt. Nu al, feitelijk”
- “Kom op, je begrijpt best wat ik bedoel”
- “Nee, wil je nou dat ik m’n handen was of niet?”
- …..?

, ,

3 reacties

Being a .NET developer in a Mac OSX world: storing null values in a database

In this post I want to shine a light on a different aspect of developing on one OS to deliver on a different OS: different implementations of the .NET framework can have different behaviour. What runs on one, might crash on the other. That happened to me when accessing my SQL Server database using ADO.NET.

Storing data using plain ADO.NET

Ok, you might argue that there is no need to talk about plain ADO.NET, since nobody in his right mind is actually doing that anymore. Of course we -developers- have evolved and use document-databases like CouchDB and Raven DB or ORMs like NHibernate and Entity Framewok.

But every now and then you need code like the code below. In my case because we were building a demo and needed to be done quickly. Which we were not, because of the problems I ran into when trying to store null values in the database.

Book book = new Book {
	Id = Guid.NewGuid(),
	ISBN = "123-456-222",
	Title = "Through the looking glass"
};
 
using (SqlConnection connection = new SqlConnection ("some connections string")) {
	connection.Open ();
	using (SqlCommand cmd = connection.CreateCommand ()) {
		cmd.CommandText = @"INSERT INTO Book ([Id], [ISBN], [Title], [Publisher], [SuggestedPrice])
		       VALUES (@Id, @ISBN, @Title, @Publisher, @SuggestedPrice)";
 
		cmd.Parameters.AddWithValue ("@Id", book.Id);
		cmd.Parameters.AddWithValue ("@ISBN", book.ISBN);
		cmd.Parameters.AddWithValue ("@Title", book.Title);
		cmd.Parameters.AddWithValue ("@Publisher", book.Publisher);
		cmd.Parameters.AddWithValue ("@SuggestedPrice", book.RetailPrice);
 
		var rowsAffected = cmd.ExecuteNonQuery();
		if (rowsAffected == 0)
		{
			Console.WriteLine("No rows inserted!");
		}
	}
}

The sql to create the table is like this:

CREATE TABLE Book (
	Id			uniqueidentifier	NOT NULL,
	ISBN			varchar(255)		NOT NULL,
	Title			varchar	(128)	NOT NULL,
	Publisher		varchar	(128)	NULL,
	SuggestedPrice	money 			NULL
) ON [PRIMARY]

Finally the Book class is this:

class Book
{
	public Guid Id {
		get;
		set;
	}
 
	public string ISBN {
		get;
		set;
	}
 
	public string Title {
		get;
		set;
	}
 
	public string Publisher {
		get;
		set;
	}
 
	public decimal? RetailPrice {
		get;
		set;
	}
}
}

The reason to use SqlXXXX objects in stead of programming against interfaces like IDbConnection and IDbCommand is that I know I have a SQL Server database and will not change that in the course of this project and the fact that I have this nice simple syntax for setting parameters on the Command object:

cmd.Parameters.AddWithValue ("@Title", book.Title);

The AddWithValue-method is not on the IDbCommand interface, but is available as a public method on the SqlCommand class.

The book object comes from somewhere outside of this piece of code normally, and I cannot make any assumptions on the properties that are filled or not. For example the RetailPrice property is a nullable decimal, so it might therefore be null. No problem, since the database column SuggestedPrice is also nullable.

No problem? No problem in Mono. Run this code in MonoDevelop and store a book with a null value for the retaill-price and the publisher. Sweet.

A problem on Windows

Copy this code (or the compiled assemblies) to your Windows VM and run it there. You get an exception:
SqlException
Why is that? Why would .NET complain about the Publisher parameter, suggesting it is not there? It contains a null value, right, but the parameter itself is there anyway.

So the message itself is confusing. It took me quite some time (and the use of the great SqlProfiler from AnjLab) to find out that the problem was in the null values. That must have happened to other people before. So Google to the rescue? Even that took some time before I found a thread on a PC Review forum from 2005 that suggested to go through all the parameters in your command to see if they are null or not and then set them to DBNull.

The platform independent version

Are you kidding me? Every time and everywhere I have a Command object and add Parameters to it, I must go through all the parameters like this?

foreach (SqlParameter parameter in cmd.Parameters)
{
    if (parameter.Value == null)
    {
        parameter.Value = DBNull.Value;
    }
}

And that has been like that since .NET 2.0? No improvements in the last 5 years? Probably, the reason you haven’t bumped into this problem lately, is that you have been using NHibernate (I did) and that solved it for you. I haven’t tried it with Entity Framework yet, but I guess that would solve it too.

I really think Mono does a better job here. When I set a parameter on a DbCommand object to null, I expect that object to translate that null value to something that the database understands. As is does for any other value.

Download the code

P.S. At one time in the process of finding a solution , I got so frustrated with Microsoft .NET and Visual Studio 2008 (since that somehow stopped building properly) that I decided to run Mono on Windows too. It took me 5 minutes to download and install Mono on my VM, then 5 more minutes to discover the existence of XPS (the Mono web-server) and I had my webservice running! Unfortunately, that was not an option for our production server, but to me it proved that the guys at Mono do a really good job.

, , ,

Nog geen reacties

Being a .NET developer in a Mac OSX world: connecting Mono to SQL Server

How did I get here?

I’m a long time Windows developer. Started with VB3 en FoxPro and such, and couldn’t imagine needing another plaform. Like the Mac that my geeky artistic brother-in-law loved so much. Windows was cool and I knew all about it and the Mac was for people that didn’t know how to use a PC.

The dawn of a new era

Then I came with my current employer and they provided a mobile phone and a laptop of course (like all companies in Dutch IT do). But this was about an iPhone and a MacBook Pro.
I decided to leave OSX on the machine, although I could have erased the disk and installed Windows Something, it’s got an Intel processor after all.
But leaving OSX on it, meant I had to install VMWare and run Windows and Visual Studio and such within that. And even though my machine is pretty fast, you notice the performance hit.

I kept trying, and started to like OSX and the applications on it. But what I liked most of all: hardly any updates and no reboots. I shut down my machine once a week or once every two weeks because I feel it’s something I should do. But I don’t have to: OSX keeps on running. Just close the lid, simply know that everything is suspended and know that everything will run as before when you open the lid the next day.

Amazing! I would shut down my Windows machine every night, just to make sure I had a stable system the next morning. My wife still has a Windows machine and to ensure that she makes backups every day, we configured the backup software to run “on system shutdown”. Because that is what you do every day, as a Windows user.

And then there was Mono

I’ve written about the Mono project before, albeit in the context of MonoTouch and iPhone development. Mono brings .NET to a lot of platforms, including Mac OSX. And it is really good. The Mono team is really close behind the Microsoft team in porting new API’s and Framework versions. .NET 4.0 is recently available on Windows, but Mono is already compatible.
And the amazing thing is that you can take your Windows assemblies and use them straight away on OSX! That might not be very imported for assemblies that you have the sources for, but it is very convenient for third party libraries you use, like log4net (although that has a Mono version) and Rhino Mocks.
And one of the best things the Mono team delivers is MonoDevelop: an excellent IDE for .NET development that will feel really comfortable when you come from Visual Studio.

Being a .NET developer, not necessarily a Windows developer

I still like the .NET framework, but I no longer feel that automatically implies I am a Windows developer. There are so many good tools that allow you to do everything on the Mac that you are normally doing on Windows. So I decided that in the new project I recently started (in which we will deliver on Windows) I will try to go as far as possible to develop my code on Mac OSX.
I will blog about my experiences in a series of posts. This first one is about connecting to SQL Server.

I can’t do without SQL Server

We will deliver our project an a SQL Server database, so it makes sense to use that during development also. It’s not that you have to, there are other options. If you have something like a nice Data Access Layer, you can run any SQLLite or MySql database and easily move to SQL Server later.
There also is a file-based no-install version of SQL Server these days that might run on Mono. Haven’t tried it yet, but could be promising.
But if you need SQL Server, you can still work in MonoDevelop in your comfortable Mac environment.

Inside the VM

SQL Server will run on Windows in your VM, but that will be the only thing you’ll need your VM for. SImply minimize the window after all the configuration is done and don’t think about it anymore.

Step one: opening up your Windows

You need access to your VM from your Mac, so you have to open up some things.

Go into Control Panel and choose Windows Firewall. Go to the advanced tab and add some ports. Port 1433 for SQL Server over TCP/IP and port 1434 for SQL Server over UDP. Maybe you can do without the UDP version, haven’t tried yet.

Firewall Exceptions

Step two: configure SQL Server

First, make sure the SQL browser is running.

SQL Browser

Then enable TCP/IP in the Client Protocols

Protocols

And check that the Default Port is on 1433.

Poort

In SQL Server Management Console open the properties of the server and make sure you have mixed authentication.

Mixed Authentication

Step three: connect from your code or MonoDevelop

In your connection string use the IP-address of your VMWare instance. Something like

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<connectionStrings>
		<add name="dossiers" connectionString="Server=172.16.86.128;Database=mydefaultdatabase;User ID=sa;Password=bladiebla" providerName="System.Data.SqlClient"/>
	</connectionStrings>
</configuration>

That is! You can test your connection from MonoDevelop: Go to Tools/Database/Add database connection/SQL server:
MonoDevelopDatabaseTools
Screen shot 2010-07-18 at 9.33.05 PM

, , , ,

4 reacties