SPA 2009 Day 1 – Real World Haskell

This session was a marathon 6 hour tutorial introduction to Haskell on a sunny Sunday afternoon. I’d installed the GHC beforehand and tried out a couple of ‘hello world’ style tutorials, but other than that walked in with no experience of Haskell or any other functional programming.

Here are my notes:

Basic Syntax

make up new types with

{{lang:haskell}}
type Lat = Double

Backticks add syntactic sugar to re-arrange the normal order of “function arg arg”:

{{lang:haskell}}
div 5 6 == 5 `div` 6

indentation is important:

{{lang:haskell}}
latLngDistance lat1 lng1 lat2 lng2 =
    sqrt((latD * latD) + (lngD * lngD))
    where latD = latDistance lat1 lat2
          lngD = lngDistance lng1 lng2

Lists

Strings are just lists (aka arrays) of characters, but rendered differently.

Use colons to construct lists:

{{lang:haskell}}
1 : 2 : 3 : [] == [1, 2, 3]

Colon adds to front of list, but is ‘right-associative’ so the right-most expression is evaluated first

{{lang:haskell}}
1 : (2 : (3 : [])) == [1, 2, 3]

Many operators are written in haskel themselves. ‘Prelude’ is a library full of these.

Functions on lists

{{lang:haskell}}
westmost [] = 0.0
westmost [lng] = lng
westmost (lng : lngs) = wester lng (westmost lngs)

Left-hand side is a pattern for parsing / matching and then splitting (for use) the input arguments. A more verbose way of doing the last one would be:

{{lang:haskell}}
westmost lngs = wester (head lngs) (westmost (tail lngs))

Guards can extend the patterns with conditions:

{{lang:haskell}}
wester lng1 lng2
    | lng1 < lng2     = lng1
    | otherwise       = lng2

Defining Types

{{lang:haskell}}
type Lat = Double
type Lng = Double
type Name = String

data Location = Location Lat Lng Name

Second Location is the name of the constructor. Doesn’t have to match the type name.

With data types, you still have to use pattern matching to pull out the memebers:

{{lang:haskell}}
distance (Location lat1 lng2 _) (Location lat2 lng2 _)
    sqrt((latD * latD) + (lngD * lngD))
    where latD = latDistance lat1 lat2
          lngD = lngDistance lng1 lng2

Underscore is just used to say ‘blah’ – don’t care about this matched element.

Point-free Style

{{lang:haskell}}
let double xs = map (*2) xs
let double = map (*2)

double [1..5]

This is a name for the practice of leaving the last argument out to build a special function that’s more generic.

{{lang:haskell}}
prepend s = (s ++)
append s = (++ s)
saveLocs = 
    writeFile "output.blah" . prepend prefix . append suffix

or

{{lang:haskell}}
saveLocs arg =
    writeFile "output.blah" (prepend prefix (append suffix arg))

You can even do this (with arity 2 functions)

{{lang:haskell}}
prepend = (++)
append = flip prepend

Dot Function

{{lang:haskell}}
(.) f g a = f (g a)

Lazy

Haskell is lazy. You can think of each function as pulling just what it needs from the next function. E.g. we can create a list of all integeers:

{{lang:haskell}}
allInts = [1..]

So you can do stupid stuff:

{{lang:haskell}}
reverse [1..]

This will just hang forever. Or

{{lang:haskell}}
infiniteListOfOnes = 1 : infiniteListOfOnes

Parametric Polymorphism

Argh.

Classes

A class is similar to an interface or Mixin, but it NOT a type.

It basically defines a protocol that will be implemented by a type.

{{lang:haskell}}
class Collection c where
  cLength :: c a -> Int
  cMap    :: (a -> b) -> c a -> c b

instance then defines the implementation for a specific type

{{lang:haskell}}
instance collection [] where
  cLength = length
  cMap = map

instance collection Tree where
  cLength = <tree length function>
  cMap = <tree map function>

Like generics in Java.

IO Actions

IO is impure, so when you want IO done, what you actually do is define an action, which will be lazy evaluated (i.e. executed) as necessary.

There is a syntax for this where you use chevrons to create actions with several steps. Or you can use the nicer ‘do’ syntax.

Type Signatures

It’s common to use type signatures even though you don’t have to. It helps you think about the goal for a new function before you write it, and it gives you machine-run safety checks
for free. Common to use them, at least for top-level function.

Uses in the Real World

Ben is using Haskell at Barcap where they have an embedded DSL which quants use to describe products. Haskell then compiles those descriptions, giving them a bunch of checks for the validity of the description.

Seems like Haskell is a good fit where you want to build DLSs with lots of type safety.

Why is it useful?

Key ideas that make Haskell special:

  1. purity – execution and evaluation separate
  2. types – lots of checking
  3. laziness

Community

Hoodlums – A user groups for people into Haskell. Formed at SPA last year. Once a month in London.

