Sunday, June 16, 2013

Feeds worth reading - saying goodbye to Google Reader

New to programming in the wild, and starving for hints on how to do it better, I would often stumble upon programmers documenting their journey on a personal blog. A big orange icon would incite readers to subscribe to their content using RSS. Taking the bait, I started using Google Reader, and found myself frantically hoarding feeds a bit later.

After a while I got fed up with going through an abundance of subscriptions daily though; it was turning into a chore. Instead of forsaking RSS, I set myself to aggressively cut down the number of feeds I subscribe to - RSS is too powerful to just dismiss. A feed I subscribe to should be fairly consistent at making what I read worthwhile. I even adapted the practice of putting a feed in quarantine before it makes it into my permanent reading list.

Being a loyal Reader user for five years, I was startled when Google announced the end of Reader. Although I somewhat understand Google feels the need to focus on a limited set of products, condemning Reader to the graveyard must hurt the trust of an influential customer segment; tech-savvy people. I for one feel less and less confident hosting my writings on Blogger, and I will definitely think twice before I take a dependency on another Google service in the future. I take comfort in the thought that Google is less likely to kill a service where they have been trusted with content that lies very close to a customer's heart, and that when they do close the books, they have a reputation of making your way out as smooth as possible.

Now that July is creeping up on us, I have to get off the fence, and elect a Google Reader successor. When I asked the Twitter crowd where they migrated to, Feedly seemed to be the consensus. I had a look at its homepage, but not offering a browser based version is a showstopper for me. I then read this Lifehacker article, and decided on trying The Old Reader, which doesn't seem to move my Google Reader cheese too much.

Preparing the migration, I took five minutes to push my OPML file, and a more readable markdown representation to Github. Find my curated list of feeds I consider worth reading here.

I'm still looking for resources on life in general and functional programming that can positively influence me. If you have any recommendations please let me know!

Sunday, June 9, 2013

Angular.js and IE8 caching

Older Internet Explorer versions are notorious for agressively caching AJAX requests. In this post, you'll find two techniques that combat this behaviour.

The first option is to have your server explicitly set the caching headers.
Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
Response.Cache.SetValidUntilExpires(false);
Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Since you don't necessarily own the server, or clients might already have cached some requests, you can trick the browser into thinking each request is a fresh one by making each url unique. Our old pal jQuery already learned this trick years ago. Angular.js on the other hand seems to have forgotten. We can get around though.

If you merge this pull request (or wait for angular.js version 1.2), you will find angular's HTTP provider augmented with request interceptors, enabling you to mold the request before it goes out.

The interceptor we're adding to kill the cache only touches GET requests, appending a 'cacheSlayer' querystring parameter with a timestamp to each url, making it unique and thus bypassing the cache. A factory is responsible for creating it, while a config block pushes it into a collection of interceptors.
var AppInfrastructure = angular.module('App.Infrastructure', []);

AppInfrastructure
    .config(function ($httpProvider) {
        $httpProvider.requestInterceptors.push('httpRequestInterceptorCacheBuster');
    })    
    .factory('httpRequestInterceptorCacheBuster', function () {
        return function (promise) {
            return promise.then(function (request) {
                if (request.method === 'GET') {
                    var sep = request.url.indexOf('?') === -1 ? '?' : '&';
                    request.url = request.url + sep + 'cacheSlayer=' + new Date().getTime();
                }

                return request;
            });
        };
    });    
I hope this helps someone spending time on more important matters. 

Sunday, June 2, 2013

Accidental entities - what about the UI?

This post is a follow-up to my previous blog post "Accidental entities - you don't need that identity".

In that post, we followed a consultant building an application for a car rental. One of the requirements was that the CEO could manage a collection of available colors. Although the tools at our disposal - a relational database and NHibernate - wanted to trick us into making a car reference one of these available colors by its identifier, we found out that the CEO really thinks of a car's color as a value, and does not care about a color's identity. This means that we didn't make a car reference an available color, but we copied its value instead. This allows the CEO to remove available colors, without it having an impact on cars that already came in that color.

The solution we're building contains a public facing web application that allows customers to make reservations online, and a backoffice web application - hosted on the intranet, that employees will use to manage the cars.

When a new car arrives at the car rental, a backoffice user will register it. Once the car is registered - and in use, backoffice users should still be able to change some of its characteristics; brand, model, color, engine size, etc...

Instinct tells us to add a page that enables editing all the car's properties. Some of these properties are free text, some radio buttons, but for the car color, it's a dropdownlist.
Halfway through implementing this new functionality, we notice that changing the color gets us into trouble. We populate the dropdownlist with all available colors, but when we want to bind the car's current color as the selected value, it's not in the list of available colors. The CEO has removed the car's current color out of the list of available colors.
After a bit of tinkering, we come up with a workaround that adds the car's current color to the available colors with a default value of -1. This allows us to determine if the color needs to be changed.


Relational databases, RAD tools, scaffolding and anemic models have poisoned our minds, making us throw up the database schema all over the UI. We can do a lot more though.
If we take a step back, and make an effort to discover what changing these properties really means to our business users, we might come up with a totally different user experience.

We leave the UI as is, and ping the CEO on Lync, inviting her for a coffee break.

After a bit of obligatory small talk, we start asking questions about what we're really after.

Us: "Can all of the car's characteristics change after the initial registration?"
CEO: "No, have you ever seen a car change brand, or model through its lifecycle?"

Us: "I can imagine the engine size also belongs to the list of characteristics that can't be changed after registration?"
CEO: "Oh, it can! We sometimes have the engine of our sports models tuned to have an edge over the competition. Guys are crazy for horsepower."

Us: "What about changing the color?"
CEO: "If a car has some nasty scratches on it, we sometimes get it repainted. If we do get it repainted, it's always in one of the colors available at that moment."

We return to our desk with a far better understanding of what it really means to change each of the car's characteristics. We discovered a whole new language, with some important constraints. Neither brands nor models change after registration. Engines get tuned, increasing their engine size. A car's color doesn't change; a car gets repainted - always in one of the available colors.

After iterating on this feedback, we're far more satisfied with the model; it captures the language far better. Our backend implementation is not the most important part of the solution though; it's useful to invest in improving the UI.

After some experimentation we come up with a more task-based UI, something that looks like this.


The UI now does a far better job supporting the language and communicating its constraints. And with that, we also solved the original problem that motivated us to ask these extra questions. There is no value in having the current color in the dropdownlist; we are better off making the process of having a car repainted explicit.

When we make an effort to really capture the language, this will be reflected in our model, but also in the UI. This can add tremendous value. It's not only about making the user experience more intuitive, but about making a language consistent for thousands of users, supporting processes and communication throughout the company.

As a disclaimer; sometimes it's fine to just throw up your database. There's a place and time for anything. But don't let CRUD be the only tool in your toolbox; you can do much more. Make sure to invest this extra effort where it matters, where it makes a difference.