The A-Z of Code Craft – U is for Users

Image

Remember users? They were big in the 1990s, back when the software itself was the product, and not the attention and the personal data of the people who use it.

One of the most important things I thankfully learned early in my career was how to approach the design of software not by asking “What will this software do?”, but by asking instead “What does that person need to do using the software?”

You may be familiar with the idea of “use cases” in software engineering, first presented by Ivar Jacobson in 1987. But, less formally, the idea of analysing users’ goals, and their mental model of tasks and associated problem domains, then driving the UI design of a system from there goes back to the 1960s.

Having been trained on object-oriented UI design approaches in the 1990s, which I’m sure you can imagine involved a lot of boxes and arrows, these days I favour a more informal “walk a mile in their shoes” philosophy to getting inside the user’s head.

If we’re writing call centre software, I’d spend time observing and, ideally, actually working in the call centre, seeing and experiencing the kinds of things they’ll be doing using our system first-hand. No amount of boxes and arrows can replace that tacit knowledge.

Then I’d create a “model office” – a simulated call centre that we control, and can use to explore and roleplay scenarios, replay production incidents and unanticipated edge cases, and to test software in the most meaningful way, which is to try to do the user’s job with it.

At the very least, more of us could eat our own dog food once in a while. I’m always amazed at just how far apart some dev teams’ opinions of how satisfied their users are can be from the actual reality when I talk to the users themselves. It’s pretty normal to discover that the team has completely failed to address those needs.

And approaching design in this user-centred way doesn’t stop at the UI. APIs benefit from being designed from the client developer’s point of view. Libraries and services, too. Even classes and functions benefit from being designed from that external perspective.

One great example of user- and usage-driven design is Test-Driven Development. The design emerges working backwards from the tests, and the tests play the role of the user. So if we’re test-driving a design for an online shopping basket, we ask not “What does the shopping basket do?”, but “What does a shopper need to do using the basket?”

In my own evolution as a software developer, my journey’s been one from not really considering the user’s experience much at all, to now seeing that everything is part of the user’s experience. It’s all UX!

Even the stuff we don’t think of as UX, like unit tests. Many might argue they play no part in the user’s experience. But as an end user I can actually tell when a product lacks fast-running regression tests by how long I end up waiting for bug fixes to be released. That’s definitely part of my user experience!

And as a software developer, I use software tools every day that – let’s be honest now – not a great deal of effort was put into the design of the user experience. I use the term “builder’s houses”. (Builder’s houses are often found in a permanent state of “It’ll be nice when it’s finished”).

This seems to be especially true of Open Source tools, when even just installing the damn things can sometimes be something of a quest.

When we invest in understanding our users and their needs, it usually pays dividends in adoption rates, in word-of-mouth, in avoided support calls, and especially in improved user outcomes.

Maybe you signed up just to make some very rich investors even richer, but making a positive difference to users’ jobs and lives is worthy of more than just lip service.


If you’re serious about building your team’s capability to rapidly, reliably and sustainably evolve software to meet rapidly changing business needs, visit codemanship.co.uk for details of high-quality hands-on training mentoring for software developers.

The A-Z of Code Craft – T is for Team

Image

Be honest. You thought “T” was going to be “TDD”, didn’t you? As valuable as I think TDD is, there’s a more important “T” we need to discuss.

Much of what’s said about code craft focuses on individual developers, and it’s true to say that personal discipline is the foundation. But it’s by no means the complete picture. In fact, at best, it’s only half the story.

I’ve watched teams of exceptional individuals produce some absolute train wrecks together, and I’ve watched teams of pretty average developers produce works of true art (in the software sense).

In software design, we know that it’s not enough that all the individual components of a system be correct. The interactions between the components have to be correct, too. Ask anyone who’s unit tested every class in their design only to discover, with systems tests, that they haven’t actually delivered a single use case end to end.

I suppose a lot of the dysfunctions in software development can be boiled down to how organisations see teams. Our understanding of software architecture may shed some light. How we package people into teams follows similar principles to how we package modules into larger components.

Do we put all the JS front-end developers on one team and all the Kotlin back-end developers on another, like packaging all the views in one component and all the business logic in another?

