Monday, September 29, 2014

Can You Remember my Password for Me?

Let's talk for a minute about bad password policies. In today's comic, some shady pythons are using social engineering to steal passwords and other important information from the unsuspecting frogs. But in real life, there are plenty of frogs and too many snakes trying to trick them. You are more likely to have your network compromised by a user falling victim to a social engineering attack than you are having a machine run some algorithm to guess a password.

And no password policy is going to fix that. In fact, it might make the problem worse.

Today I'm forced to create passwords that are terrible. Terrible in that I can't remember them. But they are "good" by someone's standards.
  • At least 12 characters long
  • Containing upper and lower case characters as well as special symbols
  • No dictionary words
  • No more than 2 of each type of character in a row
  • Has to be changed every 60 days
  • Can't be re-used for 6 years
  • Can't be remembered for more than 6 minutes
I lose hours of productivity waiting for someone from IT to reset my password every other month when it expires. But what are my other options? Write my password on a sticky note and put in on my monitor? That seems like a poor choice too.

Sometimes I forget the password after a month. Yes, after typing it in every day for a month, I can no longer do it. My fingers just want to mash random keys instead. I've had this problem as far back as I can remember. How far back is that? I forget. But for reasons I can't explain, I would forget my locker combination several times per year in high school. The combination never even changed. I had the same one all year. I just lost the ability to remember it every once in a while.

Today I can tell you the license plate number from my first car, but I can't reliably remember my passwords. I only had the license plate for 4 months, and it was 19 years ago. There is something wrong with my brain.

I really want to switch to randomly-generated multi-word passphrases (read this PDF), but unfortunately I don't set the security policy. comic for September 29, 2014

Friday, September 26, 2014

Why Do I Write Code in [insert language here]?

Starting this past Wednesday and continuing today (it will go on into next week if you must know), the frogs in my comic have hired some pythons to write software because they heard it was trendy. For the record, the Python programming language was named after Monty Python, not a snake, but that makes little difference when you are trying to select a language for a new project.

So the question is, do you pick a language to code in because it is practical or because it is popular?

And how do you even measure a programming language's popularity?

It turns out there are several groups that try to measure language popularity utilizing different methods. Take a look at the following...
So by most measures, Java and C remain very popular. It's important to see this in real objective data, because sometimes our understanding of programming language popularity becomes skewed by media attention. Often, languages that people talk about very much are used very little in production systems.

I found that all very interesting, but when I am starting a project (or re-starting, or upgrading) I try to pick the most appropriate language for the job. If there is more than one viable language for my system requirements, I pick the one that is most familiar to the team (which may be just myself). In other words, I tend to take a very practical approach to language selection.

Sometimes there is little choice. If you want to create an iOS application, your options are very constrained. This kind of specialization in certain product spaces is nothing new. When I was writing BBS Door Games in 1995, nearly all development was done in Pascal. I don't know why, I didn't really question those types of things back then. Of course, I only knew of 3 programming languages at the time...

Other times there is too much choice. If you want to build a web application, your options are nearly limitless. Personally, I have written REST web service applications in Java for a WebLogic application server and in JavaScript for Node.js. The JavaScript ones tend to be easier to write, but that doesn't mean that it's always the better choice. Knowing your particular requirements and the properties of a number of languages are the keys to making the right decision.

The take away from this is that if you want to be an extremely effective software engineer, you should be familiar with many languages and not be afraid to learn new ones. If you pick a bad one for a project, at least it's a learning experience. Don't make the same mistake again, even if it means learning something completely new. comic for September 26, 2014

Wednesday, September 24, 2014

It's the Age of Asynchronous

I'm not sure how many people have noticed this yet, but Firefox 30 deprecated synchronous XHR on the main thread. They said that it leads to a degraded user experience, and they're correct - in most cases. But I've used it on occasion without any serious side effects, I just had to be careful about what I was doing.

Still, I should probably stop doing it. How can I call synchronous XHR Ajax if the A in Ajax stands for Asynchronous? Take away the A and it's just Jax. Not cool. Of course, the X stands for XML and most people use JSON instead these days. But what is Ajaj? That doesn't even make any sense! Let's move on...

