paint-brush
Orchestrating the Code Maze: Strategies for Effective Collaboration Amongst Development Teamsby@prkhtsk
408 reads
408 reads

Orchestrating the Code Maze: Strategies for Effective Collaboration Amongst Development Teams

by Artem ProkhatskyiApril 8th, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Poor management of several development teams can lead to duplicated work, inefficient use of resources, and misunderstandings. To address these challenges, a clear system of communication and interaction between teams needs to be implemented. Introducing regular meetings between team leaders, using shared project management tools, and organizing corporate events to strengthen team spirit are crucial steps.
featured image - Orchestrating the Code Maze: Strategies for Effective Collaboration Amongst Development Teams
Artem Prokhatskyi HackerNoon profile picture

Typically, when we discuss team management in the IT context, our focus tends to be on a single team. We define the optimal team size, select the necessary specialists, and ensure effective communication among them.

The problem

As companies grow in success, their functionality expands, and so do their development teams. It is then we encounter challenges that often go unnoticed by team leaders: issues of inter-team interaction and communication. The increase in the number of teams and their functions can lead to duplicated work, inefficient use of resources, conflicts, and misunderstandings. Communication becomes more complex, especially when teams work on interdependent parts of a project.


To address these challenges, a clear system of communication and interaction between teams needs to be implemented. Team leaders should not only identify and resolve conflicts but also ensure proper coordination and support among teams. Such an approach will allow for the successful implementation of large IT projects while maintaining high company efficiency overall.


The importance of interaction between teams cannot be overstated, as it not only facilitates efficient task execution but also fosters innovative solutions through the exchange of ideas and experiences. Introducing regular meetings between team leaders, using shared project management tools, and organizing corporate events to strengthen team spirit are crucial steps.


The root cause of the problem

Let's examine the nature of these problems. Consider the typical issues of such interaction through the example of a company developing a large e-commerce portal. We have many cross-functional development teams, each responsible for a specific part of the project: one for the shopping cart (Product Cart Team), another for the product catalog (Product Catalog Team), etc.


Team Responsibility Diagram


This setup looks quite standard and acceptable. Each team has its product owner and works on its services. However, it's clear that the work of the teams cannot be completely isolated from each other. There are often certain integration points or services used by several teams. The simplest and most logical solution is to define a common responsibility for this code. That is, we can all make changes to these services, so we all are responsible for this code. Unfortunately, this strategy works very poorly in the long term. A phenomenon known as "the tragedy of the commons" comes into play.


This phenomenon occurs in a situation where many individuals, whose actions are independent, rational, and solely in their interests, deplete shared resources, even though each of these individuals is not interested in such a scenario happening.


Projecting this onto the code of your service, it's likely to "smell" because each team will be adding functionality that only they need. Functions will proliferate, the amount of unused code will grow, and the structure will become disorganized, among other issues. In simple terms — services with shared responsibility are orphans with no parents.


How to deal with the tragedy of the commons

Thus, we can conclude that components with shared responsibility cannot exist in our codebase: each segment of code should have its specific owner.


A new problem arises: imagine that the Product Cart Team needs to make changes to the Product Catalog page. For example, we want to add a cart thumbnail next to the catalog filters. Let's consider possible solutions to this problem.


Team Responsibility Diagram with orphan codebase


The classic method of solving this involves creating a task in the backlog of another team. In other words, the product owner of the Product Cart Team initiates a task in the Product Catalog Team's backlog and waits for its completion. This solution seems logical but hides numerous potential difficulties.


Since the task is a priority for another team, the product catalog team may not rush its completion. Therefore, the product owner will have to regularly remind them of the task's priority and clarify the status of its execution.


It's also obvious that the Product Catalog Team will have to interact with system elements better understood by the Product Cart Team. Thus, the development process slows down even more due to the need for constant knowledge exchange between teams, which, although beneficial, is suboptimal in this context.


The approach of the “trusted expert”

The first option involves creating a task within the team whose product manager has developed the specification. That is, in our case, the Product Cart Team of the product initiates a task for integrating the product card into the product catalog. However, the Product Cart Team does not own the codebase of the product catalog, and if its developer starts making changes to the catalog, this will lead to a situation akin to shared responsibility, carrying all the risks and problems described earlier.


To solve this issue, we can suggest a developer from the Product Catalog Team temporarily join the Product Cart Team. This will allow the Product Cart Team to share knowledge more efficiently, and the changes will be made by a team member who owns the codebase of the catalog. The entire process will take place within one team with minimal impact on the operation of the catalog team, except for the temporary absence of one developer.

"Trusted Expert" approach

This practice can be applied to all the company's teams, regularly rotating specialists among teams. A detailed rotation schedule for adjacent teams can be created to improve knowledge exchange and increase overall awareness of the company's codebase. This will not only facilitate more harmonious cooperation between teams but also increase project management flexibility, as each team member will have a broader overview of the company's projects and be able to interact more effectively with different parts of the codebase.


Embed a developer

The second option, similar to the first, involves reversing the order of actions. The product owner of the Product Cart Team creates a task in the Product Catalog Team's backlog, and one of the developers from the Product Cart Team temporarily becomes a member of the Product Catalog Team. This approach also ensures knowledge transfer between teams while adhering to the principle of strict responsibility for one's code. The main advantage of this option is that the task is solved by the responsible team, which is more likely to ensure a higher-quality code review process. However, a significant drawback is the execution of the task by a team that is not the customer of the functionality.

"Embedded Developer" approach


Documenting of responsibilities

Another important aspect is control over code ownership. If we’re using multiple repositories, identifying the team responsible for a particular repository is straightforward – this can be indicated in the README file. However, in the case of using a large monorepo, an effective solution would be to create a detailed CODEOWNERS file.


# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
# @global-owner1 and @global-owner2 will be requested for
# review when someone opens a pull request.
*              @global-owner1 @global-owner2

# When someone opens a pull request that only
# modifies JS files, only @js-owner and not the global
# owner(s) will be requested for a review.
*.js           @js-owner

# You can also use email addresses if you prefer. They'll be
# used to look up users just like we do for commit author
# emails.
*.go           [email protected]

# Teams can be specified as code owners as well. Teams should
# be identified in the format @org/team-name. Teams must have
# explicit write access to the repository. In this example,
# the octocats team in the octo-org organization owns all .txt files.
*.txt          @octo-org/octocats

# In this example, @octocat owns any file in a `/logs` directory such as
# `/build/logs`, `/scripts/logs`, and `/deeply/nested/logs`. Any changes
# in a `/logs` directory will require approval from @octocat.
**/logs @octocat

# In this example, @doctocat owns any files in the build/logs
# directory at the root of the repository and any of its
# subdirectories.
/build/logs/   @doctocat

# In this example, @octocat owns any file in the `/apps`
# directory in the root of your repository except for the `/apps/github`
# subdirectory, as its owners are left empty.
/apps/         @octocat
/apps/github

# In this example, @octocat owns any file in the `/apps`
# directory in the root of your repository except for the `/apps/github`
# subdirectory, as this subdirectory has its own owner @doctocat
/apps/         @octocat
/apps/github   @doctocat


We should not forget about the value of knowledge transfer between teams. Therefore, I would recommend conducting periodic rotations of developers between teams, even without a direct need for it. This will not only increase the developers' interest in their work but also make all team members truly cross-functional.