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?
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,
- 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.
- 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.
- 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:
- You are going to need threads, and the observer pattern can help you
keep the code clean.
- 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.
- 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.