Tips for rich client development

A common question that comes up for almost every object relational mapper is how to use it effectively in a desktop client environment. I wanted to share some of the tips we have in achieving successful desktop client development with LightSpeed.

What’s the problem?

There tends to be two specific issues that make developing connected desktop applications a challenge:

  • Completely stateful environment
  • Often in a client/server setup

In this post I’ll explore some tips for working more easily with stateful applications.

By a stateful environment, I mean that you’re not limited to the stateless request/response situation of web development. Despite the challenges of web development, the request/response type approach to building applications means there are environment imposed boundaries. For example, the start of a request, the end of the request, etc.

These boundaries initially may have seemed like pain points for developers moving to web development for the first time. However, in my opinion, we have subsequently found that this imposed application design turned out to be a blessing in disguise. Web applications are almost forced to work in atomic change sets, while desktop applications can be far more fluid due to their statefulness. In a desktop application it is therefore tempting to work in a non-transactional manner. But this doesn’t lend itself the Unit of Work pattern because the pattern is transactional in nature.

So in the development of desktop applications it is important to try and identify or create the boundaries that your application will use. In a sense, you’re creating the same type of fundamental work patterns as the request/response type nature of the web but based on your own rules. The benefits of doing this is that your application code is maintainable and your entity life cycle management is simple to work with.

Three tips to get you started:

Tip 1: Design patterns

Model view controller in rich clients

While all applications should use a higher level design pattern for structure (MVP/MVVM/MVC/Whatever) it’s more important for desktop applications as they otherwise do not enforce any natural boundaries (such as managing the request/response life cycle). It takes discipline to take the freedom of the desktop and impose your own boundaries and stick to them.

Why labour this point? The Unit of Work design pattern works best when tied to a certain section of actions to be undertaken. This means in an MVC structured application that while the rest of your application is doing various things you are likely to only need to start and finish a unit of work in your controller – usually in very short lived manner. A short lived unit of work is the best way to use the pattern.

Tip 2: Dialogs

Application dialog buttons

One natural boundary in a desktop application is a pop up window or dialog. Take for example an application where you may wish to edit an employees details. The user double clicks an employee, a dialog appears and they can edit any of the employee details. They can then elect to save those changes or cancel the operation.

Here’s how to structure this type of interaction:

  • Controller uses a unit of work to fetch the employee to edit
  • Controller closes the unit of work
  • Controller creates the view and exposes a model which the view can bind against (in this case, we could bind directly to our employee entities properties)
  • At some later stage, after editing, the user clicks “Cancel” then the dialog closes.
  • Or, at some later stage, after editing, the user clicks “Save” then the controller creates a new short lived unit of work, attaches the entity, and saves the changes.
  • Everything is nicely and neatly done!

This represents a nice and easy way to work with short lived units of work along with your higher level design pattern enforced boundaries to ensure you have a nice and clean way of working with entities. Obviously application specifics may be different (edit inline, certain users can edit only certain fields etc.); however hopefully this will provide a basis for how you can work with entities cleanly.

One word of warning – if you’re developing a multi-user system you will want to think about concurrency. For example, you may enable optimistic concurrency and trap that exception on save if another user has edited the same entity between you loading it and saving it. How you deal with such a concurrency violation would be application specific but it’s worth keeping this scenario in mind.

A second word of warning – if you’re representing a complex graph of objects that are being edited then you’ll need to be wary of items that could be lazy loaded, or otherwise require an active unit of work to be associated with the entity. If you wish to make use of these capabilities you’ll need to look at using a longer running unit of work so the entity can maintain a connection to the database.

Tip 3: Refresh buttons

Application refresh buttons

Often when building a desktop application there is the presumption that you can maintain a live data feed in the UI because you are removed from the request/response process. Avoiding this situation is generally wise because rebinding entire grids or views means that you end up fighting the nuances of the users state (“they had field three in row 97 for the employee entity in edit mode – return to that state”).

