Friday, July 12, 2013

Interviews as Hazing Rituals

REVIEW: Film provides fresh take on Greek hazing abuses – The Daily Aztec
Aggro Interviews Making Up for Um...

I started this blog as a tongue in cheek kind of play on the fact that I'd been so out of the web world for so long that when I came back to look at the web, everything was so fresh and minty. Well, it turns out that that's not the only thing that has changed since I took my long snooze. I've been putting myself out again to look for a new job and I've been pretty shocked at how awful the interviewing process has become. It's become a hazing ritual straight out of your local frat house.

At some level this shouldn't be a big surprise because the entire industry -- at least what I'm seeing here in SF -- is being taken over by brogrammers. Call me old school, but I really don't want a keg on every floor and I don't see it as a feature that you use more space for ping pong tables and other toys than you do for space for your employees to work, assuming that they ever do that. And what's up with using 8' banquet tables with two people per table? It makes me want to look for severed fingers in my software because I'm surely looking at a sausage factory instead of software development.

The Greek System


But back to interviewing. One of the biggest changes nowadays is that everybody seems to be using keyword filtering software. This software doesn't appear to be especially bright as it just seems to do an intersection between the job requirements and the words that appear in your resume. If it isn't an exact intersection, you're rejected. It doesn't seem to discriminate between required, strong preference and nice to have either. If there isn't an exact match, then you're dropped. This seems especially prevalent at big companies where they force you to fill out an extensive questionnaire because, I guess, their filtering software isn't even smart enough to do the intersection function using your raw resume text. Worse, I've seen some that require you do that before you can see their job listings. I mean, seriously?

 

The net effect is that it's fairly useless to actually apply for a job because it never gets seen. Because, of course, there does not exist somebody who actually is an expert in the 99 things that you put on your listing as "requirements". So the unfortunately lesson here is that just dropping a resume off in the job inbox is a complete waste of time.


First, drink 10 beers


The biggest cancer -- and the subject of this rant -- are tests in the form of programming tests and puzzles. This is nothing more than a hazing ritual dressed up in all sorts of self-righteous excuses. The justification is that candidates might be lying about their programming prowess, thus it needs to be conclusively proven that you can write code on the spot. Never mind that this is extremely uncomfortable for the interviewee. Never mind that what is invariably given to be written you'd be fired for reinventing rather than just googling for the answer. Never mind the fact that most interviewers can't actually explain the problem they want you to solve. Never mind the fact that once you solve it, they want you "scale it up" whatever that means.

None of this matters because the point isn't to find out if you're a great programmer. The actual point is to convince the interviewers that they're great programmers. And superior to you in every way. Unless, I suppose, you look like them and have an affinity for drunken programming. The best part of this is when they tell you "we just want to see how you think". Call me crazy, but the only part of my thinking process you're going to understand after one of these tests is how good my rote memory is. I mean, when is the last time you've been asked to write a program to enumerate all permutations of a number? When is the last time you coded up a binary tree (no fair if you've been interviewing recently).

The absolutely worst are companies that use their hazing rituals -- like frats -- to prescreen pledges before they even a) talk to you and b) give you any clue whether you want to work in their sausage factory. This is abuse, pure and simple. And the larger joke is that it's been shown that it serves absolutely no purpose other than making the frat boys judge their penises large and manly. This google paper really drives this home, and I felt very vindicated.

We're not sure if you look like a Theta Tau


Every company has a "culture". Every company is completely convinced that their culture is the best. The interviewer's job is to make certain that the wrong element is not let into their restricted and exclusive frat ("exclusively what, and restricted to whom?"). You better be, well, top drawer just like Bunny Bixler and Muriel Puce.

Now there are cultural reasons why you may not be a good fit, like it being a stressful job where the interviewee is looking to destress (and vise versa!). But let's be real here for a second: every company says they only hire the "best and brightest" but not a one of them is located at Lake Wobegon. How, exactly, does that work? Or is "culture" a dog whistle for "looks-like-me"? And didn't Enron pretty much prove that hiring exclusively for "best and brightest" isn't a guarantee of success? Which isn't to say that trying to get good people should be downplayed -- not at all. It's just that looking into your sausage factory I have to assume there must be some third world country where everybody is white, male, 25, and dresses in skinny jeans to escape poverty by being exceptionally smart. At companies who do exceptionally amazing things like making sepia filters for .jpg's, and virtual row crops for e-farmers.

The PI-Thon Frat House


Computer languages are tools. Often complicated tools to be sure, but tools nonetheless. They do not describe your life essence. The ability to use them is not written into base pairs where some people inherit them, and some people don't. You do not need to give blood and do a PCR test to determine whether you are Java negative. If you're worth anything as a programmer you can and will pick up lots of languages over your lifetime. Some of them may actually be pretty awful and will make you apologize (hi PHP!). Some of them are more applicable to some problems than others.

The same thing goes for platforms and packages/frameworks. The current rage is to silo you based on whether you're iOS or Android, but it's no different than when they used to do that between M$ and Unix. Now true enough it takes time to learn a new language or platform or package/framework so it's a valid consideration to judge how much time a candidate might take to come up to speed. And true enough, there isn't much that you could do to convince me to waste my time learning .NET or some other piece of crap language/platform/package that I have no interest in learning. So, yes, thank you for putting down all of the buzz words so that I can filter too.