http://groups.bangstrom.com/hoodlums

If Code is Written Solo in a Forest, Does it Make a Sound?

I’ve written before about my views on the importance of pair programming as a way of building a common conciousness in a team. When two people work on a piece of code together, not only is it instantly reviewed for correctness and readability, but already two people on the team understand exactly why the code is like that – the design decisions and trade-offs that went into building it that particular way, and are aware of any re-usable modules, patterns, idioms or conventions that emerged during the coding session. When each of those people goes off to work with other members of the team, those memes propogate around the room surprisingly quickly.

When you write code alone, you immediately lose this benefit, and on a system of any significant size, this is really important. You might be writing terrific code, making great decisions and innovating really creatively, but if nobody on your team has experienced those decisions and innovations with you as they happened, all you are really sharing with them is the much more shallow end result: the code.

It’s almost like they never even happened.

WANTED: Software Craftsmen (and Women)

My employer, Songkick.com are hiring for developers.

To join this team you must be, or believe you are capable of being, someone who creates beautiful software. Nothing less.

If you think that sounds like you, do yourself a favour: stop working for those idiots who keep making you rush out all that half-arsed crap and come and work for a proper team where quality matters to everyone.

One catch: you must love live music. Interested? Tell us about yourself.

Twitter me up

If you think it’s got a bit quiet here on the blog, there are two reasons for that. One: my current project is very very nearly ready for the next round of beta invites, which has keeping me extremely busy. More details on that soon.

Second, though, is that I have well and truly caught the twitter bug. If you haven’t tried it yet, I really suggest you give it a go. It’s a great way to engage in conversations, and it somehow breaks down barriers very effectively, possibly better than any electronic medium I’ve played with yet.

See you over there? http://twitter.com/mattwynne

My Real Options Story

A few weeks ago I bumped into Chris Matts and thanked him for the ‘Real Options’ session he’d lead at SPA last year. I promised write up this little story about what I took out of it.

When I got back from the conference, my team were at a point where we had to chose between two competing technologies to build something. Looking at the two options, we really didn’t know which one to go for: they both had advantages, and at that time they were both unknowns to us. Wearing my new ‘options thinking’ hat, I realised that we didn’t need to choose at this point: in fact, making a punt right now would be downright irresponsible: we didn’t have enough information to make the decision properly.

So instead of using my ‘gut feel’ to pick one of the competing options like a real hero would, I did a much more pragmatic, but less intuitive thing: I decided we would do both, until it became clear which one was the right one to pick.

We were lucky that our constraints at this point were time, rather than cost, so we could afford the luxury of having two streams of work going on in parallel, knowing that one would eventually be thrown away. Obviously the hidden deliverable even from that throwaway stream would still be a developer or two who understood the problem domain really well, and with a new technology in their toolbox to use in the future.

A week later it was much clearer which of the options we should pick, and the other workstream was stopped. And everyone lived happily ever after 🙂

Update: If you want to know more about real options, read Chris’ article on InfoQ here.

Acceptance Tests Trump Unit Tests

At work, we have been practising something approximating Acceptance Test Driven Development now for several months. This means that pretty much every feature of the system that a user would expect to be there, has an automated test to ensure that it really is.

It has given me a whole new perspective on the value of tests as artefacts produced by a project.

I made a pledge to myself when I started this new job in August that I would not (knowingly) check in a single line of code that wasn’t driven out by a failing test. At the time, I thought this would always mean a failing unit test, but I’m starting to see that this isn’t always necessary, or in fact even wise.

Don’t get me wrong. Unit testing is extremely important, and there’s no doubt that practising TDD helps you to write well-structured, low-defect code in an really satisfying manner. But I do feel like the extent to which TDD, at the level of unit testing alone, allows for subsequent changes to the behaviour of the code, has been oversold.

If you think you’re doing TDD, and you’re only writing unit tests, I think you’re doing it wrong.

As new requirements come in, the tensions influencing the design of the code shift. Refactoring eases these tensions, but by definition means that the design has to change. This almost certainly means that some, often significant, portion of the unit tests around that area of the code will have to change too.

I struggled with this for a long time. I had worked hard on those tests, for one thing, and was intuitively resistant to letting go of them. More than that, I knew that somewhere in there, they were testing behaviour that I wanted to preserve: if I threw them out, how would I know it still worked?

Yet those old unit tests were so coupled to the old design that I wanted to change…

Gulliver

In my mind, I have started to picture the tests we write to drive out a system like little strings, each one pulling at the code in a slightly different direction. The sum total of these tensions is, hopefully, the system we want right now.

While these strings are useful to make sure the code doesn’t fall loose and do something unexpected, they can sometimes mean that the code, like Gulliver in the picture above, is to restrained and inflexible to change.

