Trying to build high-concurrency systems… it’s just not easy!
When you have multiple clients working on the same data – concurrency rears it’s ugly head. How to handle two users loading the same data – and both of them editing it and trying to save it back to the DB. There is no way to keep everyone happy when this happens – either Last-In wins (potentially over-writing First-Ins work or putting objects in invalid business state) or First-In wins and Last-In’s data is lost. Of course, there are people who would try to merge the changes (and good luck to them…), but it’s not my first choice. I would rather keep it from happening in the first place.
And then comes the funny part trying to find a bullet-proof way of doing that. DBA’s would come up with a clever locking-scheme that would lock the row when one user starts editing (ReadLock-kinda-way). This might work (and when I say might – probably would not work). The problem is that we re usually in a disconnected scenario – it’s just not feasible setting a read-lock for a client, you don’t know will return it promptly. What if the client is disconnected.. what if… and so on. Disconnected clients (for obvious reasons) cannot be counted on to behave like connected clients. Besides cleaning up dead-locks in a database is just never fun (and having a shared data service hanging indefinitely is really never fun).
So, read locks at the database level are out (well, it was never really in – I just mentioned it, so DBA’s wouldn’t be left out of the fun debate). The problem is that right now, we are trying to tackle the problem at the service level – we need to go back to why the problem is happening in the first place. The problem is users are not good at telling other users what they are doing – seldom do we have an office where a user will send an e-mail around to hear if anyone is editing this Account – waiting to get replies from everyone – then going to Peter who was busy playing Minesweeper and didn’t have time to answer mails and determining that he doesn’t have that particular account open – finally, coming back to his own computer – edit the account using the 10-digit system (thus being done in 2 seconds) and promptly saving the Account. This Does Not Happen.
Users don’t work that way… They’ll open the Account, gloss over it sipping their coffee, edit one property, decide that was wrong, delete the entire field, pick up the telephone to ensure that their cable is installed today, come back to the screen, stare blankly at the screen for several minutes trying to discover what they were doing. After asking their colleagues what the score is in the NBA play-offs, they will remember that they were editing the phone-field and re-enter the data in the fax-field they had erased and then hit the save button.
The grace period we are talking here – can be several hours because most users are not very good at working like a computer. They are a spontaneous crowd who make mistakes… constantly. And most will be juggling several things at once – e-mail, phone, fax and the occasional daily-yelling-from-the-angry-boss will be competing with your application for their attention (and guess who is winning… if you guessed your application, you need to see a psychiatrist about delusions of grandeur…).
So, what to do – well, I believe in using every available UI-widget at hand to signal to the user what is a good idea – and what is a not-so-good-idea (“Are you certain that you wish to delete the database, loosing three years of work” combined with flashing radioactive signs, Darth Vader popping up to call the user a moronic imbecile who was to blame for the death (pun intended) of the Death Star). Okay, you could make it less flashy, but nobody likes a boring screen. What I’d do was to show the user a ribbon at the top of the screen alerting him that Alex did some changes – and that if he’d like, the Account can be reloaded to reflect the changes. The reason, I wouldn’t just go ahead and do it – the user would be angry at me for not letting him jot down his changes before the screen flickered (the loss of work again). And if I was feeling particularly in a good mood that day – I would even add functionality to apply his changes after the reload (if possible).
This approach would almost eliminate the friction that users feel when working on distributed data. The one thing that we cannot deal with is users supplying data at the exact same second. But we would have backup procedures for that. (“Sorry, we were unable to save your changes as Alex beat you to it – here is his e-mail: alex@someplace.com if you feel like venting”). And guess what? (No, it is not a knock-knock joke) Your first and foremost responsibility as a developer is removing friction from users! If they feel friction – they will think you application is lame no matter how brilliant everything else is.
In my next instalment, I’ll talk about how to solve this technically.