Friday, January 20, 2012

The Emperor Will Never Have Clothes!

Half a decade ago I did some fairly exhaustive research into software time and cost estimation techniques for Microsoft Services. I evaluated the effectiveness of both formal and informal techniques used within Microsoft, across the software development industry, and even in other industries. I looked at everything from Estimation by Analogy to COCOMO II.

After months of research I discovered that the most commonly used estimation techniques were Estimation by Analogy and Wideband Delphi, often done in combination. However, most of the teams using these techniques were doing so informally, and had never heard of either of these terms.

I also discovered that there were no software estimation techniques that consistently produced accurate estimates, other than for small projects, even those sophisticated parametric estimation techniques like COCOMO II. 

At the time I was doing the research the failure rate for IT projects was around 70%, and many of those failures were due to catastrophic budget and schedule overruns. It quickly became evident to me that the way the industry had historically thought about estimating software projects was deeply broken; The Emperor had no clothes! 

My final recommendation to Microsoft Services was that they adopt Estimation by Analogy and Wideband Delphi, and formally train their staff on the use and limitations of these techniques. My other recommendation was that they also invest in maturing their risk management processes, given the historical inaccuracy of software estimation in general. It was on this latter area that I focused until I left Microsoft.

Our obviously apparent inability to do accurate estimation bugged me for years after I completed this research. This itch that I could not seem to scratch motivated me to do some reading about predication in general, and in particular Quantitative Analysis and its use of Stochastic models; one would imagine that if any industry had worked out how to predict the future it would be the Financial Industry given their huge monetary incentive to do so. Obviously recent events have shown that not to be the case, but this was before all that nastiness.

And then I read “The Black Swan: The Impact of the Highly Improbable” by Nassim Nicholas Taleb, and it all made sense. It is not that we have yet to find an accurate technique to do software estimation; it is that accurate estimation of large, complex software development projects is simply NOT POSSIBLE! (given our current understanding of the laws of physics anyway). Not only does the Emperor not have clothes, but he will remain naked for the foreseeable future.

I suspect that the move to  Agile software development practices is a natural response to our inability to do accurate estimation, but I am continually amazed at how many people in the industry and how many of its customers are still in denial about this, what should now be self-evident, fact. I still encounter many projects where development teams are held to early estimates, which are typically done by non-technical project managers. And this is particularly true on fixed-cost\budget projects.

Surely it is time for the entire industry and its customers to acknowledge that this whole approach is simply broken? The illusion is that fixed-cost\budget projects shift ownership of the risk from the customer to the organization who is developing the software; but given the percentage of IT projects that still fail today, this is obviously just that: an illusion; and a pernicious one at that.

We need to start from the premise that accurate software estimation is currently, and probably forever, impossible, and go from there. Agile practices have made a good start but we obviously need to do more. And most importantly we need to educate our customers!

Here is an interview with Nassim Nicholas Taleb wherein he talks specifically about our inability to estimate IT projects:

Tuesday, December 20, 2011

Why Software Development is like Ironing a Thneed

 I’m being quite useful. This thing is a Thneed.
A Thneed's a Fine-Something-That-All-People-Need!
It's a shirt. It's a sock. It's a glove. It's a hat.
But it has OTHER uses. Yes, far beyond that.
You can use it for carpets. For pillows! For sheets!
Or curtains! Or covers for bicycle seats!
"

                                         – from “The Lorax” by Dr. Seuss

During my time in the military two decades ago I become highly skilled at ironing. And not only shirts and pants, but beds, hats, sheets and other items one would not normally consider “ironable”. I continue to this day to do my own ironing. I actually find it rather therapeutic.

Since having children I have also become reacquainted with the works of Theodor Geisel, more affectionately known as Dr. Seuss. It struck me the other day while ironing a particularly pesky shirt that software development is very much like ironing a Thneed.