A common use of the synchronous XHR is to ensure order of operations. If you have to make calls to get data from 2 URLs before doing some kind of processing, you can't guarantee which one will return first. If you can't use synchronous XHR anymore, you could stack up the calls inside callbacks so you only ever do one at a time...but then you're still only doing one at a time. If one call takes 3 seconds and the other takes 2, you have a total wait time of 5 seconds before you can continue. If you could somehow call both at once but still make sure the results are processed in a certain order, your total wait time is only 3 seconds. Saving 2 seconds might not sound like much, but it can really add up. And when you have a human being waiting for some on-screen response, 2 seconds is an eternity. Plus, performing the calls sequentially in callbacks might be fine for 2 or 3 calls, but it gets crazy when you need to stack 5 or 6 callbacks deep.

There must be a better way.

There is! If you use jQuery, the when().done() functions can handle the difficult task of making multiple asynchronous calls and keeping the responses in order.

The when() function takes as arguments as many Deferred or Promise objects as you want to pass it. When all of them have completed, the function passed to done() is called with the results of the Deferreds as arguments in the order they were given to when().

Since Ajax calls return Promises in jQuery, they can be used as arguments to when(). For Ajax Promises, the results passed to the function given to done() will be 3-element arrays. The first element in the array will be the returned data, the second will be the status text, and the third will be the jqXHR object. I've thrown together a working example of this...

Here is my test HTML page. The JavaScript starting on line 20 is the important part.

<!doctype html>

<html lang="en">
  <meta charset="utf-8">
  <title>Async Order Test</title>


  <p>when().done() test page</p>


<script src=""></script>