But where you go wrong is thinking that the lack of 7 years of mobile experience (seriously, I'm not making this up; edit: remember this is in 2013) means a priori that an otherwise competent person can't pick it up. In fact, part of the fun of a new job is getting exposure to new and different ways of approaching problems. Competent people break free of the frat they pledged to. Really.

Will nobody think of the code?


One of the most shocking things I've found interviewing is that -- except for the filters -- nobody seems to read your resume. And because they haven't read you resume, they obviously haven't seen anything online to validate your skill. The great thing about the net is that there are so many ways to show what you've done in the past, and whether it's a piece of art or a piece of crap. And since it's a given that the interviewer is smarter than Donald Knuth (even if they don't know who he is), he should be able to instantly assess whether your code is written well and whether the design choices were appropriate. Right? I've had exactly one interviewer ask me for code.

Now I understand that people lie, but it seems to me that using their own purported code to see how well they really understand what they claim they've written would be an immense help to ferret out the fakers. Much better than a real time rote memory test of coding up 2-3 tree or a lalr parser. Now this isn't failsafe because it can be perfectly legitimate for a person to not have an oeuvre that is publicly available. But to not use it as a resource when it's available? That's craziness. 

I'll pass on the spanking conga line


The Google HR guy's interview (and this one too) which says that the only thing that makes much of a difference in interviews are behavioral questions was quite a relief. I hadn't actually woken up in the alternate world where Spock and Kirk wear beards. Of course their revelation hasn't filtered out to the larger tech world, so there are still plenty of fucked companies with all of their interviewers who are looking for reassurance about their manhood. Oddly enough, it's the way I've always interviewed people too so it's doubly comforting that something I did by instinct was actually the only thing that seemingly works worth a damn. 

The last thing I'd like to say is this: instead of being paralyzed by making a mistake, do the obvious. If they can't program after you hire them, then... just fire them when you figure it out. It usually doesn't take too much time to find out somebody who interviewed well was a complete joke once on the job. And no, don't require they initially "consult" or whatever -- you're going to lose good people who view that as game playing. That and get rid of the kegs. Seriously.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Friday, May 10, 2013

MVC or Not?

With Phresheez, I've noticed a pattern that comes up over and over and over again given that most Phresheez pages are not web pages, per se, but long lasting apps that auto-refresh content dynamically. I've tried to reconcile this with the MVC (model/view/controller) pattern which is quite common, but I've never been able to tell whether the way I think of things is the same or even close to the MVC pattern.
I'm thinking that they have similarities, but that they're not really the same as MVC as far as I understand it.

So here's what I saw coming up all the time with Phresheez.

  1. There's a dynamic piece of data that needs to be fetched from the server
  2. There's a piece of HTML content I generate from that data
  3. That content needs to be refreshed as new data comes into the server
  4. I want to use that content in multiple places, but they may want to be formatted for different uses
Typically, I'd start out with a monolithic piece of code that did all of things, but I'd almost always regret it as I'd have to extend or refactor the code when I wanted to use some or all of the widget in a different context.

The rest of this post is what I'm thinking the architecture should be.

Goals


First off, I guess I should state what I want to provide.

  • A data abstraction layer that takes care of all of the grotty details of network errors, retransmissions, refreshing, etc, etc. Before refactoring, this code was ~duplicated all over the place each with its own subtle set of bugs. I want just one set of bugs.
  • A cleanish separation between content formatting and container decoration. By container decorations, I mean things like menus/nav, titles, last updated, etc. 
  • I want to be able to facilitate mixing and matching different widgets. That is, I want to be able get content from widget A, widget B and widget C and mix and match them into a new super widget D.
  • A recognition that there's some interplay between some of the aspects and not go crazy trying to ferret out every soi-disant layering violation

Data Layer


The Data Layer is in charge of getting and refreshing data between the client and the server. Other services subscribe to the data layer to get and refresh data from the server. The data layer may or may not auto-refresh depending on settings, but it will only refresh if something is actively subscribed to it.

The Data Layer should also have error callbacks for when something goes wrong. The Data Layer must never affect the DOM in any way: it is up to its subscribers to determine what is displayed.

There may be many Data Layer objects running around with different parameters to the same underlying service. For example, you might have an object that fetches the user information for user1 and another that fetches it for user2. When the Data Layer publishes the data, it must be specific to its instance.

As an optimization, however, it would be good for the Data Layer instances to know about each other such that an instance that has the same url parameters as another will share the server's results with other Data Layer objects so as not to generate useless duplicated calls to the server. I suppose that one way to accomplish that would be for them to subscribe to each other, or maybe a global data cache layer on top of the server callbacks, but that's an implementation detail.

Container Layer


The container layer is the business end of this model. It alone is responsible for inserting/updating elements within the DOM. The normal data flow is that the Container Layer subscribes to some set of data layers (or not!) and upon a published update calls the necessary content binding objects to populate the container (normally a div, but it could be anything's innerHTML really). I'm going to say that it's also its job to deal with layout and general look and feel for the container since a container may contain many objects. So it produces HTML as well, but it's much more oriented at layout than content per se.

The container layer is normally the recipient of the Data Layer's publications. It is responsible for painting the placeholders when the data is not yet available (eg, loading spinners, etc), and coordinating when it's interacting with multiple Data Layers. The Container Layer is also responsible for unsubscribing to the data layer when it has lost focus, for example, to cut down on useless chatter to the server. 

Finally, the Container Layer is responsible for implementing any callbacks (eg, onclick) that the container content requires. Which is another way of saying that the Container Layer owns the interaction with the DOM.

Content Binding Layer


The content binding layer binds data from the server to html layout and content. It never interacts with the  DOM. It merely takes the data, typically provided by the data layer, but not necessarily exclusively and grinds out the content for that data. The Content Binding layer should be thought of as effectively "stateless" even though for efficiency the Content Binding Layer ought to provide one other service: sameness. That is, if it produces the same content that the caller was returned the last time, it should inform the caller. This is needed to eliminate useless redraws at the container layer which are annoying. Note that if the content layer needs to do extensive massaging of the dynamic data, it is not a layering violation to hold onto the dynamic data (or a massaged form of it) if it wants to do delta's of old and new datasets, etc. 

It could be argued that the sameness property ought to be up to the Container Layer, but I don't think so. The Container Layer is the one that knows which bits and piece of dynamic content its using, so it alone is the one that knows if they are the same, modulo comparing blobs of HTML at the Container Layer, which I think is bad practice.

Clicks and other Events


It's not entirely clear to me who should be generating the onclick='s (typically). In the MVC pattern, I'm pretty sure that's the job of the controller, which would be more or less equivalent to my Container Layer. But that would be rather messy in practice: if you're just producing a bunch of html in the Content Binding Layer, it's much easier to insert the onclick's inline with the generated HTML. The downside here is that at the very least the onclicks need to be parameterized with the instance they represent from the Container Layer (ie, this click is associated with this container instance). And of course, the click actions across different container layers may well be very different.

What I think is probably the best compromise is let the Content Binding Layer generate the onclicks, but with input from the Container Layer's state. This still runs afoul if you want something like

<a href=# onclick="st.mywidget.clickHandler('mike')">Click me!</a>

since it is the container layer's job to handle that click, so why should the Content Binding Layer be setting up its callback parameters? Suboptimal, but in practice it haven't noticed many instances where I have one use with a set of parameters and in another use with a different set of parameters... they almost always follow a similar pattern, though you may end up with the union of parameters the various uses require.

My guess is that not stressing about this fuzziness and the apparent layering violations is best. The object here is to get better code reuse and separation of function, but that doesn't mean that we have to solve world hunger as well.

Inserts/Updates


For insert/update type callbacks to the server, I think I would keep it completely as a property of the Container Layer. This is the flip side of the argument about clicks in the previous section: the Content Binding Layer is the one that generates the input's, checkboxes, etc, so why shouldn't it provide the interface to fetch their values? I dunno, because it's sort of fuzzy in the same way that clicks are fuzzy and it would probably be messy to have a grand unified theory here. So some give and take between the Container Layer and Content Binding Layer seems reasonable.

Likewise, I don't see any particular advantage to tasking the Data Layer with the ajax callbacks to the server to save/update state. The point of the Data Layer is to deal with multiple users of data, and keeping it refreshed. It doesn't need to be the singular owner of HttpXMLRequest as well.

So is this MVC?


So have I reinvented MVC or not? Maybe it is, or maybe I've extended it a little, or something. Or maybe it's all different. You tell me. Here's my take on what I've done vs. MVC:



Thursday, May 2, 2013

Something old, something new. Something borrowed...

So I have been searching for a way to do a color picker that works ok on mobile phones. Most of the color pickers out there expect that a) mouse over works and b) that your finger is a mouse pointer. Fails on both accounts. So I found a rustic html color picker at w3schools. It uses a gif for the background, and an imagemap which is very, very old school these days. The code to do it is pretty big and definitely ugly. So I decided to do run with it and make it all fashion forward 'n stuff.

The image map contains the coordinates of the polygons for all of the hexagons in the gif. So why not just use a canvas element and render it instead of snarfing up a big png/gif? So I grabbed their source, and a couple of emacs keyboard macros transmogrified the area tags and the corresponding color into a nice compact javascript array. From there it was easy: loop through the array to draw the hexagons, and in parallel create the html for the area tags. To get the image, you just call toDataURL('image/png') on the canvas, and it can be stuffed into an <img> tag.

Their picker took the selected color and sent it back to a server to show different shades of the base color. Yuck. Instead of that, I just converted the colors to hsv and created a set of variations by changing the s and v values. Simple, easy, and most importantly relatively easy to pick with fat fingers. Does it give you the ability to pick infinitely variations on a hue/saturation/luminance? No, but a) I didn't need that, and b) it would be very unwieldy for... fat fingers. Again.

