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:
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
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
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:
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
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!