Does Your Team Know its Value(s)?

Adam Lammiman
16 min readJun 14, 2022

If we work in software we work in teams, teams are what makes modern commerce tick, but what are they and what makes a good one?

Often a ‘team’ is a just a group of disparate individuals thrown together and told to complete a task. If you’re lucky you get to pick the team you’re on or you get to build your own team, but most of the time it’s like a really bad episode of The Crystal Maze, a group of people who barely know each other are locked in a room and told to solve fiendish puzzles before the time runs out.

‘Teamwork’ in these instances can often consist of occasionally gathering together to either shout and disagree with each other, or (potentially worse) to be passively fed work and then disappear into their own silos.

For me a team is more than that, a team is a cohesive group with a shared value structure that inherently understands its collective strength is greater than that of its individual members. The actions of a true team reinforce and grow that strength.

When you can come together and mutually support each other, when you can understand each others strengths and weaknesses and how to support them, when you can create an atmosphere of trust, where people feel safe and appreciated, where people feel empowered to get the job done and are trusted to do it. Then you have a team.

When I became a team lead I really wanted to address some problems that had annoyed me when I’d been in a developer in various teams over the years.

I had worked on many teams where it didn’t feel everyone was pulling in the same direction, often people were at odds with each other in a way that was damaging. Disagreement is not a bad thing and not everyone on a team has to be best friends, but we have to work in a way that takes our different personalities and creates a feedback loop which increases our collective signal strength not dampens it.

Sometimes there were teams within teams, where smaller groups of differing opinion fought low key battles within stories and the code base trying to do things their way. Other times it was the lone wolf maverick cutting their own path, often at the expense of everyone else on the team, who then had to tidy up after them. But in every instance it was people working either just for themselves or against each other that caused friction and a massive waste of everyone's time.

I’ve been in teams where one individuals code is refactored away by the rest of the team almost as fast as they write it. Or where rival factions battle it out, complaining vehemently about the other sides shortcomings while ultimately undermining their own code base in petty conflict. Other times I’ve seen pairs of developers refusing to work with anyone else and cherry picking the stories they want, while leaving everyone else to do what’s left.

This behaviour has real detriment to the work environment, to the quality of the code and ultimately to the bottom line of the business.

The common thread in all these situations was that there was often sets of implicit assumptions or differing viewpoints that were never made explicit, never aired openly. There was never a collective will, but just differing factions.

It was sort of an expectation that those joining the team would absorb its ethos by osmosis and everyone would be happy, but without that ethos ever being defined how was anyone going to know what it was, if they agreed with it and whether they were challenging it?

In order to rectify this I came up with the concept of ‘Team Rules’ an explicit set of rules that defined the values we thought we should aspire too.

By making these statements it became possible to point at something concrete and say ‘that’s what we do’. Joining the team meant subscribing to those rules, if you didn’t like them then that was discussed up front, not 3 months in when the damage was done.

Since coming up with this concept I have found I am not the only one to have thought of it, the term ‘Designed Alliance’ pretty much summed up what I was trying to do:

A designed alliance makes explicit the implicit ways a relationship works and how it feels to be engaged with it. It encourages both parties to share from a place of honesty and transparency their respective perspectives, hopes, and fears for the partnership.

Modern Agile goes further with the concept of a ‘Charter’:

Though their concept feels broader than the team scope I was working to I feel the underlying ethos is broadly the same.

So here are our current team values, we tend to review them periodically and make sure we remember and understand them. Whenever anyone joins the team they are one of the first things I run through.

There are no experts, there is only us.

This is a quote from Elastic Leadership by Roy Osherove one of my favourite books on managing a team. I like it because it’s the dev team equivalent of ‘there are no grown ups’, it’s a reminder that all those people whose books you’ve read or videos you’ve watched are just developers like us.

You’re never going to suddenly wake up one day and find your the expert but you are going to try to be the best you can be.

Write your tests first — no testing after the fact

This is the teams hard and fast no arguments rule, it is the only binary, black and white you-are-not-doing-it-any-other-way rule in the list which is why it’s the first.

I’ve been on too many teams where (if you’re lucky) half the team writes tests first and the other half does not. The first half of the team will spend their time clearing up the mistakes, bad testing strategies and holes left by the second.