The source and docs are available on google code.


Here's the source:


/*
 *   Copyright (c) May  2 06:46:44  MTCC
 * Author: Michael Thomas
 * Module: colormap.js
 * Created: Thu May  2 06:46:44 2013
 * Abstract:
 *      License: MIT
 *    color mapper
 */

/* Edit History: 
 */


function colormap (prefix, w) {
    this.prefix = prefix;
    this.can = document.createElement ('canvas');
    this.can.width = 234;   // original image dimensions 
    this.can.height = 199; 
    if (w)
 this.scale = w/this.can.width;
    else
 this.scale = 1;
    this.can.width *= this.scale;
    this.can.height *= this.scale;
}

colormap.prototype.render = function (color) {
    var ctx = this.can.getContext ('2d');    
    ctx.scale (this.scale, this.scale);
    html = '';
    html += '<map name="'+this.prefix+'.map">';
    for (var i in this.map) {
 var slot = this.map [i];
 html += '<area shape=poly onclick="'+this.prefix+'.select (\''+slot [1]+'\')" coords="';
 ctx.beginPath ();
 for (var j = 0;  j < slot[0].length; j += 2) {
     html += slot [0][j]*this.scale + ',';
     html += slot [0][j+1]*this.scale;
     if (j < slot [0].length-1)
  html += ',';
     if (j == 0)
  ctx.moveTo (slot [0][j], slot [0][j+1]);
     else
  ctx.lineTo (slot [0][j], slot [0][j+1]);      
 }
 ctx.lineTo (slot [0][0], slot [0][1]);      
 html += '"/>';
 ctx.closePath ();
 ctx.fillStyle = slot [1];
 ctx.fill ();
    }    
    html += '</map>';    
    html += x = '<br><div id="'+this.prefix+'.shades">'+this.shades (color)+'</div>';
    return {html:html, img: '<img src="'+this.can.toDataURL ('image/png')+'" usemap="#'+this.prefix+'.map">'};
};

colormap.prototype.select = function (color) {
    if (this.onselect)
 this.onselect (color);
    var el = document.getElementById (this.prefix+'.shades');
    reliableNewc (el, this.shades (color));
};

colormap.prototype.shades = function (color) {
    var rgb = new RGBColor (color);
    var hsv = rgb2hsv (rgb.r, rgb.g, rgb.b);
    var html = '';
    html += '<table align=center><tr>';
    for (var i = 0; i < 256; i += 16) {
 if (i == 128)
     html += '<tr>';
 if (i < 128)
     hsv.v = i;
 else
     hsv.s = i-128;
 var rgb2 = hsv2rgb (hsv.h, hsv.s, hsv.v);
 html += '<td><div onclick="'+this.prefix+'.select(\''+rgb2+'\')" style="position:relative; height:30px;width:30px; background:'+rgb2+'; border: 1px solid black"></div>';
    }
    html += '</table>';
    return html;
};

// scraped from the source of http://www.w3schools.com/tags/ref_colorpicker.asp

