Tuesday, October 23, 2007

Model View Presenter Data Binding Part 2: The Model

In my Model-View-Presenter application, the Model is fairly simple, but can be extended to be more complicated (I guess that's really true for just about anything). I won't go into details on persistence, I'm going to concentrate on how I do the data binding. For the Model, I follow the same pattern for properties that I did on the View:
int _nThingy;
public int Thingy
{
   get
   {
       return _nThingy;
   }
   set
   {
       bool bChanged = (this.Thingy != value);
       _nThingy = value;
       if (bChanged) FireDataChanged("Thingy");
   }
}
The FireDataChanged(string) method will fire a PropertyChanged event for the specified property. When I'm working with collections, I create a class that inherits from BindingListBase (my custom .NET 1.1 class that implements IBindingList) or from System.ComponentModel.BindingList (when using .NET 2.0). Both IBindingList implementations will look for changes to each of the elements in the list and translate them to ListChanged events. This will make life really easy when binding to grids and lists. Oh yea, I almost forgot, there's one more piece that needs to be in place. The data object needs to implement IEditableObject. The MSDN documentation has an example on how to implement it. While this is deceptively simple, it does have some interesting consequences. Now, I can make changes to properties (with sheer impunity) and I can notify everyone else of all the changes that happen on the data objects. Here's an example: I have a program that lets the user define a set of tubular equipment that is laid end to end. Each piece of equipment has the following properties: Inner Diameter, Outer Diameter, Top Depth, Bottom Depth, Length. For the sake of simplicity, lets say they are all integers. For each equipment, Bottom Depth = Top Depth + Length. The equipment has to enforce this rule all the time. Also, when making adjustments, it should favor keeping the Length property constant. Here's how the properties end up looking:
public int TopDepth
{
   get { return _nTopDepth; }
   set
   {
       bool bChanged = (this.TopDepth != value);
       _nTopDepth = value;
       if (bChanged)
       {
           this.BottomDepth = this.TopDepth + this.Length;
           FireDataChanged("TopDepth");
       }
   }
}

public int BottomDepth
{
   get { return _nBottomDepth; }
   set
   {
       bool bChanged = (this.BottomDepth != value);
       _nBottomDepth = value;
       if (bChanged)
       {
           this.Length = this.BottomDepth - this.TopDepth;
           FireDataChanged("BottomDepth");
       }
   }
}

public int Length
{
   get { return _nLength; }
   set
   {
       bool bChanged = (this.Length != value);
       _nLength = value;
       if (bChanged)
       {
           this.BottomLength = this.TopDepth + this.Length;
           FireDataChanged("Length");
       }
   }
}
If I set any of these three properties, the others will be synced up until the system stabilizes. Also, setting any one property will not only make adjustments to another property, it will fire both notifications automatically. This is OK for a single piece of equipment, but we need to have some more interaction between the equipment. When the BottomDepth of a piece of equipment changes, the next equipment's TopDepth needs to change. When the TopDepth of a piece of equipment changes, the previous equipment's BottomDepth needs to change. To make this work, we hook into the ListChanged event on the BindingList and look at the ListChangedEventArgs.PropertyDescriptor property. If the change was BottomDepth or TopDepth, we make a change to the appropriate item. We have to take care of all the different types of ListChanged events: ItemAdded, ItemChanged, ItemDeleted, ItemMoved, and Reset. In each case, we make sure the adjacent TopDepth/BottomDepth pairs match up on the changed equipment. Once all the pieces are in place, I just need to create a list, add some items to it, then set the DataSource property of a DataGridView, sit back, and watch the magic. If you edit the TopDepth, Length, or BottomDepth columns, then the model will make the adjustments and the DataGridView will be automatically updated. Also, you can assign the same list instance to another DataGridView, then the two grids will be synchronized automagically. This is the basis for the Model layer of the Model View Presenter architecture. Using these techniques, we can bind any collection of data fearlessly to any UI component as well as binding properties with each other.

Monday, October 08, 2007

ALT.NET Conference Sessions: Architecture

I rummaged Technorati and looks like a lot of people already put up their summaries / impressions of the sessions at the ALT.NET Conference in Austin, TX. Here's some more about some of the sessions that I'm not seeing much discussion about: Architecture (Trends and Observations) The architecture chat started off a little sparse, but fattened up nicely fairly quickly. Aaron Armstrong was driving the conversation to see what people were seeing in architectures. There were a lot of familiar terms on the whiteboard (I can't really remember them all, did anyone write this down?) I stood up and talked about the Model-View-Presenter architecture of the WinForms application I'm working on at work (picture 1, picture 2). I have a post about it that I'm planning to turn into a series of posts with some code and stuff. There was some interest in the data binding work I was doing, too. I'll talk more about that later. The main point that I was trying to make was that you can have multiple Models that don't know anything about the Views and are tied together using the Presenters. You can have multiple Models aggregated (in whole or partially) into one or more Views. Aaron asked how someone would handle the scenario where you have a composite View in a WinForms application. The approach I would use would be to expose the different sub-Views on the composite View as properties and use an Inversion of Control framework to tie it all together. In the application I'm working on, I'm using Spring.NET to tie everything together (coincidentally, Mark Pollack was in the back of the room). My property data binding would then keep everything in sync. The conversation then moved to more distributed architectures and web-related systems. There was some mention of the technique of using commodity hardware and/or software to create cheaply replaceable systems. On a similar note, Amazon released a white paper (papers?) on "Dynamo", their network architecture. It is designed with the simple fact that hardware will fail and needs to be easily (and cheaply) replaceable. We also talked about Service-Oriented Architecture and what to do about data. Some people feel compelled to integrate all the databases and data sources into one unified database. This leads to some friction as the different functions of the system move forward. When the data stores are properly separated, then the needs of the different applications (or services) can be met without affecting other applications (or services) that may be using the same data store. Everyone agreed that the database should not be used as an integration tool. Someone (I forget who) also explained the idea of thinking of the data flowing through the distributed system as a "document" instead of just messages going back and forth. We also talked a little about how to have a good architecture while still doing agile development. Agile development is against "Big Design Up Front", but sometimes you will need to have a vision and an architecture to scale properly. The main idea is to keep the architecture simple at first, get the project working, then make refinements as needed. Don't optimize too early, otherwise you may end up debugging strange issues that would not have risen from a simpler design. Also, you can more easily optimize when you start from a simple design and you can do small steps at a time to keep the system stable as you try to improve performance. That's all I can remember off the top of my head. I'm sure others will fill in the gaps and make corrections. All in all, it was a very interesting talk. Software Architecture is one of the subjects that I am very interested in and I found it very invigorating to hear from others and their thoughts on architecture.

ALT.NET Conference Sessions: DSL

I rummaged Technorati and looks like a lot of people already put up their summaries / impressions of the sessions at the ALT.NET Conference in Austin, TX. Here's some more about some of the sessions that I'm not seeing much discussion about: Domain-Specific Languages for Business Users / Developers The DSL talk started off a little rough (the organizer wasn't there), but Arafat Mohamed stepped up and started the conversation. Just about everyone in the room was there to learn about DSLs and were not really using them in their projects. We talked about what we thought a DSL really was. It seems that just about anything can be a DSL (depending on how specific you are to what domain). According to Martin Fowler, "a domain-specific language is a veneer over an API" (I think that's the verbage he used). He differentiates between an internal DSL (one that is consumed by developers) versus an external DSL (one that is consumed by the users). Martin Fowler has some more information on his website. There is also some information on Wikipedia. One of the primary applications for DSLs that I can think of is a business rules engine. For example, you have a cell phone provider who has complex billing semantics and wants to be able to add new rules easily. There are a lot of concerns with this, however. Developers may not want the analysts modifying the behavior of the system as they may not be as disciplined. On the flip side, managers want the analysts to do the work to keep the developer freed up. It is a delicate balance that can only really be helped by properly training the analysts so that they know the proper practices. You can also avoid problems by creating the proper tooling. Going to the more practical side... Scott Guthrie pointed out that IL had some pragmas that could be used to give the debugger hints on what the original source file was and what line of that source file corresponds to the generated code. He said that they used this mechanism for debugging the generated code from XAML, XOML and the other declarative constructs. You could also use Boo as a meta-language to construct your DSL. In theory, Visual Studio should be able to debug Boo since Boo compiled to IL and _should_ have the line numbers and source file information embedded in the PDB files. (in theory). Boo is also the source of Boobs (the build system with an oral fixation) and Binsor. Oren (Ayende) has a lot of posts regarding Boo. Also, if you want good IDE support for Boo, look at SharpDevelop. If you need to develop your own language from scratch, Antlr seems to be the way to go. The people in the room who had used it said it was better than the old-school lexx / yacc approach. There are a lot of concerns though in creating a DSL in that you would have to maintain it and train everyone how to use it. This reminds me of two things: 1) Wasabi, the language created by Joel Spolsky for FogBugz (linky) 2) The MUMPS System (linky) In both cases, developers will basically have a bunch of work that they can't really put on their resume because their expertise is in an in-house language. A DSL may create the same sort of situation. Also, whoever develops the DSL will be the authority on it and if he/she decides to leave the company without properly documenting it, the DSL will be useless. At the end of the session, I think everyone got a good feel for the positives and negatives of creating and using domain-specific languages. I learned that I would need to think long and hard before considering implementing a DSL and that there are a lot of solutions (Boo, Ruby, scripting) that would require a lot less work up front and would provide fellow developers with some take-aways. Another summary on the DSL session: David Woods