So let’s make some assumptions about a Thneed based on the description above. Some poetic licence and imagination will be required.

  1. Nobody is entirely sure what a Thneed is, not even the manufacturer.
  2. When customers buy a Thneed they have only a vague idea of what they need it for and how it is going to make their lives better.
  3. No two Thneed’s are exactly alike; they are the snowflakes of garments.
  4. Thneed producers create new and improved Thneed’s all the time.
  5. A Thneed is too big and awkwardly shaped to fit on your ironing board and Dr. Seuss makes no mention of a Thneed-press.
  6. It is hard, if not impossible, to estimate how long it will take you or a highly trained team of Thneed-ironers to iron a Thneed, with any level of accuracy or confidence in your estimate.
  7. The market for Thneed-ironing accessories is confusing in its profusion, pace and super-competitiveness.
  8. Thneed-ironing methodologies were derived from shirt and pants ironing methodologies, but they are actually poorly suited.
  9. A Thneed is like most other garments in that it occasionally requires ironing.
  10. Thneed manufactures’ own Thneed’s are usually the worst ironed.

So based on the assumptions above, how does one go about ironing this Thneed thing? Well the trick is known by every person who has ever had to iron a shirt.

Manipulate the garment so that a small piece of it is flat on the ironing board and then iron that piece. Then get another piece flat and iron that piece, and so on and so on, until you have ironed the entire garment. If you are foolish enough to try to iron large sections of the garment at the beginning, you will become very frustrated and will probably run out of steam before you are done. You have to “divide and conquer” when it comes to ironing a Thneed; that is the winning strategy.

I don’t think that I need to actually spell out why this is like software development; if you have done any software development in your life you will know that I am right (or mostly so).

Maybe someday I will post “Why Architects are like the Lorax, and Users like the Once-ler”. On second thoughts maybe I won’t.

Happy Ironing!

Wednesday, December 14, 2011

Apache Hadoop on Windows Azure

The brilliant Alexander Stojanovic talking about his latest project, Isotope, which is Microsoft’s Hadoop distribution. Yes, you read that right; Microsoft is going to be packaging up HDFS, MapReduce, Flume, Sqoop, Hive, Pig, Pegasus, Mahout, Lucene and some new technology into a Hadoop distributed for the Windows and Windows Azure platforms.

Update (June 10th, 2012): It looks like Channel9 removed the video for some reason.

Monday, December 12, 2011

Ghost in the Wires

I just finished reading “Ghost in the Wire : My Adventures as the World’s Most Wanted Hacker” by Kevin Mitnick and William L. Simon. It reads like a spy thriller and I literally had a hard time putting it down. The stories of Kevin Mitnick’s social engineering exploits are truly amazing, and regardless of one’s ethical stance on hacking one has to respect his extraordinary audacity.

Given that Mitnick himself admits to being a master of social engineering, i.e. lying and manipulating people, I still cannot say for sure whether or not I believe that all his hacking was motivated by curiosity alone. But I don't think it matters really; I agree with Kevin and his supporters that he was treated rather poorly by the US Justice System.

In hindsight though, I can also totally understand why he was treated as harshly as he was; at the time they simply did not have the necessary understanding to ascertain just how big a threat he was, and so they had to assume the worst, and defer to sources who obviously had issues with him that went well beyond the morality and legality of his hacking activities. I also don’t think it mattered that he had apparently not used any of the access or data he obtained for nefarious purposes; it was simply the fact that he could have caused significant damage and loss if he so chose. It was just pure luck on the part of the targets of Kevin’s hacking that he was not malicious;  and I would hazard a guess that contemporary jurisprudence is not underpinned in any way by luck (though I am no expert in this area, so one never knows).       

This book is well worth the read and I highly recommend it for anyone interested in computer security. It shows that the weakest link in any system is unarguably always the human components, and that without strictly adhered-to policy that no system can be made secure, regardless of the size of the technology investment.

P.S. The book refers to a film that was made by Kevin’s supporters; it is called Freedom Downtime - The Story of Kevin Mitnick. It was obviously made on a shoestring budget, and apparently before hacking became a lucrative new line of business for organized crime world-wide, but it is worth watching. It also happens to be available in its entirety online, and I have embedded it below:

Friday, December 9, 2011

Processing.js Snowflake Fail