colormap.prototype.map = [
    [[171,180,180,184,180,195,171,199,162,195,162,184], '#993333'],
    [[153,180,162,184,162,195,153,199,144,195,144,184], '#800000'],
    [[135,180,144,184,144,195,135,199,126,195,126,184], '#990000'],
    [[117,180,126,184,126,195,117,199,108,195,108,184], '#993300'],
    [[99,180,108,184,108,195,99,199,90,195,90,184], '#CC3300'],
    [[81,180,90,184,90,195,81,199,72,195,72,184], '#996600'],
    [[63,180,72,184,72,195,63,199,54,195,54,184],'#663300'],
    [[180,165,189,169,189,180,180,184,171,180,171,169],'#990033'],
    [[162,165,171,169,171,180,162,184,153,180,153,169],'#CC0000'],
    [[144,165,153,169,153,180,144,184,135,180,135,169],'#FF0000'],
    [[126,165,135,169,135,180,126,184,117,180,117,169],'#FF3300'],
    [[108,165,117,169,117,180,108,184,99,180,99,169],'#CC6600'],
    [[90,165,99,169,99,180,90,184,81,180,81,169],'#FF9900'],
    [[72,165,81,169,81,180,72,184,63,180,63,169],'#CC9900'],
    [[54,165,63,169,63,180,54,184,45,180,45,169],'#996633'],
    [[189,150,198,154,198,165,189,169,180,165,180,154],'#660033'],
    [[171,150,180,154,180,165,171,169,162,165,162,154],'#CC0066'],
    [[153,150,162,154,162,165,153,169,144,165,144,154],'#FF5050'],
    [[135,150,144,154,144,165,135,169,126,165,126,154],'#FF6600'],
    [[117,150,126,154,126,165,117,169,108,165,108,154],'#FF9933'],
    [[99,150,108,154,108,165,99,169,90,165,90,154],'#FFCC00'],
    [[81,150,90,154,90,165,81,169,72,165,72,154],'#FFFF00'],
    [[63,150,72,154,72,165,63,169,54,165,54,154],'#CCCC00'],
    [[45,150,54,154,54,165,45,169,36,165,36,154],'#999966'],
    [[198,135,207,139,207,150,198,154,189,150,189,139],'#993366'],
    [[180,135,189,139,189,150,180,154,171,150,171,139],'#CC6699'],
    [[162,135,171,139,171,150,162,154,153,150,153,139],'#FF0066'],
    [[144,135,153,139,153,150,144,154,135,150,135,139],'#FF6666'],
    [[126,135,135,139,135,150,126,154,117,150,117,139],'#FF9966'],
    [[108,135,117,139,117,150,108,154,99,150,99,139],'#FFCC66'],
    [[90,135,99,139,99,150,90,154,81,150,81,139],'#FFFF66'],
    [[72,135,81,139,81,150,72,154,63,150,63,139],'#CCFF33'],
    [[54,135,63,139,63,150,54,154,45,150,45,139],'#99CC00'],
    [[36,135,45,139,45,150,36,154,27,150,27,139],'#666633'],
    [[207,120,216,124,216,135,207,139,198,135,198,124],'#990099'],
    [[189,120,198,124,198,135,189,139,180,135,180,124],'#CC3399'],
    [[171,120,180,124,180,135,171,139,162,135,162,124],'#FF3399'],
    [[153,120,162,124,162,135,153,139,144,135,144,124],'#FF6699'],
    [[135,120,144,124,144,135,135,139,126,135,126,124],'#FF9999'],
    [[117,120,126,124,126,135,117,139,108,135,108,124],'#FFCC99'],
    [[99,120,108,124,108,135,99,139,90,135,90,124],'#FFFF99'],
    [[81,120,90,124,90,135,81,139,72,135,72,124],'#CCFF66'],
    [[63,120,72,124,72,135,63,139,54,135,54,124],'#99FF33'],
    [[45,120,54,124,54,135,45,139,36,135,36,124],'#669900'],
    [[27,120,36,124,36,135,27,139,18,135,18,124],'#333300'],
    [[216,105,225,109,225,120,216,124,207,120,207,109],'#993399'],
    [[198,105,207,109,207,120,198,124,189,120,189,109],'#CC0099'],
    [[180,105,189,109,189,120,180,124,171,120,171,109],'#FF33CC'],
    [[162,105,171,109,171,120,162,124,153,120,153,109],'#FF66CC'],
    [[144,105,153,109,153,120,144,124,135,120,135,109],'#FF99CC'],
    [[126,105,135,109,135,120,126,124,117,120,117,109],'#FFCCCC'],
    [[108,105,117,109,117,120,108,124,99,120,99,109],'#FFFFCC'],
    [[90,105,99,109,99,120,90,124,81,120,81,109],'#CCFF99'],
    [[72,105,81,109,81,120,72,124,63,120,63,109],'#99FF66'],
    [[54,105,63,109,63,120,54,124,45,120,45,109],'#66FF33'],
    [[36,105,45,109,45,120,36,124,27,120,27,109],'#009900'],
    [[18,105,27,109,27,120,18,124,9,120,9,109],'#336600'],
    [[225,90,234,94,234,105,225,109,216,105,216,94],'#660066'],
    [[207,90,216,94,216,105,207,109,198,105,198,94],'#CC00CC'],
    [[189,90,198,94,198,105,189,109,180,105,180,94],'#FF00FF'],
    [[171,90,180,94,180,105,171,109,162,105,162,94],'#FF66FF'],
    [[153,90,162,94,162,105,153,109,144,105,144,94],'#FF99FF'],
    [[135,90,144,94,144,105,135,109,126,105,126,94],'#FFCCFF'],
    [[117,90,126,94,126,105,117,109,108,105,108,94],'#FFFFFF'],
    [[99,90,108,94,108,105,99,109,90,105,90,94],'#CCFFCC'],
    [[81,90,90,94,90,105,81,109,72,105,72,94],'#99FF99'],
    [[63,90,72,94,72,105,63,109,54,105,54,94],'#66FF66'],
    [[45,90,54,94,54,105,45,109,36,105,36,94],'#33CC33'],
    [[27,90,36,94,36,105,27,109,18,105,18,94],'#009933'],
    [[9,90,18,94,18,105,9,109,0,105,0,94],'#003300'],
    [[216,75,225,79,225,90,216,94,207,90,207,79],'#9900CC'],
    [[198,75,207,79,207,90,198,94,189,90,189,79],'#CC00FF'],
    [[180,75,189,79,189,90,180,94,171,90,171,79],'#CC33FF'],
    [[162,75,171,79,171,90,162,94,153,90,153,79],'#CC66FF'],
    [[144,75,153,79,153,90,144,94,135,90,135,79],'#CC99FF'],
    [[126,75,135,79,135,90,126,94,117,90,117,79],'#CCCCFF'],
    [[108,75,117,79,117,90,108,94,99,90,99,79],'#CCFFFF'],
    [[90,75,99,79,99,90,90,94,81,90,81,79],'#99FFCC'],
    [[72,75,81,79,81,90,72,94,63,90,63,79],'#66FF99'],
    [[54,75,63,79,63,90,54,94,45,90,45,79],'#00FF00'],
    [[36,75,45,79,45,90,36,94,27,90,27,79],'#00CC00'],
    [[18,75,27,79,27,90,18,94,9,90,9,79],'#006600'],
    [[207,60,216,64,216,75,207,79,198,75,198,64],'#9900FF'],
    [[189,60,198,64,198,75,189,79,180,75,180,64],'#9933FF'],
    [[171,60,180,64,180,75,171,79,162,75,162,64],'#9966FF'],
    [[153,60,162,64,162,75,153,79,144,75,144,64],'#9999FF'],
    [[135,60,144,64,144,75,135,79,126,75,126,64],'#99CCFF'],
    [[117,60,126,64,126,75,117,79,108,75,108,64],'#66CCFF'],
    [[99,60,108,64,108,75,99,79,90,75,90,64],'#66FFFF'],
    [[81,60,90,64,90,75,81,79,72,75,72,64],'#66FFCC'],
    [[63,60,72,64,72,75,63,79,54,75,54,64],'#00FF99'],
    [[45,60,54,64,54,75,45,79,36,75,36,64],'#00CC66'],
    [[27,60,36,64,36,75,27,79,18,75,18,64],'#339933'],
    [[198,45,207,49,207,60,198,64,189,60,189,49],'#6600CC'],
    [[180,45,189,49,189,60,180,64,171,60,171,49],'#6600FF'],
    [[162,45,171,49,171,60,162,64,153,60,153,49],'#6666FF'],
    [[144,45,153,49,153,60,144,64,135,60,135,49],'#6699FF'],
    [[126,45,135,49,135,60,126,64,117,60,117,49],'#3399FF'],
    [[108,45,117,49,117,60,108,64,99,60,99,49],'#33CCFF'],
    [[90,45,99,49,99,60,90,64,81,60,81,49],'#00FFFF'],
    [[72,45,81,49,81,60,72,64,63,60,63,49],'#00FFCC'],
    [[54,45,63,49,63,60,54,64,45,60,45,49],'#00CC99'],
    [[36,45,45,49,45,60,36,64,27,60,27,49],'#339966'],
    [[189,30,198,34,198,45,189,49,180,45,180,34],'#666699'],
    [[171,30,180,34,180,45,171,49,162,45,162,34],'#3333CC'],
    [[153,30,162,34,162,45,153,49,144,45,144,34],'#3366FF'],
    [[135,30,144,34,144,45,135,49,126,45,126,34],'#0066FF'],
    [[117,30,126,34,126,45,117,49,108,45,108,34],'#0099FF'],
    [[99,30,108,34,108,45,99,49,90,45,90,34],'#00CCFF'],
    [[81,30,90,34,90,45,81,49,72,45,72,34],'#33CCCC'],
    [[63,30,72,34,72,45,63,49,54,45,54,34],'#009999'],
    [[45,30,54,34,54,45,45,49,36,45,36,34],'#669999'],
    [[180,15,189,19,189,30,180,34,171,30,171,19],'#333399'],
    [[162,15,171,19,171,30,162,34,153,30,153,19],'#3333FF'],
    [[144,15,153,19,153,30,144,34,135,30,135,19],'#0000FF'],
    [[126,15,135,19,135,30,126,34,117,30,117,19],'#0033CC'],
    [[108,15,117,19,117,30,108,34,99,30,99,19],'#0066CC'],
    [[90,15,99,19,99,30,90,34,81,30,81,19],'#0099CC'],
    [[72,15,81,19,81,30,72,34,63,30,63,19],'#006699'],
    [[54,15,63,19,63,30,54,34,45,30,45,19],'#006666'],
    [[171,0,180,4,180,15,171,19,162,15,162,4],'#000066'],
    [[153,0,162,4,162,15,153,19,144,15,144,4],'#0000CC'],
    [[135,0,144,4,144,15,135,19,126,15,126,4],'#000099'],
    [[117,0,126,4,126,15,117,19,108,15,108,4],'#003399'],
    [[99,0,108,4,108,15,99,19,90,15,90,4],'#3366CC'],
    [[81,0,90,4,90,15,81,19,72,15,72,4],'#336699'],
    [[63,0,72,4,72,15,63,19,54,15,54,4],'#003366']
    ];

