A Node.js Web Spider

It’s been a while since I’ve written this kata.  It’s different every time I do it.  This being node.js, all IO is asynchronous, and there’s only one thread.  I fairly quickly realized that I didn’t necessarily want to hammer the remote server, so I needed to come up with a way of keeping the number of requests down.  This being JavaScript, there are vastly more regular expressions in the code than if I’d written in C#.  Being a little too fond of LISP at the moment, there’s hardly any classes and everything’s done via closures.  Hope you like CoffeeScript.

The Work manager exposes one method: please.  The parameters amount to a function call with a callback.  The first eight please calls are executed immediately, the others are queued.

http = require 'http'
fs = require 'fs'
site = 'yourwebsite.com'
rootUrl = '/blog'
baseUrl = "http://#{site}#{rootUrl}"
client = http.createClient 80, site

# Throttle the number of requests
class WorkManager
  constructor : (@maxRequests) ->
    @queue = []
    @count = 0
  please : (f, args..., callback) ->
    @count++
    task = =>
      args.push =>
        @count--
        @queue.pop()?() # Pop and execute
        callback.apply this, arguments       f.apply this, args     if (@count >= @maxRequests)       @queue.push task     else       task() wm = new WorkManager 8 # Don't bother the website too much

Next, we need a routine to get HTML files down.  It also performs rudimentary logging.  This is the only output.

# Perform web requests
count = 0
get = (url, callback) ->
  req = client.request 'GET', url, {'host' : site}
  count++
  console.log "Requested #{count} : #{url}"
  result = ""
  req.on 'response', (res) ->
    res.setEncoding 'utf8'
    res.on 'data', (chunk) -> result += chunk
    res.on 'end', ->
      count--
      console.log "Received #{count} : #{url}"
      callback result
  req.end()

Finally, we need some actual spidering to take place.  The spider consists of three functions. 

  • IsInternal is used to prevent our spider from attempting to slurp the internet.
  • Standardize is used to prevent us pulling down the same page twice.
  • The Spider function itself just asks the workmanager to get a page.  When the page is pulled down, it searches it for URLs, throws away external URLs, standardizes the internal ones and spiders them if necessary.
# The actual spider logic

# Detect internal links
prefixes = new RegExp "^" + p, "ci" for p in ['http','ftp','javascript']
isInternal = (url) ->
  return true if url.indexOf(baseUrl) == 0
  return false if p.test url for p in prefixes
  return 0 == url.indexOf 'javascript-error'

# Standardize urls
parentRegExp = new RegExp "[^/]+/[.][.]/"
baseRegExp = new RegExp "//[^/]+(/.*)"
standardize = (url, base) ->
  url = url.replace /#.*/, '' # ignore #urls
  url = url.replace //default[.]aspx$/, '/' # ignore default.aspx
  url = url.replace /%20/, '+' # standardize spaces as +s
  url.replace parentRegExp, '' while parentRegExp.test url
  # take out parent references
  m = baseRegExp.exec url
  if m && m.length
    m[1]
  else if url[0] =='/'
    url
  else
    base+url

