Blog

  • 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.

  • 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. (more…)

  • What’s in an SPA? Part II, the A in SPA

    As you may remember from the first part of this thrilling SPA saga, the only object I’ve invoked right now is the Application. What is this Application that everyone in the ‘hood is talking about?

    For starters it should be your main dispatcher for all the objects in your application. Remember, we’re not doing a web page or a bunch of html files with some javascript, but an application. Think of it as of your safehouse. Whenever you’re lost (you shouldn’t but you will be) in the maze of your code you can reach up to your fair objApp variable and crawl down from it to known territories. For example, to execute the orderMoreTunnel() method of the Tunnel module. (more…)

  • Lo que hay debajo

    La mayoría de los frameworks modernos utilizan algún tipo de atributo añadido a los elementos para indicar como dibujar o que controlador asignar a dicho elemento. Por ejemplo, en jQueryMobile y en bootstrap se utilizan los atributos “data-“ para indicar roles, estilos, etc.; de la misma manera, en AngularJS se asignan atributos con el prefijo “ng-“ para asignar, por ejemplo, un controlador a un <div> concreto. No es la única manera de “dopar” la página; la mayoría de las librerías tienen métodos para aplicar un behaviour concreto a un objeto de nuestra página. (more…)