Or do we package people not by their specific skillset, but by who needs to work with whom to deliver a specific outcome? If you’ve read any of my thoughts on package design, you won’t be surprised to hear that I don’t subscribe to the “socks go in the sock drawer” style of packaging. Rather, I advocate a “winter coats go with woolly scarves” approach. Things that are used together belong together.

I view team makeup in the same way. If delivering a mortgage application feature requires web front-end development, server-side Kotlin and Oracle PL/SQL, then the “Mortgage Application” team should ideally encapsulate all those skills.

To me, a team is a multidisciplinary unit organised around a shared outcome or goal. By all means, encourage centres of practice (e.g., a UX Excellence group), but the teams themselves need to be organised around the extent to which people need to work together, just like components in distributed systems should be organised around which internal modules need to interact with others.

Making teams more cohesive also brings the same benefit as making system components more cohesive, in that it reduces *coupling* – the interactions – between teams. Just as inter-component communication can be expensive, so too can inter-team coordination. When teams are designed around layers in our tech stack, for example, that can greatly increase the amount of inter-team coordination required – and therefore the cost – to deliver a feature.

Of course, even if the team encapsulates the range of skills they need to achieve their goals, things will slow down dramatically if they have to run every decision by management. So the the other thing teams need to encapsulate is the decision-making authority required to get things done.

As for the skills makeup itself, I also strongly advocate “T-shaped” team members. (There’s a third “T” for the price of one!) A T-shaped developer has a wide range of software development skills – UI/UX design, programming, software architecture, databases, testing, ops, etc – that are mostly shallow: the 20% they’d use 80% of the time. And they may specialise in one or two areas (e.g., a database specialist, or a testing specialist) for when more than that 20% of knowledge is needed.

This can quite dramatically reduce skills bottlenecks in development. If we have to wait 100% of the time for the database specialist to tackle our SQL problem: BIG BOTTLENECK. If we can handle it ourselves 80% of the time, the bottleneck tends to disappear.

This, of course, has implications for the way we learn our craft. We’re not just bricklayers or carpenters, we’re builders. In construction, people who train to be building contractors – my Dad was one – have to study longer and study wider than people aiming for individual trades.

And yes, I am implying that a 12-week boot camp or a 6-month internship won’t cut it. 3-5 years of on-the-job mentoring and part-time training is more realistic. (Interestingly, that’s the average duration of the UK’s L6 degree apprenticeship for software development.)

Finally, there’s the skillset that dare not speak its name: some call it “teamwork”, I call it team craft. Because marketing.

Teams tend to grossly underestimate the amount of communication and coordination it *really* takes to keep everybody on the same page. And if teams are cohesively organised around achieving shared outcomes, then being on the same page isn’t really optional.

(They also tend not to have agreed protocols – for want of a better word – that govern how they interact. I’m a fan of team contracts. Just as any group or community or society requires some basic rules around how we get along, teams can really benefit from a similar social contract.)

I can maybe best illustrate with an exercise. You’ve possibly heard of the Mars Rover coding kata. Most developers can complete this exercise on their own in an hour or two. A team of developers will typically take longer. And, of course, the more people we add to the team, the longer it tends to take them.

I know this for a fact, because I’ve watched many dozens of groups attempt the Team Rover exercise on my Code Craft training workshop, and it’s much harder than doing it by yourself.

In particular, working as a cohesive team demands a level of situational awareness – what many developers call “interruptions” – that, if anything, teams actively try to avoid.

You do need to know what other people on the team are working on. You do need to keep one eye on the status of the build, and you do need to regularly pull and look at the changes other people are making to the code.

And you need to talk. A LOT.

Some groups tackling the Team Rover discover that the best way to approach it is not to split off into subgroups or pairs and attempt to work on different features in parallel, but to actually stay together as a group and tackle each requirement in series – taking turns at the keyboard for each feature as per the rules of the exercise.

You may have heard of this approach. It goes by several names now, including “mob programming”, “ensemble programming” and “teaming”. I like that last one, because it has the fewest syllables.

Remember that, in these modern times, it’s rare that any one developer knows everything they need to know to deliver features in our fangled, wibbly-wobbly, timey-wimey tech stacks. So to deliver a feature end to end could well require the smarts of the entire team or a subset of it. That means communication. If the people we need to ask are currently tied up working on a different feature in parallel, they become a blocker. We can unblock by pulling that person into the mix to enable real-time, as-we-need-it interaction.