# Spider urls
internalUrls = {}
externalUrls = {}
regexps =-> new RegExp p, "gi" for p in [
    'href='([^'<>]+)'',
    'href="([^"<>]+)"',
    'href=([^'" <>]+)'
]
spider = (url) ->
  base = standardize /.*//.exec(url)[0], ''
  onContent = (content) ->
    for re in regexps()
      while match = re.exec content
        url = match[1].toLowerCase()
        if isInternal url
          url = standardize url, base
          unless internalUrls[url]
            internalUrls[url] = true
            spider url
        else
          externalUrls[url] = true
  wm.please get, url, onContent
spider rootUrl

It’s interesting to observe that in Clojure, “please get, url, onContent” would be “please get url onContent” whilst “get url, onContent” would be “get url onContent”.  The lisp style doesn’t think you’re doing anything weird here.  Most other languages do.

Just shy of 100 lines, including a work manager and comments.  Of course, by the time you’ve compiled it to JavaScript, it’s about 150 with no comments.  About 35 of those extra lines read “close curly brace”.

UPDATE: Embarrassingly, the original version of this code didn’t quite work.  I clearly didn’t pay enough attention to exactly which version I put up.  The problem was that the regular expressions were static, which means you can only use them once in Javascript.  Coffeescript made this an easy bug to fix: put a “->” in front of the regexps variable turns it into a function, and () where it is used to invoke it.

As shown in the comments, I used to pass a “c” flag to the regular expressions, which is completely useless.  That has been removed.

The only other change is an undocumented feature of coffeescript.  The code originally read “t = pop();t() if t?”.  Now, in coffeescript, “t?()” calls t if it is not null.  This allows the two lines to be simplified to “pop()?()”, which is either elegant or hermetic, depending on your experience.

Technorati Tags: ,

JavaScript: Everything’s an Instance

I’ve been coming to the opinion for some time now that static methods aren’t the problem.  Global variables are the problem.  You may think that your code doesn’t have many globals in it, but effectively, it’s littered with immutable global variables:

  • Static Methods are immutable globals
  • Classes are immutable globals
  • Namespaces are immutable globals

If this all sounds a bit like I’m saying “Look at all these trees!  There must be a wood nearby!” you’re right.  The point I’m making is that techniques such as dependency inversion are all geared to reducing the impact of this immutable baggage we’re carrying around.

Let’s contrast the Java/C# approach with JavaScript:

  • function() just declares a variable.  It’s of type function.
  • This variable has properties that you can add or remove, just like any other object.
  • One of these, prototype is normally considered to be the “class” of the object.
  • The prototype, however, is just another instance object.
  • Globals is, itself, an instance variable you can manipulate.

But that’s not the coolest bit.  The coolest bit is “require”.  Require is the function you use in CommonJS to import a module.  However,

  • Require just returns an instance.
  • You can actually replace require (although you’re unlikely to, because it has properties allowing you to tweak its behaviour)

I’m not sure even Clojure allows you to just replace the module loader (although bindings are extremely powerful). 

To put it another way, if namespaces aren’t a problem, how come their names are so long?

Hacking State in Vows.js with CoffeeScript

I can’t tell if you’re meant to do this kind of thing to vows.  I honestly can’t.  It’s either a demonstration of the power of the architecture, or it’s a phenomenal hack that shouldn’t be allowed out in broad daylight.  Either way, I’m probably thinking too LISP-ily for my own good.

Let’s say that you’re trying to test the behaviour of a workflow.  Under certain conditions, certain things should happen.  The problem is, some of those certain conditions are pretty verbose.  In fact, if you’ve got three yes/no decisions to make, you’re left having to set up eight different scenarios (more if you’re testing the intermediate states).

Now, in most testing environments, this is what you have “setup” for.  However, it only really works if you can have nested setup procedures, like “before” in RSpec.  Vows, on the other hand, creates a topic once and then tests run against that one topic.  Not really ideal for testing workflows.  So, I thought “why not make the topic itself a factory”.  That way, I could call the topic in each test and set it up repeatedly.  Then it occurred to me that, ideally, later topics should contain instructions on how to get the topic into the correct state, reducing the amount of repetition that we saw in my previous post.  Finally it occurred to me that, ultimately, the entire batch specification is just a hash table.

So, I wrote a function that rewrites a batch to do workflows:

withSetup = (batch) ->
  setupTopic = (f) -> (topic) -> ->
    # N.B. The topic is a factory.  The setupTopic function returns a factory as well
    return f() unless topic? # Resolve item
    # Apply item to topic and return topic
    t = topic()
    f(t)
    t
  inner = (item) ->
    # The item is a test
    # Take the topic, resolve it and run tests in "item"
    return ((topic) -> item topic()) unless typeof item == 'object'
    # The item is a batch
    for k,v of item
      item[k] = (if k == 'topic' then setupTopic else inner) v
    item
  inner batch

All you need to do is add withSetup to the addBatch invocation.

vows.describe('Guessing Game').addBatch(withSetup({
  'Player is playing a guessing game' : {
    topic : -> new game.Player(new StubEmitter(), guessingGameFactory)
    'should be able to start a game' : (p) ->
      assert.isFalse p.game?
      p.client.emit 'message', { action : 'start' }
      assert.isNotNull p.game
      assert.equal p.client.data.question, "Guess what number I'm thinking of"
    'after game has started' : {
      topic : (p) -> p.client.emit 'message', { action : 'start' }
      'correct guess' : (p) ->
        p.client.emit 'message', { action : 'answer', answer : 1 }
        assert.isTrue p.client.data.wasRight
      'wrong guess' : (p) ->
        p.client.emit 'message', { action : 'answer', answer : 2 }
        assert.isFalse p.client.data.wasRight
      'after correct answer' : {
        topic : (p) -> p.client.emit 'message', { action : 'answer', answer : 1 }
        'We're now on the second question' : (p) ->
          assert.equal p.playerActions.game.currentQuestionCount, 2
      }
    }
  }
})).export module

As I say, I can’t figure out if this works because Cloudhead’s really smart or I’m really stupid.

Getting Syntax Colouring in HTML using Vim

If you’re wondering how I got the syntax colouring on my CoffeeScript post, here’s the important bits:

  • The VIM :TOhtml command absolutely rocks.  (Thanks to the Vim gurus who pointed me towards it.)
  • The molokai colour scheme is very pretty.
  • The ability to :so! a list of commands in Vi saves a lot of time.

Here’s the commands I use (formatted, of course, using the program itself)

/<body
:s/bgcolor="/background : /
:s/" text="/; color : /
:s/<body /<pre class='code' style="/
:s/"><.*//
A; -moz-background-size: auto auto; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">^[kdgg
/</body
dGo</pre>^[
:2,-1s/<span.*/span>/<span>/
G:2,-1s/<br>/</span>/

Vim’s colour-coding of keyboard macros leaves something to be desired, but hey, you can’t have everything.  What I do have is something significantly easier to use than the solution I’ve been using for Visual Studio.  There’s a couple of things the Visual Studio solution gets right, like highlighting mutable variables and showing interfaces and classes in different colours, but there’s a lot more manual work involved.

If you are using it, make sure the HTML is the only buffer currently visible.  I’d be very glad to hear from someone who knows how to fix that particular bug.  For non-VIM users, this may look like line noise, but I assure you you’ll be able to read it after a fairly short period of time practicing Vim.  More usefully, you’ll be able to write your own.  One final tip: ^[ is a single character: use CTRL-Q CTRL-[ to get it on Windows.

Technorati Tags: ,,

CoffeeScript: Looking for the Catch

I’m just starting out with CoffeeScript, but it’s currently looking incredible.  Normally I loathe languages that rewrite other languages, but CoffeeScript appears to be well thought out and targets the JavaScript syntax whilst leaving the semantics pretty much unchanged.  Runtime errors are found in the generated files, not the originals, which is a bit rubbish but I’m guessing fixable (as long as V8 supports it).

Let me share with you some code I wrote the other day.  (Feedback on the idioms in the code are welcomed: I’m just starting with node.js.)

var util = require('util'),
    EventEmitter = require('events').EventEmitter;

function SocketPlayer(client) {
  EventEmitter.call(this);
}
util.inherits(SocketPlayer, EventEmitter);

exports.Game = function (questionFactory, questionCount, player, setTimeout) {
  var self = this;
  this.setTimeout = setTimeout || process.setTimeout;
  this.questionFactory = questionFactory;
  this.delay = 1000;
  this.questionCount = questionCount;
  this.currentQuestionCount = 0;

  function advanceQuestion(wasRight) {
    self.currentQuestionCount++;
    self.currentQuestion = questionFactory();
    var dto = self.currentQuestion.dto();
    dto.wasRight = wasRight;
    player.send(dto);
  };
  player.on('answer', function(data) {
    console.log(data.answer);
    var wasRight = self.currentQuestion.isCorrect(data.answer);
    if (wasRight) {
      advanceQuestion(true);
    } else {
      var explanation = self.currentQuestion.explanationDto();
      explanation.delay = self.delay;
      explanation.wasRight = wasRight;
      player.send(explanation);
      self.setTimeout(advanceQuestion, self.delay);
      self.delay *= 2;
    }
  });

  advanceQuestion(false);
}

So, this represents an abstract game.  The player gets the next question if they get one right, an explanation of the right answer if they got it wrong.  (If it helps, think of hangman.)  I think this code is alright.  However, take a look at the version in CoffeeScript

util = require('util')
EventEmitter = require('events').EventEmitter

class SocketPlayer extends EventEmitter

class exports.Game
  constructor : (@questionFactory, @questionCount, @player, @setTimeout) ->
    @setTimeout ?= process.setTimeout
    @delay = 1000
    @currentQuestionCount = 0
    @advanceQuestion = (wasRight) ->
      @currentQuestionCount++
      @currentQuestion = @questionFactory() # Returns the next question
      dto = @currentQuestion.dto()
      dto.wasRight = wasRight # but the answer to the previous question
      @player.send(dto)
    @player.on 'answer', (data) =>
      console.log data.answer
      if wasRight = @currentQuestion.isCorrect data.answer
        @advanceQuestion true
      else
        explanation = @currentQuestion.explanationDto()
        explanation.delay = @delay
        explanation.wasRight = wasRight
        @player.send explanation
        @setTimeout (-> @advanceQuestion(false)), @delay
        @delay *= 2
    @advanceQuestion false

How About Testing?

Here’s the tests I wrote in JavaScript:

var vows = require('vows'),
    eyes = require('eyes'),
    assert = require('assert')
    game = require('../src/game.js'),
    util = require('util'),
    EventEmitter = require('events').EventEmitter;
function guess(n) {
  this.isCorrect = function(a) { return a == n; }
  this.explanationDto = function() {
    return { correctAnswer : n };
  }

  this.dto = function() { return { question : "Guess what number I'm thinking of" }}
}

function StubPlayer() {
  EventEmitter.call(this)
  var self = this
  this.send = function(data) { self.data = data }
}
util.inherits(StubPlayer, EventEmitter);

function GuessingGame() {
  this.player = new StubPlayer();
  game.Game(
    function() { return new guess(1); },
    10,
    this.player,
    function(action, delay) {  });
  return this;
}

vows.describe('Guessing Game').addBatch({
  'Given a guessing game' : {
    topic : GuessingGame,
    'when you guess correctly' : {
      topic : function(topic) {
        var t = new GuessingGame();
        t.player.emit('answer', { 'answer' : 1 });
        return t;
      },
      'then it says you were right' : function(topic) {
        eyes.inspect(topic.player.data);
        assert.isTrue(topic.player.data.wasRight)
       }
    },
    'when you guess wrong' : {
      topic : function(topic) {
        var t = new GuessingGame();
        t.player.emit('answer', { 'answer' : 2 });
        return t;
      },
      'then it says you were wrong' : function(topic) {
        assert.isFalse(topic.player.data.wasRight);
      }
    }
  }
}).export(module);

Again, let’s see what it was in CoffeeScript.

vows = require('vows')
eyes = require('eyes')
assert = require('assert')
game = require('../src/game2.js')
EventEmitter = require('events').EventEmitter

class Guess
  constructor : (n) ->
    @isCorrect = (a) -> a == n
    @explanationDto = -> { correctAnswer : n }
    @dto = -> { question :  "Guess what number I'm thinking of" }

class StubPlayer extends EventEmitter
  send : (data) -> @data = data

class GuessingGame extends game.Game
  constructor : ->
    super((-> new Guess 1),
      10,
      new StubPlayer,
      -> 0)

vows.describe('Guessing Game CoffeeScript example').addBatch({
  'Given a guessing game' : {
    topic : GuessingGame
    'when you guess correctly' : {
      topic : (topic) ->
        t = new GuessingGame
        t.player.emit 'answer', { 'answer' : 1 }
        return t
      'then it says you were right' : (topic) ->
        # eyes.inspect topic.player.data
        assert.isTrue topic.player.data.wasRight
       }
    'when you guess wrong' : {
      topic : (topic) ->
        t = new GuessingGame()
        t.player.emit 'answer', { 'answer' : 2 }
        return t
      'then it says you were wrong' : (topic) ->
        # eyes.inspect topic
        assert.isFalse topic.player.data.wasRight
    }
  }
}).export module

The actual vows stuff is slightly shorter, but it’s the setting up of the stub classes that really makes CoffeeScript shine.  StubPlayer is a very good example of this.  All it needs to be is an EventEmitter that captures what it is sent.  The sheer ceremony involved in declaring that in JavaScript was pretty painful.

The Smooth and the Rough

Although this code is pretty short, it’s a pretty good tour of some tricksy things about CoffeeScript.  First, it’s worth understand that CoffeeScript really is JavaScript.  If you don’t understand JavaScript, you won’t get anywhere with CoffeeScript.  Let’s see some examples of this:

  • the difference between -> and => requires you to understand how “this” behaves in JavaScript. 
  • If you take a look at the function “advanceQuestion”, you’ll see that it’s instantiated in the constructor, not added to the prototype.  This makes no sense until you realize the function is called from the constructor, and in JavaScript, the whole idea of calling a prototype method from the constructor makes no sense at all.

Some other cool things about constructors:

  • extends deals with all of that util.inherits nonsense
  • super is vastly more pleasant than copying class names all over the place.  But you still need to explicitly call super
  • parameters that begin with an @ sign are automatically made instance fields (more languages should have this feature)
  • Just like in JavaScript, the classes are just variables.  Declare a variable as “exports.Game” and you’ll export “Game” from the module.  Everything else is private.

The ugly:

  • You don’t have to type in brackets, but you need to careful where you leave them out.  For instance, if “addBatch” doesn’t have an explicit bracket, the implicit close bracket ends up after module, rather than before export.  (This might be fixable.)
  • Debugging pretty much requires you to read the generated JavaScript.  Luckily, it’s pretty good JavaScript.

Getting JsTestDriver and QUnit running

I’m in the habit of writing articles describing exactly how to get various pieces of technology working.  They’re easily my most heavily read articles.  However, today I don’t really feel the need to put a lot of work into it, because Jesse Cooke did it for me.  Just follow his short instructions and everything works.

Technorati Tags: ,

Chuck Norris Understands Concurrency

…but I sure don’t.  After promising that I had posted my very last article on the subject of load balancing, I spent another three months tweaking the code I’d put up in production.  The gist is now pretty close to the production code (there’s a couple more Console.Writes so you can see what’s going on).  So, here’s what I learned:

The reason QueueChannel and the nServiceBus distributor are dumb is for a very good reason: even small, rare failures in the distribution code can be horribly fatal.  This I knew intellectually, but not in my gut.  The code now has some amazing defensive code around AssignShardsToPendingQueueItems.  Furthermore, it’s got a channel for reporting errors in the sharding.  Obviously, you have two choices when such a piece of code fails: you can kill processing or attempt to keep going.  ShardingChannel attempts to keep going, but it’s a decision everyone has to make for themselves.

I had to simplify the locking.  Taking out multiple finer grained locks turned out to slow down the system.  Now there’s one lock on pendingQueue, the list of items that have yet to be assigned.

Receiving whilst processing can present challenges of its own.  The wakeup code is appreciably different.  Publishing a message now only wakes at most one thread.  Since the consumers now tracking whether they are sleeping, this can be done without locks.  This prevented a situation in which a large number of empty consumers receiving messages that processed quickly could actually choke the channel so that it couldn’t even receive messages.

Sometimes you should use degenerate data representations.  This violates DRY and makes your code hard to keep correct but sometimes, that doesn’t matter.   The mapping of items to queues is now significantly more complex:

  • A dictionary that maps all shards to the list of items for the shard.
  • A queue of shard, list pairs, in the order that the shards were created.  Only inactive shards appear in this list.
  • A hashset of active shards.

All three of these were needed to keep the code running fast.

Finally, and most surprisingly, if a consumer finishes with a shard, it now asks the channel if there are any more messages for that shard.  This change has produced a phenomenal performance improvement in the target system.  In particular, on the test system it went from being IO-bound to CPU-bound.  If there’s a lesson to be learned here, it’s that disk caches really do matter.

Sometimes, Complexity Wins

There was one other change: the wait until empty method is now an empty event. The interesting thing about this was that it was the only one that relates to the way we usually discuss code quality: I slightly reduced the responsibilities of the class.  Pretty much all of the other changes made the code harder to understand and pretty much none of the performance improvements were susceptible to naive complexity analysis.

Tuning code for performance is fascinating.  It’s very rarely the same problem twice, and it can be a constant challenge to unlearn your standard “best practice” responses. 

  • Complexity analysis is fine, but the exact implementation of the algorithm matters.
  • SOLID principles are fine, but they’re just part of a larger trade-off.
  • The more complex version of the code is better than the simple one.
  • You’ve got to actually understand the machine upon which the code executes.

Vim Windows Paths Can be Case Sensitive

I just spent 15 minutes working this one out. I’ve got a machine called “Julian-Lucid”. I’ll let you guess what operating system it’s running. However, my Windows copy of Vim wouldn’t allow me to cd to the directory. Typing in “:cd \julian-lucid” gave me this error:

E344: Can't find directory "\julian-lucid" in cdpath
E472: Command failed

Long story short, Vim on Windows can be case-sensitive even when the path isn’t. “:cd \JULIAN-LUCID” actually works.

Technorati Tags:

Design Patterns: Factories are a Function of the Consumer

Sometimes i think I spend my time on this blog just trying to explain the thinking of people much smarter than me.  This is definitely one of those cases.  I’ve probably learned more about programming from reading the Retlang source code than any other.  It’s both remarkably free of compromises and easy to read.  Sometimes you learn not from any individual snapshot, but from the evolution of the code base.  For instance, here was the process context factory in Retlang 0.3:

    public interface IProcessContextFactory : IThreadController, IObjectPublisher
    {
        IMessageBus MessageBus { get; }
        IProcessContext CreateAndStart();
        IProcessContext Create();
        IProcessContext CreateAndStart(ICommandExecutor executor);
        IProcessContext Create(ICommandExecutor executor);
        IProcessContext CreateAndStart(string threadName);
        IProcessContext Create(string threadName);
        IProcessContext CreateAndStart(ICommandExecutor executor, string threadName);
        IProcessContext Create(ICommandExecutor executor, string threadName);
        IProcessBus CreatePooledAndStart(ICommandExecutor executor);
        IProcessBus CreatePooledAndStart();
        IProcessBus CreatePooled(ICommandExecutor executor);
        IProcessBus CreatePooled();
    }

Even ignoring the extra inherited interfaces, this is a pretty big interface.  There’s 11 different ways to create 2 different objects.  Now, when I decided to use this, I created my own interface:

    public interface IRetlangFactory : IDisposable, IHaltable, IChannelCreator
    {
        ICommandTimer CreateCommandTimer(bool isHaltable);

        ICommandQueue CreateContext();

        ICommandQueue CreateContext(ICommandExecutor executor);

        void Stop(ICommandQueue queue);

        void Stop(ICommandTimer timer);

        void WaitForQueues(IEnumerable<ICommandQueue> queues);
        void WaitForTimers(IEnumerable<ICommandTimer> queues);
    }

So, it’s a smaller interface that does more.  I’m not holding this up as an example of great design: it understands ISP about as well as I understand Xhosa.  But from 11 methods to create objects, I’ve got only three.  What isn’t obvious is things like CreateContext always starts a queue at the same time.

So why is this interface so much smaller than the Retlang one?  It’s pretty simple:  I knew which methods I needed.

Still Getting Schooled

This might seem like an insurmountable problem for a library writer, but it isn’t.  By Retlang 0.4, the interface just simply wasn’t there.  Graham Nash had resolved the problem with a couple of hints from Alexander the Great.  So, in the old days my factory called through to Retlang’s factory.  Now, my standard “make a thread” method now reads like this:

    var fiber = new ThreadFiber(new DefaultQueue(_haltableExecutor));
    fiber.Start();
    return fiber;

The haltable executor is actually from my very first post from two and a half years ago.  Of course, if I hadn’t wanted to change the default behaviour, I could have just used the empty constructor, because that implements some sensible defaults.  This technique is decried in some quarters as being “poor man’s IoC”, but I fail to see the problem.  You can write your own factory, or configure a DI container to do the construction for you.  Either way, you’ve lost no flexibility.

So, I think all in all, there’s no point in defining a factory interface within your library unless you’re defining an injection point for your own code.  Controller Factories in ASP.NET MVC are an example of this.  On the other hand, it’s hard to see why IWindsorContainer exists. 

FOOTNOTE:  For design patternistas, you’ll observe that I’m making no distinction between factories, abstract factories or builders.  Truth be told, I’m not seeing many codebases that bother either.

What’s an architect?

I was recently watching Dan North’s latest presentation on InfoQ.  Right near the start, he pops up a Dreyfus ladder, leading to expert programmer and then… novice architect.  Now, I’m a fully paid up member of the school of “once you’ve mastered something, it’s time to go find something you suck at”.  However, I was thinking about the various things we mean by architect.  Looking back, I’ve been described as architect a few times and met many others described as such.  But the roles didn’t have very much in common.  Here’s a quick taxonomy of software architects

The Policeman

For some people, the architect is the guy who insists that everything is done on Oracle, regardless of context.  Or writes documents that say things like “All IPC must go through SOAP”.  This guy is the policeman of the company’s software infrastructure.  Typically, you’ll come up with a design and he’ll have to “validate” it before you build it.  Usually, you’ll find that this process and this role treats innovation as a defect.  In general terms, the very existence of this job is a sign your employer doesn’t trust her developers.

I’ve been this guy.  Luckily I had the opportunity to get this out of my system when I was 24.  Apart from anything else, getting talented developers to toe the line is a value-destroying exercise.

The Numbers Guy

Then there’s the numbers guy.  He’s actually contributing.  What he’s doing is trying to figure out when things are going to break.  Can you handle twice as much business as you currently do?  Could you do what you’re currently doing faster?  Is our pipe wide enough?  And most importantly, what’s going to break first?  How do we avoid this? 

Sometime this guy’s actually a DBA.  I’ve met a number of DBAs with deep and intimate knowledge of routers, disk access times and an uncanny ability to pull information (rather than data) out of PerfMon.  Sometimes he’s a junior developer with a Rainman-like grasp of the latency figures coming out of Firebug.

If there’s a problem with this role it’s that shouldn’t really be a full time job.  Everyone should care about this.  A lot of the time you’ll see him gathering data.  Data that should be there in plain sight, in the logs.  In fact, some of his responsibility actually lies within the operations team.  All in all, this is a good guy, and he’s doing valuable work.  But when you decide to hire someone to own this, it’s a sign you have a problem elsewhere.

The System Expert

These days you’ve got a big important system that does a number of critical things.  But five years ago, it was stuck together with gaffer tape and string by someone in a month.  You’re lucky, and he’s still with the firm.  Sometimes the expert didn’t build it, but he has supported it for three years, and knows its quirks pretty well.

At best, this guy’s your shaman: the guy who understands the history of the project and your organization.  The guy who remembers “why we didn’t do it that way”.  The guy who’s got a good idea of the quickest way to implement the feature your manager needs yesterday.  He’s incredibly valuable. 

The danger here is emotional attachment to the system in its current form.  When this happens, you retard the progress of the project by failing to recognize that circumstances have changed.  You’re offended when fundamental structures in the system are replaced.  If you’re recognizing yourself here, it’s time to take a back seat, listen to some Sting and chill out.

The Great Developer

You’re a cracking developer, so they give you a fancy title.  Make sure it comes with a raise.  Recognition is nice, but you’re doing the same job as before.

The Go-to Guy

I like being this guy.  A lot of the time, he doesn’t actually have architect in his title.  He’s just the guy you go to when you can’t figure a bug out, or you need to talk something over, or you suspect there’s a better way of doing something than the one you’ve come up with.

You get to be this guy through three qualities: technical ability, accessibility and patience.  The first is a given: if you’re just starting out, no-one wants your opinion (which is their loss, frankly.).  Accessibility is necessary as well: you’ve got to have time for people.  You’ve got to be genuinely glad to see them and make them welcome.  Talk to them, not just fob them off with a link (URLs are for the end of the conversation, not the beginning).  Finally, patience is key.  Sometimes you’ve got to go back to the start of the problem and painstakingly work through every step to find the solution.  Sometimes you’ve got to answer the same question five times in the same day.

The best bit about go-to guys are: you can have more than one.  Even if someone else occupies this role, there’s nothing stopping you trying it too.  You don’t need to know everything, you just need to be useful.

Apart from anything else, even the go-to guy needs someone to go to.

The Literal Architect

Picture of All Souls Church It’s worth remembering that we used to believe that building construction was a viable metaphor for software development.  This guy still thinks it is.  His job is to design the software down to the last detail, yours is to do the rather uninteresting task of actually building it.  Usually in a development environment the architect doesn’t understand.

If you’re working in this organization, I’m sorry.  I feel for you.  You’ve probably also got a modified waterfall SDLC.  You probably even know what SDLC stands for.  If you’re really unlucky, you know what PRINCE2 means as well.

Ironically, this guy is the only one who really warrants the title architect.  He does the thinking, you just lug bricks around.  However, beautiful as the ivory tower shown is, it hasn’t changed in the last two hundred years.  The requirements for your project have changed two hundred times in the last month.  Architect is a nice title, but it’s the systems experts, the numbers guys, the great developers and the go-to guys who will make a system sing.  And design?  Well, everybody should be doing that.

Technorati Tags:

Notes: The “numbers guy” is, of course, Al Capone.  The Sting video is from the Nelson Mandela concert.  The “ivory tower” is All Souls Church, a phenomenally beautiful building by John Nash.  If you’re ever near Oxford Circus in London you should visit it.  Nash also designed Buckingham Palace.  an artist’s best known work isn’t necessarily his best.