Reuse code, not user experience
Let's face it: as a developer, I'm lazy. I just want to write just enough code. What is more, I want to reuse it whenever possible. I want it to be abstract.
If I'm asked to implement a view which needs a sortable grid, one of those whose rows you can sort by any column by clicking on it, I'll either make use of any sortable grid widget available in the project's UI framework of choice or build sorting functionality into a regular one. No matter the choice, I would end up with a grid widget that sorts strings lexicographically, dates chronologically and numbers... well, you get the idea.
Sounds reasonable, doesn't it? Yes, it does... in general. In general means that statistically it IS the desired behavior, provided that we know nothing else about the context of use. If we don't focus on the task we're trying to help the user accomplish, if we don't wear her shoes, we risk ending up happy with our reusable grid at the cost of making it less usable.
Let's take a look at an example of a team which clearly cares for its users:
So, let's see. Name is a string field, then we should sort it lexicographically... wait a minute! If it's in lexicographical order why is it that "5 - In Your Eyes!!s" is placed between "05 - Heartbreaker" and "05 - Intermedio (JadeI)"? Because it makes sense in this context.
Odds are I don't care whether the track number starts with zero or it doesn't. By discarding the general approach to sorting strings, the iTunes' team made its users' experience a little bit more pleasant. And, at the end of the day, all those little details add up to make an overall satisfactory experience.
Now, if you ask me, at least when I sort my list by song name, I usually don't even care about the track number and whichever other characters prefixing a song's title. I would even ignore all those characters and start sorting by the first alphabetical character. But I can't assure most iTunes users would agree with me. Maybe it's a good example of a decision you would like to make based on the results of usability tests.
To sum up, if you're a lazy developer like me, don't let your appetite for abstraction and reuse leak into the user experience. Less is more, except sometimes when more is more!
Don't make me think... nor work more than I'm supposed to
Don't make me think is a great book about usability and interaction design written by Steve Krug. One of the best things about it is that Steve has used the very same principles he preaches at in his book in the design of its reading experience. The book goes straight to the point, focuses on a handful of very clearly stated ideas and can be read in just a couple of hours!
I don't mean this post to be a review of Don't make me think, it's just that it was the first thought which came to my mind when I received the following "update email" from a very well known group mailing system:

Who's the new member? Do I know her? Wouldn't it make sense to be able to see some of her profile info right there, without needing to go to the group's home page? Why do I have to make an additional step to get that info? Don't make me work more than what's strictly necessary!
By the way, "geochatUsers-Geochat Users Community" is a link, but you just get to know that once you hover over it and your mouse cursor turns into a pointer. I remember having got this wrong in my own developments countless times: links which don't look alike links. Don't make the user think! If there's something that she can click or act over, it has to be apparent. That's what designers call affordance: it's what an object's appearance, smell, texture, sound, etc, tells us about what we can do with it.
Last but not least, when I clicked the link I had to manually log in before being able to enter the group's home page. The group mailing system already knew it was me (or it could have easily known it), because I clicked the link from my email box. That takes us to another principle: user input is sacred, don't lose it nor ask more of it than necessary.
Have a nice week!
Upgrading to Rails 3: @routes is nil
I'm currently in the process of upgrading an application from Rails 2 to Rails 3. Fortunately, it's not the first time someone does so, and there's plenty of resources throughout the web that will help you to work it out. In particular, I chose to follow the steps demonstrated by Ryan Bates in an outstanding series of three railscasts, titled Upgrading to Rails 3 (Part 1, Part 2, and Part 3).
Everything was going smoothly, until while trying to get my functional tests to pass I got the following error:
test_should_decode_a_message_with_a_plain_code(DecodeControllerTest):
RuntimeError: @routes is nil: make sure you set it in your test's setup method.
/Users/mverzilli/.rvm/gems/ruby-1.9.2-p180/gems/actionpack-3.0.5/lib/action_controller/test_case.rb:388:in `block in process'
/Users/mverzilli/.rvm/gems/ruby-1.9.2-p180/gems/actionpack-3.0.5/lib/action_controller/test_case.rb:386:in `each'
/Users/mverzilli/.rvm/gems/ruby-1.9.2-p180/gems/actionpack-3.0.5/lib/action_controller/test_case.rb:386:in `process'
/Users/mverzilli/.rvm/gems/ruby-1.9.2-p180/gems/actionpack-3.0.5/lib/action_controller/test_case.rb:47:in `process'
/Users/mverzilli/.rvm/gems/ruby-1.9.2-p180/gems/actionpack-3.0.5/lib/action_controller/test_case.rb:355:in `post'
test/functional/decode_controller_test.rb:67:in `block in '
/Users/mverzilli/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.5/lib/active_support/testing/setup_and_teardown.rb:67:in `block in run'
/Users/mverzilli/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.5/lib/active_support/callbacks.rb:428:in `_run_setup_callbacks'
/Users/mverzilli/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.5/lib/active_support/testing/setup_and_teardown.rb:65:in `run'
As usual, I resorted to allmighty Google looking for "@routes is nil", since "someone must have already stumbled upon this before"...and no luck. So I started comparing some of the files in my upgraded app with their correspondent files in another (working) app which had developed using Rails 3 from scratch. I found out there was a slight difference between both "test_helper.rb" files:
require 'rails/test_help'
That line was present in the Rails-3-from-scratch app but not in the one I'm upgrading. Then, I just added that line and the "@routes is nil" error was gone. I should have payed more attention, because when running rake rails:upgrade:check, I was getting the following warning:
Deprecated test_help path
You now must require 'rails/test_help' not just 'test_help'.
More information: http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices
The culprits:
- [...]test/test_helper.rb
That's right, the rails_upgrade plugin had let me know of the issue and even how to solve it, but I just skipped that suggestion. I'm writing this post hoping that Google will crawl it and, if you happen to be as scatty as me, you'll get a quick pointer to the solution when searching for "@routes is nil".
So, in short (please write this down, Google), if after upgrading to Rails 3 your app, you're getting a "@routes is nil" error, just add the line require 'rails/test_help' at the beginning of your test_helper.rb file, and that should do the trick.
Contratos de alcance opcional: una traducción de "Optional Scope Contracts", de Kent Beck y Dave Cleal
Rápido, sin pensar demasiado, decime cuántos de los últimos diez proyectos de desarrollo de software que encaraste (como proveedor o como cliente) terminaron en la fecha convenida, con el 100% de los features implementados. ¿Hay alguno? Si tuviste el rol de proveedor, ¿cuántos de esos proyectos agregarías a tu portfolio para mostrar orgulloso tu compromiso con el desarrollo de productos de alta calidad? Si fuiste el cliente, ¿cuántos de esos proyectos salieron a producción inmediatamente, generaron algún tipo de beneficio y/o te hicieron sentir que obtuviste lo que correspondía a cambio de tu dinero?
La semana pasada, por recomendación de Nico di Tada, leí el paper Optional Scope Contracts, de Kent Beck y Dave Cleal. En ese trabajo, Beck y Cleal explican por qué creen que la respuesta a muchas de las preguntas que le hago al hipotético lector en el párrafo anterior pueden tener como respuesta "Ninguno".
Parece ser que la costumbre de firmar contratos que fijen el costo, la fecha de entrega y el alcance de un proyecto tiene como consecuencia el sacrificio de la calidad del producto ante el primer inconveniente. ¿Te suena? Por suerte, los autores no se quedan en la mera crítica y proponen (y justifican, y defienden...) una alternativa: los contratos de alcance opcional.
Con el consentimiento de Kent, traduje su paper al español y decidí ponerlo a disposición en este post, con la intención de aportar mi granito de arena a "transmitir la palabra" en el mundo de habla hispana en general, y en nuestro país en particular:
Install the RMagick gem in the painless way with Homebrew
Introduction
Disclaimer: this section is just happy talking, if you want to get right to the beef, skip it and go right to the beef.
Yesterday was a sad day for me. It wasn't meant to be like that.
I began the day with the intention of setting up a development environment for this amazing RoR application I'll tell you about some other day. You know what it is like to set up a RoR environment: just a few gem installs here, a couple rakes there and voila! Two minutes after you started, you're all set to begin coding.
Well, no. One of the required gems was RMagick, a wrapper of the arch-famous ImageMagick graphics processing library. In order to be able to install the RMagick gem, you need first to install ImageMagick.
So far so good, but this library has a whole lot of dependencies, and if you're not a Unix and C Jedi (I'm not), it may be painful to get to a happy ending. I spent the day googling around looking for a good tutorial, and most of them recommended one of two alternatives:
- Use MacPorts: tried, no success.
- Use a script that some guy put together once. Basically it consisted of downloading, compiling and installing all the dependencies, and then ImageMagick: tried, no success.
I guess the reason why I failed with both alternatives is that at some point of the installation, I made a wrong a choice of version for any of the dependencies. By the end of the day, I still hadn't been able to start debugging the application.
Then I spoke to my colleague Adrian Romero (who unfortunately doesn´t have a blog to point you to), and he suggested me to try with Homebrew. This is how the story ends, I used Homebrew, and was able to get back on track quite quickly.
Brewing magic
2) Install Ghostscript:
sudo brew install ghostscript
Pre-3) Update! Before brewing imagemagick, you may need to install git:
sudo brew install git
I might have not realized this step was necessary because I had already installed git in my machine before. Thanks Nielson for pointing out this!
3) Install ImageMagick:
sudo brew install imagemagick
Ok, step 3 may not be that easy. One of the dependencies, Little CMS, may fail to install because they removed the file from the URL where Homebrew looks for it. This causes the ImageMagick installation process to abort.
I worked this issue around by replacing the URL in the Little CMS Homebrew formula with a location where at the moment of this post's publishing it can be found.
3a) Edit the formula:
sudo brew edit little-cms
3b) Look for this line:
url 'http://www.littlecms.com/lcms-1.19.tar.gz'
3c) Replace with:
url 'http://www.imagemagick.org/download/delegates/lcms-1.19.tar.gz' (or an URL where you could find "lcms-1.19.tar.gz")
3d) Try again to install ImageMagick (it should work now):
sudo brew install imagemagick
4) Welcome back home, just install the rmagick gem:
sudo gem install rmagick
5) Celebrate
Happy brewing!
How do I unit-test a class which depends on HttpContext?
Suppose you have to fix a bug in an ASP.NET application. You’re a TDD-guy so once you identify it, you write a test which should reproduce it. Then you run it and… null pointer exception. Your testing framework may have pointed you to the exact line, so you inspect it and see something like:
var foo = HttpContext.Current.[...];
Then you realize the guy who wrote the buggy class wasn’t a TDD-guy!
You need somehow to be able to inject an HttpContext object so you can run your tests without the need of running a web server. If you can do that, then you just mock it and… wait! HttpContext is a concrete class! So now, what?
Well, ASP.NET MVC comes with the assembly System.Web.Abstractions which adds classes to the System.Web namespace such as HttpContextBase, HttpRequestBase, and other abstractions of ASP.NET intrinsic objects.
Cool! Now you can mock HttpContextBase and inject it to the tested class.
Are you done? Not yet. HttpContextBase is of course a newer class than HttpContext, so not surprisingly HttpContext does not derive from HttpContextBase. Nevertheless, System.Web.Abstractions provides an HttpContextWrapper which does inherit from HttpContextBase and receives an instance of HttpContext through its constructor.
Now all you have to do is encapsulate or your uses of HttpContext.Current in some way that let’s you substitute it for an injected mock transparently for the user code.
In my case, it was more convenient to inject via a setter:
private HttpContextBase context = null; /// <summary> /// Allows HttpContext injection, mainly for testing purposes /// </summary> public HttpContextBase CurrentHttpContext { get { context = context ?? new HttpContextWrapper(HttpContext.Current); return context; } set { context = value; } }
But it would be exactly the same to do it via a constructor. Then, you just have to replace all your HttpContext.Current calls with calls to the property CurrentHttpContext:
var foo = CurrentHttpContext[...];
When you see there’s an assembly called “Abstractions” with abstract classes and wrappers for preexisting concrete or even sealed classes, it becomes obvious that the ASP.NET MVC team has written its code with testability in mind, and that’s great! So kudos to them
Neyun is here!
I'm glad to announce the first Beta Release of Neyun has been oficially launched!
Neyun is a web application which lets you navigate and query through all your pictures, emails, messages, videos and links, no matter if they come from your RSS feeds or your Facebook, Gmail, Twitter, Flickr, YouTube, Digg or Del.icio.us accounts.
Neyun automatically imports your data and extracts tags from it. Then you can visualize it in an homogeneous way, just like if it all came from the same application. You'll have a tag cloud where you'll find all these extracted tags. Using them, you'll be able to filter your data: you can select one of them to see all its elements, or intersect two of them to see which elements are tagged with both.
But these are not the only ways of filtering your data. By activating the "timeline view" you'll be able to see the elements matching your criteria ordered above a timeline, which gives you the ability to see when an element has been added at a glimpse.
If these filters are not enough, you can do a full text search over the elements.
Neyun also extracts relations between your elements. So, let's say you are browsing a Facebook contact's profile (let's call him John Doe... pretty creative I am), you can see John's pictures, events, etc, listed in the same place. So, what if you have a picture of your boyfriend in Flickr and somebody else of your Facebook list uploaded another one? You'd like them to be related to your boyfriend, wouldn't you? Ok, we know Neyun is not thaaaaat smart to realize of this relation (at the moment... just give us some time to look into it
), but you can manually set it.
I could spend hours talking about Neyun (I acknowledge I'm not very objective when I do), but why don't you try it yourself? Go get your beta at Neyun's homepage, and let me know what you think!
Martin
Programming paradigms and correctness
For many, programming nowadays means writing some code in an object oriented programming language such as C#, Java or C++ at a lower level. Well, those are the mainstream languages nowadays and the reigning paradigm is the object oriented one.
What is a programming paradigm? It's a philosophical and theoretical framework within which solutions to problems of algorithmic nature are formulated. What a definition! Well, to say it simpler, a paradigm represents a way of thinking, thus a programming paradigm is one way of thinking about programming.
Let's take for example C#, Java, C++, etc. They're all in fact imperative object oriented languages. How do you think about programming when you use an imperative language? You're thinking in state, which is a snapshot of your machine's memory. Can you guess what I was thinking about when John Doe asked me to write a function which adds 5 to a given parameter and I wrote this?
int Add5(int x) { for (int i = 0; i < 5; i++) { x++; } return x; }
This is what I thought: "x comes with a value, stored somewhere. I can add 1 to that value and store it again. So now I have x+1 instead. The next time I add 1, I'll have x+2. If I add 1 five times... bingo!"
Ok, if I did think that "smoothly" it'll take hours to write the simplest program, and I would be fired in a couple of days. I, as any imperative programmer, do it pretty naturally, but that's because we have assumed and internalized the paradigm!
That kind of reasoning ("I have this value stored here, then I transform it in this way, then I transform the result in that way, etc") is exactly what we do when we demonstrate correctness of an imperative program according to a specification.
And that happens in general: the mechanisms to prove correctness of a program in a given paradigm are deeply connected with the way we think when we write programs in that paradigm.
An alternative to the imperative paradigm is functional programming. This one may not be that familiar to all programmers, since it's more rarely used in industry. Those with an academic background will know it for sure.
What are we thinking of when we program with a functional language? We are thinking in composing and applying functions. There's no state here. If we need to repeat some task, we make use of recursion. Programs look a lot more like math equations than in imperative. Functional programming lovers, say a functional program is so much more declarative and self-evident than an imperative one. I agree, but that's true once you got used to think "in functional". At first, if you come from imperative programming, it's not that easy to get it.
Let's see our completely useless "Add5" function written in Haskell, a functional programming language:
add5 :: Int -> Int add5 x = addN 5 x addN :: Int -> Int -> Int addN 0 x = x addN n x = 1 + addN x (n-1)
I had to use an auxiliary function called addN, which let's me recurse over N and repeatedly add 1 five times. That's what I meant when I said repetition is performed through recursion.
Now, have you noticed the arity of addN? Int -> Int -> Int. To simplify things, we could say the 2 first parts of it mean the function expects 2 ints as parameters, and the last one says it returns an int. That would work. However, it would hide the power of functional programming. In functional programming, functions are first class citizens. They can be understood as operations as usual, but they can be used as values also. They can even be data structures. The way to parenthesize Int -> Int -> Int, is Int -> (Int -> Int). What does that mean? addN is a function which takes an Int and returns another function! The arity of the new function is Int -> Int. Knowing this, we could redefine add5 in a simpler way:
add5 = addN 5
See? We don't need to use both parameters of addN at once. If we did, we would obtain an int. Instead, we just give it the first one, and we get a function! So we defined a whole family of functions by defining a single function! We can do this due to another feature of the paradigm: partial application of functions. We are partially applying addN when we just give it the first param.
This is just the top of an iceberg about functional programming. Trust me, it's amazing.
How do we prove correctness in functional programming? Basically through induction. Since the repetition artifact is recursion, and all the statements are given as equations, this mathematical tool is all we need. That's one of the advantages of not having to rely in state to perform our computations. And that gives us the clue of what we think of when we program in the functional paradigm: recursion and equations.
Finally, a third paradigm (there are dozens of paradigms!): the logic paradigm. It has a pretty famous language: Prolog.
What do we think when we program in the logic paradigm? Well, we think in what we don't know and what we do know. The result we want to get is what we don't know. The program consists in stating which are those things we don't know and we want to know (called "goals") and stating which things are true (called "knowledge base"). Let's go back to add5, now in Prolog:
nat(zero). nat(suc(X)): - nat(X). add(zero, X, X). add(suc(X), Y, suc(Z)) :- add(X, Y, Z). add5(X, Y) :- add(X, 5, Y).
I also needed to define a couple of auxiliaries. First of all, in Prolog all our statements are predicates. A program is a set of predicates and a goal. In the first 2 lines, we define the naturals. We assert to things: "zero is a natural" and "if X is a natural, then suc(X) is a natural". Then we define the relation "add". First we say that the result of adding zero to any number is the same number. Then we say, "if I add one to one of the operands, then the result also must be greater by one". As in functional, repetition is expressed through recursion. Then we define add5 in terms of add.
To execute this program, we have to ask Prolog to find what we don't know in terms of this knowledge base. We would do it like this:
? add5(10, X)
And Prolog would answer 15. If there were more than one feasible result, we could ask Prolog to return another answer. The question means: "find any X such that add5(10, X) is true". Prolog then tries to infer X from the given knowledge base.
How do we prove correctness? Well, the answer is... we don't! The one who proves correctness in this case is Prolog. We just state truths, then Prolog proves that the result it found is correct according to those proves.
Knowing more than one programming paradigm helps us think in different ways when it comes to solving a problem. You may not use many of them usually, but it's a great mind exercise to at least try them a couple of times. If you didn't yet, I hope this post encourages you to take a look at them!
Martin
Silverlight 2 RTM problem with Internet Explorer 6 and GZip compression: a workaround if you're using Jetty
We are developing a Silverlight application since some months ago. As you may know, an RTM of Silverlight 2 has been released recently, so we decided to migrate our project to it. Surprisingly, it stopped to work in IE 6 after the migration. The exception raised by Silverlight looked like:
[BrowserHttpWebRequest_WebException_RemoteServer]
Arguments:NotFound
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=2.0.31005.0&File=System.Windows.dll&Key=BrowserHttpWebRequest_WebException_RemoteServer
Pretty mysterious, isn't it? Well, fortunately I googled it, and I found the following thread in the official Silverlight forum:
https://silverlight.net/forums/p/42908/123627.aspx
According to Vijay Devatha, from the Silverlight team:
This is a known issue that, unfortunately, currently has no workaround. We definitely plan to fix it in the following release; but like I said, for the time being, to get this scenario to work in on IE6, you're going to have to either disable compressing the content (on the server side), or have the server not set the Cache header to no-cache.
I didn't have the Cache-Control header field set to no-cache, so that wasn't the problem. Then I tried disabling GZip compression and it worked!
Great but... GZip compression was there for a good reason. Having to disable it for Firefox, Safari and even IE7 just because it didn't work with IE6 didn't sound like a great deal... So the most reasonable workaround seemed to disable GZip just for IE6.
Using an exclusion list of user agents to disable GZip in Jetty for some browsers
In the second part of this post, I'll show how to disable GZip compression for a fixed list of browsers. It is simple, but I had to figure it out from scratch, because I didn't find much documentation on the subject.
If you want to implement GZip in Jetty, you just have to add a GZipFilter to the filter chain of your Jetty context. Usually, this is done as follows:
context.addFilter(GZipFilter.class, "/*", 0);
Now, we want GZipFilter to be applied just when the request comes from some browsers. There's an initialization parameter which allows us to do that: excludeUserAgents.
So the above code now will look as follows:
GzipFilter gzipFilter = new GzipFilter();
FilterHolder filterHolder = new FilterHolder(gzipFilter);
filterHolder.setInitParameter("userAgent", "(?:Mozilla[^\
compatible;
\\s*+([^;]*);.*)|(?:.*?([^\\s]+/[^\\s]+).*)");
filterHolder.setInitParameter("excludedAgents", "MSIE 6.0");
context.addFilter(filterHolder, "/*", 0);
Since we need to customize some parameters from GzipFilter, we can't let the Jetty Context instantiate it anymore.
There's an overload of addFilter which expects a FilterHolder object instead of a Class. The FilterHolder will act as a proxy and will set up the GzipFilter instance for us when a request has to be satisfied.
So we inject the GzipFilter instance into the FilterHolder constructor and set up the custom parameters we need. The "userAgent" parameter is mandatory, it states which user agents will be processed. The regex I'm using should match any of the main browsers out there.
Now we just need to exclude the browsers we don't want to receive gzipped content. This is done by setting the "excludedAgents" parameter. It expects a comma separated list of user agent ids. In my case, I just needed to filter out IE6, so I set "MSIE 6.0"
This way we can have our application working on IE6 while we wait for the problem to be fixed.
Martin
OneDay Santander at Microsoft Argentina on 09/15/2008
Last Monday I had the opportunity to join Brian Cardiff at OneDay Santander to give a conference on ASP.NET and Ajax. OneDay Santander was an event organized by Microsoft Argentina attended by Banco Santander's IT team.
It was a great experience, which let me learn a lot from an outstanding speaker like Brian and be in touch with colleagues from Microsoft and Banco Santander.
Thanks Miguel Sáez, Brian and Manas for this great opportunity!
PS: you'll be able to download the conference's slides from Brian's blog soon...
