Loose Coupling and High Cohesion in Teams

Most software engineers are familiar with the OK design principle of loose coupling and high cohesion from the Gang of Four Design Patterns book. I have been reflecting on my experiences leading teams while reading Leading with Honor by Lee Ellis and realized a correlation of this same principle for high performing teams.

Highly coupled teams are like an assembly line. Everyone is specialized, and everything moves along well until something breaks. In a team with low cohesion, the only ones who can fix the break are those responsible for the area of the assembly line that broke, which means most of the team is not working while the problem is identified and fixed. If a team has high cohesion, then some members can switch roles to help out with the area that is broken, but the rest of the assembly line is still stopped.

Highly cohesive teams are those that have high collaboration with one another and typically are composed of members with different specializations. Everyone can contribute to any part of the work. If the team is highly coupled, however, then the loss of one team member or the need for that team member on any given task causes the rest of the team to grind to a halt while waiting on that team member to free up. A loosely coupled team can continue working on multiple tasks concurrently with no hard dependencies on any one person.

Much like in software, my experience suggests highly cohesive but loosely coupled teams are far more efficient and effective at achieving their objectives. I’m curious whether you’ve had a similar or different experience, and I’m interested in any research on this topic. Please share in the comments.


Blazor Server Tip: Sometimes you need Task.Delay(1)

I recently encountered an issue with server-side Blazor in which the UI didn’t refresh after calling StateHasChanged. The UI refreshed just fine until I added about 30k more records to a database table, which caused a query to take a bit longer to run. I filed an issue here.

I debugged through the issue by trying different things like using an in-memory data store, re-checking against a smaller data set, and wrapping StateHasChanged to make sure it was actually called. Everything was working as expected with the in-memory store and smaller data set, and StateHasChanged was always called. However, with the larger data set, the components’ lifecycle methods were not called.

I finally stumbled upon a solution using an old JavaScript trick: adding await Task.Delay(1); This magically worked. If you run into something similar, you may try await Task.Delay(1); and see whether that resolves the issue.