Monday, September 22, 2014

When Computed Styles aren't Computed

I noticed something unexpected the other day when working with jQuery to read CSS dimension properties. Maybe everyone else in the world is already aware of this but I'll talk about it anyway.

Typically, whenever you use jQuery to read the value of a height or width property of an element, the value is always returned in pixels. You can set the value in %, px, em, cm, whatever. But it always comes back to you in pixels. It will actually be a string with "px" at the end.

Except when it's not.

I was relying on this behavior. I would grab the value, remove the "px" from the end, and turn it into a Number. But sometimes I was getting "NaN" as my value. Upon closer inspection, it turned out that I was getting a value like "82%" instead of "435px" which was throwing everything off.

Technically, jQuery is giving me what is known as the computed value of the property. Sure, sometimes getting the value in pixels is not what you want, but as long as it's consistent you can deal with it. I was encountering the problem that sometimes it was in pixels and sometimes it was the value that I set it from, which happened to be percent.

It took me a while, but I finally figured out what was going on.

When the element's parent (not the element itself) has a display value of "none," the browser can't give me the computed dimensions because it has no way to compute them. Instead, you get whatever value the CSS says.

Check out this test page I put together to demonstrate the issue.

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>CSS Test</title>
</head>

<body>

  <div id="container" style="width: 400px;">
    <div id="test" style="width: 50%">test</div>
  </div>

</body>

<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script>

$(function() {

    console.log($('#test').css('width'));

    $('#container').toggle();

    console.log($('#test').css('width'));

    $('#container').toggle();

    console.log($('#test').css('width'));

});

</script>

</html>

Here is the console output.


As you can see, the test div has a width specified as 50% but when the value of the "width" CSS property is printed out, it is "200px". This is exactly correct, since 200px is 50% of the 400px width specified on the parent container.

After I toggle the visibility of the parent container (the jQuery .toggle() function) and print the width of the test div again, I get a value of "50%". That's what the style attribute says.

Toggle the parent container visibility again (make it visible) and you see "200px" on the console again.

Once I learned this and restored my sanity, I was able to fix my problem easily by making my elements' parent visible before I tried to read the dimensions. Originally I was trying to read them, perform some calculations, and then make the parent visible. There were no real issues with switching the order around a little in my case, but your mileage may vary.

Amphibian.com comic for September 22, 2014

Friday, September 19, 2014

Talk Like a Pirate

Today is International Talk Like a Pirate Day. In honor of this occasion, I will present a short list of  my favorite pirate words and phrases for you to use. I use some of these year-round.
  • Avast ye! means pay attention!
  • Hornswaggle means "to cheat"
  • Cackle fruit are chicken eggs
  • Blimey! is something said when one is in a state of surprise
  • Scallywag is a name that is used as an insult to someone
  • Son of a biscuit eater is another insult
That's pretty much it for today.

Amphibian.com comic for September 19, 2014

Wednesday, September 17, 2014

Simple Animation

In my web comics, I wanted to be able to take full advantage of the web as a medium. Not like the size between small and large, medium like the singular of media. Like the stuff we use to communicate.

I just wanted a simple and extensible way to make some parts of the comic cells move or change color or things of that nature. I use jQuery which has some animation features, but they are mostly geared towards the changing of CSS properties. I may want to do that sometimes, but not exclusively.

Here's what I came up with.

When I set up a type of animation on an img object, I set a few attributes on it. First, I set animated = 'true' to flag the animated images in a way that's easy to grab them using jQuery. Then I set another attribute that specifies the animation function to use. Something along the lines of animationType = 'flicker' for example. Then I set other attributes specific to that type of animation.

I might end up with some HTML like this:

<div>
    <img src="something.png" />
    <img src="frog.png" animated='true' animationType='flicker' flickerSpeed='1.5' />
    <img src="whatnot.png" />
</div>

I then have a setupAnimation function which performs the initial setup for my animated images. Here is a simplified version of what I use.

function setupAnimation() {

    window.animated = [];

    $("img[animated='true']").each(function(idx, elem) {

        var aType = $(elem).attr('animationType');

        if (aType === 'flicker') {

            // assign a function here. function must
            // be defined somewhere. we can also perform
            // any necessary initialization here.

            elem.aniFunction = flicker;

        } else if (aType === 'something else') {

            // other types can go here

        } else {

            // unknown animation type value
            elem.aniFunction = function() {
                // no op
            };

        }

        window.animated.push(elem);

    });

}

In this function, I am basically searching for all the animated elements, setting their animation functions, and performing any initialization that may need to happen. Then I save them in an array which I can later use to find them without having to use the jQuery selector again. I call this setupAnimation function once when the page is done loading.

