For this reason we had an event and called it the 'Christmas CodeFest'. (Yes, the name wasn't very good but the event was.)
From the original event advert:
We all learn in different ways. While it can be good to learn by hearing people present and demonstrate new techniques, it can also be good to learn by seeing how different people solve the same problem. That's what we hope to do at the CodeFest.
The plan is for everyone to write automated players for a simple game. Don't worry if this sounds complicated, it will only involve implementing an interface containing 4 methods (and one of them just returns your name!). The logic therein can be as simple or complicated as you want to make it. It will be practical to achieve something good in the time frame available and plenty of examples will be provided to get you started.
In addition to having each persons 'player' compete against each other we'll also look at the way each person approached the problem and how successful that was.
My initial expectation was that this may not be a popular event - after all I'm not aware of any other user groups having done an event like this before. Perhaps there's a reason why?
Writing something productive and fun in about 2 hours is actually quite hard. If you want to make it possible for people with varying skill and experience to be able to achieve something in the time limits things further.
If you've scanned down to the image below you'll see that the game used was Connect 4. This was deliberately not made known before the event so no-one could get a headstart on working out any game logic or tactics.
What I provided for those who came along to use:
A solution containing:
- A WinForms 'host' application which displayed the board, managed 'players', etc. (This host also allowed manual playing of each player.)
- A WPF user control to represent the game board.
- A set of tests to verify the logic in detecting wins, etc.
- A library containing the interface that each player was required to implement
- A copy of MEF Beta 2 Preview 8 (which was used to load players from the individual DLLs)
- A sample player written in C#
- An identical sample player written in VB.NET
- Open Solution
- Add new class library
- Add reference to ComponentModel (project)
- Add reference to IConnect4Player (project)
- Create a class that implements IGamePlayer (make sure to include necessary export attributes)
- Write some code to implement your player!
The aim was simple: everyone has about 2 and a quarter hours (including a break for food) to write the code to implement their player. We then allowed each player to compete against the others in a knock out tournament (using the sample random players to make up the numbers - so no one got a bye).
2 players were beaten by the random player in the first round. Boo!
The games were played projected onto a screen so everyone could see what was going on. The host app automatically called each player in turn until there was a winner. There was a slight pause (500 milliseconds) between each each move. This gave everyone a chance to see what was happening and allowed for some audible reactions as people were blocked from winning moves or failed to make winning moves. The host app I had developed required manually loading the players each time. In practice it would have been useful and saved time if the players could all be loaded at once and it take care of managing who played who and recording the results.
The final came down to a best of three between Jeremy and Mark. Mark won the best of 3 games by taking the first 2.
A selection of swag as prizes from our generous sponsors (http://www.devevening.co.uk/links.aspx) was available on a winner gets first choice style. People who found bugs in my code also got a choice of prize.
Speaking of which. Unfortunately a couple of bugs were found in my host app code.
Both of the people who were using VB.NET found a bug (now fixed) in my host code where I didn't handle the player returning the 'GiveUp' move correctly. At the time I was happy to dismiss this as a bug in the way I had done something which affected interacting with VB in some way. They were both certain that they were never returning a GiveUp result.
In my subsequent analysis of their player code I discovered that for one 'player' there were valid paths through their code to determine which move to make next which returned the default value for an enum. Sneakily of me this default value was 'GiveUp'. I looked at working out where the error in the code was but it was highly complex (lots of conditionals and recursion) and used lots of single letter variable names so I decided to pass.
After a bit more digging in the other VB player's code I found that on certain passes through multiple nested loops it tried to access an array element which didn't exist and then threw an error.
Both of these issues show me the importance of making code easy to read and follow. Also to be very wary of complex nested loops. I actually used nested loops in some of the host code which checks for wins. During the evening I had a discussion about this issue. I chose to use nested loops only once I had a large number of tests in place and beccuase it allowed me to massively reduce the amount of code I had to work with. Nesting loops is definitely a tick in the negatives column so to use them they must provide a benefit which puts a bigger tick in the positives column.
A bug was also found where it sometimes reported the wrong person winning. Oops.
One of the players was not developed with the instructions I gave. Instead they customised one of the sample random players. This caused problems when the developed player was drawn to play against the random player. Based on my very limited knowledge of MEF the problem experienced was one that shouldn't be possible as both players were loaded in different containers. I'll definitely investigate this further when I have the time. Maybe we've found a bug in MEF?!
What I learnt from organising the event
Unsurprisingly it was a very different DevEvening to 'normal'. Part of me was expecting that I'd be running around answering questions, etc. I hadn't expected that most of the time everyone would be quietly working. In theory this is a good thing. In practice it's something to be aware of for the future.
Analysis of what people did (a random collection of observations - not marking any code)
- Some people still use Apps Hungarian notation for variable naming.
- The people who used TDD had code that was really easy to follow.
- The people who used detailed, explicit names created code that was easier to understand.
- Some people use properties for things that I assumed would always be constants.
- I'm more positive about opening a code file for the first time if there is an accompanying test file (even when I haven't seen the tests)
- Assumptions documented in comments in the code are reassurring that the original coder has thought about what they are doing and have to do.
- Seeing lots's of TODOs in the code is reassurring that the original coder has thought about what they are doing and have still to do.
- I've learnt that there's a 'Assert.Inconclusive'
- I've seen some people default "unwritten" tests to return true. I'm not sure this is a good idea.
- Some people, seemingly, started by using using the sample random code and replaced this bit by bit as they wrote their own. - Seems like a good plan.
- Code is easier to read when spread across multipel lines.
- I find use of the conditional shorthand operator (? :) difficult to read when all on one line and I'm not familiar with the code.
- 2dimensional arrays seem to lead to code that is just as complicated to understand as a number of Lists (or equivalent) - at least when there are a small number of 'Lists' in use.
- Hooray for amusing comments!
- Comments which add no value are disappointingly common.
- Lots of people wrote code which they didn't use - presumably because they thought they would need it later. This seems a bad but understandable thing to do when very limited with time.
What I got from the experience
- I got to exposure to the way some other people work.
- I got new ideas for how to solve a problem.
- I had an excuse to do some practical development with MEF.
- I had an excuse to do some more work with WPF (embedded in a Winforms app)
- I had an excuse to use T4 in an actual project.
Some random/assorted statistics I gathered on the night:
- Teams/people who made notes on paper before starting: 1
- People who used the internet for reference: 0
- People who looked at the code I wrote for reference: 0 (assuming everyone was honest when asked.)
- Teams/people who wrote tests (of any sort) for their code: 4
- Which external libraries did teams/people use: only NUnit
- Teams/people who felt they had "finished" in the time allowed: 0
- Players developed by pairs fo developers: 3 (of ten players)
- People who used a black background in Visual Studio: 5
If I can come up with another suitable task/game/project we'll definitely do this again. The feedback from the people who came was very positive that they'd come again. I'm not sure how well this would work with much larger groups or how we'd fit many more people in
If you're interested in knowing more or running this or something similar at another user group drop me a line.