No es agencia para viejunos

Hace unas semanas me di de alta en una empresa de alquiler de coches joven, moderna y dinámica. La idea es estupenda. Sobre el papel. Como siempre, es la implementación la que importa. Concretamente, la implementación del proceso de reserva. Para empezar reconozco que no soy el público objetivo de este servicio: no tengo coche y no se ni quiero saber de coches.

La primera experiencia, añadir mi número de tarjeta de crédito ya fue sospechosa: encontrarte en mitad del proceso con páginas en aleman no es algo que inspire confianza. Que te hagan un cargo sin avisar previamente tampoco. O tal vez sí avisan, pero es que el alemán no es lo mío.

El problema serio llegó a la hora de hacer la primera reserva. Entro en la página y selecciono el modelo de Reserva Básica. Es una empresa moderna, hay tres formas de hacer una reserva. Cada proceso completamente distinto del otro y con sus propios WTF. Lo que podría entenderse como testing A/B¿/C?, pero mal hecho. Me pregunto, de hecho, si realmente analizan los resultados de esta especie de test.

Así que estoy en una pantalla básica, para un usuario básico. Pero este usuario básico no tiene memoria, así que no queda otra que abrir otra ventana para ver la correspondencia entre los chupinombres que la empresa asigna a sus categorías y los modelos reales. Y la información es parca: foto de catálogo y modelo de coche. Cuando me dicen que el modelo es un Kya Ceed me quedo exactamente igual que al principio. En las páginas de alquiler “viejunas” dan información sobre los vehículos que alquilan. Así, cuando necesito ir a un centro comercial o irme con tres amigotes a montar una exposición se si la capacidad del maletero será suficiente.

Entre la mala experiencia de sufrir una página mal diseñada –si no permites que la reserva sea de menos de 60 minutos no dejes que el usuario elija ese intervalo de tiempo, procura que la información relevante esté siempre visible, no la escondas en tooltips y si usas un diseño responsive comprueba que realmente funciona en todos los anchos– y que no me apetecía ponerme a buscar catálogos de coches por internet, opté por usar una agencia de alquiler tradicional. El coste en dinero es superior pero todo el proceso fue rápido e indoloro así que, sumándolo todo, no hay tanta diferencia de coste.

Seguro que alguna de las “pegas” se solucionarían en reservas posteriores, una vez conoces los modelos de coches. Pero lo de tener que hacer experimentos porque una empresa, joven y dinámica, no quiere o no sabe proporcionar al cliente toda la información que pueda necesitar en el momento en que la necesita me cuesta tiempo y dinero. Lo mismo que tener que sortear las idiosincracias de la web de reservas. Ahora estoy en la fase de encontrar la forma de darme de baja de la moderna empresa de alquiler. Pensada para gente joven y que sabe de coches. No soy el público objetivo: yo sólo quiero alquilar un coche, muy de tarde en tarde, sin pegarme con el proceso.

Be careful what and how you “optimize”

Sometimes we tend to over-engineer our code. Just because we think it will look smarter, or run faster, or be more canon-compliant. Let’s take, for example, this function that gets a value from the server and translates it into a class name to apply to an element.

angular.module('widgetTransactionsFilters', [])
       .filter('transactionType', function() {
	return function(input) {
		var strClass = 'type-0';

		switch(input) {
			case 'Payment Credit Card':
				strClass = 'type-1';
				break;
			case 'Cash Withdrawl':
				strClass = 'type-2';
				break;
			case 'Bill Payment':
				strClass = 'type-3';
				break;
			case 'Salary':
				strClass = 'type-4';
				break;
			case 'Online Transfer':
				strClass = 'type-5';
				break;
		}
		return strClass;
	};
});

it’s not the most elegant filter, but hey, it’s mine! As they say, devil will find code for idle hands to refactor. In this case, I decided, don’t ask me why, to change the switch for an array lookup. To make it less legible, mainly. To make any changes to the filter slightly difficult? Who knows. In any case, this was the second version.

angular.module('widgetTransactionsFilters', [])
       .filter('transactionType', function() {
	return function(input) {	
		return 'type-' + 
				(['Payment Credit Card',
				'Cash Withdrawl',
				'Bill Payment',
				'Salary',
				'Online Transfer'].indexOf(input) + 1);
	};
});

Despite my feeble attempts at AngularJS I know some things about JS. One of these things is that most of the array methods are not very optimized. So maybe it’s time to check which version is faster. Or less slow. Fortunately there’s an online tool that can help us to quickly solve this questions: jsperf.com.

Using jsperf.com. you can create a set of tests that will be run in a loop for some time. The speed of the test will be determined by the number of loops executed in that time. Additionally you can run the same tests using different browsers in different platforms. This is specially useful when you’re optimizing your code for an hybrid app where you know the browser and the platform.

You can code your setup, and add a number of tests. This is the setup:

<script>
  Benchmark.prototype.setup = function() {
    function bySwitch(input) {
        var strClass = 'type-0';
    
        switch(input) {
                case 'Payment Credit Card':
                        strClass = 'type-1';
                        break;
                case 'Cash Withdrawal':
                        strClass = 'type-2';
                        break;
                case 'Bill Payment':
                        strClass = 'type-3';
                        break;
                case 'Salary':
                        strClass = 'type-4';
                        break;
                case 'Online Transfer':
                        strClass = 'type-5';
                        break;
        }
        return strClass;
    }
    
    function byArray(input) {   
        return 'type-' + 
                        (['Payment Credit Card',
                        'Cash Withdrawal',
                        'Bill Payment',
                        'Salary',
                        'Online Transfer'].indexOf(input) + 1);
    }
  };