These team craft skills take work and practice. But where are the team katas?

Here’s a bigger one – typically takes 4-6 hours – to work those team muscles.

Oh, and one more thing. If you’ve been following me for the last few years, you may know that I have a different view of what the *real* product of software development is.


If you’re serious about building your team’s capability to rapidly, reliably and sustainably evolve software to meet rapidly changing business needs, visit codemanship.co.uk for details of high-quality hands-on training mentoring for software developers.

The A-Z of Code Craft – S is for Safety

Image

Everything we do in code is an experiment, and experiments can fail.

Every change we make to code carries risk: risk of breaking it, risk of making the design harder to change, risk of negatively impacting performance or scalability, risk of introducing security vulnerabilities, and so on.

Programming’s full of wrong turns and dead ends, and the impact of taking those wrong turns will depend mostly on how easily we can back out and try something else.

Picture someone walking a tightrope stretched between the tops of two mountains. This is a very risky thing to do. The further you go, the higher the fall – probably not survivable – and the further it is back to safety.

Now picture the same tightrope, but tied to wooden posts 2m apart and 1m off the ground. If you fall, it’s not far, and you’ll be able to pick yourself up, dust yourself off, and carry on. Importantly, you’re never more a metre from safety if you need to turn back.

A core discipline of code craft is progressing in small, safe, reversible steps. The micro-iterations of continuous testing, Test-Driven Development, refactoring and Continuous Integration are the programming equivalent of the second tightrope.

We change the code a bit, we test it, and if the tests all pass, we commit those changes. If the tests fail or we’re unhappy with the result of refactoring, we can easily revert, losing maybe just a few minutes work at worst. It’s an easily survivable fall.

We move forward in small steps from one working iteration of the code to the next working iteration, leaving a trail of potentially shippable breadcrumbs in our version history and the ability to go back to any of those versions easily.

This, it turns out, is a superpower. While it might feel super-cautious, I’ve observed in myself and in others many times how it can actually embolden developers, making them more comfortable experimenting with their code. The psychological effect can be quite profound.

And, yes, it feels slow, putting one foot in front of the other like that. But when we measure progress not by how fast we write code, but how soon we deliver working changes into the hands of users, it turns out it’s not slow at all. Quite the contrary. Remember, shippable software’s never more than a proverbial metre away.

A good way to practice working in short, safe, reversible steps is Test && (Commit || Revert). Run your tests from a shell script that, if the tests pass, automatically commits those changes, and if any tests fail (or the code won’t build or run), automatically reverts to the last working commit.

Every additional change to the code you make increases the risk of breaking it, and TCR can train you to reduce the risk by changing less between test runs.

(I’ve been meaning to try a CI version of TCR where, if you break the build, it automatically rolls the repo back to the previous working build and your local copy.)

The relationship between batch sizes and risk translates into all of the feedback loops in software development, not just those inner technical loops.

If you’re doing big releases every 6 months, and one new feature’s hated by the users, that’s a big deal to fix.

If you’re releasing one new feature per release, and the next release is only a day away, you can quietly disappear that change tout de suite with very little damage done.


If you’re serious about building your team’s capability to rapidly, reliably and sustainably evolve software to meet rapidly changing business needs, visit codemanship.co.uk for details of high-quality hands-on training mentoring for software developers.

It’s The Team, Stupid!

Image

Complexity Theory predicts that organisational outcomes are more likely to be determined not by individuals, but by the interactions between individuals & groups of individuals.

Any approach to improving team effectiveness that focuses on individual performance is likely to fail.

This is borne out by research that finds that the nature of interactions within a group or team – e.g., psychological safety (Google’s Project Aristotle), communication patterns (MIT Media Lab’s Sociometric Badges) – is a more reliable predictor of overall performance than individual ability.

But, culturally, we’re drawn to sensemaking hindsight narratives that seek to pin success or failure on individuals and groups of individuals. And, of course, to pin success or failure on tools or methodology.

In reality, cause and effect in complex systems is typically unknowable. These are just stories we tell ourselves to make sense of the chaos.

