String Micro-Benchmark

I was having a discussion with a colleague a while ago. To whit: which is 'better', Groovy's GString interpolation or simple, brain-dead String concatenation?

In the grandest spirit of discovery, I said: "let's see."

A simple Groovy test 'framework':

@Grab(group='commons-lang', module='commons-lang', version='2.6')
import org.apache.commons.lang.time.StopWatch

def concatenator = { i ->
  def i2 = i * 2
  def iCubed = Math.pow(i, 3)
  'i == ' + i + '; 2i == ' + i2 + '; i**3 == ' + iCubed
}

def interpolator = { i ->
  def i2 = i * 2
  def iCubed = Math.pow(i, 3)
  "i == ${i}; 2i == ${i2}; i**3 == ${iCubed}"
}

def interpolator2 = { i ->
  "i == ${i}; 2i == ${i * 2}; i**3 == ${Math.pow(i, 3)}"
}

def tmr(c) {
  // warmup
  for(i = 0; i < 100; i ++)
    c.call(i)

  def timerS = new StopWatch()

  timerS.start()

  // work for real
  for(i = 0; i < 10000000; i ++)
    c.call(i)

  timerS.stop()

  timerS.toString()
}

println "Concatenator: ${tmr(concatenator)}"
println "Iterpolator: ${tmr(interpolator)}"
println "Iterpolator2: ${tmr(interpolator2)}"

And the result:

Concatenator: 0:00:16.470
Iterpolator: 0:00:04.406
Iterpolator2: 0:00:04.380

Probably not the most definitive investigation ever but as far as I am concerned: interpolation FTW!

Tags: Groovy

January 2012 GroovyMag

I completely forgot to publicise my January 2012 GroovyMag article! The topic "Testing and Evaluating a Simple Set of Classes" covers testing using Spock, CodeNarc and Cobertura.

Tags: Groovy, GroovyMag, Programming

More Scribbling

This time with HTML5′s <canvas> tag, jquery-1.7.2 and coffeescript-1.3.1.

<!DOCTYPE html>
    <head>
        <meta charset="utf-8" />
        <title>CoffeeCanvasScribble</title>
        <script src="js/jquery-1.7.2.js"></script>
        <script src="js/coffee-script.js"></script>
        <link rel="stylesheet" href="css/cs_scribble.css" />
    </head> 

    <body>
        <canvas id="canvas" width="800" height="500"
                style="width: 800px; height: 500px; border: 1px solid gray"></canvas>
        <div id="buttons">
          <div> </div>
          <input type="button" id="clear" value="Clear" /> 
          <input type="button" id="red" value="Red" /> 
          <input type="button" id="green" value="Green" /> 
          <input type="button" id="blue" value="Blue" /> 
          <input type="button" id="black" value="Black" /> 
          <input type="button" id="snapshot" value="Snapshot" />
          <div> </div>
          <div class="filler"></div>
        </div>

        <div id="snapshotDiv"> </div>

        <script type="text/coffeescript">
          canvas = $('#canvas')
          offset = canvas.offset()
          # this is the 'real/non-jquery' document.getElementByID:
          canvasDoc = canvas[0]
          context = canvasDoc.getContext '2d'

          #
          # canvas handling
          #
          button = null

          # useful for debugging...
          #
          # usage: console.log dump(o)
          # dump = (obj) ->
          #   str = ""
          #   for own key, value of obj
          #     str += "#{key} = #{obj[key]}\n"
          #   str

          $('#canvas').mousedown (e) ->
            button = e.button
            x = e.pageX
            y = e.pageY
            x -= offset.left
            y -= offset.top
            context.beginPath()
            context.moveTo x, y

          $('#canvas').mouseup (e) ->
            button = null
            context.closePath()

          $('#canvas').mousemove (e) ->
            return unless (button?)
            x = e.pageX
            y = e.pageY
            x -= offset.left
            y -= offset.top
            context.lineTo x, y
            context.stroke()

          #
          # HTML button handling
          #

          # usage: logToMessage "((#{x}, #{y}))"
          #
          # needs <div id="message"> </div> somewhere
          #
          # logToMessage = (message) ->
          #   $('#message').show().html message

          $('#red').mousedown (e) ->
            context.strokeStyle = 'red'

          $('#green').mousedown (e) ->
            context.strokeStyle = 'green'

          $('#blue').mousedown (e) ->
            context.strokeStyle = 'blue'

          $('#black').mousedown (e) ->
            context.strokeStyle = 'black'

          $('#snapshot').mousedown (e) ->
            img = canvasDoc.toDataURL()
            $('#snapshotDiv').show().html "<img id='snapshotImg' src='#{img}'/>"

          $('#clear').mousedown (e) ->
            context.save()
            # Use the identity matrix while clearing the canvas
            context.setTransform 1, 0, 0, 1, 0, 0
            context.clearRect 0, 0, context.canvas.width, context.canvas.height
            # restore transform matrix
            context.restore()
            # clear any snapshot
            $('#snapshotDiv').show().html '&nbsp;'
         </script>
    </body>