As you see above, when the animation type is "flicker" I set the element's animation function to be "flicker." This implies that I have a function named flicker defined somewhere. I like this simple method of assigning a method to perform a certain type of animation because it allows me to easily add new types or modify the internal workings of existing types independent of the HTML. If tomorrow I want the "flicker" animation type to use a new "flicker2" function that I make, I can do that. If I want to totally change how the "flicker" function works, I can do that too.

As a future enhancement, I could have animation types self-initialize and put themselves in a map or something so I could get rid of the if...else if...else block here. Writing code that does not contain if...else statements should be the ultimate goal of every programmer, but I prefer to keep things simple at first and then refactor to better patterns later. I know it might sound like procrastination, but it works. It's a thing I do.

Anyway, once I have the animation set up, I have to kick off some kind of animation loop.

$(function () { 

    var lastTime = null;

    function run(timestamp) {

        window.requestAnimationFrame(function(e) { run(e); });

        var elapsed;
        if (lastTime === null) {
            lastTime = timestamp;
        }
        elapsed = timestamp - lastTime;
        lastTime = timestamp;

        animated.forEach(function (elem, idx) {
            elem.aniFunction(elapsed);
        });

    }

    window.requestAnimationFrame(function(e) { run(e); });

});

I leverage the window.requestAnimationFrame function to ensure smooth animation. The general contract of requestAnimationFrame is that it calls the given callback function and passes a really really accurate timestamp in milliseconds as the parameter. And if you want it to run again, you have to call it again from within the function that it calls. That's why I define a run function that takes the timestamp as a parameter and then call it from an anonymous function declared as the parameter for requestAnimationFrame.

In my run function, I use the timestamp argument to calculate the elapsed time since the last call, and pass that to the aniFunction of the elements in the animated array. The general contract of one of my animation handler functions is that it will receive a single argument indicating the elapsed time in milliseconds since the last call. This elapsed time value can be used to calculate how far an element should move, how much it should change color, if it should toggle its visibility, if it should change to a different image, or whatever else imaginable.

Here is my flicker animation function, so you can get an idea of what I am talking about.

function flicker(e) {

    if (typeof this.timespan === 'undefined') {
        this.timespan = -1;
    }

    if (typeof this.counter === 'undefined') {
        this.counter = 0;
    }

    if (this.timespan === -1) {
        // pick a new timespan value, based on speed
        this.timespan = Number($(this).attr('flickerSpeed')) * 1000 * Math.random();
    }

    this.counter += e;
    if (this.counter > this.timespan) {
        this.timespan = -1;
        this.counter = 0;
        $(this).toggle();
    }

}

It is a fairly simple animation that produces a flickering effect like an old fluorescent light bulb. After making sure that the timespan and counter properties are initialized, I check to see if I need to calculate a new wait time before toggling. It will be a random number between 0 and flickerSpeed seconds. In all cases, I add the current elapsed time to the total counter. If the counter is greater than the last calculated timespan, the element's visibility is toggled and timespan is set to -1 in order that a new timespan will be calculated the next time through.

It all works great, with one small catch. There are still web browsers out there that don't support the window.requestAnimationFrame function. I've found that at the very least, iOS Safari prior to version 6 does not. Since iPhones still running iOS 5 are not that uncommon, I needed to do something to provide them with animation.

The answer was to include a polyfill. A polyfill? Like pillow stuffing? Not quite. Polyfill in this context means "a piece of code that provides the technology that you, the developer, expect the browser to provide natively". That definition is from Remy Sharp, who explains the origin of the term on his blog. I basically had to check to see if the browser already had a requestAnimationFrame function defined, and if not, define it myself. The backwards-compatible solution is to use window.setTimeout and call the given callback function with a single argument representing the current timestamp in milliseconds. Here is what I use:

if ( !window.requestAnimationFrame ) {
 
    window.requestAnimationFrame = ( function() {

        return window.webkitRequestAnimationFrame ||
               window.mozRequestAnimationFrame ||
               window.oRequestAnimationFrame ||
               window.msRequestAnimationFrame ||
               function( callback, element ) {
                   window.setTimeout( function() { callback((new Date()).getTime()); }, 1000 / 60 );
               };

    } )();

}

I originally found that in a Gist written by Paul Irish, but it didn't pass the current timestamp to the callback function. So I added that part and we're all good now. Try it on your first-generation iPad. It will work. I have one. I tried it.

And that, my friends, is how I do simple animation in my web comics. It doesn't actually seem that simple now that I've written it all up, and I even simplified it for this post. Maybe I should refactor?

Amphibian.com comic for September 17, 2014

Monday, September 15, 2014

You Don't Need Ninjas

No, you don't need ninjas.

Or rock stars.