Friday, April 5, 2013

Web Look and Feel, Part 2 -- Does Native look actually matter?

In my previous post, I explored how I think we got to where we are right now with App and Web look and feel. With the Web, there really isn't any standard look and feel (still), but with Apps the dominate ones are iPhone and Android. Phresheez took a lot of lumps -- especially very early on -- for not looking like a "native" app. So the question I posed last post is that if I had a pile of cash to redo Phresheez, say, to make it look like a "native" iPhone/Android app would I do so (even if I used still web technology)?

The answer may seem surprising but I think that my answer would be "no". I have two different axis that are somewhat contradictory from which I draw that conclusion: 1) I'm not convinced that for the average user there is any meaningful "native" look and feel and 2) there are potential forces at work that could unify web look and feel, or at least provide a better base level set of similar look and feel, making any platform specific look and feel largely irrelevant.

What Look and Feel are We Talking About?

When I consider what people mean when they talk about native look and feel, there are a number of different things to consider:
  • Does the app navigate like a modern phone app these days?
  • Does it take into account that fingers are gigantic?
  • Does it take into account that people hate typing?
  • Does it follow the expected for zooming and  panning?
  • Does the app fit the form factor instead of relying on all kinds of panning and zooming (ala unreconstructed web sites)?
  • Does it count on mouse-overs to function properly (oops!)
  • Etc, etc
