Bindable LINQ: How it came about

Desktop applications have state. A lot of state. I believe that managing state is the direct cause of most complexity in desktop applications, and SyncLINQ is designed to address that. Let me explain why I believe this, and why SyncLINQ might help, in the context of an example:

Readify is a services company. I recently built an application which we use internally, which allows us to schedule consultants against engagements. Here’s what the window looks like conceptually:

 image

The workflow is that you select an engagement to schedule, drag it onto the canvas under the name of the consultant, and stretch it down over the days of the engagement.

The list of engagements on the left allow you to filter them. They are grouped by the customer, since we could be doing multiple things for one customer in a month. Some examples of filters are:

  • Underscheduled Orders - when the customer asks for a 7 day engagement, and we have only scheduled 6 days, that’s an under-scheduled order.
  • Internal Orders - we schedule sick leave, professional development time and internal work using this tool as well.

When you consider the Underscheduled Orders filter, you realize that it relies on a lot of objects:

  • It shows a filtered list of Orders
  • It groups them by the Customer
  • It uses a list of ScheduleDays to calculate whether an Order is under-scheduled

These dependencies introduce a number of behavioral requirements:

  1. When the user stretches an engagement in the canvas so that it is no longer under-scheduled, the order should disappear from the list.
  2. If they shrink the engagement, it should appear again.
  3. If the application synchronizes with the server in the background, and someone else has resized it, it should also appear/disappear as appropriate.

Problems like this can sometimes be solved by adding code to force the list to rebuild whenever one of these scenarios are triggered. However, this can introduce messy code, and can lead to a bad user experience. Rebuilding the whole list every time might be slow, and if the user had an item selected, their selection may be lost (unless you manage that manually, which introduces more code).

Real State and Derived State

If you took a memory dump of most applications, you would find two kinds of state:

image

Real state is made up of the objects that usually represent your “source of truth”. In the application above, this would contain the Order, ScheduledDay and Customer objects.

Derived state is made up of objects whose values are derived or transformed from real state, or from other derived state. Whenever you filter, transform, aggregate, group, format, convert or combine real state, you are creating derived state. In my application above, the object which combines a customer and its collection of orders is derived state. The object which exposes the filtered list as a collection is derived state. If you are programmatically looping through Orders and adding TreeViewNodes to a TreeView, the TreeView represents derived state. All applications have derived state.

In some applications it can be hard to tell the difference between objects which are real state, and objects which are derived state. Sometimes, an object may be both - the source of truth for one piece of information, but also composed of other pieces of derived information.

Two design decisions that can make an application simpler are:

  1. Making a distinction between classes which represent real state or derived state, and trying never to mix the two
  2. Limiting the number of copies of real state objects. Avoid having two instances of customer Bob in memory at once; it just makes consistency hard.

The problem with derived state

Derived state is a good thing, and is unavoidable in anything but the most trivial of applications. However, in desktop applications especially, it needs to be managed correctly if you want to avoid complexity, bugs and hacky code.

When you take one object and transform, filter, aggregate, group or combine it into another object, you are creating derived state. Doing this means there must be a relationship between the first object and the second one.

If you use a LINQ query or some manual code to do this, it becomes a one-off operation.

image

When you get a bug report saying that the list of the left is out-of-sync with the canvas, you add a load of hooks and manually rebuild it:

image

The problems come when you miss one of these manual hooks. This is why I love the data binding interfaces (INotifyPropertyChanged, and INotifyCollectionChanged), as they provide a complete API around notifications that something has changed, and they can be consumed by your own code as well as the UI. Inventing your own system of re-transforming derived state when real state changes is madness.

Of course, these interfaces and their events only tell you that something changed - they don’t help you process them and keep things consistent. That’s why we often end up writing hundreds of lines of code to manage these events (“if they stretched, I’ll remove the order. If they shrank, I’ll add the order”), or going the simple “rebuild” path and providing a second-rate user experience.