Writing tests after the fact is an anti-pattern, proper TDD and BDD are superior methods period. I have gone from no testing, to ‘testing after’ to learning how to apply TDD and BDD properly, as have a lot of my current team, so we have all learnt this lesson from hard and bitter experience.

I have never met anyone who writes their tests second who does testing as well as someone who applies TDD, so why would we want to accept doing second best when there’s a better method that we can teach you?

Simple over complex — don’t be too clever

When I work with junior developers the one lesson I will try to impart is ‘Don’t be a clever developer’, I hate clever developers and thankfully I am not intelligent enough to be one.

I’m not a great programmer, I’m just a good programmer with great habits — Kent Beck.

This, like the ‘no experts’ quote above, is one I live by. ‘Clever Developers’ are my generic term for the developer that spends an inordinate amount of time thinking about the best design, spews out a load of overly complex and unintelligible code, bungs in a few design patterns for no understandable reason, wraps a few monumental cursory tests on it, ties a ribbon on it and sits back to bask in their intelligence. Then they patiently wait for other developers on the team to have to come and ask them how the hell it works.

Design evolves and it evolves by doing, it’s not about writing the best software in one go just so you can demonstrate you know what a Decorator is. It’s about growing the best software through process designed to encourage it.

Start simple and add complexity where it is needed. Code is not about showing off how much you know, it’s about working software.

Code as communication — what message am I giving?

Code is a narrative, you are communicating to the computer but you are also communicating to other developers (including yourself). If that is the case then what permission am I giving myself and other people? If I write in this dirty hack to save time am I setting a precedent that others will follow? Like the ‘broken window’ theory once permission is given then it’s easy for a code base to degrade quickly.

Everything is done for a reason — (even if it’s not a good one)

If someone has or hasn’t done something don’t automatically assume it was from ignorance. Too often developers think they’re the cleverest people in the room (see don’t be too clever), this can translate into a tendency to put other developers choices down to a lack of understanding not a deliberate decision.

To give a couple of examples. A while back we had a newer but experienced developer join a team I was on, he came across a problem where using JSON tags was a possible solution. He implemented them, fixed the problem and then added them in a couple other of places without checking in with the rest of the team. His assumption was that no one had used them because we didn’t know about them.

Actually the team did know and had consciously made a choice not to use them a few months previous and instead use a different approach (which would have been explained if he’d checked in with others on the team). So the mistakes were the assumption of ignorance and the lack of communication (hey guys I notice you’re not using JSON tags, is there a reason for that?).

A second example happened quite recently, we were looking at an issue with a build step and someone found there was what appeared to be a duplication in the way the nuget packages were created. This time the developer who found the duplicate followed the rule, asked the team before removing the seeming duplication and found out there was a good reason for the two different steps. Some of the projects in the solution needed to be built in a slightly different way.

We agreed that it wasn’t entirely clear and amended the step title and description to make it obvious, but the difference to the first example was that the team members reaction was one of trust. If this is here it must be here for a reason I wonder why that is?

This rule also promotes a focus on house keeping and keeping things tidy. If that was the third time this week the developer had found a superfluous build step that had been left and never removed then their reaction would have been very different. In order for this to work you need to be applying rule three (code as communication) and rule 8 (If you find it it’s your/our problem).

Everyone needs a Studdle

A Studdle is a terrible name for a great idea, it stands for ‘Story Huddle’ and it’s a technique we use instead of things like Code Review.

The problem with Code Review is that it’s too far to the right (if we use Lean speak), too close to the end of the process to be efficient or effective. Firstly whoever has worked on the code is automatically on the defensive, after two weeks of hard slog having someone criticise your hard effort is never going to go down well and as a reviewer it is impossible to get entirely into the headspace of the developer who wrote the code you are reviewing.

Secondly unless you are really strict the impetus is always going to be on approving and waving through than on rigour and sending a story back. ‘Sorry Product Owner but the design choice was appalling and the story is going back round again, you’ll have to wait another sprint’ is never going to be an easy conversation. By the time the code goes back the developer has often moved to something else so they have to context switch back.

