Friday, 27 April 2012

ACCU day two thoughts

This is my second attempt to write these notes.  Turns out that writing in an online editor whilst connected to hotel wi-fi is a very bad idea!

Today's keynote was given by Phil Nash, and was entitled "The Congreuent Programmer".  The message seemed to be that we live our lives according to a set of beliefs, values and principles.  If these are aligned then we are fine, otherwise we find ourselves in a state of cognitive dissonance.  One example I have for this is that I believe in TDD (at least to some degree!), but I very rarely find myself practicing it!  

Next I went to a talk on "Go, D, C++ and the multicore revolution" by Russel Winder. The aims of this talk were to convince me that shared memory multi-theading is not appropriate for application development (I don't need much convincing on this point!) and also that the new threading related features of C++ 11 may have saved it from the dustbin.

The multicore revolution is already here.  I'm writing this on my dual core iPad and chances are you (hi mum!) are reading it on a multicore machine of some description.  Since the multicore revolution, software has started to lag behind hardware.  As software engineers, we're the people holding things up!

The distinction was made between concurrency (a design tool) and parallelism (a tool for improving performance).  Three models of controlling concurrency were then presented.  None of the are new ideas, but they are well understood tools that are only now beginning to be recognised as important.

The actor model controls concurrency by having multiple independent processes (important to note that this process need not be a separate OS process, it's just a lump of code with an independent address space) communicating via asynchronous messages.  Erlang is an example of a language that has direct support for the actor model.

The data flow model is a spreadsheet model where the computation reacts to changes in inputs.  this has a role in big data as a counterpart to the map/reduce app.  By running a data flow net as a continuous query that updates based only on the diff, it's possible to get more immediate results.  Lucid is an old, but interesting, example of a data flow language.

Finally, Communicating Sequential Processes (CSP) was presented.  This is a formal model of concurrency where processes communicate via synchronous messages.  Go reinvented CSP and called it go-routines.

Next Russel presented a simple example that calculated Pi.  The example was kept consistent as the languages moved to higher level abstractions, from C and pthreads to Go and D with C++ and MPI in between.  The obvious point was higher level abstractions make things easier to understand.  All in all, I enjoyed this talk!

Henrik Berglund ran a quick 45 minute session on "Real Teams".  I have to admit I initially chose this one purely because the door was open so it was a break from the unbelievably hot rooms!  Luckily for me this turned out to be an excellent choice.  The introduction talked about the curious case of the astronauts that went on strike.  Despite being highly trained, military disciplined and very intelligent a bunch of astronauts went on strike in space simply because the working conditions were so hard.  Building great teams is hard!

Getting the conditions right for a team is very important and Henrik outlined some of the things that he had seen with successful teams.
  • People need influence over their working conditions.  This can be achieved by using self managing teams that have clear authority.  Delegation poker might be one tool to try out for this.
  • Compelling direction.  A vision, a product, a sprint goal.  One of the more interesting points was that goals should be challenging and it was suggested that a 50% failure rate was optimum.  I definitely want to try this when I get back to work!
  • Clear boundaries.  Understand who is on the team.
  • Nobody succeeds unless everyone succeeds.  This avoids the done vs done done dilemma.  Problems should be given to teams not people.
  • Trustworthy feedback based on results.  No proxies between users and the teams.  The role of the product manager is to be the vision guy, not to shield customers from engineers.
  • Need to depend on each others skills.  It's OK to specialize and build up independent skills (got to be careful of the bus number!)
  • Be able to give negative feedback if needed.  This needs trust on the team and this takes time to build up.
    Team building requires effort.  Undertsanding the needs and motivations of your colleagues is an important part of working together
I enjoyed this talk a surprising amount and there's definitely some ideas I can take back to work.
After this talk I caught the tail-end of "When only C will do".  C is supported everywhere and has a standard application binary interface (ABI).  This ubiquity makes it an easy choice.  C++ doesn't have a standard API and embedded devices may choose to drop some features (e.g. runtime type information or exceptions) which makes life harder.  The conclusion seemed to be that most of the time you can use C++, but you may need to expose a C interface to be compatible with the rest of the world.
The afternoon finished with a talk on "Refactoring to Functional".  I don't think I was the target audience for this presentation.  The talk introduced some foundational functional concepts but through the medium of Google's Java's Guava library (curiously its missing a fold/reduce operator).  This has some of the worst syntax I have ever seen.  The noise to useful ratio is stupidly high and it just made me so grateful for C#.  Yuck!

They chose this style because it made the core logic simpler (and presumably eventually their brains learned to unsee the syntactic abominations).  They did try Scala, but found that you had to think at both the Scala and Java layers.  I think using the functional style in a language without first class functions is a mistake.  It's like trying to write C in an object-oriented style.  You can do it, but you can constantly fighting it and that's not good.  Maybe Java 8 will resolve these problems in a few decades.

Wednesday, 25 April 2012

ACCU 2012 - Day One

I'm lucky enough to be at ACCU 2012 this week, and I thought I'd try and write up my notes after each day so that I have more of a chance to digest the information being thrown at me!

The opening keynote today was entitled "Project Patterns: From Adrenalin Junkies to Template Zombies" by Tim Lister of PeopleWare fame. Tim was keen to point out that this wasn't about patterns in the strong Patterns sense, but more about some of the habits from teams he'd worked with.

The first pattern mentioned was "The Safety Valve". Successful teams often have a release mechanism, be it making popcorn, riding a pink tricycle (!) or playing foosball. This pattern rang true. In good projects I've been involved in I can always identify a safety valve. The converse is also true, when working on shitty projects its mostly just been heads down, stress up, writing code until its done.

The second pattern was mañana. This describes the problem with long deadlines. A lack of urgency means apathy. If something is outside of my mañana window, then I don't really care about it. As an engineer, my mañana window is about a sprint in length. If its not needed for this sprint, then it's off my radar. In contrast management types need to have a much longer mañana period.

Next up was "Lessons unlearnt" that made the controversial point that the lessons learnt in a retrospective rarely trigger change in the organisation, they only cause change in those that encountered the problems in the first place. This was backed up by the observation that long running software companies are no better at making software than those with little history.

"Project Sluts" or managers that just can't say no was another pattern that struck a chord. I suspect everyone has experienced this one!

Finally was the "Dead Fish Pattern". It's a project where everyone knows it is doomed from day one, but nobody says anything. I've direct experience of this one (it being the major reason why I left a previous job). We all knew the project was doomed, but the politics of the situation meant this could never be voiced, and the team just hunkered down into a marine corp death march mentality (see Death March by Edward Yourdon, a great book!). There was a great quote about heroics from developers to keep it running by the use of "code defibrillators".

I really enjoyed the talk, and I think I was successfully not-so-subliminally convinced to buy the book!

Next up was the Code Simplicity talk I (I was actively trying to avoid the Goldberg contraption that it C++ 11). It was a good talk using examples from the Qt framework to demonstrate complicated code.

Make it simple. Make it memorable. Make it inviting to look at. Make it fun to read

The biggest takeaway for me was looking at code from the perspective of consumers. There's no point designing a clever, simple API for yourself, if you hoist all the complexity on the users of the API (for example, requiring implementation of a huge interface). I also learnt a new useless acronym TATUC (throw away that useless code). Someone for the audience also gave a memorable composition over inheritance quote, "if you marry you can get divorced, but parents are forever".

The speaker also tried to encourage the boy scout rule. Since bad code is easy to spot,you should take every opportunity you can to tidy it up. This is much too idealistic for me, tidying code is always a risk (most of the time it won't have tests) and its all too easy to make a messier working code base into a prettier, but subtly wrong code base.

Bit of lunch and the onto Parallel Architectures. This turned out to be an interesting review of parallel architectures from the hardware side, and then the software side. In the beginning there was the Z80, and life was simple. Then the was pipelining


Pipelining is a leaky abstraction. Instructions can be reordered by the compiler/hardware and this can break your code in subtle, non-obvious ways. The best example of this is probably double checked locking. Cache coherency is another problematic abstraction. If you write something to cache, and this needs to be available to another core then the memory management unit (MMU) must flush the cache to make that data visible. This causes a huge performance problem (see here for a great example).

Multithreading is just one damn thing, after, before and during another (Alexandrescu)

On the software side of things, there was recognition that both mutex and atomic based approaches aren't suitable long term. Both are non-composable, and (apparently) there's evidence that mutex based approaches simply won't scale to large number of cores. Transactional memory was mentioned, though it's slow. Importantly though, transactional memory is composable and is simple to reason about. The Intel Haswell processor will provide hardware support, so it'll be interesting to see whether this provides an alternative to the actor models that seem to be in vogue at the moment. I'm looking forward to seeing how things change with concurrency over the next few years (I hope for a revolution, but I bet we just find more intricate ways of just about making things work).

Finally, I went to the "Objections on TDD and their refutations". This covered the many excuses that developers come up with for not doing TDD, ranging from the cop-out (my manager wouldn't let me) through to the delusional (I don't make mistakes). My feelings on this are mixed. Code without tests is just a lump of synctactically valid code, but not much more. Tests give substance. I'm not so sure whether unit tests are the best way to do this. There was a quote on Twitter today which stated that unit tests provide existential qualification whereas types provide universal qualification. I dig that!

TDD also seems to be used inappropriately for hard problems. In this case, it feels like simulated annealing; it seeks out a local solution to the problem, rather than finding a global optimum. My favourite example of this is Sudoku. Compare Ron Jefferies epic adventures with Peter Norvig's application of brain power.

Looking forward to day two.


Tuesday, 27 September 2011

Avoid C# Enums!

C# enums are closer to glorified integers than Java's. In Java, you're able to avoid the horrible pattern where the function has to throw an exception if a new enum is added, such as that shown below. This pattern is yucky because the compiler is unable to determine this at compile-time.

   public enum Foo { Bar, Baz };

   // Has to throw the exception
   public void doSomething(Foo f) {
     switch(f) {
        case Bar:
           System.out.println("!! Bar");
           break;
        case Baz:
           System.out.println("Baz !!");
           break;
        default:
           throw new IllegalArgumentException("Unsupported enum type!");
      }
   }

In Java, you can give the enum behaviour.

   public enum Foo { 
     Bar("!! Bar"), 
     Baz("Baz !!);

     private string stringRepresentation;

     private Foo(string s) { stringRepresentation = s; }

     public string getString() { return stringRepresentation; }
   }

   public void doSomething(Foo f) {
      return f.getString();
   }

This is cool because the only way you can add a new enum value and get it to compile is to give it a valid string representation.

In C#, enum's can't have behaviour so I think they should be avoided like the plague. Changes are if you are switching on an enum value then the behaviour you are executing belongs on the class anyway!

You can simulate enums with a class, a private constructor and some static instances of the class representating the enum values.

  public sealed class Foo 
  {
    public static readonly Bar = new Foo("!! Bar");
    public static reaodnly Baz = new Foo("Baz !!");

    private string m_StringRepresentation;

    private Foo(string stringRepresentation) {
        m_StringRepresentation = stringRepresentation;
    }
  
    public string StringRepresentation { get { return m_StringRepresentation; } } 
  }