Or yetis, or unicorns, or oscilloscopes, or whatever crazy new metaphor somebody comes up with for a software engineer with some kind of magical talent for exactly what you think you might need at this very moment.

I get frustrated when I see a job listing looking for someone with an extremely specific skill set. It's usually something trendy. Unless you were someone ahead of the trend by starting to work on Technology X years before normal people ever heard of it, you don't qualify.

This is the tool. The only tool.
The best analogy I ever heard to describe this situation is the following. Try to hire a carpenter to build you a house. But he must have 15 years of experience with Black & Decker Model #CS1014 circular saw. Sounds silly, right? You just want a guy who knows how to handle any saw or drill or whatever tool. Maybe he has a preference for a certain brand or model, but that's probably based on his experience as the guy doing the actual building. This kind of thing happens all the time for software jobs.

What ever happened to hiring competent software engineers who were capable of learning new things? People who can stay with you long-term, and use their lifetimes of knowledge to enhance any project on which they work?

I've worked projects in Pascal, C, C++, Visual Basic (I don't know why I admit this one), ASP (or this), Java, and JavaScript. I've never worked a real project in Python or Ruby, but I don't think I'm incapable of doing so. I know programming. I can probably learn any language quickly, at least well enough to be a useful contributor.

And in this environment, we supposedly have some kind of software engineer shortage. The data to support those claims are not clear, if you ask me (see here and here for starters). But if you believe there is a shortage, maybe it's because everyone has unrealistic expectations. Maybe it's really just a shortage of ninjas, rock stars, and unicorns.

But you don't really need them. Just don't hire rodeo clowns.

Amphibian.com comic for September 15, 2014

Friday, September 12, 2014

Express Routers as Middleware

Lately I've been developing my web applications in JavaScript, using Node with the Express framework. It's easy to get something thrown together and working very quickly, but like anything else, if you want to maintain it for long it should be well-organized.

Using Routers as Middleware is nice way of partitioning your applications into smaller, easier-to-handle modules that can even be re-used in other projects.

Sometimes you end up with a lot of different routes that have similar prefixes. In my comic application I have things such as

GET  /images
GET  /images/<image>
POST /images
GET  /data/<id>
PUT  /data/<id>
POST /data