</html>

And the 'beautiful' results, as shown in IE9:

It's actually slightly more beautiful in Safari, but one screenshot is quite enough.

Note the use of the data: URL.

I guess that this doesn't really show the power of coffeescript but it was fun to make, and adds another Scribble implementation to the JRuby versions already here.

A Tool For The WiFi Itinerants Among Us

If you're the kind of person that travells the WiFi universe a fair bit, you'll probably appreciate Autoroute SMTP as much as I do.

Autoroute SMTP (ARS) is designed for automatic switching between SMTP servers depending on what network you are currently working in.

The tool is tiny, unobtrusive and free, which are nice attributes.

Given that the maker, Emma Labs, seems to be all about "e-mail marketing professionals…our products allows you to create targeted mailing lists using essential data from communities and services required [sic] a membership." I can but hope that it isn't siphoning all my sent mail off to somewhere undesirable!

I have never found any bad comments floating around out there…or any good ones, to be honest. CurrPorts doesn't show any badness so for now, I'm keeping my head firmly stuck in the sand…

Tags: Tools

What The Flip Is Happening On My Network?

A question I often find myself asking…and attempting to answer.

For Linux/OSX I use iftop. I just can never remember the name! Whenever anyone asks me the above question, I am always reduced to stammering and delaying while groping around in my murky-at-the-best-of-times memory.

For Windows I use CurrPorts. One of the many components comprising the excellent Nirsoft Tools.

Tags: Tools

History

Here is three generations of my family in one photo.

Left-right…my father: Charles Brown, my Grandfather: Robert Simmons and me: Robert Charles Brown. The dog's name was 'Patch.' For the life of me, I can't remember what we called The Rabbit (somehow sums up the futility of life!). The photo would have been taken around 1970 at the back of our house in Duston, Northampton, England.

Which is just here:


View Larger Map

Not sure there is any other similar picture in existence, so I thought I'd give The Wayback Machine a chance to eventually preserve it for posterity.

Tags: Retrospectives

More GroovyMag Verbosity

Another article in this month's (March 2012) GroovyMag: "To Kill a Mocking Problem - Using Betamax to mock HTTP-based interactions."

Wherein I take Rob Fletcher's very nice 'Betamax' tool out for a spin along with friends Gradle, Spock and Geb.

Tags: Groovy, GroovyMag, Programming

JDBM

A colleague recently came up to me with a problem: he had a trace file representing the history of several years' worth of CRUD operations on many records. Something resembling:

1:create:hello
123:create:xxx
12345:create:hello
123:update:uuu
999:update:42
123:delete
1:update:xxx
1:update:iuu
12345:update:hello world
1:delete

The task at hand was to work out which records were active at the end of the trace and to determine the most up-to-date value each active record.

The expected result here is:

Didn't find 999 to update. Creating new entry.
Results:
        12345 => hello world
        999 => 42

This instantly reminded me of a concordancing problem.

The natural data structure for this is a Map. Thus we have the first potential solution for the problem:

def m = [:]
new File(/..\data.dat/).splitEachLine(':') { line ->
    def (id, op, data) = line
    switch (op) {
        case 'update':
            if (!m.containsKey(id))
                println "Didn't find ${id} to update. Creating new entry."
        case 'create':
            m.put(id, data)
            break

        case 'delete':
            m.remove(id)
            break
    }
}

println "Results:"
m.each { k,v ->
    println "\t${k} => ${v}"
}

This works nicely: it's clear and concise…all the things I like! Groovy makes it even nicer :-)