I probably should be writing a post about Microsoft’s SOA and BPM platforms, but I need a breather from that particular topic, so instead I am going to write about my recent frustrations with Processing.js. I was hoping to be able to create some flashy new sketches, but unfortunately my recent experiments have uncovered a critical bug in Processing.js that will only be fixed in the 1.5 release. 

My 3 year-old daughter can’t stop talking about snow so I decided to create a little snow generator for her and post it on this blog. I also wanted to experiment with Processing.js’ ability to load SVG files, which can then be used in a sketch. My idea was simple; create an SVG file that contains a number of shapes that can be randomly combined to create snowflake shapes. Then generate a collection of those random shapes and animate them. Not an ambitious project in the least.

My previous experiments with Processing were done with the stable 1.5.1 release of PDE. I thought I would try the latest alpha version of the Processing 2.0 PDE for this experiment, primarily because it has a JavaScript mode, and will export a web page that loads Processing.js and your sketch (and detect the necessary browser capabilities too!). It does not seem to provide an option to embed the sketch script directly in the HTML, so the sketch is always referenced as an external pde file.  It took me a couple of hours to create the SVG file in InkScape, and a sketch in PDE that did exactly what I wanted. While prototyping the sketch I was working in the Standard mode, i.e. it generates a Java applet, since that offers the best development-time performance.

When, after completing the sketch, I changed to the JavaScript mode my sketch failed to pretty much do anything other than draw the background gradient.

The original sketch looks like this when running:

snowfalkes

Processing provides a loadShape method that takes the path or URL to an SVG file, parses the SVG, and generates Processing-native PShape objects. There is currently no way to load SVG elements that are embedded directly in the HTML. Hopefully this will come in a future version of Processing.js. Processing also provides a  getChild method to get shapes nested within the root PShape. PShapes can be drawn directly to the screen or drawn off-screen to a PGraphics object which can then be used at some later time to draw to the screen by calling the image method.

To generate my snowflakes I created an array of PGraphics objects (each with a little wrapper) and then drew random snowflakes to each. I also added some noise and toy physics to make the whole thing a little more realistic. It looked great in PDE.

Note: I initially was sorting the array from smallest to largest and then drawing them in that order, but after comparing the results I could not see a difference and simply omitted the sort. I had to write my own sort function because the sort implementation that is provided in Processing will only sort arrays of int, float and String. 

There was only one small problem; off-screen drawing of PShapes is broken in the current build of Processing.js. I have filed a bug and it looks like this will be fixed for the 1.5 release of Processing.js. So this post obviously does not include the running sketch.

Another Note: I tried using the tint method to modify the apparent brightness of the snowflakes based on their scale each time the snowflake was drawn, rather than explicitly adjusting the stroke color. This KILLED the performance even when it was running in the Standard mode on my quad-core 8GB laptop with hardware-accelerated graphics. Another bug perhaps?

Rather than find a work-around in Processing.js, I will probably try to port this sketch to one of the other JavaScript graphics APIs, like Raphaƫl for example. And of course I will post the running result and code in some future post on this blog.

Since I cant show the final result, here is my Processing code for the sketch (usual caveats and disclaimers apply):

color bkground = #000080;
color bkground2 = #0000FF;
snowFlakeFactory factory;
snowFlake[] flakes; 

void setup()
{
  size(600, 200);
  smooth();
  frameRate(60);
  factory = new snowFlakeFactory("snowflakes.svg");
  flakes = factory.createFlakes(60);
}

class snowFlakeFactory
{
  color _background;
  PShape _template,
  _spoke, 
  _centerHex, 
  _centerCircle, 
  _star, 
  _longArms, 
  _mediumArms, 
  _shortArms, 
  _endCircle;

  snowFlakeFactory(String templateFileName)
  {  
    _template = loadShape(templateFileName);
    _template.disableStyle();
    _spoke = _template.getChild("spoke");
    _centerHex = _template.getChild("centerHex");
    _centerCircle = _template.getChild("centerCircle");
    _star  = _template.getChild("star");
    _longArms = _template.getChild("longArms");
    _mediumArms = _template.getChild("mediumArms");
    _shortArms = _template.getChild("shortArms");
    _endCircle = _template.getChild("endCircle");
  }