The promise of writing automated tests up front is regression confidence: if every change to the system is covered by a test, then it’s impossible to accidentally reverse that change without being alerted by a failing test. Yet how often do unit tests really give us regression alerts, compared to the number of times they whinge an whine when we simply refactor the design without altering the behaviour at all? Worse still, how often do they fail to let us know when the mocks or stubs for one unit fail to accurately simulate the actual behaviour of that unit?

Enter acceptance tests.

By working at a higher level, acceptance tests give you a number of advantages over unit tests:

  • You get a much larger level of coverage per test
  • You get more space within which to refactor
  • You will test through layers to ensure they integrate correctly
  • They remain valuable even as underlying implementation technology changes

Admittedly, the larger level of coverage per test has a downside: When you get a regression failure, the signpost to the point of failure isn’t as clear. This is where unit tests come in: if you haven’t written any at all yet, you can use something like the saff squeeze to isolate the fault and cover it with a new test.

They’re also much slower to run, which can be important when you’re iterating quickly over changes to a specific part of the system.

To be clear, I’m not advocating that you stop unit testing altogether. I do feel there’s a better balance to strike, though, than forcing yourself to get 100% coverage from unit tests alone. They’re not always the most appropriate tool for the job.

To go back to the metaphor of the pulling strings, I think of acceptance tests as sturdy ropes, anchoring the system to the real world. While sometimes the little strings will need to be cut in order to facilitate a refactoring, the acceptance tests live on.

The main thing is to have the assurance that if you accidentally regress the behaviour of the system, something will let you know. As long as every change you make is driven out by some kind of automated test, be it at the system level or the unit level, I think you’re on the right track.

MagLev: Death of the Relational Database?

I just got around to watching Avi Bryant’s talk on MagLev, a new Ruby VM built on top of GemStone’s Smalltalk VM.

http://www.vimeo.com/1147409

Presumably this is the kind of thing Smalltalkers have been able to do for decades, but to me the prospect of having this kind of freedom on a Ruby platform is very exciting. Terrific stuff. I wonder what performance is like.

Minesweeper Dojo

This evening I facilitated our first coding dojo at work. I’d spent some time over the holidays putting together a progression of Cucumber acceptance test cases to build up the solution, and had solved the problem once myself.

I used the minesweeper kata from http://codingdojo.org/ which was a really nice easy problem for our first dojo I think.

Format

Executive summary:

  • Randoori format
  • 6 programmers (plus me, facilitating)
  • 2 hours.
  • 10 minute iterations
  • 10 minute retrospective at the end.

I was clear at the start to point out that it was rude and disruptive for the crowd to criticise design when tests were failing, but that once tests were green, we would have a design review and do some re-factoring.

In fact, as we got into it, we began stopping the clock for design discussions (though perhaps these could also be timeboxed to keep the urgency up) so that people got a fair chance at the keyboard, but we also got plenty of time to analyse the design.

Summary

I held a little retrospective at the end where we collected some thoughts, then a few of us went for a pint afterwards and talked about it some more.

Good points:

  • Most people seemed to enjoy working on a ‘toy problem’:
    • everyone had worked on it equally so design discussions were never personal
    • we could really focus on getting the best solution to the problem, because it was so simple
  • Doing it out of hours meant we could really relax and have fun with it
  • It was a great way to get the team to rapidly build consensus about conventions and coding style
  • Having flog stats in the rake task made the final re-factoring stage much more worthwhile and fun

Bad points:

  • Some people found the problem too easy to solve, meaning we spent a fair amount of the session ‘polishing’ a working solution
  • I forgot to reset the stopwatch sometimes, which meant things got stale
  • There was a tendency for people to just rotate in / out in order which meant you kept getting the same combinations of pairs In the end I started drawing them out of a hat
  • We suck at git, particularly moving files from one branch to another
  • We suck at understanding flog’s feedback very well

Ideas for next time:

  • Find a way to visualise the changing Flog scores between commits
  • Try other programming languages
  • Need to mix up the type of kata: some people would prefer doing things they’d find more challenging, like a tough re-factoring
  • Get some food and beer in
  • Try shorter iterations?
    • In fact, try short / long pairs and see which we prefer!

I tend to perfectionism, so I really enjoyed the last half hour where we just re-factored the right-but-ugly first solution to the problem, extracting methods and classes and moving code around, ironing out the wrinkles and getting the flog / reek scores down. I enjoyed the discussions as we traded off different design principles and weighed up the appropriate route to take. Some people definitely found this time less rewarding, but I wonder whether they rather missed the point: this isn’t about solving a tough problem – we do that all day – this is about solving a simple problem the right way so that next time we hit one of those tough problems, we might be able to solve it a little more elegantly.

Legacy

I put the git repository where we worked on the problem up on gihub here:

http://github.com/mattwynne/software-craftsmanship-katas/tree/master/minesweeper

I would be stoked if anyone forked the repo and pushed their own solution. How low can you get your flog scores?