Top Albums of 2009
Well ladies & gentlemen, it’s that time of year again where I make a list that nobody reads or cares about. Considering this is more an exercise in reflection than it is in sharing my highly-toted-to-nobody-in-particular opinion, here are my favourite albums of 2009 without any explanation. YMMV.
#10 – Kurt Vile: Childish Prodigy
#09 – Real Estate: (ST)
#08 – Bat For Lashes: Two Suns
#07 – The Antlers: Hospice
#06 – Bonnie “Prince” Billy: Beware
#05 – Animal Collective: Merriweather Post Pavillion
#04 – Grizzly Bear: Veckatimest
#03 – Future of the Left: Travels With Myself And Another
#02 – Micachu & The Shapes: Jewellery
#01 – Do Make Say Think: Other Truths
MashedIn – Fuelling Your Connections With Oxygen
This past week my team and I worked on version 8 (Oxygen) of MashedIn. We had 2 goals going into this version:
- Provide a better, more predictable user experience when authenticating with the product
- Do a better job at handling badness when talking with Facebook, Twitter, and other social partners
- Fix bugs!
It never ceases to amaze me how much our team can accomplish in as little as 3 days of development time. Here’s the fifty thousand foot view.
- 4 improvements to how we authenticate and manage sessions with our social partners
- Bunch of preliminary branding work. Pretty pictures! Human readable copy! Personality provided by cheeze wiz!
- 13 bug fixes
- 8 bagels eaten
- Several dozen carafes of coffee confidently consumed
Now, that may not sound like too much, but that’s a full 3 days of work across a team of 4 developers, including design meetings, decision making, and the occasional head butting. I believe we tackled some good things this sprint, and the experience we provide to the user is a little more predictable; we shouldn’t be shattering your expectations anymore.
There were 2 main challenges we faced in Oxygen. First, the more we investigated how to better manage expectations for the user (that is, not shock and awe the user with unexpected, crappy behaviour) the more subtleties we discovered. Most of these subtleties came in the form of Facebook Connect. Managing your sessions can be quite difficult thanks to the persistently authenticated nature of Facebook Connect (and the fact that we don’t control any of it). What happens when I sign into Facebook using an alternative set of credentials, but then I visit MashedIn and MashedIn determines that I have a different Facebook user associated with my account than what Facebook Connect dictates? What’s the best way to handle this? How transparent do we need to be to the user? Do we really want to provide a bunch of subtle options? Are those options going to frustrate the users? It’s a tough call, and we believe we’ve made the right decisions, but a good round of user testing will definitely help us out.
The 2nd challenge was one of irony: Facebook has been biting the proverbial dust all week. Without Facebook we can’t grab social information for the visitor. Without social information we can’t effectively perform what we want our product to do. Without doing what we want to do in the app we’re wasting the time of our users by providing them crap all for value. With Facebook crapping out this week, we were able to uncover a lot of really poorly written code. We were able to eat our own dog food, and it tasted like… well, dog food. It sucked. We all went crazy. Brett, one of our developers, started wearing a monkey suit to work. It was total chaos. As a result, we addressed a bunch of the Rainy Day scenarios and made our dog food taste more like a bottle of cheap wine. While what is there isn’t perfect, we believe the overall quality of both the code and the user experience is better. One week at a time, my friends, one week at a time.
Next week we start our 9th sprint. If you’re a chemistry buff you’ll know that Fluorine has an atomic weight of 9. You’ll also know that Fluorine is an extremely toxic element, one that may cause severe burns when it comes in contact with the skin. As such I think it’s fitting that we’re attempting to accomplish a lot of painful things in Fluorine. We have 2 goals for next week:
- Fail faster! By that I mean improve performance by not allowing several retries that ultimately result in failure. Fail hard, and fail now! (Note: we’ll be doing lots of other things to improve performance… embracing failure is just one of them)
- Make it pretty! We’ve spent a lot of time during Nitrogen and Oxygen gearing up our look and feel, branding, etc. Now we want to start pulling the trigger on those ideas.
Next week should be interesting and pose a lot of new challenges. I’m expecting that by the end of Fluorine we’ll have a better performing, better looking product. One that will hopefully make you smile and bring a tear to your eye. So keep checking back, and make sure to go give MashedIn a spin and let us know what you think (good, bad, terrible, fantastic – all feedback is welcome)!.
Until then, The Dude abides.
MashedIn – Bringing Y’all Together One Element at a Time
Over the past 7 weeks I’ve been working on a project at work called MashedIn. The goal of the project is to provide social context to otherwise contextual-less online media. For example, pretend I write a blog (which I do… somewhat… kinda…). Using MashedIn I can put a widget on my blog which allows the visitor of my site to see how he or she is connected to me through Twitter, Facebook, and other social networking services (some coming in the near future). This may seem like something trivial (note: it’s not), and on the outset it may seem like something that provides very little value (note: not true), but the fact is it can be a tool of great power when used in the proper setting.
That proper setting is locality. If your’e reading my blog chances are you don’t know me. About 90% of my hits come from a few keyword searches and Google. If I had the MashedIn widget on my blog, and you actually decided to see what it was all about, you’d likely be quite disappointed because – well – we’re likely in different cities, if not other countries. However, imagine you’re viewing the website of your local butcher shop and they have the MashedIn widget on their site. You may have never done business with the butcher shop, you may not even know that the butcher shop in question works only with lamb (they really love their mutton), but by signing into the widget you suddenly realize that you know a few people that work there, and you have several mutual friends. Suddenly you have a boatload of people you can ask about this butcher shop.
That functionality may still sound trivial, but if you start with that foundation the power and complexity that may be provided to you the visitor can suddenly ramp up, especially if you integrate the mashed social graph with other online crowdsourced services (such as StepRep’s recommendation system). Out of the box the widget doesn’t seem very impressive, but we’re only 7 weeks in and we have a huge backlog of ideas that can make this thing pivotal to bloggers, local businesses, etc.
We’re developing MashedIn 1 week at a time (each week named after the element with the corresponding atomic weight). Every Friday morning we plan what we’re going to do for the following Monday through Wednesday. Every Thursday we wrap things up; do one last round of integration, testing and debugging, and then release. The velocity is high and the focus intense. Lots of fun agile practices such as Test Driven Development, pair programming, etc. But more importantly there’s lots of interesting challenges to be solved.
In the 4th week of development (named Beryllium because Beryllium has an atomic weight of 4, you getting this now? Yea, nerdism at it’s best) some pretty bad design decisions were made regarding how we manage all the different social networks MashedIn works with. We spent a bunch of time on the 3 subsequent sprints (Boron, Carbon and Nitrogen) fixing these decisions, and we’re finally at a state that we’re content with… for now. This exercise has been interesting, however, and has proven what we all heard in first year comp-sci: The most expensive part of software development is adjusting code that’s already been released. Keep in mind we spent 1 week (3 days, really) back in Beryllium to write the code that’s pivotal to handling MashedIn’s core system. The design was so poor that it cost us the lion-share of Boron, Carbon and Nitrogen to fix. That’s some rather hefty opportunity cost to pay for not having spent a few more hours group-thinking about a better solution. Thankfully we can finally move on and get back to concentrating on some of the more interesting problems.
Monday marks Day 1 of Oxygen (our 8th week). This sprint’s theme is more consistent and user friendly session management with our various social partners. This is a complicated task because Twitter’s implementation of OAuth is significantly different than Facebook Connect, and who knows how that is different from all the other social networks. We’ve developed patterns over the past few sprints which have significantly improved the experience, but there are still some gotchas that need handling. How do we gracefully handle an expired session, especially since that session is outside of our control and can literally expire at any time? What do we do when a visitor is looking at a widget and the owner of that widget has failed to allow for Facebook’s persistent permissions? How do we balance what the visitor of the site cares to see and do vs. the system’s requirements to do all that crazy processing (thus requiring special permissions from the owner of the widget)? It’s an interesting mix of challenges, and I look forward to seeing what we come up with next week.
Until then, The Dude abides!
Google AppEngine and Separation of Concerns
In the world of writing software there are 2 challenges every developer must face: how to keep your concerns separate, and how to survive the impending deadly boredom of writing all your data CRUD (Create, Update, Retrieve and Delete) functionality. There are a gazillion solutions out there for both. In the realm of functional isolation much has been written, studied, and practiced for separating your program’s concerns. You can adhere to various design patterns; you can establish a pattern and an engine to manage that pattern yourself; you can use one of the several freely available frameworks that already exist (such as Spring). This is good.
In the realm of CRUD management (and boy, is it a crappy job… ba-da-dum!) there’s a plethora of available frameworks for almost every language. These object persistence frameworks handle all the boring, lowdown, uninteresting CRUD functionality that developers loath (but which is a necessary evil). This is also good.
What’s bad, however, is the interoperation of these two challenges rarely seems “natural”. The reason is that object persistence frameworks can really mess with your separation of concerns. The domain classes you write can suddenly become the transport means in your data access layer, thus blurring the lines of what code goes where.
A week ago I started a new application that uses Google AppEngine. Google AppEngine provides an object persistence framework as part of its platform. It also provides a Model-View-Controller type of framework for writing all your web apps. From day one my colleague Kevin Pierce and I have struggled to determine how to separate domain logic from data logic. In AppEngine, your “onion” from the outermost layer to the innermost looks more or less like the following:
[Template] (html/js/css) -> [View] -> [Model] -> [DataStore]
The problem with the above onion is between the View and the Model. Without having something in between your views can (and will) become enormously bloated, full of miscellaneous helper modules, and will operate directly against the Model/Datastore, thus blurring the lines of responsibility in your application. This will eventually make your life a living hell. Kevin and I decided to throw in an intermediary layer between View and Model, called Domain, which houses all the business logic of our application.
[Template] -> [View] -> [Domain] -> [Model] -> [DataStore]
The idea is that the View layer will only ever directly interact with the Domain layer, and never directly against the Model layer. For example, if the View needs to retrieve a Person from the DataStore, instead of going directly using the Model, the View will ask the Domain for an object that’s responsible for retrieving a Person from the DataStore and interact with that object (a classic Factory). Because Python is a dynamic language, in which everything is an object (including classes, functions and modules) this becomes extremely easy. Take the following example:
# in myapp.models.person module
from google.appengine.ext import db
class Person(db.Model):
first_name = db.StringProperty()
last_name = db.StringProperty()
def get_person_by_id(person_id):
return Person.get_by_id(person_id)
# in myapp.domain.person
class PersonProxyFactory(object):
def create(self):
from myapp.models import person
return person
# some_view.py
def get_person(request, *args, **kwargs):
from myapp.domain.person import PersonProxyFactory
factory = PersonProxyFactory().create()
factory.get_person_by_id(request.GET.get('person_id'))
# return some template
In the above example the View has no direct knowledge of the Model; the only layer the View explicitly knows about is Domain. The Domain has knowledge of the Model, and because in python a module is just another object, the Domain’s factory can return the actual person module. The View need not be aware of what the returned object actually is, instead it need only understand what the interface of that object is.
This separates the concerns nicely while still allowing us to use the persistence framework, but it poses some difficult questions. To what extent must we wrap functionality? Is it appropriate for layers above the Model layer to assume that a Person class know how to save itself (via an instance method of save() or put())? Where do we draw the lines with this solution?
How have you tackled the dichotomy of object persistence frameworks and the separation of concerns?
Google AppEngine PolyModels and ModelForms
I recently created my first PolyModel class in Google AppEngine for a new feature. The feature was pretty straight forward - allow comments for some of the entities in our application Homebook. We wanted each comment to be tied back to its target entity – a room, house, or image – in a 1-to-many (each entity can have many comments). Using PolyModel we found this to be pretty easy without duplicating a bunch of code. Essentially the structure of Comment class hierarchy looked like the following:
class Comment(PolyModel):
# bunch of common fields
class RoomComment(Comment):
target = db.ReferenceProperty(reference_class=Room, collection_name=’comments’)
class HomeComment(Comment):
target = db.ReferenceProperty(reference_class=Home, collection_name=’comments’)
class ImageComment(Comment):
target = db.ReferenceProperty(reference_class=Image, collection_name=’comments’)
Really straight forward – simple class inheritance. I then created a simple factory method that would fetch the proper class type for a given instance of one of our commentable entities. Things were moving along nicely (complete with lots of beautiful unit tests – you do write unit tests, right?) and it was time to create the add_comment view.
For the most part we use Google AppEngine’s djangoforms ModelForms, a theoretically clean and easy way to create web forms based on data models. I created my standard ModelForm class (based on our parent Comment class) and the view against which the form would post, only to be blindsided by the oddest of validation errors:
- _class
- This field is required.
Huh? _class? What gives? Well, after a couple hours of soul searching, googling (which turned up nothing), and a few tears, my genius coworker Tony Arkles had an epiphany: The PolyModel class has a _class field which is used to keep track of the PolyModel instance’s class hierarchy. We added the _class field to our form’s exclude list and the world righted itself, cats and dogs learned to coexist, and Liz Taylor finally discovered a happy marriage.
Now the question is, why is the ModelForm rendering a field that’s not a google.appengine.ext.db model property? Can anybody from Google answer me that?