None of these are specific to a given platform. They are all about making the app work in the given form factor and while that is still somewhat in flux, there's far more agreement about what "working within the form factor" is, than argument. Take swiping. You swipe to go forward/back in a related sequence. Be it dates, pictures, etc. Zooming is done by pinching. And so on. 

So what do the native bigots actually mean then when they say it "doesn't look like an iPhone app"? One has to assume that it's the set of native widgets that the app uses. What else could it be? 

Heretics and Heresies

My feeling is that people on phones these days use their phone mainly for a few tasks:

  1. Social networks -- Facebook, Twitter
  2. Messaging -- email/texting
  3. Games/Vids
  4. Tracking themselves skiing (<-- kidding)
Let's take Facebook and Twitter, here are their screen shots in the Android store:



In both of these cases, I've put up the iPhone and Android versions. Can you tell which is which? There are minor differences to be sure, but it's not clear they have anything to do with the much vaunted "iPhone" or "Android" look and feel. More like the different dev teams just disagreed. These are hugely popular apps and from what I can tell nobody ever says "that doesn't look like my phone's app!!!". They just get used to it.

Built in Messaging Apps

So with built in apps, you'd expect that they'd be paragons of their respective "Look and Feel", right? Well take the Texting apps on both. For the most part they're identical -- they both use the comic speech bubbles, neither of which to my knowledge are native widgets. Apple's uses Aqua-like gradients on their bubbles more, but there isn't really anything beyond that. The inboxes seem to both be standard-esque listviews, but they're both very utilitarian. I find it difficult to believe that people fawn over the inboxes. So it there much here that showcases platform specific look and feel? Not in my opinion.

Mail on iPhone looks a little more standard with their back button paging (their navigation controller iirc). But it too is pretty utilitarian: a mail program is a mail program is a mail program. Nor does Android win any beauty contests either. Maybe some people really do stress about the minutia of differences between the two, but then again there's a Stress Betty for just about everything. For the most part, I can't see what the big deal is, unless you're a bigot of some variety. Note I'm only talking about the look and feel here, not functionality. I'm very willing to believe that there are non-bigoted reasons to prefer one platform's native this to the other platform's, but I expect that's functionality/nav much more than look and feel you can attribute to being on a given native platform and using its look and feel.

Games

Is there any native look and feel across gaming whatsoever? Take for example Words with Friends:


Is there any appreciable difference that you can attribute to the particular platform's look and feel? They look pretty much the same to me. They play pretty much the same too. 

I expect that's true of just about any game out there. And the same goes with viewing videos: the look and feel is the payload itself, not anything that the native platform brings to the experience.

[note: I'm most emphatically not implying a web platform is a viable candidate for gaming, just saying that  native look and feel for a major use case for phones is a no-op]

Back to Web Look and Feel

Now let's be clear, Facebook, Twitter, and Words with Friends are huge and create their own wind. But their existence pretty much makes a lie of the notion that it's some platform specific look and feel that is giving them a boost in the minds of their users. I doubt it even enters their users minds at all. To be sure, all of these guys have big budgets to throw at their look, feel, and interaction, but it's clear that a credibly designed app will be accepted by users regardless of whether it conforms to a particular native platform toolkit's look or not.

So what are the implications for using WebViews in apps and/or mobile sites? The high level bit from my standpoint is that it matters far more that the app is designed well for the form factor than any particular look and feel which is typically a secondary aspect of what a user sees with most apps (ie, date pickers, say). 
The nav has to work properly, the buttons have to be big enough, etc, etc. In the early days, that was far more important as people were groping around in the dark trying to figure out what constituted "well designed" for the phone form factor. The Native toolkits definitely gave devs a leg up on that account. But I'd say that was far more of getting both developers and users to come to gradual agreement on what constituted "obvious" and "intuitive" (neither of which happen in the real world, IMO). When they did that, it ceased being particularly important what the bling looks like so long as the bling is pretty.

That said, there still is the bootstrap problem for new apps. Eventually successful apps have their own look and feel and move away from the boring native widgets, but it's useful to have them at your disposal in the beginning. With no budget. Boring is better than outright ugly, after all. And that's the big drawback of the web approach: there isn't a base level widget library to fall back onto that looks familiar and comforting, if a bit stodgy. So you have to suffer through designing all of that crap yourself, and for non-UI kind of people it's probably going to look not so great.

Enter Firefox OS

Think what you will of the concept of booting Gecko on a phone, but there is a potential high level bit that people might be missing if they dismissively predict its uselessness: FFOS too has to provide a "native" widget toolkit to be viable. That is, they need to have high level constructs like date pickers, selector boxes, listviews, modal dialogs, tabs, etc, etc. in order to compete with iPhone and Android. At this time, it doesn't look (from the outside) like they've got much fleshed out, but they do seem to understand that this a necessary baseline that must be provided. It's a little early to tell whether it will be "beautiful", but the high level bit here is that it will exist. And it will exist using regular old -- and standards based -- web technology. (it's really too bad that Palm/WebOS croaked, it too could have provided the same). 

This is potentially very important if they pull it off. Since it's just a bag of js, html and css it can trivially be ported to non-Gecko OS things like, oh say, iPhone and Android webviews. Or to mobile websites. Or even to regular old websites for that matter. Here finally we potentially get back to a solution for Rip Van Webble's expectation that there be widget libraries for the web. And since the widget toolkit effort is its own ends (rather than the usual means to an end for website developers), Moz devs can actually take the same pride and ownership that Apple and Android widget developers take with their respective toolkits. That's important, because then there is incentive to get to parity with what native libraries can do, but using web technology which has huge code reuse advantages for app developers.

Conclusion

I'm really kind of hopeful about this. I think that web technology has been given a bad rap that isn't really its fault per se. It's a victim of the atmospherics and reality distortion fields for the most part, and was abandoned for app/mobile development just as it became a credible player. But so goes fads, and the rush to Native is mainly another fad, in my opinion. Don't get me wrong: I'm glad that Native shook things up, and we'd be much poorer for the experience if we had to wait for W3C to provide everything that Native app api's provide today, but look and feel is something that ought not be one of the reasons that you decide to develop a native app. 