</script>

And these are the tests, along with the results.

performance1

As you can see, the array lookup is way more slow than the old fashioned switch. Not surprises here, people. The only surprise can be the huge difference of performance between Chrome Canary and WebKit when you perform the same test in both browsers.

performance2

Corollary: be careful when you start refactoring and always test the performance of your code.

UPDATE: Vyacheslav Egorov, aka @mraleph, noticed this post and thankfully redirected me to this excellent presentation on how to avoid benchmarking pitfalls due to the JIT optimization. Basically “optimizer eats µbenchmarks for breakfast”.

performance3

I’ve modified the first function to force the switch input NOT to be treated by the compiler as a constant, by changing it from switch(input) to switch(input.toString()). And here are the updated results.

performance4

The difference is still there, both between browsers and ways to test for the string. But the number of iterations for each test shows that all (or most) of the code in each of my tests is being executed. Or so I hope. BTW, the benchmark is located here. Feel free to use and abuse it.

So, the bottom line is: 1. don’t trust blindly in microbenchmarks, 2. don’t assume anything about the language and 3. run, don’t walk, to see mraleph’s presentation.

On AngularJS Considered as one big fat Trojan Horse

A couple of weeks ago I was thinking about the relationship between AngularJS and this company that buys or starts projects and later sink them just because. No, no that company, the other one: Google. While perusing thru job boards AngularJS was appearing as a MUST in the same way (and intent) as .net appears for backend products. And then Google announced their real strategy.

Because, while there other JavaScript libraries out there that do two-way binding, template support and so on, there’s only one with a plan behind. Four years ago Google added AngularJS to its properties portfolio by adding their creators to its engineers portfolio. Just another JavaScript lib in a company where its main JavaScript apps are written in Java. A company that launched (and soon recanted) Dart, another scripting language, as the JavaScript replacement. Thanks to its initial simplicity AngularJS gained some traction. Add behind some marketing muscle and you have a winner.

Then Google announced their plans for AngularJS 2. A total rewrite (they should learn from Netscape) in ATScript. Not in JavaScript. Don’t worry: ATScript compiles to ECMAScript… and Dart. But, of course, there will not be an update path for all the code working in AngularJS right now. They’re just keeping the name. And maybe the logo.

Now I’m gonna dive into prediction territory. Let’s not forget that the business of Google is not in the development tools but in the advertisement. Everything and everyone in the company works for the ads division, directly or not. And one of the hidden but huge costs behind it are the fees payed to Firefox and Apple so they put Google in their respective navigators search box. Chrome on the other hand, been a Google property, adds no cost beyond the engineering resources destined to code it. As well as the Chrome OS, and the Chrome Notebooks.

I say that Google will announce in a months that Chrome will run native ATScript code. And, being a business movement as well as a typed language, quicker than JavaScript. Just another little push to those developers reluctant to embrace the jump from AngularJS to AngularJS 2. The bait: you can code in our language, run it at full speed in our browsers, and still compile it into JavaScript for those other losers still making us pay big bucks to Firefox or Apple.

On the other hand, we have another explanation for the switch to ATScript: the same way Apple has introduced Swift for iOS and MacOS development, maybe Google will introduce Dart (with AngularJS 2 to sweeten the deal) for Android (and Chrome OS) development. But this is just some wild fantasizing.

The toString conundrum

Last week, in the course of a technical job interview I was asked this question:

    How to make

      console.log(test.plus(6).minus(4))

    return

      9.

The first part, chaining functions, is trivial. As you (should) know, you just need to return the object in each chainable method.

function Counter (numInitial) {
      this.counter = numInitial;

      this.plus = function (howmuch) {
            this.counter += howmuch;
            return this;
      };

      this.minus = function (howmuch) {
            this.counter -= howmuch;
            return this;
      };
};

To test this class in your browser you just need to instantiate it like this and then call the required methods:

test = new Counter(7)
> Counter {counter: 7, plus: function, minus: function, toString: function}

console.log(test.plus(6).minus(4))
> Counter {counter: 9, plus: function, minus: function, toString: function}

Of course, the result is not the expected. The tester is asking for the code to return “9”, not the object. Fortunately, there are two methods in the Function() that we can override. These methods are used internally whenever JavaScript need to make a comparison, returning the native value of the Function().

// automatically called to return a String representation of our class

Counter.prototype.toString = function () {
      return this.counter;
};

Of course, you can define this method inside the original definition of the class. I’m just writing this way for you to copy and paste step by step in your browser’s console.

In any case, by overriding the toString method in our class we should get “9”, since console.log() is returning an String. But it doesn’t. It seems that console.log don’t use .toString or .valueOf in FireFox or Chrome. You should thinks of this as a bug, but if you think of it, the function of the console is to give us accurate information of the objects and variables we pass to it. Converting them would, most of the time, not desirable.

The way to really show that our code is working is to force it to return an String, by converting it before passing it to console.log().

// before overriding toString

console.log(test.plus(6).minus(4) + '')
> [object Object]

// after overriding toString

console.log(test.plus(6).minus(4) + '')
> 9

Monday Rant: del pago al contado y otras leyendas urbanas

Todo el mundo conoce el ¿chiste? del congreso internacional de contables donde el representante español alardea de la gran cantidad de formas de pago que conoce hasta que otro delegado le descubre una nueva: pago al contado. Esa leyenda urbana. Un sistema de pago desconocido en un país donde los primeros en estafar a los proveedores son los organismos oficiales, generando impagos porque ellos lo valen. Continue reading