Most of what organisations do to attempt to produce (or re-produce, like with “The Spotify Model”) specific outcomes amounts to little more than rain dances.

Any attempt to impose order on a complex system from the outside is usually doomed to fail. Order emerges, it can’t be designed. Top-down change may seem to produce initial results, but the system will eventually be drawn back to its attractors by more fundamental behaviours (the unwritten rules).

That’s not to say we can ignore individual ability. Skill still matters (with the best will in the world, a jazz band who can’t play their instruments is going to sound like crap no matter how much psychological safety – but they will likely *learn* faster without that fear of failure).

But the performance of an organisation’s more about the dance than the dancers.

_____________________________________________

At Codemanship, I help teams address one simple question: what difference would it make if the trains left every five minutes?

I train and mentor teams in the skills that create products and systems that can be shipped at any time, as often as the business needs, enabling them to reliably, rapidly and sustainably evolve working software that meets changing business needs.

I focus on fundamental, foundational developer and team behaviours that shrink the outer business feedback cycles by shrinking the inner loops of development, helping businesses to out-learn their competition.

Please don’t ask me to get involved in your “Agile transition” or “Scaled Agile adoption”, as refusal can often offend 🙂

Visit codemanship.co.uk to find out more.

The A-Z of Code Craft – R is for Refactoring

Image

“Refactoring” is a very widely used and even more widely abused term in software development. You probably think you’ve done some refactoring, but there’s a high probability that you actually haven’t. Allow me to explain…

Refactoring is improving the internal design of software to make it easier to change without changing what the software does. The two parts of that developers tend to get wrong are “easier to change” and “without changing what the software does”.

Replacing an Oracle database with a SQL Server database isn’t refactoring. Moving from React to Vue.js isn’t refactoring. Fixing bugs isn’t refactoring.

Restructuring your code to make it easier to replace an Oracle database with a SQL Server database? That’s refactoring. Reshaping the front end to make it easier to move from React to Vue.js? That’s refactoring. Introducing dependencies by injection to make it easier to unit test a bug fix? That’s refactoring.

Refactoring is restructuring the internal design of our software to more easily accommodate changes. As Kent Beck, who literally co-wrote the book on refactoring, puts it: “Make the change easy, then make the easy change.”

On that second misunderstanding, surprisingly few developers have even seen the discipline of refactoring being applied to those restructurings. Each restructuring – each refactoring (it’s both a verb and a noun) – starts with working code and ends with working code, with no changes to externally visible behaviour. Each refactoring is a behaviour-preserving rewrite of the code.

How do we know we preserved the behaviour? TESTS, MOFO!! We perform one refactoring, and then we run our tests to make sure everything works as it did before.

And each refactoring is atomic. Consider renaming a function: we can’t just change the name, we have to find all the call sites to that function and update them with the new name. There’s no “half a rename” that gets us back to code that works. So we change the name, update the call sites, and then RUN THE TESTS.

Mix in judicious use of version control to make it easy to go back to any working version of the code if your refactoring experiment doesn’t work out, and you have a process that can move architectural mountains putting one foot in front of the other, never losing our balance.

This is the most common misconception. When most developers say “I am refactoring my code”, they’re not performing a sequence of atomic rewrites with continuous testing and frequent working commits. They’re just hacking away at the code, wandering further and further from the path into the deep dark forest.

Restructuring code through a sequence of refactorings is a hard skill to learn. It’s a bit like playing chess. Every move has specific mechanics you need to know, and you need to be thinking several moves ahead to get from Design A to the Design B you have in mind without leaving the code broken for extended periods.

And it’s because refactoring at scale is difficult to learn that the vast majority of developers don’t do it, even if they think they do. But the ability to reshape code to accommodate changes, keeping it working (and shippable) throughout, is a development superpower. It’s worth its weight in gold. New requirements? No problem! Legacy system? No problem! Wrong design choice? No problem! AI-generated slop? No problem! (Wanna make some real money in a couple of years’ time? Learn to refactor!)

If you want to see what refactoring really looks like, check out my video “Refactoring. You keep using that word.”


If you’re serious about building your team’s capability to rapidly, reliably and sustainably evolve software to meet rapidly changing business needs, visit codemanship.co.uk for details of high-quality hands-on training mentoring for software developers.