This is why I'd still not use a native app look/feel and their associated native toolkits, even if I had a pile of money to do so. Maintaining two different code bases suck regardless of how much money you have to throw at the problem. Minimizing the differences and reusing code to the degree possible is still a very worthwhile goal. The biggest problem with the Web UI approach is the bootstrap problem given the lack of widget toolkits for your average schmuck web developer. But given FFOS -- and eventually a lot of toolkit imitators if successful -- there is hope that that advantage of Native will be going away. Given that most people don't notice or care that major apps they use day-to-day have little resemblance to a platform specific native app, it shows that native look and feel isn't a disqualifer, per se. The app working well for the form factor is far, far more important. Which, hopefully, emerging web based widget toolkits will give web-centric developers a leg up on.

Web Look and Feel, Part 1 -- Why web development is at a disadvantage over native

When Rip Van Webble first woke up, I fully expected that the abstraction layers on the web design would have followed the window based world's examples by building on the rather primitive world of css, divs, etc and there would be plethora of toolkits with a few dominate ones. Sort of like, oh say, GTK or Cocoa, or QT, and all the rest. But when I asked around, the answer seemed to be "no". No such things had gained any traction that I could tell. JQuery doesn't fit the bill -- it's an abstraction to make dealing CSS easier for the most part, but takes no position in the style wars. Maybe things like Drupal do what I'm thinking of, but they come with a huge amount of other stuff -- it's a CMS first and foremost. I just expected something in between: a standardized date picker, for example. Better modal dialogs than alert(). Etc.

I guess this wasn't entirely surprising thinking back on this. All content was being created for the most part server-side instead of client-side. So that means that a toolkit would have had to either be created for each of the P languages, or people would have had to buy into client-side rendering which was pretty much heresy in the times IE6. Not impossible, but for whatever reasons it never seemed to take off. And then of course browsers were a) slow and b) well, IE6'ed. So everything was hand coded, and there wasn't much pressure to do anything different because the diversity of web life was taken for granted, even if most of it could use an aesthetic comet to snuff it out.

And that comet did come: apps. When the iPhone was released in 2007, it was fawned on as being "beautiful" and all of the other adjectives that Steve Jobs got. It's certainly true that the iPhone was a huge advance over the Windoze phones of the day which were as hideous as they were inappropriate for the form factor. The phone form factor changes everything about UI design, especially on touch screens, but even with keyboards. Nobody had been paying attention to that really. Well, I'm sure that BlackBerry's mail client was serviceable but web browsing was an exercise in torture. The initial iPhone laid down a marker: design for the form factor or be uncool, and most especially extinct. And that of course is exactly what happened to Windoze and BlackBerry. We can thank Steve Jobs for that.

As with many things though, when the herd found out that Apple would allow third party developers to create apps for the iPhone they confused the actual marker: "design for the form factor" with the reality distortion field: "the form factor can only be serviced by native widgets", and of course the only native widgets that would save you from extinction were Cocoa widgets designed by Apple. A great marketing strategy that played perfectly with the iSheep bigot's precepts.

To be fair, there was some reason in 2008 to take a look again at native vs. web. Browsers were just barely coming out of the dark ages where you could get decent cross-browser compatibility with decent feature sets, and javascript was just barely being paid attention to for speed. Doing cutesy animations wasn't impossible, but it wasn't great either compared to a native toolkit which was designed from the beginning to do those cutesy animations. But native toolkits -- especially with Apple -- really have one main purpose: vendor lock in. So Apple threw out some visual bling and everybody forgot in an instant why the web was so important 15 years before: vendor lock in sucks.

So what happened to browsers in the mean time? They've gotten hugely a) faster, b) compatible and c) featureful. And that's true of the browser apps on phones, as well as the WebView widgets you can embed in apps. But apps with WebView's are still considered by many -- especially by the iBigots -- to be poor relations to the "beauty" of native apps. My assertion is that that is mainly Apple marketing BS: a WebView is capable of replicating pixel for pixel what native apps do for the most part. Especially now that processors have gotten so much faster on phones.

What's missing to do that? Web-based toolkits. I understand that things like Sencha and maybe Phonegap try to bridge these two worlds and they claim some amount of success. It's not like laying down pixels on bitmaps is voodoo, after all. You want something that looks like Cocoa? Pay some team to replicate it. You want something  that looks like Android? Pay some team to replicate it. You want to be able to write a base app that can be themed like Android or iPhone depending on what it's running on? Pay for those two teams to be in the same room when the high level API's are designed.

And when you do that, you get back to what the original promise of the web was: no vendor lock in. Which is hugely important for developers these days. It is complete chaos whenever you have to keep two completely separate development teams to design the same app for different platforms and keep feature parity. In reality that parity rarely happens, and worse: usually one platform withers and dies in the long run.

With Phresheez, I took the approach of using WebViews and leveraging them heavily from the very beginning. It wasn't any sort of deep insight on my part, only the realization that I couldn't possibly maintain two different code bases for all of its UI stuff. And we've been dinged for that a lot. In the past, mainly. But a lot of what we got dinged for isn't the fault of the core web technology, it's because I didn't have the money (or inclination, honestly) to hire a team of people to design the look and feel to fool the bigots. But given a pile of money, I could have. More to the point: a lot of Phresheez early problems were my not understanding the form factor itself. Since we started designing it in 2008 we were hardly unique -- not many people understood how to design for the phone form factor. Using native widgets could have helped (and in the beginning we used them a lot more), but it was far more about understanding how people would come to use their phones, and what the accepted wisdom was -- when it was rapidly evolving at the time. C'est la guerre. I think we're in a better place now though.

In the next part of this, I'll explore whether given a pile of money I would  spend it on making Phresheez look like native iPhone/Android apps today.

Thursday, April 4, 2013

Authoring Content vs. HTML5 Canvas

One of the great promises of HTML5 is getting to play with real vector graphics again, mainly with the HTML5 canvas tag, but OpenGL too as well as it matures. The canvas tag drawing primitives seems pretty serviceable, though I've not looked at it any real depth. I have experience in a previous life writing the rendering engines for laser printers and graphics terminals so I'm not completely clueless (if a bit rusty).