If you use Code Review ask yourself the question, when is the last time something failed code review and had to be re-done? If the answer is never or rarely then you’re either writing awesome code or the reviews aren’t worth the pull request they are written on.

The Studdle approach reverses that pattern, when a story is pulled in then a Studdle is called, either the whole team is brought in or a quorum of team members. The story is re-discussed and the potential implementation options mulled over. Eventually a decision is made and the story begun.

This has two main benefits. Firstly we can tap into the ‘Team Hive Mind’ and gather everyone’s experience together, which increases the likelihood the design will be good and shares knowledge around the team. Secondly by discussing the problem as a group we own it as a group there is less likely to be the ‘why the hell did you do it like that!?!’ discussions if everyone has by in from the beginning.

It also increases the trust levels in the team, even if you weren’t involved in a Studdle you will start to trust that those who were have discussed it fully and will tend to abide by their decisions.

This rule combined with the next one removes the need for Code Review and increases efficiency by making sure stories move in one direction, left to right.

We never walk alone

Pairing or mobbing as a norm not an exception. The squad is stronger than the solider, we don’t work as individuals we are stronger as a team. Pairing is a skill that needs to learned, understood and worked at, same with Mob programming.

Two developers working together is not automatically a pair, there are certain rules and habits that make good pairing. I think that some developers can dismiss pairing simply because they’ve never worked in a pair that knows how to pair.

I do get ‘pairing isn’t for everyone’ or ‘some developers like to work alone’ occasionally but most of the time I’ve found that a complete nonsense, if the culture of the team is a pair mentality then it is accepted and it becomes second nature. Like the TDD rule sometimes you have to say ‘no we are doing it like this’ to get people past their reticence and feel the benefits for themselves.

By being clear in our expectations and our behaviour we’re being open from the start and if people really, really don’t want to pair then don’t join the team.

Collective responsibility

We own the code and are responsible for it’s health and upkeep from end to end, in doing that we favour the T shape developer model. This is where a developer will have a broad set of skills and one or two areas of depth (the vertical of the T) where they will probably have more of a leaning than the rest of the team.

There is no Ops person or Database developer, no Q&A or testers. Anyone should be able to pick up the next story on the backlog whether it requires a new build pipeline or a change in the frontend.

Because we work in pairs or groups strengths and weaknesses even out and knowledge is shared. This week you’re working with someone who knows more about the underlying nature of a database and the next week you’re explaining to the same person the subtle nuances of Typescripts type system.

This engenders a feeling of collaboration, by increasing trust you lose the fear of not knowing something (never be afraid to look like an idiot I often say to the team, and I will happily lead by example as often as possible) and finally it distils a sense of ownership. If something goes wrong then it is the responsibility of everyone to try and understand how to fix it, it is not OK to hope that someone else will notice it and deal with the problem.

If you find it it’s your (our) problem

This is really an extension of the collective responsibility rule, but this is there to target what I like to call the ‘raise a story’ problem. If during the development of a feature you come across an issue, a problem that needs fixing or a bit of refactoring then it can be tempting to say ‘let’s raise a story and come back to it’. Unfortunately this will invariably lead to a bottom of the backlog pile that steadily grows and is never addressed.

If you find a problem fix it, if you can make the code better then do so (instead of working around it), if you uncover a big issue then pull that Andon cord (a cord that was used in Toyota to stop the production line if a problem was found), call the team in, decide a course of action and do something about it.

Hang on! I hear you cry, what about sprint goals? What about the value of the story? We can’t let those pesky developers start tinkering with things, they’ll spend ages doing that and not finishing the work they’re supposed to be doing.

If you treat your team like infants then they’ll behave that way, if you treat the team as a group of professionals with intelligence and judgement then they will act like that instead. Yes developers can sometimes disappear down a rabbit hole and you’ll have to chase after them, but I’d rather have a team I have to stop from going too far than a team that sacrifices quality in pursuit of velocity at any cost.

Sometimes things may take longer but I’ve found that if this rule is followed the amount of things you have to battle decreases, while the opposite is true if things are left to wallow in a backlog.

No Heroes