How SyncLINQ helps

This complexity of managing derived state is the reason I created SyncLINQ.

A LINQ query is the perfect way to express many transformations from real state to derived state, such as in the case of my Underscheduled Orders filter above. Unfortunately, a LINQ query is a one-off operation. That’s why I created SyncLINQ - the real state is always synchronized with the derived.

SyncLINQ, and binding, doesn’t just exist at the UI layer. Maintaining state consistency is necessary in all layers. I believe that SyncLINQ - and Binding Oriented Programming in general - can radically reduce the complexity in desktop applications while also providing better user experiences.

Unlike LINQ, SyncLINQ is starting to step outside of collection-driven queries, and will soon be able to create bindable transformations of individual objects and expressions. In my next post, I’ll talk about the three different kinds of queries SyncLINQ performs, and show how powerful it can be for managing derived state.

Update: Read the three Categories of SyncLINQ Queries

In the meantime if you haven’t watched them already, check out my SyncLINQ YouTube videos:

21 Responses to “Bindable LINQ: How it came about”

  1. […] I blogged about Real State and Derived State in desktop applications. There were three ideas I put […]

  2. SyncLinq: Haven’t Tried It, But Love The Concept

  3. Hi Paul,

    Can you tell me what software you use to do your diagrams?
    They look rather good and I want to make something similar :)

    Cheers,
    Jack

  4. Hi Jack,

    I do them all using PowerPoint 2007 and the inbuilt themes, then take snips of them using the Vista Snipping Tool. They aren’t UML but they look pretty :)

    Paul

  5. And there I was thinking it was Visio….

    After having played with Visio for a few days now, I’ve come to the conclusion that it really doesn’t deserve to be an ‘Office’ product at all. I will give PowerPoint a try….

    Cheers

  6. […] Link to PaulStovell.NET » Why SyncLINQ should matter to you […]

  7. […] first prototype I made of SyncLINQ was on September 1st this year. As of yesterday, that makes SyncLINQ officially 3 months old. […]

  8. […] months ago when I dreamed up SyncLINQ, I dismissed it as being too hard. Three months later I built a prototype, and was surprised at […]

  9. […] about the use of extension methods over interface methods. Having used extension methods heavily in SyncLINQ, there’s something I wanted to highlight when it comes to choosing between regular methods […]

  10. […] is simply not true. The SyncLINQ source, for example, isn’t one 40,000 line C# class with thousand-line methods. I’d bet […]

  11. […] developer’s intent is one that we see over and over again in LINQ. It’s also one of my design intents behind SyncLINQ. In PLINQ, you express what you want, and add an extra keyword to tell it to execute in parallel. […]

  12. […] a class which he uses in order to aggregate items. Towards the end, he suggests that SyncLINQ might have helped him. Allow me to answer […]

  13. […] LINQ to Bindable Sources (SyncLINQ) […]

  14. […] LINQ to Bindable Sources (SyncLINQ) […]

  15. […] from Microsoft keeps a list of links to all things related to LINQ. I’m pleased to see SyncLINQ just made the […]

  16. […] LINQ to Bindable Sources (SyncLINQ) […]

  17. thank you!
    can you please give us an idea how to make a data acess layer with linq to sql and wpf. I mean what kind of design should that be for this CRUD-Desktop application
    Thanks in advance

  18. […] LINQ to Bindable Sources (SyncLINQ) […]

  19. […] learnt this the hard way with SyncLINQ. The code-base was littered with code like the above, until a couple of the unit tests I wrote to […]

  20. […] We kicked off the day with Jonas Folleso, followed by Greg Low and Bill Chesnut with two rapid fire sessions. Next up it was Shane Morris and then Peter Myers. That is a pretty impressive line up already. Paul Stovell of Readify fame is up at the moment showing off some technology that he has been working on for a while - SyncLINQ. […]

  21. […] More information about SyncLINQ […]

Leave a Reply