What strikes me is that there's a real disconnect between the way that web production is done now versus where it eventually needs to go. Right now, Art is generated by graphic artists who give you .png and .jpgs. They hand over the images at the right resolution, and the geeks take it from there more or less. There are no knobs are anything like that with images so it's all very simple.

There really isn't an equivalent production pipeline for HTML Canvas that I've seen. Canvas is a javascript API so the natural thing that the Artist should produce for canvas vector artwork would seemingly be... javascript, right? Which moves the pen up/down/around, fills regions, etc, etc. Yet I haven't actually seen anything take that step. It may be my ignorance, but this is all pretty new and Google was being very equivocal about my search terms, so I'm guessing that I'm not alone groping around for a solution. How do artists and geeks interact in the Canvas world?

Let me give a for instance. In Phresheez, I wanted to create a cute graphic of a skier/boarder where you can click on various pieces of your gear and enter in the manufacturer, etc. That is, I want a customizable avatar. So far so good: I could do this with .png's like normal but I wanted a few features that make .png's problematic like, for example, I want my users to be able to color their parka one way, their skis another, etc, etc. I certainly don't want in the backend to have dozens of different color .png's to cover every combination -- yuck.



So I decided that canvas would a reasonable since it's vector graphics, I can just apply the fill/stroke colors on the fly as its rendering it. Great idea! Should work great!

Except for the disconnect I started out with. I'm a bad enough graphic artist to begin with, so I'm certainly not going to be creating art with naked context2d calls in javascript with lots of trial and error. I needed an authoring tool like, oh say, Google Draw, or Adobe Illustrator, or in my case Inkscape that I happen to have on my linux box. They, of course, have no clue about emitting javascript though. They do know about emitting SVG, but SVG as a native format (regardless of whether you think this is good or bad) is not well supported, especially on mobile browser technology (read: iphone/android) . And in any case, the authoring tools even if they do emit SVG don't really have a way to annotate the SVG in a way that I can manipulate in the geek realm (maybe I'm ignorant, but even then it's beside the point because I don't want SVG in the first place).

But there is some Google code (canvg) that takes SVG input and generates canvas pixels. Which is kind of like what I am looking for, but is still gross. What I did is drew my stuff up in Inkscape and labeled all of my fill colors with special colors and I just do a string replace with them to the appropriate colors. Simple, fast, and utterly grotesque and not scalable with real graphic designers, IMO. And this is a very simple example.

What it seems to me that I want is an authoring tool that both directly emits the javascript to create an object for drawing into a canvas, but also the exposes the knobs that can be played with at execution time. In my case, that would be the ability to affect the color(s) of the objects, but I might want many other knobs too, like, oh say, rotation knobs, scaling knobs, 3d effects knobs, animation features, etc, etc.

So what I really want is both the blob of code that renders the vectors into the canvas bitmap, but also an external set of public methods that I can play with in code to do what I need to do.

Oh, and my graphic designer needs to be able to produce those knobs too, and the answer better not involve my graphic designer understanding anything about programming, let alone javascript. My feeling is that this is an invented wheel in the visual effects business since you need to have discreet objects that real artists design, but obviously need to have attributes and methods for manipulation at higher levels. I know very little about this workflow though, but it seems to me that a vastly simplified Hollywood workflow (we're not creating Shrek MCM here, after all) would be a good place to look. Maybe not take their tools wholesale, but recasting their production pipeline's concepts into discreet functionality that the web can understand, and train both sides (eg Artists, Geeks) for the brave new HTML5 canvas world.

In conclusion, we need some cross pollination from the heavy-duty worlds of Hollywood (and probably the gaming world too) that allows lighter duty webbish vector art to start to grow. Until there's a well-understood set of interfaces between artists and geeks in the vector world, it's going to be slow to take off.

Friday, March 22, 2013

Transistors over HTTP

Sometimes you should probably just ignore a waking dream, and that's probably what I should have done here but what the heck. I like doing somewhat crazy things just for the heck of it. There's a lot of reducto ad absurdum kinds of things on the net like javascript engines written in javascript and IP over avian carriers, so I figured why not go for the whole enchilada: transistors which are the basis of everything on computers and fabricate them out of php and http rather than silicon and wire.

So here's what I did. I created three modules, fab.php, scope.php and transistor.php. Fab creates/modifies transistors, and scope tests the input and outputs of the pins of our http transistor (oscilloscope, duh). Each site has a sqlite database of the transistors it serves, their configuration, and state.

A typical transistor has three pins: a collector, a base and the emitter. The collector and base are inputs, and the emitter is the output depending on the state of the two inputs. For mine, I just wired this as a logical AND which I'm pretty sure is not really what NPN transistors (for example) perform, but what the heck I'm not a real EE so I can make my base transistor perform the logic I want it to.

The way we change the pin inputs on our transistor is to inform the transistor of the pin's state using transitor.php:

http://mtcc.com/ee/transistor.php?id=1&pin=base&state=1

This tells the base of transistor 1 on mtcc.com that it's state is now a 1. If we want to change it:

http://mtcc.com/ee/transistor.php?id=1&pin=base&state=0

and now it's state is 0. Simple right? The trick here is to wire up a network of transistors like you would with a real circuit. That's where our wire -- http -- comes in. Inside our transistor is an output field which tells our transistor to contact its neighbor (if any, and in reality it should be one to many). If it has a neighbor a change in output state of the emitter causes it to curl:

http://mtcc.com/ee/transistor.php?id=2&pin=base&state=0

Note id=2 which is its neighbor, and the state=0 because our transistor is an AND function and the base is now zero. So when we change our emitter state on id=1 back to 1:

http://mtcc.com/ee/transistor.php?id=1&pin=base&state=1

assuming the collector is already 1, it will then contact id=2's base with state=1 causing id=2's emitter to now read 1!

Here's a diagram of a network I actually implemented:


In principle I could make lots of different types of transistors -- and probably other components too like diodes -- but this was a fit of dementia and two hours of work, so sew me. The other cool thing about this is that it can span any number of servers implementing the transistor. The one thing I haven't actually tested is feedback like flip-flops. I do have dampening logic to only send changes when the emitter's output changes, but until proven I'm a bit afeared.