SoCraTes 2012

I kid. I didn’t just drink German beer for the whole four days. In fact, there were periods of several hours where I didn’t touch the stuff. Instead, I sat, listened and absorbed as much information as I could, and occasionally contributed some of my own ideas back.

So, what did I learn?

Practice constantly

Katas, dojos, and other repurposed Japanese words. Do exercises. Multiple times, in different ways, using tools and techniques both familiar and foreign. Always push yourself.

Martin ran the code retreat on the last day, and pointed out that musicians practice for months so they can perform for a few nights. We spend a lot of time learning on the job, but sometimes it’s useful to practice on something that doesn’t ask you to rush, cut corners and work when you’re not functioning at 100%. Adi and Erik ran a series of sessions on writing the best code you can, for which I am massively thankful. I’m going to steal their session on brutal refactoring and hopefully run it at an LSCC hands-on session soon.

Know which rules you are breaking and why

This, for me, was the most important. It’s OK to break the rules, as long as you’re aware you’re doing it and can justify it. This includes actually knowing the rules. Ones that come to mind are:

Red, green, refactor.

Take baby steps.

Acceptance tests are good.

Conditionals are bad.

Write the code you want to read, then implement it.

If you do something complicated three times, automate it.

SOLID is pretty cool, with the exception of the open/closed principle, which still makes no sense to me.

Of course, you may disagree with some of these, but there’s a huge difference between disagreeing and being ignorant of them. They should always be running through your mind, and an alarm should go off when you break one. If you choose to ignore the alarm, you better have a good reason for doing so.

Library functions are better than language features

Watching Andreas demonstrate Smalltalk, I realised something that had been ticking in my brain for a very long time. The most well-designed languages don’t have many features. They don’t need them—the few they have are powerful enough to simply express anything. Smalltalk doesn’t even have the if keyword or similar. Instead, booleans are objects. As a resuit, they can have methods, and do. The most important one, ifTrue:ifFalse: takes two blocks (closures), and calls one of them depending on the boolean you’re calling it on. Conditionals, implemented in the standard library. Pretty cool, right? It’s all handled through polymorphism: true and false simply implement the method differently.

The other thing I took away from this short talk was that Java is not object-oriented. It just isn’t. Object have behaviour. If the language encourages you to ask for values rather than tell an object what to do, it’s not OO.

Monads are hard to explain

But often you can make similarities with things more common in the Java/C#/C++ world. Some things are comparable to dependency inversion, some to container and collection types, and some are unfortunately just batshit insane.

Following the single responsibility principle is difficult

Let’s talk about if statements. It’s fairly clear that a method with an if has two responsibilities, not one. While making decisions is a necessary part of program execution, it should happen at the highest level possible, not deep down where it’s difficult to find and understand. What’s not so clear are the boolean logic operators, && and ||.

That covers all four rules. The problem is it does a bunch of things. I can’t even tell how many at a glance—it requires studying the code. The boolean logic operators are basically if blocks in disguise.

I’ll let you fill in the other implementations of Neighbours yourself. Perhaps at a code retreat. 😉

DDD simply realises that a thing has several different facets

This is by no means a complete definition of Domain-Driven Design, but it’s something I took away from Cyril’s session on it. We often talk about an Account class when we’re dealing with that hypothetical bank kata, but accounts have several different viewpoints.

If I’m the account holder, I want to see my balance and transactions.

However, if I’m a bank manager, I probably want to see information such as the account owner’s name and address, salary and whether she’s making full use of all account features. I probably want to find out if she’s using her packaged travel insurance and how much, so I can see whether I can upsell a new account with even more features.

If I’m a teller, I should probably see a recent list of transactions and the dates and times of when the money actually transferred (as opposed to when the account holder actually paid for something), so I can figure out why a payment didn’t go through.

We should represent these things as concrete objects in our system, instead of having a single Account class which is used by everything.

BDD is not ATDD is not E2ET

Let’s define those three things.

End-to-end testing is simply the process by which you write a test that covers the entirety of a system, or at least as much as concerns the feature under test.

Acceptance test driven development is something I picked up from The Pragmatic Programmer—before starting on a feature, determine what is required for this feature to be complete. Then, and only then, start on implementation (which should include unit testing).

Behaviour-driven development is closely related to ATDD, but involves writing that acceptance test with someone invested in the business who understands the customer. Ideally, it would be the customer himself.

Why is this important? It comes down to understanding your tools. I hear people talk about BDD when all they’re doing is writing a lot of end-to-end or integration tests, which is missing the point. Lots of integration tests are harmful to efficient software development—they’re slow, usually because they’re testing the same thing over and over again with slight variations in one small area (further reading: Integrated Tests are a Scam by J. B. Rainsberger). True acceptance tests should be small in number and simply prove that the feature is working approximately as expected. Unit tests should cover the rest.

You should practice architecture

Honestly, it’s worth it. Benjamin ran two sessions on solving architectural katas which really opened my mind to different designs, but more importantly, they pointed out to me how easy it was to miss requirements. It’s worth just sitting down and talking about what you need—you’ll find that half the time is spent throwing ideas away and the other half is coming to realisations which mean you might have to introduce something completely different. The process also really helps in clarifying the way you communicate, both inside your team and to the outside as you explain your end result, either through words or diagrams.

Metrics are not a replacement for thinking

You can combine metrics to make new ones. A simple example is Number of Methods / Lines of Code = Average Lines per Method.

You have to think. You can’t follow the metrics blindly.

Simple stuff, but always good to remember.

Kanban is more than a to do list

Erik showed us exactly how his personal kanban works, and I learnt a lot. The most important thing was that at work, we don’t do kanban. We call it a kanban board, but it’s really not. There are a few reasons for this:

We don’t limit work in progress.

Things often pile up.

Our backlog is absolutely humongous.

It’s something I believe we need to fix. I find I don’t get much out of the online software we use unless I put myself into tunnel vision and ignore most of it, which isn’t healthy. I’ve been using a personal one on my desk which is much, much simpler for the last couple of days and it’s made my working life a lot better.