I’ve just posted up on GitHub a quick example WPF application that shows an MVVM-style progress meter dialog, using the .NET 4.5 Task Parallel Library (TPL). Specifically demonstrating:
- A progress meter using .NET 4 Tasks (not BackgroundWorkers).
- Async support.
- Cancelling of Tasks via CancellationTokens.
- Exception handling back to the original thread.
- Reporting background progress updates via IProgress<T>.
- Tasks can either be declared as void, or have a return value.
- Progress can be reported from multiple tasks chained together.
- An injectable, stateless IProgressDialogService, that can be injected for unit testing purposes.
- Using an attached property to hide the close button in the progress dialog’s title bar using Win32 interop.
- Using an attached property to implement a close window command using MVVM.
It’s based off a blog post by Jürgen Bäurle but converted to use MVVM and the TPL.
You can check it out here: https://github.com/rdingwall/wpf-mvvm-task-progress-dialog/
May 12, 2013 | Leave your comment
What happens in situations where the developers and the business don’t agree on the terminology — the Ubiquitous Language — of a system?
Developers propose a more precise name
Sometimes in conversations you will find different users speaking about the same concept, but using different words. Alternatively, they might use a common slang term, or short-hand abbreviation. As part of the vocabulary of your system (ubiquitous language), you should settle on a single name, unabbreviated, that is clear to everyone what it means (including new developers).
Here’s a very simple example of this, a new developer’s thought process when looking at a class in a market risk system:
- Ticker — okay, probably some sort of ticker symbol. But I know different exchanges and data providers use their own proprietary symbols and notation, so I better not make any assumptions.
- Bloomberg Ticker — ah. It is a symbol ticker that came from Bloomberg. I know where to look it up, and also that it’s not necessarily referring a stock traded on an exchange (it could be a country for example).
This is an improvement that clarifies the concept using the most formally correct — but maybe less commonly used — terminology.
As well, expanding abbreviations may be supported by programming language conventions — for example, in .NET, abbreviations are usually discouraged in favour of longer identifiers, expressed using full words.
Dev team proposes using a term that has never been used before
Generally, you should not ever need to do this. Introducing your own terminology can be confusing, and if it is a well-established business area, they will already have a well-established vocabulary.
The only situation I can think of, where it might be acceptable for the development team to propose that the business should use a different term for something, is when building out software for a brand new business area, where a firm vocabulary has not yet been established — For example, in a software startup still figuring out their business model.
If you do go this route, you must ensure the new term has to be agreed by everyone (developers, UX people, and the business) before you start adopting it. And keep an eye/ear out — if people still keep using the old term, cut your losses and revert to the old term in your code too.
Product Owner says, “let’s just rename the label on screen”
The third situation where implications may be unclear is when a product owner drops you a quick note, asking you to please change the name of a field in the UI. Technically, this is a quick change, but does this mean the ubiquitous language has changed, we should rename it all through the code as well?
This is a situation I’ve certainly encountered more than once, and more often than not, it comes from a cost/schedule/risk background. Read between the lines — what is the Product Owner considering when he or she makes this request?
- Renaming a field in the UI: a small that should be quick to implement, without much risk of breaking anything.
- Renaming a field all the way down to persistent storage (e.g. database tables): this is a much bigger change that will require a lot more time (more $$$), may impact the schedule, and could cause many things to break.
Use your judgement here. Is this really just renaming a field on screen, or has the vocabulary of the business changed?
If you think you can rename all through the code/database quickly, and have good unit/integration test coverage to prove everything still works, you might as well do it. But if you think it will take longer, the most pragmatic thing would be to perform the UI label change as requested, but keep an eye/ear on the users to see whether the ubiquitous language really has changed.
If you don’t pay attention after, you run the risk of your code diverging from reality:
Changing terms in APIs and wire protocols
Another question is what to do in the case the term that is changing is part of an API signature or wire protocol, which you can’t change because it will break compatibility with other systems. I don’t think this is such a big concern, to leave the old name here:
- This is only one place, at the very boundary of your system, with an inconsistent name.
- APIs are typically well documented, including explanations, background and “gotchas” about every field. (Example here from the Twitter API).
- In future versions of the API you will have a chance to rename it. Or, if accepting flexible formats like JSON, you can accept both forms (under the robustness principle).
February 16, 2013 | Leave your comment
So you’ve got a new release coming up, including upgrading your production SQL database. You’re writing great upgrade scripts, but now your DBAs are demanding rollback scripts as well. How do you approach this?
Do we really need them?
Rollback scripts are an expensive overhead to development because of the time and effort involved in writing and testing them. There are only two valid reasons you should ever need to provide them:
- Your database is very large, and quickly restoring a backup is not practical.
- Your have an agreed non-functional requirement to support downgrades.
For everyone else, just restore a backup.
The naive approach (don’t do this)
So we really do need a rollback script. Okay. Here’s one that might be generated by a tool:
-- upgrade.sql ALTER TABLE Customer DROP COLUMN CreditCardNumber; -- rollback.sql ALTER TABLE Customer ADD COLUMN CreditCardNumber VARCHAR(24);
What’s wrong with this? A rollback script is supposed to return you to a previous point in time. This example restores the schema version, but not the data — if you run it you’ll lose all the data in the
CreditCardNumber column. It is not a proper rollback!
Rolling back the data
In order for data to be rolled back, it has to be kept somewhere as a backup. We have to detach and reattach it from our schema.
During the upgrade we need to:
- Detach any old table or columns from the schema. Rename it to e.g. “_backup_CreditCardNumber”, unlink any foreign keys, and remove any constraints or triggers. But don’t drop it — we need to keep it as a backup in case rollback is required.
- Apply new schema changes e.g. create new table and populate it from the backup table.
Your schema should now look something like this. The tables and columns are still present, if we need them, but no longer active.
To roll it back we need to reverse any changes and reattach the objects:
- Drop any new schema objects.
- Reattach each backup table or column to the schema. Rename it back to its original name, and recreate the old foreign keys, constraints and triggers.
Backup tables can then be dropped at any point after the release, when they are no longer required. This can be done as a DBA task, or during the following release.
Testing your Upgrade/Rollback Scripts
At work we have a build set up in TeamCity that replays all our upgrade and downgrade scripts against a test database every time one is checked in — we are continuously integrating and testing our SQL scripts. It performs the following steps, and fails if any SQL errors are raised:
- Create an empty database.
- Run all the upgrade scripts, from version 1 up to current.
- Run all the downgrade scripts, from current back down to version 1.
- Run all the upgrade scripts again.
The second upgrade pass is important because it detects any objects that were missed in a rollback script: if you forgot to drop something, it will fail with an “object already exists” error. This saves a lot of time, and reduces the chance of nasty surprises on release day.
We have a big market data risk analysis database at work and this detach/reattach rollback pattern (with continuous testing) has worked well for us so far. We expect it to continue scaling as we grow, although if inserting/updating hundreds of millions of rows becomes too slow for a single release window, we may need to use streaming to populate new tables/columns offline before switching them over during an outage. But the same attach/detach principles will still apply.
September 23, 2012 | 5 comments
App.net is a new alternative to Twitter that’s been getting a lot of coverage lately.
They have taken a unique approach to funding, where instead of depending on advertising revenue, they simply charge each user an up-front $50 annual subscription fee.
The idea behind this is to eliminate any risk (in future) of privacy and platform access being eroded when corporate/advertising goals start to diverge from those of the non-paying users — a problem Twitter has recently appeared to have experienced.
This sounds like a pretty solid idea, and has garnered a lot of support so far. But funding is only one problem facing a new social network, and now they have another big challenge: how to get more users?
Here is where (I think) App.net has executed a real stroke of genius. By requiring a full year’s payment just to join the alpha, every user has a real, quantifiable incentive to evangelise App.net to their friends. With fifty bucks on the line, every user has much more interest in the success of the platform than an indifferent take-it-or-leave-it free service like Google+.
This was a smart move, solving two problems, that could only have been done right on day one. Best of luck to the App.net guys — it will be interesting to see how it all goes over the next few months.
August 22, 2012 | 1 comment
“I’m sorry, the feature you wanted is not currently available in the public API”.
It’s common these days for web applications to provide some sort of RESTful API for third party integration, but too many of them are built after the fact, as a lacklustre afterthought — with holes and limitations that makes them useless for all but the most trivial applications. Here’s some common pitfalls I’ve seen (and been partially responsible for!) arising from this style of development:
- Only a narrow set of features supported: The application may have a hundred different tasks a user can do in the GUI, but only a handful are supported through the API.
- Impractical for real-world use: APIs that fail to consider things like minimizing the number of requests through and batching and bulk APIs. Just think, how you would implement GMail’s “mark all as read” button if you could only update one conversation at a time?
- API features lag UI features: For example a new field might be added to the UI, but there is no way to access it in the API until someone requests it.
- Weird/buggy APIs: Bad APIs don’t get as much developer attention if no one’s using them, making them a natural place for bugs and design quirks to harbour.
Instead of restricting developers to a limited, locked-down set of operations, the goal is to empower developers to be as creative and productive as possible with your API.
A better way to design an API
Don’t try to build the sort of API you think people will want. Flip the problem on its head and eat your own dog food: make a rule that, from now on, all new UI features can only be based on the public API. Abandon your traditional, internal back-end interfaces and start using the public API as an interface for all your front-end applications.
“All Google tools use the API. There is no backdoor. The web UI is built on Google App Engine, for example.”
This quote from High Scalability beautifully summarizes the design of their API. There is no backdoor, no privileged internal interface — Google developers have to use the exact same API as you at home.
Twitter is another great example of an application that dogfoods its own API – click view source on twitter.com and you’ll see, apart from tracking and advertising, it’s mostly AJAX calls to their public developer API – the very same API all the thousands of third party apps use.
August 15, 2012 | Leave your comment