...mixed in with a bunch of other routes. All of the /data/* routes are related, and all of the /images/* routes are related. It would be nice to extract them out into their own modules.

We can do this by creating Routers for each set of related paths and using them as Middleware in the main application.

Creating a Router is simple.

var express = require('express');
var myRouter = express.Router();

But how do you use it for something? The Router is a Middleware itself so you use it the same way you use any other Middleware.

var express = require('express');
var app = express();

var myRouter = express.Router();
app.use('/path', myRouter);

Of course, that Router won't really do anything. Let's add a path /cheese that we can GET. Here is a complete app.

var express = require('express');
var app = express();

var myRouter = express.Router();
myRouter.get('/cheese', function(req, res, next) {
    res.send(200, 'cheese is good');
});

app.use('/path', myRouter);

var server = app.listen(3000, function() {
    console.log('listening on port %d', server.address().port);
});

Now we're making progress. If you request /path/cheese you'll get the response "cheese is good." Which it certainly is.

That's great and all, but if you want to really perform some good modularization, the definition of the Router's unique functions should be moved into a separate file. So we would make a new file, cheese.js, that would look something like this.

module.exports = function(express) {

    var myRouter = express.Router();
    myRouter.get('/cheese', function(req, res, next) {
        res.send(200, 'cheese is good');
    });

    return myRouter;

};

And then your main app.js would look like this.

var express = require('express');
var cheese = require('./cheese');
var app = express();

app.use('/path', cheese(express));

var server = app.listen(3000, function() {
    console.log('listening on port %d', server.address().port);
});

And a request for /path/cheese should still tell you that cheese is good.

That's great and all, but here is the real benefit. You can add the same Router for multiple paths. Obviously, you could also reuse your cheese.js module in other applications as well. In the following example, I add the cheese router to both /path and /goat.

var express = require('express');
var cheese = require('./cheese');
var app = express();

var cheeseRouter = cheese(express);

app.use('/path', cheeseRouter);
app.use('/goat', cheeseRouter);

var server = app.listen(3000, function() {
    console.log('listening on port %d', server.address().port);
});

Now you should be able to GET /path/cheese and /goat/cheese. Goat cheese tastes much better than path cheese. Oh, what is path cheese? Well I'm sure you're familiar with leaving a trail of breadcrumbs. If you leave yourself a trail of bits of cheese you have path cheese.

My cheese example is highly simplified but if your module had a number of GETs and POSTs and stuff at different paths, the benefit of breaking it out into a separate file becomes much more clear. It also helps when some routes might need to import another module via require and no other routes need that module. Everything stays neat and self-contained.

Much easier to maintain.

Amphibian.com comic for September 12, 2014

Wednesday, September 10, 2014

Learn How to Punch Ducks

If you've come here by following the link at the bottom of today's Amphibian.com comic, you might expect me to talk about duck punching. I'm going to mention it but not really discuss it at length. Sorry, maybe some other time. If you really want to read about it, I would recommend this Paul Irish blog post from 2010. It's getting quite old now but still a good introduction to the abuse of water fowl.

What I really want to talk about is the more subtle message in the comic. That is the constant need to keep your skills up to date by learning new things. If you want to be a software engineer who remains employed long-term, you need to be constantly learning. Education is a lifelong process. Where are the people today who refused to learn C++ because they would always need FORTRAN developers? Yeah, I'm sure there are still a few FORTRAN programmers out there but not nearly as many as there are Python programmers. And don't get me started on COBOL...

If you are still reading you might ask yourself, "how does one accomplish this?" I'll tell you how not to do it, and that's expect your employer to do it for you. Odds are, you are going to be employed to develop a system in a particular language and unless it is a totally new system you'll be expected to follow some already established design patterns. And by all means, you should do that. Gotta keep the people happy who sign your paychecks. So this lifelong commitment to learning thing has to be something you do on your own time.

But here's the real key:

You need to code outside of your comfort zone.

If you are a professional Java developer like I am, learn how to create an application in Python. If you only work on back-end data processing systems, learn how to make an iPhone app. Never heard of duck punching before today? Learn Ruby and get punching. If you've only ever processed text files and displayed data in ASCII tables with dashes and vertical pipes and octothorpes and whatnot, you need to learn OpenGL.

Even if you are a Java developer for your entire career, which seems unlikely but always possible, learning how to do things in a different language will make you a better Java developer. It will make you a better software developer in general. It will make you more confident when your boss tells you that you need to move to a new project that is totally different from your last project. It will even make you smarter and more popular.

I make no guarantees of any of these claims.

But I do adhere to this myself. I think it works.

Amphibian.com comic for September 10, 2014

Monday, September 8, 2014

How Big is that Library?

Last weekend I took an old web application that had a Java back-end, a lot of hand-made JavaScript in the client, and a Node server just for websockets and converted everything to an all-JavaScript application to be run via Node.

Along the way I was also switching the JavaScript client library from Dojo to jQuery.

While the process was generally a positive one, I did learn a few things. The one I'll talk about today is the size of the client JavaScript library.

I was surprised to learn that in my case, jQuery was not a smaller client download than Dojo. If you look at their most recent versions, 1.10 for Dojo and 1.11 for jQuery, jQuery is smaller. But I was using a rather old version of Dojo, 1.4.3, which was only 87KB. The current version of jQuery is 94KB.

This got me wondering how large jQuery was back when I first made the app. I decided to perform some analysis just to satisfy my curiosity. Here is what I learned.

jQuery Version Size (KB) Release Date
1.11.0 94.1 1-23-2014
1.10.2 90.9 7-3-2013
1.9.1 90.5 2-4-2013
1.8.3 91.4 11-13-2012
1.7.2 92.6 3-21-2012
1.6.4 89.5 9-12-2011
1.5.2 83.9 3-31-2011
1.4.4 76.8 11-11-2010
1.3.2 55.9 2-19-2009
1.2.6 54.5 5-24-2008

Dojo Version Size (KB) Release Date
1.10.0 117 6-13-2014
1.9.3 115 2-20-2014
1.8.5 114 6-14-2013
1.7.4 101 10-5-2012
1.6.1 89.6 5-20-2011
1.5.1 88.2 4-12-2011
1.4.5 87.4 8-24-2010
1.3.2 79.6 7-15-2009
1.2.3 76.8 12-8-2008

The sizes I list above are for the minimized code of course. I highlighted the versions of each that were the latest when I originally made the application. At the time, jQuery was smaller but not by an enormous margin. I was more familiar with Dojo at the time, which really drove my decision to use it more than the size of the download.

The other thing I thought was interesting here was how stable jQuery has been in terms of size since 2012. The Dojo Toolkit has jumped all over the place but jQuery has been near 90KB for quite some time. In fact, you have to go back to 2009 to see a really significant change in code size.

As for the changes I had to make in my application when I switched, well, they weren't all that significant. I changed things like

dojo.byId('something')

to

$('#something')

and modified the AJAX calls a little, but there were no really major problems with the conversion. These days I just prefer working with jQuery mainly because I think the syntax is easier to remember and I have a much better experience finding useful information in their online documentation when I'm looking for something. I don't know why more products can't have online documentation as easy to use as jQuery's.

Amphibian.com comic for September 8, 2014