  snowFlake createFlake()
  {
    snowFlake flake = new snowFlake();
    PGraphics graph = createGraphics(450, 450, P2D);
    graph.beginDraw();
    graph.background(0,0);
    graph.smooth();
    float br = 4000 * flake._scale;
    graph.stroke(br, br, 255);
    graph.noFill();
    graph.strokeWeight(13);
    graph.shapeMode(CORNERS);
    radialDraw(graph,_spoke, 225, 225, 0);
    if (heads())
    {
      if (heads())
      {
        graph.shape(_centerHex, 225, 225);
      }
      else
      {
        graph.shape(_centerCircle, 225, 225);
      }
    }
    if (heads()) graph.shape(_star, 225, 225);
    if (heads()) radialDraw(graph,_endCircle, 225, 225, 190 );
    PShape[] arms = {
      _longArms, _mediumArms, _longArms
    };
    if (heads()) radialDraw(graph,arms[(int)random(0, 2)], 225, 225, 100);
    if (heads()) radialDraw(graph,arms[(int)random(0, 2)], 225, 225, 130);
    if (heads()) radialDraw(graph,arms[(int)random(0, 2)], 225, 225, 160);
    graph.endDraw();
    flake._image = graph;
    return flake;
  }

  snowFlake[] createFlakes(int flakeCount)
  {
    snowFlake[] flakes = new snowFlake[flakeCount];
    for (int i = 0; i < flakeCount; i++)
    {
      flakes[i] = createFlake();
    }
    return flakes;
  }

  void radialDraw(PGraphics graph, PShape feature, float originX, float originY, float rad)
  {   
    float xOffset = rad * cos(PI/6);
    float yOffset = rad * sin(PI/6);
    graph.shape(feature, originX, originY + rad);
    feature.rotate(PI/3);
    graph.shape(feature, originX - xOffset, originY + yOffset);
    feature.rotate(PI/3);
    graph.shape(feature, originX - xOffset, originY - yOffset);
    feature.rotate(PI/3);
    graph.shape(feature, originX, originY - rad);
    feature.rotate(PI/3);
    graph.shape(feature, originX + xOffset, originY - yOffset);
    feature.rotate(PI/3);
    graph.shape(feature, originX + xOffset, originY + yOffset);
    feature.rotate(PI/3);
  }
}

class snowFlake
{
  float _posX;
  float _posY;
  float _scale;
  float _rotation;
  PGraphics _image;

   snowFlake()
  {
    _posX = random(width);
    _posY = random(height);
    _scale = heads()? random(0.01,0.03) : random(0.04,0.1);
    _rotation = random(0, PI/6);
    _image = null;
  }

  void drawFlake()
  {
    pushMatrix();
      translate(_posX, _posY);
      scale(_scale);
      rotate(_rotation);
      image(_image, -225, -225);
    popMatrix();
  }
}

void draw()
{
  drawBackroundGradient(bkground,bkground2);
  for(int i = 0; i < flakes.length; i++)
  {
    snowFlake flake = flakes[i];
    float gravity = flake._scale * (10 + random(0,5));
    float wind = flake._scale * (5 + random(-2,2));
    flake._posY += gravity; 
    flake._posX += wind; 
    flake._rotation += 0.01;
    flakes[i].drawFlake();
    if(flake._posY &rt; height + 20) flake._posY = -20;
    if(flake._posX &rt; width + 20) flake._posX = -20;
  }
  
}

void drawBackroundGradient(color c1, color c2)
{
  noFill();
  for (int i = 0; i <= height; i++) {
    float inter = map(i, 0, height, 0, 1);
    color c = lerpColor(c1, c2, inter);
    stroke(c);
    line(0, i, width, i);
  }
}

float _prob = 0.75;
boolean heads()
{
  float rand = random(0, 1);
  return (rand < _prob);
}

And here is the SVG:

<svg id="snowflakeTemplate" xmlns="http://www.w3.org/2000/svg" height="1000" width="700" version="1.1">
<g id="mainLayer" stroke="#000" stroke-miterlimit="4" stroke-dasharray="none" fill="none">
<path id="spoke" stroke-linejoin="round" d="M0-0,0,190" stroke-linecap="round" stroke-width="10"/>
<path id="centerHex" stroke-linejoin="miter" d="m-36.48-23.229,0,44.146,36.184,20.891,36.775-21.232,0-41.606-35.987-20.777z" stroke-linecap="butt" stroke-width="10"/>
<path id="star" stroke-linejoin="round" d="M53.858-31.273,49.838-86.48-0.015-62.659l-50.032-24.126-4.3663,55.188-45.979,31.37,45.814,31.287,4.3801,55.416,49.918-23.819,50.097,24.128,4.4815-55.112,46.094-31.294z" stroke-linecap="round" stroke-width="10"/>
<path id="longArms" stroke-linejoin="round" d="M49.142,11.646,0-11.646-49.142,11.559" stroke-linecap="round" stroke-width="10"/>
<path id="mediumArms" stroke-linejoin="round" d="M28.782,6.4858,0-6.4858-28.782,6.3986" stroke-linecap="round" stroke-width="10"/>
<path id="shortArms" stroke-linejoin="round" d="M-12.226,2.7043,0-2.7915,12.226,2.7915" stroke-linecap="round" stroke-width="10"/>
<circle id="endCircle" cx="0" cy="0" r="10" stroke-width="10"/>
<circle id="centerCircle" cx="0" cy="0" r="36.5" stroke-width="10"/>
<rect id="diamond" stroke-linejoin="round" transform="rotate(45)" height="8" width="8" stroke-linecap="round" y="-4" x="-4" stroke-width="10"/>
</g>
</svg>

Friday, November 18, 2011

Simple L-system Processing.js Code

Here as promised is the code from my previous post:

<script src="http://processingjs.org/content/download/processing-js-1.3.6/processing-1.3.6.min.js" type="text/javascript"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.0.6/modernizr.min.js" type="text/javascript"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js" type="text/javascript"></script>
<div id="blogpostcontent"><!-- Blog Text -->
</div>
<div id="nocanvas" style="display: none; color: Red;"><!-- Fail Text -->
</div>
<div id="procanvas"><canvas id="processingCanvas"></canvas></div>
<div><!-- More Blog Text -->
</div>
<script type="text/javascript">
var words = $("#blogpostcontent").text().replace(/[\.,-\/#!$%\^&\*;:{}=\-_`~()]/g, "").replace(/\s{2,}/g, "").split(' ');
if (!Modernizr.canvas) { $('#nocanvas').show(); $('#procanvas').remove(); }
</script>
<script type="text/processing" data-processing-target="processingCanvas">

Tree tree;
int wordCount = 0;

class Stack {
ArrayList aList;

Stack() {
aList = new ArrayList(1024);
}

Stack(int initialSize) {
aList = new ArrayList(initialSize);
}

boolean isEmpty() {
if (aList.size() > 0) return false;
return true;
}

void push(Object obj) {
aList.add(obj);
}

Object pop() {
int n = aList.size();
if (n > 0) return aList.remove(n - 1);
return null;
}
}

class Branch {

float x = 0;
float y = 0;
float theta = 0;
float thickness = 0;

Branch() {
};

Branch (Branch branch) {
x = branch.x;
y = branch.y;
theta = branch.theta;
thickness = branch.thickness;
}
}

class Tree {

String axiom, currentString;
String productionRule;
Branch branch;
Stack branchStack;
int pos = 0;
color col;
float angle = PI/10;
float angleChaos = 1;
float initialThickness = 18;
float thickness = initialThickness;

Tree () {
axiom = "F";
currentString = axiom;
branch = new Branch();
productionRule = "F[+FF-F-F][-FF+F-F]";
branchStack = new Stack();
}

void grow() {
grow(1);
}

void grow(int generations) {
for (int i = 0; i < generations; i++) {
String nextString = "";
for (int j = 0; j < currentString.length(); j++) {
char c = currentString.charAt(j);
if (c == "F") {
nextString += productionRule;
}
else {
nextString += c;
}
}
currentString = nextString;
}
}

void draw() {
for (int i = 0; i < currentString.length(); i++) {
this.drawBranch();
}
}

void drawBranch () {
if (pos >= currentString.length()) return;
char c = currentString.charAt(pos);
switch (c) {
case "F":
fill(100 + random(-40, 40), 42 + random(-40, 40), 42);
String word = (wordCount < words.length - 1) ? words[wordCount++] : "noword";
branch.thickness = thickness;
textFont(createFont("Helvetica", branch.thickness));
pushMatrix();
translate(branch.x, branch.y);
rotate(branch.theta);
text(word, 0, 0);
popMatrix();
float extension = textWidth(word);
branch.x += extension * cos(branch.theta);
branch.y += extension * sin(branch.theta);
break;
case "-":
branch.theta -= (angle + random(-1.0 * angle * angleChaos, angle * angleChaos));
break;
case "+":
branch.theta += (angle + random(-1.0 * angle * angleChaos, angle * angleChaos));
break;
case "[":
branchStack.push(new Branch(branch));
if (thickness > 3) {
thickness -= 3;
}
else {
thickness = 1;
}
break;
case "]":
branch = (Branch)branchStack.pop();
thickness = branch.thickness;
break;
}
pos++;
}
}

void setup () {
size(500, 500);
background(#141414);
frameRate(60);
smooth();
tree = new Tree();
tree.grow(3);
}

void draw () {
translate(width/2, height);
rotate(1.5 * PI);
tree.drawBranch();
}

</script>

The L-system code is based on this Processing code written by Daniel Jones.

A Simple L-system in Processing.js

Recently I attended TEDxVancouver 2011 and my favourite talk by far was by a brilliant generative artist named Jer Thorp. I have always been a fan of generative art, but have never been motivated to create any of my own. Jer's talk inspired me to play with one of the tools that he uses to create his works;Processing, which is a Java-like programming language, development environment and runtime, optimized for creating images, animations, simulations and interactive visuals.

Processing projects or "sketches" are typically packaged as self-contained Java applets and can be embedded in web pages or run stand-alone. This however requires that a JVM is installed and that the user has given Java applets permission to run in the browser, so I was very happy to hear that Processing has been ported to JavaScript, which allows Processing sketches to be embedded in, or referenced by HTML pages, and run directly by any HTML5-capable browser. The new API, called processing.js, makes use of the new HTML5 Canvas element, and WebGL for 3D rendering. Processing.js supports about 90% of the Processing language.

Processing.js provides three ways to reference a sketch in an HTML page:
  1. You can reference the file that contains the Processing source code in the same way you would reference an external JavaScript file.
  2. You can embed the Processing script directly in-line in the HTML, again in the same way you can embed JavaScript directly in an HTML file.
  3. You can use Processing.js as a pure JavaScript API.
In the first two cases Processing.js parses the Processing code and converts it to JavaScript. This obviously has performance implications, but it is very convenient to be able to prototype your sketches in the Processing IDE, and the DOM and other JavaScript embedded or referenced in the page is still accessible to your Processing code. If you want a richer development experience there is also a Processing plug-in for Eclipse, and the Processing API has also been ported to other languages including Ruby, Scala and Clojure.

For my initial project I decided to build a simple L-System, to simulate the growth of a plant and then progressively render the resulting simulation. A Lindenmayer System is a string-rewriting technique that can be used to simulate plant growth. I also wanted to experiment with having the Processing code interact with the DOM and other JavaScript in an HTML page, so I decided that I would wrap my experiment in a blog post and use the words in the blog as the "branches" of the plant.

It took me a few hours to implement an L-Systems in Processing, and then a few more to get my code working as embedded Processing.js code in a simple web page. I also spent a couple of hours researching how to deal with older browsers that do not support HTML5 and the Canvas element, but in the end I decided to simply fail elegantly (I hope) in the absence of support for the Canvas element, which I detect using Modernizr.

And then I tried to get it all working inside a Blogger blog post. This was probably the hardest, most frustrating and time-consuming part of the whole process. After a good four hours of finding the right CDN for each script, modifying script load orders, editing the blog template, and minifying my code, I got it all working. I have tested it on IE 6 through 8 (elegant fail), IE9 (success!) and a number of versions of Firefox, Safari and Chrome, but you never know;if it causes your browser to throw an exception, I apologise.

And here is the final result (which has probably completed animating while you read the post so go ahead and refresh the page):

Update (March 16th, 2012): I finally got the code in this post working again. The reason that it broke is that both the Blogger web editor and Windows Live Writer do some infuriating auto-formatting which breaks the inline Processing script! I broke the code by attempting to fix a typo using first one and then the other of the aforementioned tools. Two rounds of auto-meddling left the page totally broken. Fixing it was a pain in the arse, but here you go.


If anyone is interested I will post the code in a subsequent post. Everything is embedded in this very page, but finding it amongst all of the boilerplate/template markup is a pain in the arse.
I plan to make my L-System more complex and reflective of real plant growth so look out for more posts and more code.

Tuesday, November 8, 2011

All Your node Are Belong to IIS

I recently wrote a post in response to a criticism of node.js. The author’s major gripe was about the performance characteristics of node, which is essentially single-threaded. I asserted that you could probably address this by load-balancing across multiple instances of node on the same server. Well Tomasz Janczuk has developed a better solution, called iisnode, which allows you to host node in Internet Information Server and leverage some of IIS’ process management, security, logging, scalability and management capabilities.

Tomek has documented how to get iisnode up and running in his blog post titled Hosting node.js applications in IIS on Windows.

The prolific Scott Hanselman, who is the Kurt Vonnegut of software development bloggers, has a great post about iisnode titled Installing and Running node.js applications within IIS on Windows - Are you mad?. It provides a thorough overview of iisnode and also includes some interesting performance data.

Tuesday, October 18, 2011

Built-In Obsolesce

Here’s another of those thoughts that has nothing to do with software but that I think is interesting enough that I want to post it.

I am a huge fan of science fiction, and I just got done reading a brilliant book by one of my favourite authors, China MiĆ©ville, called “Embassytown”. MiĆ©ville does not disappoint with his latest work; mashing up New Weird and Space Opera to create a most thoroughly enjoyable yarn. I highly recommend it!

This story got me thinking about the cultural evolution of sentient species. The one concrete example I have leads me to believe that the same sentiency that allows these species to dominate their worlds, also all but guarantees that they will all eventually self-destruct in the rare case that they are not made extinct by some environmental catastrophe. Though their demise will probably be brought about by technology-accelerated runaway consumption (as my subject species is demonstrating), I suspect that there is a more subtle reason why their demise is inevitable: the species-wide nihilism that I assert is inevitable as the species unravels the mysteries of its own existence and the Universe.

As the human species begins (and I do assert that we are only in the paddling pool of self-discovery) to unravel the nature of their own existence and the Universe of which they are a infinitesimal part, one by one the things that they imagine are vitally important will become meaningless. For example, how can the significance of any individual’s hopes, dreams, aspirations, desires and beliefs, stand firm in the face of an understanding of the biological evolutionary process. I would assert that they cannot.

George Bernard Shaw wrote the following about Darwinism in the preface to Back to Methuselah:

“But when its whole significance dawns on you, your heart sinks into a heap of sand within you. There is a hideous fatalism about it, a ghastly and damnable reduction of beauty and intelligence, of strength and purpose, of honor and aspiration, to such casually picturesque changes as an avalanche may make in a mountain landscape, or a railway accident in a human figure.”

Note: Shaw wrote this as a criticism of Natural Selection; he was a Lamarckist.

Though there are still many who do not even believe in Evolution, let alone understand it well enough to come to this miserable and inevitable conclusion, it is an unstoppable meme; inevitably all of humanity will come to understand it, assuming we don’t self-immolate first of course. And when the entire species succumbs to this meme it will simply expire from collective nihilism. Perhaps this is why there has been, and continues to be such resistance to this so-obviously correct idea; on some level our genes “know” that this level of species-wide self-awareness is fatally dangerous. And Evolution is not the only dangerous idea that undermines the human condition.

I am a self-confessed Nihilist and Atheist so maybe I am just projecting, or this might just be my attempt to understand the Conservative and “Anti-science” worldview.

It should be kept in mind that I had a smile on my face the entire time I was writing this. I don’t take myself too seriously and neither should you.