The best solution here is to make liberal use of “refresh” buttons in your application. You grabbed the data once and wait until the user has decided they wish to refresh the information before you actively go looking for changes.

Again, this is where the design patterns help out. Having a controller able to call a generic Refresh() method which rebinds the primary UI has the benefit of being easily callable from elsewhere in the controller. For example, if a user elects to edit an employee then when the controller has saved those changes it could also call the Refresh() method to ensure that as the dialog closes the primary UI is also updated to show the changes (and any other changes that other users may have made since the last refresh).

What tips do you have?

These are just a few tips but every developer has experiences to share. What are some of the tips and tricks you have found? We would all love to hear them!

kick it on DotNetKicks.com

Tagged as LightSpeed

10 Responses to “Tips for rich client development”

  • Tips for rich client development…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  • Question. I have WCF between client and application server, which means model entities will not be sent to the client, but rather their respective simple DTOs (Data Transfer Objects).
    How to avoid stateful environment if I want to use entity change tracking which you are preparing for Lightspeed 3? You’re expecting client to manage two copies of DTOs – one with originaly fetched values and one with edited values?

  • Hi Marko,

    I’m not 100% sure what you’re asking here so I will assume you’re wondering how change tracking would work in a distributed environment?

    With LightSpeed generating the DTO’s and Entities, you would simply send your DTO down the line and then when it is returned (with or without changes) you can use the CopyTo extension method that LightSpeed generates to apply any changes.

    The act of applying the changes means that the change tracking in LS3 will then be able to report what changes have been made.

    The is no provision in LS3 for providing change tracking on the client side for DTOs – you simply send the DTO back and let the server side manage the change tracking.

    If you wish to do change tracking on the client side (perhaps to test if you should bother sending a DTO back to the server) you would need to apply your own code to test for changes that may have been made to the DTO.

    I hope that helps but please let me know if I’ve missed the point of your question.

    Cheers.

  • Hi JD,

    I’m trying to make a point about the moment of using CopyTo method with DTO and getting that report of changes.

    I am expecting model entities will be responsible for change tracking, which means they can be detached and Uow disposed like in the article.

    But, if I have a stateless application server and DTOs, after receiving back DTO I have to recreate the entity and use CopyTo method. I will then get a report about changes compared to the current entity copy from the database (I expect a refetch from DB will occur at that process).
    I will not get the same report “client modified values” which I would get if I hold on to the original entity which was fetched when client requested start of editing.

    Of course, report will not be the same if somebody else changed the record in DB in the meantime, and yes, this is concurrency violation territory. But, for resolving concurrency violation I would be better of if I have the correct information which properties is the client request actually trying to modify (for resolving concurrency I would want to use the rule like LINQ’s RefreshMode.KeepChanges – “forces the refresh method to keep the current value that has been changed, but updates the other values with the database values”).

    So, to cope with that situation in a stateless environment you’re suggesting, it looks to me I would need the client to keep a copy of originally fetched values (which I guess means an extra DTO with original values). Or use a stateful application server.

    I hope I was a bit more clear now. If I’m missing something, let me know.

  • Hi Marko,

    Sorry for the slow reply! You’re correct about needing to hold a copy of the orginal values yourself if you wanted to reconcile with the entity as it stood when you created the DTO from it.

    It seems we have two issues here:

    1. Only tell me the changes that the user has made against original values – not against what is currently in the database.

    The way we’re currently exposing the change tracking is to use a simple record per property that holds property names and their old + new values. This is built against an entity which is why you would need to currently replicate existing property values if it would be an issue to reconcile against the database version.

    You could certainly create two DTO’s and hold original values with one. You could also update the templates for the DTO generation to build an Original*PropertyName* field per property. I’m not suggesting this is the best idea, just sharing a way to reduce DTO classes.

    2. Reconcile the changes for concurrency violations

    Currently we are not offering functionality to do this however the exposure of the change tracking will allow developers to reconcile themselves. So far however general feedback is that most applications deal with concurrency issues in their own way. We would want to help with common case scenarios – which is similar to what L2S is offering from what you’re saying.

    We’re pretty busy with LightSpeed 3.0 so post 3.0 we’ll look at a Refresh() capability.

    Thank you for your feedback Marko :-)

  • Hi JD,
    I’m about to start delving in to MVC with Winforms as a learning exercise (in C# 3.5) and re-writing an old application so that there is something at the end of it rather than a bunch of trial code. Do you have, or can you point me in the direction of any concrete code examples on using MVC and winforms ? I don’t really want to take on WPF as well at this stage if possible.
    If you’ve got any example code knocking around that uses Lightspeed, all the better !
    Cheers
    Paul

  • Hi Paul,

    You might want to google around for “windows forms mvc” for some general samples and advice — obviously not LightSpeed specific but I get the impression that at this stage you’re more trying to get your head around the pattern. http://stackoverflow.com/questions/654722/implementing-mvc-with-windows-forms seemed a reasonably good collection of links and resources. In particular you should check out the references to Model-View-Presenter (MVP) as an alternative to MVC.

    However… I understand why you are reluctant to tackle WPF, but do bear in mind that Windows Forms is basically at the end of the road. It hasn’t been enhanced in the last 3 years and that’s not about to change. This wouldn’t be such a consideration if you could take your MVC/MVP experience gained on WinForms to WPF, but WPF works best with a different architecture known as Model-View-ViewModel (worst architecture name ever). You’re in a tricky situation where you rightly don’t want to have to learn a new UI framework and a new architecture all in one go; but if you learn a new architecture on your existing UI framework, you may not be able to take that knowledge forward, and you’ll end up having to learn the new framework and new architecture all in one go anyway at some later date.

    That said, the MVC pattern remains very relevant and elegant in the Web environment, so it’s certainly not wasteful to spend time mastering it. (And for Web work you will definitely be wanting to grok MVC not MVP, as the modern version of the ASP.NET framework has gone the controller route not the presenter route.)

  • Hi,

    I’ve only just downloaded LightSpeed, so forgive my naivety. ;-)

    I was reading in What’s new in V3 and saw that you seem to have implemented a ‘Fowler’ style version number pattern which works simply by adding a LockVersion property to each domain entity. I assume that this gets incremented each time a successful update takes place, but within that there is a check to see if the LockVersion is the same as it is in the object being persisted? If it doesn’t then the OptimisticConcurrencyException is raised and us as the developer deals with it in an appropriate fashion.

    In terms of the ‘original’ state of the entity I’m thinking simply get two copies of the dto on and then compare for any user changes in the current UOW but you mentioned above that “The way we’re currently exposing the change tracking is to use a simple record per property that holds property names and their old + new values. This is built against an entity which is why you would need to currently replicate existing property values if it would be an issue to reconcile against the database version.”

    Could you explain a bit about this please and how version 3 may have changed in that sense?

    Regards
    Colin

  • Hi Colin,

    You are correct – the LockVersion is tested if it exists and throws an optimistic concurrency exception if it does not match.

    Regarding the change tracking in LightSpeed 3.0, this can improve things but only if you’re using an entity directly, not a DTO. We don’t serialize change tracking details with the DTO’s we generate so the best way to check when using DTO’s is to hold two copies. If you had a LightSpeed Entity you could check the change tracker to see what has changed. LightSpeed 3.0 has not changed how you would check the changes when using DTOs.

    I hope that makes sense and answers your question – if I have missed something then please let me know :-)

    John-Daniel Trask

  • Just to add to JD’s info: LightSpeed-generated DTOs are partial classes so you can add the LockVersion to the DTO if you want. In this case you will need to implement your own mechanism to copy the value from the entity to the DTO; you can do this by implementing the partial methods declared in the generated DTO classes.

  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top