Search code examples
oopdesign-patternsagile

Good architecture for desktop client application


I've already run several times into the issue of creating a desktop client app for working with some server, and every time I ended with ugly code, which becomes just impossible to support after couple of releases.

I have highlighted the following key points:

  • All operations must be asynchronous, without any dummy windows for relative fast operations (i.e. less than 30 seconds)

  • App has to periodically connect with the server and check, for example, user account

  • All heavy operations must be cancelable

But, most important, all of this must be "naturally" in code, without creating unnecessary difficulties (singletons, hacks, etc)... only really needed code with minimal overhead.

How would you design such kind of app? What pattern would you use? What open source project with good architecture you can recommend?


Solution

  • This seems a little too broad, but instead of flagging I'll try and give an answer as I find the question interesting. I invite you to add more details if they come to mind.
    Even though your design concerns the design of the application, there are a number of languages, patterns and technologies that would suit your requirements. Keeping it general,

    1. If your want your operations to be asynchronous, you are going to need multiple threads. Their implementation and use may vary depending on the language that you are using, but the concept behind is the same. So, just spawn a thread every time you need an asynchronous task, and implement a way to be noticed when the task is done (with or without errors). This can be done in a number of ways, since you asked for pattern I suggest you have a look at observer.
    2. The second requirement is not completely clear to me, I assume you want to periodically check that the client's data is aligned with the server's, and maybe perform security checks ("Are session and authentication credentials still valid?"). The first solution is to actually ask the server every n seconds, again using another thread. This kind of polling might not be the best option though: how do you factor in the possibility of connectivity issues? Even if your client cannot operate without a working connection to the server, it might bother the user to be disconnected and lose his work just because his Wi-Fi router rebooted. I would suggest you perform alignment checks at I/O, perhaps distinguishing between critical and non-critical ones. For example, if you decide the user's profile has to be aligned, then you would retrieve updated data from the server upon viewing it. On the other hand, if your app offers the user a list of cooking recipes and you don't care about him not viewing the one that has been inserted on the server 10 minutes in the past, you could simply cache these items and refresh them in a background thread every minute, without even noticing the user in case the update fails. Last but not least, if you are also concerned with concurrent modifications of data, again based on your requirements you can decide to implement locks on data being edited, to performs checks on save operations to see if the data has changed in the meanwhile, or to simply let the user overwrite the data on the server no matter what. All in all, hoping I interpreted your question correctly, this requirement is nontrivial and has to be adjusted to your particular use case.
    3. Assuming the data is eventually saved on some sort of database on the server, one answer are transactions, which allow you to treat even complex sequences of operations as "all or nothing", atomic instructions. You might implement your own system to have the same result, but I don't really see the point of not using this powerful instrument when possible. Keep in mind one thing: I'm assuming "cancelable" means "cancelable before some point in time, and not after" (a sort of "undo"). If you're looking for complete revertability of any operation of data, the requirement becomes far more complex, and in general not possible to guarantee.

    I believed I already answered in a way that helps you minimize "hacks" in code where possible. To recap:

    1. You are going to need threads, and the observer pattern can help you keep the code clean.
    2. Again, you can use threads, or focus on check on I/O operations. In the second case, you might consider an application layer specifically for client-server synchronization, embed it in one or more classes, and perform all your checks there. Have a look at the proxy pattern.
    3. Use transactions to revert operations, and issue a COMMIT only when you are sure that the operation is confirmed, a ROLLBACK in every other case. Encapsule this logic in your server's code so that the client is not aware of the actual transaction system being used, and your code should be quite clean.

    Please comment if my answer is not satisfying or clear.