I remember working with someone a few years ago who was recounting the epic weekends spent at his last company guzzling pizza and energy drinks as they slept under desks and tried to get a software release out. He recounted the story with what seemed a sense of masochistic relish as bugs were battled, scripts run and fires (metaphorical not literal, I think) put out.

No, just no. I get it, it’s easy to get caught up in the comradery and sense of purpose of situations such as these, and sometimes out of hours work can be unavoidable. But if it is the norm then it is not something to be applauded or be proud of, it is a sign of deep seated problems that need to be addressed.

The first thing that should be discussed after some heroic effort is how can we never, ever have to do that again? Appreciation needs to be shown but people and teams should not be commended or patted on the back for spending 18 hours babysitting a data migration every month for the last 6 months, it is a failure pure and simple and it needs to be addressed not lionised.

Experimentation not chat

So we’re currently adding some improvements to contract testing in our solution. We noticed last year that we were in danger of creating a ‘distributed monolith’ where we felt our components had become tightly coupled and we didn’t feel confident releasing them individually. So we put together a basic contract testing solution started using it in a few places.

The results were an increase in confidence of our deployments in the areas it was being used, this has spurred us to improve it and start to roll it out wider.

The point is that we saw a problem, we tried a solution and then we improved upon that solution. We didn’t start a working group, we didn’t spend weeks discussing options, we didn’t talk about it and never do it, we tried something got feedback and then tried something else.

Learn from actual experience, it’s better to be discussing something you’ve done that’s failed than something you have yet to try.

Change is our only constant

A release of software is a snapshot of a system in constant flux, software is a process that needs to be managed not an artefact to be protected. A team should be striving to understand the best and safest ways to manage and control change, not stifle it.

We should be constantly seeking new ways of doing things and instigating incremental processes to prevent ourselves and the software becoming stagnant.

We recently over many months migrated a Javascript solution to Typescript a bit at a time.

A member of our team has recently been doing a stirling job of upgrading our solutions to .Net 6. He figured out how to multi target our solutions to different frameworks which has allowed him to gradually migrate a solution at a time while leaving everything else working.

Another team member rewrote and overhauled our installation scripts when he got a new laptop because he wasn’t happy with how they were working.

By engendering a culture that embraces change you encourage the team members to innovate and find ways to make that change happen, in every situation look for the angle to make change happen, the do it and give permission for those around you to do the same.

We’re only human

Everyday we try to live by the above and everyday we probably mess up. That’s fine, these are what we aspire to but at the end of the day we are fallible human beings (obviously when our machine overlords take over everything will be fine). The important thing is we have something to aspire to, we have defined to ourselves what we think good looks like and then we try to live up to it.

When we invariably fall flat on our face we have something to hold ourselves accountable by and a measure to check our success or failure against.

Remember there are no experts, there is only us.

Conclusion

The rules above were created to serve a specific purpose. I was stepping up to take leadership of a team that was open to or already following the rules above. I’d already been a member of the team for a year prior to being promoted so I knew everyone in it. My aim for codifying the rules was primarily to give the team something concrete to define themselves by and make it clear what the expectations were when anyone new joined.

I do think the rules are generic enough to be applied to most teams, they’re really just codifying best practice, but if I took leadership of a new team and slapped those rules down on the first day I would expect to be more likely mobbed not hugged.

How the above is applied and introduced would really depend on where the team is currently at, is it a team or a collection of individuals? Are they stable or constantly fire-fighting their mistakes?

For instance telling a group of developers that are entrenched in a test after mode of working that they now have to write all their tests first would be carnage. You have to build the workflow of red, green, refactor as a skill and without guidance people would soon start sneaking back into old habits.

A better approach would perhaps be training and mentoring with small groups to build a core of people who get it and who can then begin to propagate out, or bringing in people from outside the team to aid transformation. This is similar to the dev ops model or a facilitation team defined in Team Topologies.

Whatever the approach I have found that the above principles have become a core part of how I approach running my team and how the members of the team approach what they do. They are not always referred to directly but I can see everyday how they permeate the team culture and drive the decisions that we make.

I would encourage any of you to really think about what your team values are and if they are not defined to go through an exercise of doing so, you maybe surprised at what you find.

--

--

Adam Lammiman

Making software is a creative pursuit, not just a technical exercise. Exploring the best techniques for its development.