Software Developers, Code Should Not Be Your Only Point of Collaboration
We tend to learn to code at first as a solitary activity; at a keyboard, alone with our thoughts.
But if coding eventually becomes part of our day job, it’s more likely we’ll be developing software together, as a team. This is a very different undertaking yet, for some reason, we don’t seem to see it as a skill to be acquired in quite the same way as coding.
Perhaps as a result, I’ve noticed that software teams often fall into the trap of collaborating in a few somewhat restrictive ways, maybe because they never learned others. They focus on things that make their collective success feel more likely but which, counterintuitively, can actually make it harder to achieve working software with happy, engaged users.
If you bring a bunch of software developers together, you might notice that we like to discuss the concrete, tangible, visible aspects of our projects. We talk about things we can actually show and point at: code, data, demos, prototypes and visuals such as user interfaces.
Which is strange, if you think about it, for people who spend all of our time building software, which is essentially invisible in its execution… other than its side effects.
Maybe it’s understandable, particularly for developers who began their journey in software via the “Learn to Code” route where code was, by definition, the main focus. Showing working solutions was what mattered. Talking about what you were about to build, less so.
But I’ve found fixating on code and concrete things to be be somewhat limiting, when it comes to writing great software together. Maybe counterintuitively, it restricts our ability to home in on innovative solutions to the very problems we’re trying to solve.
We might feel that focussing on code is closer to solutions, but it often leaves us with less-than-ideal implementations we’re reluctant to change once they exist (attachment), or find hard to change sufficiently to reflect better choices (limits of refactoring).
BUT WE’RE ULTIMATELY GOING TO WRITE CODE, SO WHY SHOULDN’T WE TALK MAINLY ABOUT CODE?
Well, we should talk about it often. But we shouldn’t only talk about code… or UIs… or prototypes. There are some other things that we should talk about too, perhaps before we get to code and regularly as we write it.
THE REAL LANGUAGE OF SOFTWARE AND SOLUTIONS ISN’T A PROGRAMMING LANGUAGE
The concrete things we seem to prefer discussing aren’t created out of thin air: They are just the tangible, visible outcomes of a much more complex thought process — one often conducted alone and subconsciously — involving invisible, far-less-tangible things such as ideas, concepts and abstractions.
Some of these ideas are in the form of software design and architecture, which are close to code. But, well before those, we should also think in terms of the concepts and the mental model a user will bring to the system when they attempt to use it. What will they be thinking? What problem will they be trying to solve? What concepts are involved?
If we can start our discussions there, and continue talking as we work our way back through abstractions built upon these concepts, through to architecture & design that flows from them, then it’s more likely that the code we write will solve the intended problem.
And crucially, we need to move back and forth on that continuum, from user concepts to code, discussing and collaborating on what we find and revising it until it solves the problem well. That work mustn’t be conducted in solitude; it must be a shared activity, at least to some extent.
Teams that learn to collaborate throughout that continuum and on those often-invisible ideas and abstractions, rather than just code or prototypes or demos, have far more leverage to align their collective thoughts and efforts where they can be shaped more easily. They can often solve the problem in-hand more effectively at that abstract level, before and in parallel with the ideas which manifest as the inevitable tangible, brittle, less-changeable things that we get attached to, such as code.
Attachment to things that “work” (for some definition) is why software outcomes often seem to just happen, rather than being chosen. We tend to stick with what has already been built, in an attempt to “show something working”, rather than considering a broader range of possible solutions in abstract, before and while they are crystalised as code.
We tend to end up with what gets built first, rather than necessarily choosing it. And then it can be hard to refactor it sufficiently to reflect better fundamental choices.
WHAT’S SO HARD ABOUT DISCUSSING ABSTRACT IDEAS?
We seem to resist collaborating on concepts and abstractions. Why, when they seem to be a much more powerful focus to align on as a group?
Ideas, when compared to code or architecture, can seem fleeting and ephemeral. We can’t point at them. We can’t put them down and pick them up again tomorrow. We can’t easily share them.
It is far harder to demonstrate the validity or correctness of a mere idea, unlike working code or an architecture diagram. Two proposed ideas might both sound sensible, but figuring out together which one stands a better chance of success requires discussion and hand waving… and potential disagreement.
It is hard to communicate ideas so that everyone has the same understanding of them. We’ve all had discussions in which two or more people were talking about the same thing yet disagreed… and, conversely, ones in which they seemed to agree but clearly had a different idea about what they had agreed upon.
And so, naturally, teams tend towards concrete things, which are easier to show, to discuss, to put down, pick up and ultimately to agree upon.
But teams who give up on abstract ideas and fixate purely on what “works” are missing a trick and a significant chance to build better software together.
So let’s learn to work more effectively with ideas?
Here are a few things that I’ve discovered often help and encourage teams to use abstract ideas at the heart of their collaboration…
NAME THEM, CONSISTENTLY
We need to name concepts with good words, agree on them and use them consistently. Call out use of the wrong terminology, or lack of it. In a let’s-get-something-built team it might be seen as “picky”, but those words are our only signposts to an invisible concept we’re trying to make use of together.
If it’s the wrong word, then change it. When all you have to point at abstract concepts are words… choosing the right ones matters.
Keep a list of key terminology somewhere central, stick it on the wall, refer to it often.
(A crucial point is that it must be possible to name the concepts we’re talking about with real words, or we have likely created the wrong abstractions. A “widget” should be a warning sign, but an “account grouping” represents something understandable)
SKETCH THEM, INFORMALLY
Sketch ideas (on paper, on a whiteboard, on a tablet), capture them (smartphone camera), share them. Re-draw them, point at them, discuss them.
Note that I’m talking about hand-drawn sketches here, not laboriously-drawn Visio or Powerpoint diagrams (which are a huge barrier to visualising ideas)… unless you’re immortalising what you know to be the final idea… but who does? You can always smarten up a sketch later, or smarten the text if your handwriting is as bad as mine, but put the early version where folks can see, point at and talk about it.
Then maybe reject it, and draw a better one.
Use sketches as a quick method to convey ideas, then improve upon them. Get used to drawing as you explain. Hand people a pen (or an online drawing tool) if they want to explain something in return. Get used to sketching as a regular part of team conversations.
I once worked at a company with no whiteboards. Needless to say, not much innovation took place there!
WRITE ABOUT THEM, CONCISELY
Compelling descriptions, not walls of text. Capture the essence of an idea concisely. Refine and remove redundant words. Make it tight, make it terse, make it use the right terminology (see earlier). Check that it is understandable to others. Include those sketches too; it shouldn’t all be text.
START WITH USER-FACING CONCEPTS, AND BUILD ABSTRACTIONS AROUND THEM
Start with the concepts that the user will understand. Real-world things. Yes, concrete things, but in the user’s world not ours. And then figure out which abstract concepts we need to introduce to describe the problem we’re solving for them, and the solution.
This is where it becomes abstract, as we plan the proposed bridge between the user’s world, our own abstraction of it, and the architecture, design and implementation (yes, code!) of a solution.
What if you have no end users, such as when you’re building an API? Then name the concepts the API will allow a connecting system to work with.
What if you’re building a backend for someone else’s UI? Then collaborate with the UI team and make sure you’re discussing the same concepts the user would understand, and visualisations / abstractions built on top of them. Be in-sync with what that UI team is collaborating on, or risk creating a fragmented user experience.
LAYER THEM, FOR UNDERSTANDING
Split them up into layers to ease understanding. Divide and conquer. Foundations first, then more complex ideas built on top.
Sometimes focussing on one layer at a time can ease discussions about abstract concepts. Being able to separate talking about one layer versus another increase the chances of everyone understanding.
Call out accidental blurring of the layers. As for use of incorrect terminology, it might seem picky but it’s crucial to group understanding.
And obviously, the layers themselves are up for debate, so get them right. Do we have the right concepts? Which concepts fit into each layer? These are useful starting discussions. The code that necessarily follows will then use the right concepts in the right places, rather than muddling them, as often happens when we fixate on code.
SOCIALISE THEM, SHARE & RISK THEM
Socialise, expose, discuss, to see if they stand up to scrutiny. Don’t be precious or protective of ideas. The sooner you find out if they are helpful and if others align, the sooner you settle on ideas that everyone can work with.
I’ve seen too many great engineers only willing to share their ideas with folks they know will agree with them. What use is that, for the overall project? You should seek out the person least likely to agree with your ideas first, to validate or reject them.
DISAGREE ON THEM & THEN ALIGN
Where disagreement occurs, and it naturally will, compare ideas more formally in table form: Candidate ideas along one axis, criteria for assessing them on the other.
This enables easy jumping around between ideas without losing context, and anyone can throw in new criteria for assessment without causing confusion. But crucially, it means everyone can see at-a-glance how the ideas stack up against one another.
Capture this comparison, use it to discuss points of disagreement, to move towards agreement / compromise, and use it to revisit old decisions later.
I could write a whole post on this topic of agreeing via tabulated discussion, it’s so unexpectedly powerful. It exposes a whole topic, no matter how complex and nuanced and disagreed upon, in a single view.
ITERATE & REVISE THEM
Ideas should be iterated upon until they seem likely to work. You won’t get them right first time… that that’s where implementation comes in, as a way to validate the ideas.
Then come back to improve upon them. Revisit old sketches, descriptions and tabulated comparisons of them (see points above). If there is new information, or facts have changed, modify what you sketched, wrote or decided. Ideas and abstract concepts are easily-changed, so take advantage of that when appropriate.
CAPTURE & REVISIT THEM
Longer-term, retain sketches, written descriptions and comparisons/decisions for posterity and context. Being able to see the ideas that led to the more concrete, tangible implementations can be helpful. Beyond mere code, ideas can explain where a product or solution came from, and why.
DOESN’T THIS RUN COUNTER TO AGILE AND MINIMUM VIABLE PRODUCTS?
We’re encouraged, particularly at startups, to get something working, to be “agile”, to work iteratively and to rapidly build a Minimum Viable Product (an “MVP”). Doesn’t that race for a working solution run counter to all this?
No, MVPs and agility remain great advice, but that MVP must still only be seen as the iterative, ever-changing end result of an ongoing collaboration and discussion that is rooted in user concepts and abstractions built upon them.
A working MVP can help to validate an idea in the real world, with paying customers… but that idea must still be thrashed out and revised at an abstract level for it to really hit the spot.
Our next iteration might not simply be a code-level mutation of the previous; it might be a complete transformation of part of it based on a change that we’ve decided is now necessary at a much more fundamental level due to something we learned; a level we’ll only be talking about if we’re able to collaborate on abstractions, not just code or architecture.
We might learn that we’ve misunderstood a fundamental user concept, or used the wrong abstraction to represent it, or we want to add some new concepts into the mix.
So abstractions have a place in the fast-paced world of startups too. In fact, they can often help us steer more rapidly towards working solutions, because we’re talking about the problem in user terms and reasoning about what to build to solve it using the right abstractions and concepts. We aren’t getting stuck clumsily talking about these things only in terms of our own code or architecture.
IN SUMMARY… LEARN TO DISCUSS ABSTRACT CONCEPTS
Collaborating on abstract concepts and ideas is a far more powerful way to achieve innovation in software than heading straight for code or even architecture at first.
We should encourage the acquisition of the skills necessary to discuss ideas, and be willing to name, sketch, describe, compare, share, capture and revisit what we can’t necessarily point at… alongside the inevitable code, architecture, prototypes, data and UIs that they lead to.
Then the software we build together might be more than the sum of our individual efforts… which is, after all, the whole reason for building it together in the first place?!