$(function() {



    ).done(function(a, b) {






And here is my Node/Express server app.

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

app.get("/something/a", function(req, res, next) {
    // simulate a long response time for this path.
    // we won't send the response for 3 seconds.
    setTimeout(function() {
        res.status(200).send("this is a");
    }, 3000);

app.get("/something/b", function(req, res, next) {
    res.status(200).send("this is b");

// ------------ static content

// ------------ start the listening
var server = app.listen(3000, function() {
    console.log("listening on port %d", server.address().port);

I've set up the /something/a resource to take a long time to respond. The /something/b resource should respond as quickly as possible. Therefore "b" should pretty much always return first even though it is second in the list passed in to when(). Looking at the console output, it is clear that the "a" response is printed out first despite returning last.

The when() function can be used for other types of Deferreds as well - it is not limited to Ajax calls although these are perhaps the most common uses.

If you're not using jQuery (perhaps you have a similar issue on the server side in Node), there are other libraries available that provide similar functionality. Check out Async.js for a good one. If you are a hardcore computer science fanatic, you could implement something yourself. Here is an example I quickly threw together for doing it in Node...

var http = require('http');

function waitFor(urls, cb) {

    var countDown = urls.length;
    var retVals = new Array(countDown);

    function processResponse(idx) {
        return function(response) {
            var str = '';
            response.on('data', function(chunk) {
                str += chunk;
            response.on('end', function() {
                fillInData(idx, str);

    function fillInData(slot, data) {
        retVals[slot] = data;
        if (countDown === 0) {

    for (var i = 0; i < countDown; i++) {
        http.get(urls[i], processResponse(i));


var urls = [ 'http://localhost:3000/something/a',
             'http://localhost:3000/something/b' ];

waitFor(urls, function(results) {

My example is not quite as flexible as what jQuery or Async.js offer, but you can see the basics of how it works. Given an array of URLs and a callback, my waitFor function will request data from all the URLs asynchronously but only call the callback when all the requests have completed. The array of data passed to the callback will be in the same order as the URLs were given. It works using a countdown latch mechanism. For each response received, the countdown in decremented. If the countdown reaches 0, all responses have come in and the callback can be called. The callback is passed an array that has been populated with each response's data. The data went in the proper array index because the index of the URL was passed along to to the function that handled the response. The only unusual thing is how the processResponse callback is given to the http.get function. Calling processResponse and passing an index actually returns an other function which is the real callback for http.get. The reason for this is to create a new closure for the index so that the response callbacks are not affected by the for loop continuing to run and incrementing the index. Without that extra function, the data from all responses almost always goes into the same position, 2, in the retVals array.

Working with lots of asynchronous functions can be confusing and frustrating sometimes. A good library like jQuery can help make it less painful. comic for September 24, 2014

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">
  <meta charset="utf-8">
  <title>CSS Test</title>


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


<script src=""></script>

$(function() {









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

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

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





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) {


    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;


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




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. comic for September 8, 2014

Friday, September 5, 2014

Your Local Bugs

Just a short note today. I found this link interesting:

Pennsylvania Insects and Bugs

You can look up insects by your state as well. I found this while trying to identify a large spider that lives by my garage door.

Have you ever walked out your door and put your face in a spider web? Yeah, it's pretty terrible.

"Hogna lenta 18" by Patrick Edwin Moran - Own work. Licensed under CC BY-SA 3.0 via Wikimedia Commons. comic for September 5, 2014

Wednesday, September 3, 2014

FCaaS (Fried Chicken as a Service)

Maybe you've heard of Software as a Service. SaaS. Maybe you've heard of Platform as a Service. PaaS. You can get just about anything as a Service these days. XaaS they call it. X stands for anything I guess.

Today's comic was about Photosynthesis as a Service. If trees could somehow turn the process of converting solar energy into chemical energy into an on-demand thing you purchased via the web, they probably wood. Sorry, I like tree puns even though they're not poplar.

Well I was reading this article about Everything as a Service. Go read it now and then come back. Really, I'll wait. Okay, now we can continue. So I read that article and I was thinking about what Colonel Sanders would do. No, that's not weird. I often think about what Colonel Sanders would do in different situations.

Here's the thing - one of the points of the "Everything as a Service" article was how the food service industry in particular is starting to embrace the outsourcing of parts of the business. Now for the Colonel Sanders part. You may or may not know that the Colonel is credited with inventing the franchise model for the fast food business. That was big at the time, but if he was starting his business today he might go with the Whatever as a Service model as his big idea.

Fried Chicken.jpg
"Fried Chicken" by Mike DelGaudio from USA - Fried Chicken.
Licensed under 
CC BY 2.0 via Wikimedia Commons.
Let's say you had a great recipe for fried chicken. The best fried chicken anyone ever tasted. You go around to some cities and train a bunch of people to cook your fried chicken in their homes. You put a website together where people can order your home-cooked fried chicken and have it delivered to them in these select locations. Someone in one of those cities goes to the website and orders some fried chicken. Seconds later, one of your trained chicken fryers in that area gets a notification on their phone that they need to fry up some food. At the same time, your system automatically sets up delivery from the home of the chicken fryer to the home of the chicken eater using one of these Car as a Service (CaaS) providers like Uber or Lyft. In 30 minutes when the chicken is done, it gets picked up and delivered. The consumer paid online when they ordered. You give the cook and the car their shares of the funds and keep the rest. The only way this could possibly get better is if you delivered the fried chicken with an aerial drone or something.

Voila! Fried Chicken as a Service. Using other things that are services. comic for September 3, 2014

Monday, September 1, 2014

Making Up Words

In addition to being a software engineer and a web comic author, I also create new words. Well, not with any sort of legitimacy I suppose. As far as I know, none of the words I've made up have ever found their way into the dictionary.

The title of today's comic is one such example.


Much like photosynthesis (the suggested technology in the comic) comes from the roots "photo" and "synthesis" to mean creation of something from light, verdosynthesis is to mean the creation of something from greenness. But in this case, I am talking about the 21st century American definition of green which is of course best translated as "environmentally friendly."

Why did I use "verdo" as the first part of this word? You may be familiar with the Spanish word verde which translates to green in English. But the Spanish (and Italian) word traces back to the Latin viridis which was most likely from an even older root word that meant "growing plant." The same Latin root also carried forward into Old French as vert (which is the same word for green as in modern French - some things never change). From here, we got verdure in English which was used to describe a fresh, green color. But no one has really used that word since the 15th century. Words starting with verd- as an indication of something being green are not common in English today. There is verdigris, but that's used almost exclusively in chemistry (the green color of oxidized copper - like the Statue of Liberty) and not in the vernacular. For whatever reason, modern English uses the word green which I believe has Germanic roots.

The next question you should be asking yourself is why I know any of this. I guess you would say that I have an unusual interest in etymology. I say unusual because, seriously, how many people have an interest in etymology? Twelve? Maybe fifteen?

Also, don't confuse etymology with entomology. One is the study of word origins and the other is the study of insects. Very different. Although I suppose frogs would be more interested in entomology. comic for September 1, 2014