But (there's always a but…sadly) my colleague had lots of data to process. Too much to be realistically held in memory.

The tool I would normally reach for in this circumstance is a plain old database, but hey! this is the age of noSQL.

Enter JDBM3:

JDBM provides HashMap, TreeMap, HashSet, TreeSet and LinkedList backed up by disk storage. Now you can insert more than a billion records into collection without running out of memory. JDBM is probably the fastest pure Java database.

Ten minutes of hacking and version one had transformed into version two:

import net.kotek.jdbm.*

// uses JDBM3-alpha-2 from https://github.com/jankotek/JDBM3

final path = /..\data/

// start with non-existent database
new File(path).eachFile { it.delete() }

new DBMaker(path + /\ids/).build().with {  db ->

    db.createHashMap("ids").with { m ->

        new File(/..\data.dat/).splitEachLine(':') { line ->
            def (id, op, data) = line
            switch (op) {
                case 'update':
                    if (!m.containsKey(id))
                        println "Didn't find ${id} to update. Creating new entry."
                case 'create':
                    m.put(id, data)
                    break

                case 'delete':
                    m.remove(id)
                    break
            }
            db.commit()
        }

        m.each { k,v ->
            println "\t${k} => ${v}"
        }
    }

    db.close()
}

Still nice, clear and concise…but now capable of dealing with a (few) billion records.

Even more to like!

Update:
It is now possible to simplify this further. After mentioning to the developer that:

If there is one small thing I would like tidied up in the example code, it is this:

> // start with non-existent database
> new File(path).eachFile { it.delete() }

Having to delete the database/files by hand, rather than just specifying a create-truncate mode of some sort 'feels' wrong.

He responded within hours:

…it is done now, check DBMaker.

This means that one can now do:

new DBMaker(path + /\ids/).build().deleteFilesAfterClose().with {  db ->

Open source FTW!

Tags: Groovy, Programming

Nokia with Windows Phone Training

Just attended the Brisbane "Nokia with Windows Phone Training" event.

Thanks to Microsoft and Nokia for setting up this free two-day talkfest!

I got a good overview of the various new features and APIs comprising Windows Phone.

Thanks especially to the presenters Andy Wigley (http://appamundi.com/about/) and Nick Randolph (http://nicksnettravels.builttoroam.com/). They did a good job of showing the tools and APIs: got the right balance between diving deep and splashing around in the shallows.

I came away feeling quite upbeat.
(…this could just be a reflection on how low-down dirty and mean my current project is making me feel, but still…)

As Andy and Nick were speaking I was hacking (I think I was the only attendee nerdy enough to do so); keeping one ear/eye on the presentation and the other ranging between the program and the internet.

As a result, I would like to give you The Finger.

There's absolutely nothing special here, but it pleased me to be able to knock something together so easily (little things please little minds :-))

Starting from scratch, I worked/hacked out a fair bit:
* the basic framework
* standard pages, pivot pages
* basic event handling
* buttons and menus
* animation with Expression Blend
* icons, tiles
* isolated storage
* tombstoning
* etc., etc.

Not too shabby!

Thanks to the wonders of the Internet and NuGet, I was able to pick up the Coding4Fun colour picker component. I also adopted the Orange Monster (a personal favourite) for the logo.

You can grab the VS solution in all its raw, un-prettified glory!

The Finger follows an enduring Transentia tradition: I typically try to create a (David Flanagan) scribble-style application in any new environment I come across. On this site I already have Java, Groovy, JavaFX and JRuby versions. I have a mental image of a huntin' 'n fishin'-style trophy room with walls lined by scribble programs mounted on shields…

I found WP7 substantially easier to program than the iPhone. Give me C# over Objective-C, Expression over Interface Builder and Visual Studio over XCode any day (it hurts me to say that but it's true, nevertheless). Microsoft have always done good development environments/kits…

Now that the Windows 8 Consumer Preview has been released it is easy to see how Microsoft is trying to link the two platforms together. Both feature big bright tiles/buttons, a swipe-oriented interaction 'language' and a set of shared, cloudy services, etc…. Welcome back, my friends to the Microsoft walled community.

Regardless of the technical or other merits of WP7, I predict a bright future: people are always looking for the Next New Thing and WP7 is different enough to be that Next New Thing. It may-just may-even become A Better Thing.

PS:
Just came across this blow-by-blow writeup from a sister event in Melbourne.

Tags: C#, windows, windows phone, wp7

The Wheel Is Turning

Perhaps?

Here's a great post that states the obvious: Homegrown solutions: The good and the bad.

Gotta love an article that includes stuff like:

"…nontechnical management gets the heebie-jeebies when presented with a plan that includes homegrown, self-supported solutions. Many executives would rather have a passel of slightly technical folks and vendor support than highly skilled and highly paid technologists to keep the trains running on time. … you may be able to measure your savings in terms of the electrical bills and IT payroll, but the hidden costs can make those savings disappear. … When you need to "make things happen," you simply can't - you get stuck in months of apathetic meetings and general buffoonery from every angle. That's not even touching the problems inherent with outsourcing help desk and general computing tasks."

I wish this didn't match my experiences so exactly, I really do!

Tags: Rant