A collaborative approach to software development

Luca Strazzullo
10 min readMar 24, 2020

--

Software development is a discipline that every member of a multi disciplinary team contributes to, no matter what specific role they have.

In a well functioning and successful team, every member actively contributes to engineering, design, product management, product ownership, data analysis and so on.

In doing so, every member contributes to the development of the software. Software is after all the reflection of the whole company (software company)

Few years ago, when I joined my first team at ustwo, I was captured when I read on the team principles board the following: everyone is willing to at least try.

I immediately realised what it meant when I saw software engineers that would join user interviews or sketching sessions along with business analysts and key stakeholders at some times. Designers and product managers that would help software engineers to solve tricky problems on a whiteboard or with a simple google search. Every single person deeply cared about each other’s challenges and areas of knowledge.

Obviously they all had their own roles and levels, every team member had a deeper knowledge and experience in their specific field relatively to each other, however each team member had a conscious understanding and proactive involvement in every aspect of the product development.

I had the great fortune to witness and collaborate with a few great teams. I feel very humbled to have worked with very talented and extremely collaborative product people.

The main feelings for me in such a team are continuous learning, fulfilment and love.

I recently made up the following metaphor which helps me define a great team:

Great teams behave as if they were an orchestra. Although each member plays a different instrument, they all play the same song. They all help each other in having their best performance.

Every instrument works in harmony with one another. Sometimes the guitar comes in and takes on some space for a solo, while all the other instruments lower down in volume and/or rhythm complexity. Sometimes the piano steps in, or the harmonica, or the voice.

With this post I’d like to share with you a few principles that I extracted along the way.

My main goal is to get you inspired about great collaboration and the beauty of being a servant for the purpose of the product you are building.

I’ll try to take it mostly from a software engineer perspective and highlight how these values and principles have an impact on my core discipline which is software development, and how eventually impacts the team, the user, and eventually the business.

Be Servant

Every decision that I make on the codebase has an impact on: my future self, my team, the user, the business.

This is probably the most important principle for me. It conveys the whole meaning of being part of a team, of making impact on people, whatever decision I make has an either negative or positive impact on users, customers, team mates, and even my future self.

Let’s make an example:

I write software. I’m part of a team.

Very early in the development stages, I need to make a decision: do I put effort into writing self explanatory software, with good attention to details such as meaningful naming, balanced horizontal and vertical space, clear and communicative architectural structure … or do I write viscose and hard to read or even misleading code?

In the short term, it’s probably “more intuitive”, if my goal is to go “fast” (I.e. get stuff done as soon as possible), that I don’t put much care on details and it’s very easy to tell myself a classic excuse: don’t put too much effort on code communication, we need to release! Or something along those lines.

However, let’s look at the same problem based on the ”be servant” principle. Let’s see what being servant means in this context.

Let’s do it by applying a user centred approach to the problem.

Who’s the user in relation to my software’s readability? Most likely it is gonna be myself or obviously another (current or future) member of my team!

So I put conscious effort to empathise with the next person who’s going to work with what I’m writing right now. As software engineer, I do know that an easy to read and understand codebase makes me work way faster than if I had to work on a viscose, hard to understand and intertwined codebase.

And here’s the magic. I completely shift my perspective: I’m not writing software because I’m a software engineer and that’s what I’m supposed to do: get stuff “done”. I write software to serve a bigger purpose. I write software keeping in mind that there will be a user for my code. There will be the next person who’s going to make a change to what I wrote soon or later.

Now, imagine the feeling of being part of a team, where every engineer writes software with the aim to make your life easier when it’s your turn 😌

Imagine how “low” the cost of change would be, if everyone works on building capability for everyone else to make a change faster!

Imagine how it would impact the user, when we discover that their needs have changed, or we learn something new about their needs, we can adapt faster.

The idea of being a servant obviously expands way beyond the code readability and the software itself, it goes all the way across the whole company, this is just a little example to highlight how much deeper this principle can be effective.

Keep it simple stupid

Product development is a complex world and particularly software tends to become complex as it grows. Acknowledging that, is a very good first step.

The next step is to tame that complexity in a conscious and diligent way.

One of the overarching goals for the team is to keep the cost of development and therefore the cost of change as low as possible.

By keeping things simple and building just enough process, structure and solutions to solve the current problem and defer unnecessary work (eliminate waste), the risk of investing more than what was really needed is very low.

It enables the team to keep control over the system with a higher focus and aim for stability by being able to easily predict, with a good enough accuracy, the consequences of the decisions over the product.

This principle applies to many aspects of product development. It applies to team processes and tools for example.

The more complex a process is, and the harder it is to grasp, the more friction there will be in the team members to get along with the process, and also to maintain it.

Think for a moment that each team member has their own perspective on tools or process choices, they all have their own reality. Alignment becomes a huge effort, confusion starts overtaking, and the focus of the team shifts from being a servant and building a product that would change the world, to a continuous attempt to fix their process.

The worse that happens sometimes is that the “obvious” solution seems to nbe to add even more processes or adopt more tools and add more process.

