May 2010 Entries
Command query separation is a strategy, proposed by Bertrand Meyer, that each of an object’s methods should be either a command or a query. A command is an operation that changes the state of a system, and a query is an operation that returns a value.
This is not the same thing as CQRS, hence why I think that CQRS is poorly named.
An Example of Command Query Separation
Consider a system that models books and shelves. There is a rule that a shelf may not be removed if it holds any books. One way to implement the removal is to write a method Shelf.Remove() that internally checks to make sure that the shelf is empty before removing it. If the shelf is not empty then it is not removed and an error is returned. To implement this feature following the principle of command query separation would require two methods, one to query the shelf and determine if it is empty and a second method to remove the shelf. Separating the query from the command makes the shelf class simpler to use because the state change is clear and explicit.
This weekend I have been in Sydney at the MS Web Camp, learning about web application development. At the end of the first day we came up with application ideas and pitched them. My idea was to build a web management application for mongoDB.
mongoDB
I pitched my idea, put down the microphone, and then someone asked, “what’s mongo?”. Good question. MongoDB is a document database that stores JSON style documents. This is a JSON document for a tweet from twitter:
db.tweets.find()[0]
{
"_id" : ObjectId("4bfe4946cfbfb01420000001"),
"created_at" : "Thu, 27 May 2010 10:25:46 +0000",
"profile_image_url" : "http://a3.twimg.com/profile_images/600304197/Snapshot_2009-07-26_13-12-43_normal.jpg",
"from_user" : "drearyclocks",
"text" : "Does anyone know who has better coverage, Optus or Vodafone? Telstra is still too expensive.",
"to_user_id" : null,
"metadata" : {
"result_type" : "recent"
},
"id" : {
"floatApprox" : 14825648892
},
"geo" : null,
"from_user_id" : 6825770,
"search_term" : "telstra",
"iso_language_code" : "en",
"source" : "<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"
}
A mongodb server can have many databases, each database has many collections (instead of tables) and a collection has many documents (instead of rows).
Development
Day 2 of the Sydney MS Web Camp was allocated to building our applications. First thing in the morning I identified the stories that I wanted to implement:
Scenario: View databases
Scenario: View Collections in a database
Scenario: View Documents in a Collection
Scenario: Delete a Collection
Scenario: Delete a Database
Scenario: Delete Documents
Over the course of the day the team (3.5 developers) implemented all of the planned stories (except ‘delete a database’) and also implemented the following:
Scenario: Create Database
Scenario: Create Collection
Lessons Learned
I’m new to MongoDB and in the past I have only accessed it from Ruby (for my hare-brained scheme). When it came to implementing our MongoDB management studio we discovered that their is no official MongoDB driver for .NET. We chose to use NoRM, honestly just because it was the only one I had heard of. NoRM was a challenge. I think it is a fine library but it is focused on mapping strongly typed objects to MongoDB. For our application we had no prior knowledge of the types that would be in the MongoDB database so NoRM was probably a poor choice.
Here are some screens (click to enlarge):

This post is a message in a bottle. It cast it into the sea in the hope that it will one day return to me, stuffed to the cork with enlightenment. Yesterday I tweeted,
what is the name of the pattern where you replace a multi-way conditional with an associative array?
I said ‘pattern’ but I meant ‘refactoring’. Anyway, no one replied so I will describe the refactoring here.
Programmers tend to think imperatively, which leads to code such as:
public int GetPopulation(string country)
{
if (country == "Australia")
{
return 22360793;
} else if (country == "China")
{
return 1324655000;
} else if (country == "Switzerland")
{
return 7782900;
}
else
{
throw new Exception("What ain't no country I ever heard of. They speak English in what?");
}
}
which is horrid. We can write a cleaner version, replacing the multi-way conditional with an associative array, treating the conditional as data:
public int GetPopulation(string country)
{
if (!Populations.ContainsKey(country))
throw new Exception("The population of " + country + " could not be found.");
return Populations[country];
}
private Dictionary<string, int> Populations
{
get
{
return new Dictionary<string, int>
{
{"Australia", 22360793},
{"China", 1324655000},
{"Switzerland", 7782900}
};
}
}
Does this refactoring already have a name? Otherwise, I propose
Replace multi-way conditional with associative array
David Starr interviewed me for his pluralcast podcast. We talked about software craftsmanship and how to spread knowledge.
According to Wikipedia, “why the lucky stiff was the persona of an anonymous, but prolific writer, cartoonist, musician, artist, and computer programmer”. He looks a bit like Jack Black.
His book, Why’s Poignant Guide to Ruby, is a classic, though it can be hard to find since Why disappeared. If you want to learn the Ruby programming language I highly recommend Why’s Poignant Guide to Ruby. I am including a link here so that others who search for it may find it more easily.
I have not had a significant side project for a while but I have been working on a product idea. Its an analytics application that analyses twitter data and reports on market sentiment. The target market is companies who want to track trends in consumer sentiment.
My idea is to teach the application to divide relevant tweets into ‘positive’ and ‘negative’ categories. If the input was the set of tweets featuring the word ‘telstra’ the application would find the following tweet:
and put it in the ‘negative’ category. Collecting data in this fashion facilitates the creation of graphs such as:
which can then be correlated against events, such as a share offer or new product release.
I may go ahead and build this, just because I am a programmer and it amuses me to do so. My concerns are:
- There is no market for this tool
- There is a market, but I don’t understand it and have no way to reach it.
The above error occurred when I executed a linq query using the following expression:
(s) => s.Book.Slug.Equals(bookslug) && ids.Contains(s.Id);
ids in this case is of type IEnumerable<Guid>. As indicated by the error message the fix is to change ids to ICollection<Guid>, then the query executes successfully.
Tonight the Brisbane Alt.NET group is doing a coding dojo. I am hoping to talk someone into pairing with me to solve the kata in CoffeeScript. CoffeeScript is an awesome language, half javascript, half ruby, that compiles to javascript. To assist with tonight’s dojo I wrote the following micro test framework for CoffeeScript:
<html>
<body>
<div>
<h2>Test Results:</h2>
<p class='results' />
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
<script type="text/coffeescript">
# super simple test framework
test: {
write: (s) ->
$('.results').append(s + '<br/>')
assert: (b, message...) ->
test.write(if b then "pass" else "fail: " + message)
tests: []
exec: () ->
for t in test.tests
test.write("<br/><b>$t.name</b>")
t.func()
}
# add some tests
test.tests.push {
name: "First Test"
func: () ->
test.assert(true)
}
test.tests.push {
name: "Another Test"
func: () ->
test.assert(false, "You loose")
}
# run them
test.exec(test.tests)
</script>
<script type="text/javascript" src="coffee-script.js"></script>
</body>
</html>
It’s not the prettiest, but as far as I know it is the only CoffeeScript test framework in existence. Of course, I could just use one of the javascript test frameworks but that would be no fun. To get this example to run you need the coffeescript compiler in the same directory as the page.
Last night Richard Banks recorded Paul Batum and I for his podcast. We talked about Alt.NET Seattle 2010 and my software craftsmanship tour. It was a lot of fun and I hope you enjoy it.