Sunday, October 07, 2007

Back from ALT.NET Conference

I just got back from ALT.NET Conference (http://www.altnetconf.com/) in Austin and it was a blast. I've only been to a few other "conferences" but this is the only one that I would actually consider a "conference" more than a one-way brain dump. I met a lot of interesting people who I've been reading about, but didn't really know. Everyone is really passionate about their work and they have strong opinions (that are not really set in stone). Everyone was very receptive to alternative techniques, theories and interpretations. I'm looking forward to participating more in this community. I would also like to thank everyone for being there and making my weekend spectacular! And also to thank the organizers for giving us such a unique and fulfilling opportunity. I think a few people were interested in the WinForms MVP data binding work I've been doing, I'll try to continue that series of posts as soon as possible (I started one a month ago, but haven't really continued it). I'll get some recreated code samples up too.

Tuesday, September 04, 2007

Model View Presenter Data Binding Part 1: The View

When I first started using Windows Forms, I immediately realized that it doesn't scale unless you put forth some effort and discipline in building some infrastructure. The built-in data binding is dodgy unless you just use the Forms Designer to do everything in Visual Studio. There's no definitive documentation on how you can do data binding on something that's not a DataSet or DataTable. There are some unofficial guidelines (can't find the link now, but will post when I do), but nothing that really serves as a reference. (If there is some documentation... then I guess I just didn't look deep enough on the Internet). I went down this route because at work I was trying to bind a POCO (Plain Old CLR Object) to a third-party grid (http://xceed.com/Grid_Winforms_Intro.html). Luckily, the documentation that Xceed distributes with their product pointed me in the right direction and gave me some sample code as a start. The key is IBindingList, which has its own manual of rules. I got a little bit of a start and managed to create a base class to make life as easy as possible. One issue to note is that I'm still using .NET Framework 1.1, which doesn't have generics. .NET 2.0 has a generic BindingListBase type that will work a lot better than my simplified approach. The nice thing is that I'll be ready for the jump to 2.0 since I'm already using this brand of collection. The other nicety that .NET 2.0 provides is INotifyPropertyChanged. .NET 1.1 has the delegate type (PropertyChangeEventHandler) and the EventArgs type (PropertyChangeEventArgs), but is just missing the interface to tie it all together. Again, I'm thinking ahead and I'll be ready for the jump to 2.0. Back to Forms data binding: Windows Forms has a really extensive set of APIs and helpers and types (oh my) to bind controls to DataSets which are, in turn, tied to databases directly using ADO.NET, but doesn't play as well with POCOs that are common with having a business layer or with ORM scenarios. I tried to get it to work... but there was always something missing. To make life easier, I created my own set of binding methods based partly on this CodeProject article (http://www.codeproject.com/csharp/simpledatabinding.asp). The article describes a simpler binding mechanism that is able to bind any property to any other property. It tried to take advantage of IConvertible to change types that are compatible but not exactly the same. This approach is super easy because custom types can just implement IConvertible and they'll "just work" with the binding. Also, if you bind properties of the same type, then you don't even need IConvertible, it will just assign the value. I added some extra capabilities to the binding and allowed it to take a reference to an ISynchronizeInvoke object that will make sure that the synchronizing code is executed on the right thread when dealing with UI objects. The basic syntax is as follows: ThreadAwareBinding.Bind(myDataObject, "Property1", myTextField, "Text", myTextField); The really neat thing (and this is from the article) is that at bind-time, the binder will examine both properties and look for an event named "Changed", where PropertyName is the property that is bound. In my version, I allow the user to specify a trigger event explicitly, or it will look for my version of the INotifyPropertyChanged interface. Whichever it finds first, it will use that mechanism for binding. If more than one is provided, it will prioritize. On the data objects, I specify properties with the following pattern:
int _nThingy;
public int Thingy
{
    get
    {
        return _nThingy;
    }
    set
    {
        bool bChanged = (this.Thingy != value);
        _nThingy = value;
        if (bChanged) FireDataChanged("Thingy");
    }
}
I made a macro in Visual Studio so that all I had to do was type the name of the property and it would be expanded into this template. So, for the "View" aspect of the Model-View-Presenter, I do the following things:
  1. Create a Form or UserControl called "MyView".
  2. Create an interface called "IMyView" that has all the properties declared that we want to display on the control / form.
  3. Implement the "IMyView" interface on the form or user control, also implement the INotifyPropertyChanged interface.
  4. In the Load event, bind the properties to the desired controls (I have automated this step somewhat, I'll talk about it in another post).
The end result is that the View can be modified through its interface properties and can be swapped out for a mock object or something else if we want to do some testing.

Saturday, February 24, 2007

Linux Love

A while back I posted about my Gentoo Linux Laptop. It served me well, but it was becoming a hassle keeping it up to date. I was checking for updates like daily and then watching all the updates compile. It was an addiction. I found myself visiting http://packages.gentoo.org several times a day to see what new stuff was out, then I would curse myself for not being able to remotely SSH into the box to do upgrades. I'm admitting that I have a problem, and that I have addressed it. I wiped my Linux partition on the laptop and installed Ubuntu 6.10 (Edgy). The update process only includes necessary security / bugfix updates (not full system upgrades). The release process is every 6 months, so I can expect a full system upgrade every 6 months. That's manageable. Plus, all the updates are binary so they'll just install smoothly. Someone else has already done all the footwork for me. THIS is what Linux is all about, making life easy. However, don't get me wrong, I'm still a big Gentoo fan, but just not for my primary laptop that has a Pentium M 1.7GHz with 512MB RAM. It's not a beast, but does the job. Compiling stuff takes time and I don't want to have to deal with it. My desktop, on the other hand, is (well, was) a beast. Now it is slowly becoming obsolete. I need to replace it with a sexy Core 2 Duo system. Mmmmmm.... tasty. But that will have to wait. Right now I don't really use it all that much, favoring the laptop for day-to-day stuff. I don't do much independent development either. Plus, the northbridge and GPU fans are crapping out on me and I need to replace (or supplement) them. I think I should put the graphics card (Radeon 9800 All-In-Wonder) in my brother's desktop and then sell the motherboard (dead NIC, messed up NB fan), and processor (2.4GHz with a big-ass heat-sink and fan) on eBay or something. Speaking of Linux love, my girlfriend is teasing me with thoughts of putting together a Linux-based multimedia system for streaming Chinese soap operas into the living room. That's hot.

2 double-oh 7

All right, it's already two months into 2-double-oh-7 and I'm finally updating my blog. Blogger had a huge upgrade and (as you can see) I switched over to a new template. It's also nice that I can log in using my Gmail instead of something else... First, I'd like to look at last year and see how I did on my New Year's resolutions...
  • Get my weight below 200 pounds: d'oh. I think I gained a little weight. I must have plateaued. I'm still fitting into my clothes though, so it's not bad. I'm holding at about 215 to 220 (with clothes and shoes and after work).
  • Keeping in touch with my extended family: Woo hoo! I got to know my cousins more and the six of us got a lot closer this year. We're all busy busy, but we keep in touch more.
  • Learning Armenian: umm... didn't get around to this. Boo on me.
  • Attending an Armenian youth event: My brother and I attended a few AYF (Armenian Youth Federation) meetings. It was... interesting... It wasn't our cup of tea, although now we can say that we went and tried. I got some good reading materials out of it though (although I haven't even read any of it yet).
Observations about 2006:
  • On the love front, I'm in love, been in love, gonna remain in love. Hoo-Yeah!
  • On the home front, I'm keeping in touch with family and being a good son.
  • On the work front, I think I vastly improved my people skills. I believe I have been making great strides in being easier to work with and recognizing other people's contributions. The fact remains though that I am hard to impress (in software terms).
  • I started working on my MBA in the fall. It's tough doing the school + work thing, I have utmost respect (always have) for people who do the school + work (or work + school, the additive property holds here) thing. The work is easy, but tedious, and it burns me out. Luckily it is only 2 nights a week. It's manageable. I've been trying to go to the gym on campus for those days, but work's been really busy and they've needed me to stay to 4 to help out instead of leaving at 3 to go to school. It's worth it though, bonus time is coming around and I know that my contributions will be recognized.
Forward-Looking Statements for 2-double-oh-7
  • I want to get my weight down. Below 200 may not work, but at least near 200. I plan to go to the gym for longer sessions, try to attend some of those classes they have. I also plan to consistently go to the gym at school. Finally, I need to know my limits with food. I'm finding that my body tells me when its full, but I keep eating anyway (this goes for dinner mainly). I think I can manage it. I think starting school messed me up a bit, but I can adjust and persevere.
  • I want to learn to read and write Armenian. I have resources, and I just need to set a schedule for myself. It's going to be tougher now that I have my MBA classes as well (until 2009), but I think I can manage.
  • I want to learn to speak / understand Cantonese, at least on a basic level. It's an interesting language, but I feel I have an obligation to myself and my family to master my own language first. There are 10 months left in the year, plenty of time.
I think that's a good start. I may add to the list as I see fit.