A good way to avoid this scenario is to constantly reflect back on processes and tools that are currently in place, and ask a very simple question:

“what is this tool or process solving right now?”

The keyword here is ”right now”.

Although it might have been something that solved some problem in the past, it might potentially be the case that it’s just legacy.

So if the answer is “nothing”, then that’s a great reason to get rid of that tool or process or solution immediately.

If the answer is “it solves problem X”, then the next question would be:

“Is there anything we could do to solve the same problem in an easier way?”
Or “do we already use a tool or a process that can also solve this problem?”

The goal is to get rid of waste. The goal is to go down to the simplest possible process and tools that are good enough to solve the current problems.

So look back with the aim to remove before even thinking to add.

Again this is just an example of how this value applies to collaborative product development, it obviously applies to the way we solve problems for our users from a visual and experience design perspective, to the way we implement solutions from a software design perspective, to how we manage the project.

Be inclusive, be transparent

Ambiguity is another tough beast in product development. Ambiguous situations create chaos, amplifies misalignment, lead to uninformed decision making or even worse irreversible decision making.

One great way to fight ambiguity is to be extremely transparent and inclusive.

One of the most powerful ways I like to approach the decision making process on software design is to include and involve every team member into critical design decisions rather than constraining those decisions only to the engineering team.

This approach pushes me to write communicative and self explanatory code in first place. The software gets easy to read and understand not only for other engineers but also for other team members.

It also brings in a few immediate advantages:

  1. A wide shared understanding of the current state of the implementation, feasibility and opportunities both short and long term.
  2. It makes it easy and accessible for the team and the business to make informed decisions on how to iterate on the product.
  3. The conversations become smooth and clear, it becomes easy and quick to get on the same page and move forward with the development.
  4. The offset between design and development gets reasonably reduced enabling the team to work on short iterations with a short feedback loop.

A beautiful example of a very transparent and inclusive collaboration is a practice that I had the fortune to experiment and develop in collaboration with a couple of designers on two different projects.

We called it Design in Code.

This practice shares the same principles of pair programming. It focuses on the user interface and experience, creating shared understanding and ownership across the wider team.

A designer and a developer sit next to each other in front of a machine, tweaking and finalising the UI straight in code rather than passing documents such as Sketch files or PDF around between the designer and the developer.

The best way I could come up with in order to involve a designer in this practice for the first time is to tell them: I’m your design tool :)

In addition to a shared understanding and ownership, it increases the capability to build the final solution in response to the learnings gained from an instant feedback.

By looking at the real result on a real screen or multiple screens, they can adapt the solution on the spot, and most importantly they both know the rationale behind the final solution. They both know what trade offs they took and why. They both know what’s the current state of the codebase. They both understand better each other’s challenges and languages.

Now imagine when this happens on a regular basis within a team. Imagine how the expectations are aligned across the whole team. Imagine how smooth it would be to estimate future implementations based on the experience that they gain in working together on implementing the UI right in code!

Learn big, iterate small

One of the best qualities I’ve found in great teams is the ability to learn fast and learn a lot, then make small iterations and learn again.

The more iterations, the shorter the feedback loop, the higher are the chances that the team moves towards the “right” solution.

Small iterations are a good way to keep the software flexible and maintainable. Each iteration involves refactoring. Continuous refactoring leads to a very fluid design, cohesive objects, separation of responsibilities, better decoupling, and to a tailored abstraction.

Most importantly it supports pragmatism, it highlights the areas of the software that need most attention and higher design principles conformance, as well as areas that are most likely to remain the same and therefore need less conformance. Which leads to efficient decision making when it comes to define trade offs and balance costs.

Small iterations allow the team to test feasibility, desirability and usability quicker, and gives a clearer sight on the path to follow to solve users problems.

It helps to maximise the work not done, which means spending effort on the work that has higher chances to make positive impact first to the user and eventually to the business itself.

Most importantly it allows the team to learn fast and big. Having a potentially shippable product as result of a small iteration means that we have options:

  1. We could release into the wild and learn from real users.
  2. We could start testing the end to end solution internally (or we could just go down the street and literally ask people around) and learn from it.

While we learn, we also have options on what to do next:

We could prioritise and work on something else because we learn that the iteration we just released is good enough for the problem we’re solving. And we want to solve another problem or learn on a different area of the product.

We could learn that the solution we’re building isn’t desirable or that we were trying to solve the wrong problem. So we can discard that path altogether and focus on something else that might give better chances of success.

We could learn that the small iteration which we have released is actually solving multiple problems that we hadn’t anticipated, or it can be reused for other solutions we have in the backlog.

Conclusions

These are the principles that I learned and boiled down to along the time spent as being part of great teams:

  • Be servant
  • Keep it simple stupid
  • Be inclusive, be transparent
  • Learn big, iterate small

They resonate with me because they are based on values which are part of me and I can’t live without, values that gravitate around quality and creativity, people and interactions and deep care.

I hope that some (if not all) of them resonate with you and inspire you with your current or next project.

--

--