A while ago I was supporting a company that offered a digital platform to small and medium-sized business in a specific industry. Great people, interesting ideas — a very enjoyable experience.
This platform was composed of independent products which were connected only very loosely. Some of these products were also marketed to customers independently of this platform.
Greater flexibility, greater inconsistency, more duplication of effort
This approach provided great flexibility to the company and its partners, independence and perhaps even a friendly and good-natured competition of ideas and approaches. However, these products (or services) provided very different experiences to their users — in terms of visual design, but also in terms of interaction design, terminology, data structures etc..
This could be considered to be largely acceptable as users understood (at least to some degree) that different products were used by this platform, but a higher degree of consistency would likely have been appreciated by users. However, that company also experienced a higher degree of feature duplication than would have been acceptable in any of the initiatives I’ve worked before.
Trading consistency for team effectiveness and efficiency?
More cohesive platforms (products, services, applications, whatever), or platforms that are desired to be perceived as more cohesive by users, can be negatively impacted by much subtler inconsistencies than the ones I described above. Avoiding these inconsistencies while maintaining team effectiveness and team efficiency is what this discussion is all about.
There seems to be a broad consensus that many types of software are best built and developed by cross-functional, self-organizing teams with about five to nine members using lean and agile approaches. (There are types of software and problem domains that require different approaches or need to be supplemented by additional practices, for example in health and safety related domains. I don’t focus on these here.)
Much software requires more than a single team to build and run. At this point, a decision on how to shape these teams and which responsibilities they take on becomes necessary. This decisions will have a significant impact on how the teams work, on how they collaborate and communicate with each other, and on the results they produce.
Teams shaped by functional domain
The common approach seems to be to organize teams by feature or functional domain. In this case, the teams would cover the full technology stack from front-end via services and application down to databases, storage, integration and compute infrastructure. This is certainly better than organizing teams by software layer such as user interface, application logic, underlying domain logic, and the data access layer.
In an e-commerce context, one team might take responsibility for product browsing and selection while another team might be responsible for the checkout process. A third team might take responsibility for account maintenance.
This might look something like this:
This is not unreasonable when we look at a single web application — but it may not be without problems even in this limited case. Great care needs to be taken so ensure that the boundaries between these teams do not lead to observable boundaries between these features or functional domains. For example, we do not want the user interface to subtly change when moving from product selection to checkout. (Think Conway’s Law.)
Going further, how does this approach scale to different client apps and interfaces? What if we want to add an iOS app? An Android app? Plus a public API? And support for voice assistants?
Adding people with the necessary skills to the teams is likely to cause the teams to grow beyond a reasonable size (even if individual team members are skilled in multiple areas). And the problem of ensuring integrity in these client apps and interfaces multiplies with the number of apps and interfaces.
App teams and service teams
To me it seems beneficial to separate the responsibilities for the client apps and interfaces from the services (or components) providing functional capabilities (i.e. managing access to data, implementing calculations, or implementing a business interaction such as placing an order).
This might look like this:
This allows app teams to focus on their users, the context they live and work in, their needs and preferences. Ensuring experiential and structural integrity within a single app becomes easier. App teams can also develop deeper expertise in the app-specific technology stack (e.g. web front-end vs. native mobile front-end vs. API management infrastructure).
Similarly, teams taking responsibility for services (or components) in a functional area can develop deeper expertise in this functional domain (e.g. pricing, order fulfilment, or product configuration). These teams can also develop deeper expertise in their service-specific technology stack.
Broad and shallow vs. narrow and deep responsibilities
I view app teams as having broad yet shallow responsibilities while service teams have narrow yet deep responsibilities. This refers to the breadth of functional scope and the depth of the technology stack. (I do not imply that app developers are somehow less technically adept or that their work is less technically complex than that of service developers. But in order to display a price to a user I do not have to know how to determine that price. And in order to determine that price I do not have to know when and how to effectively display that price to a user.)
I envisage these broad app teams and the deep service teams like this:
This approach to organizing teams requires collaboration between the app and the service teams to design and evolve the service API. We replace informal collaboration between team members (e.g. those focused on the UI and those focused on service implementation) with formal cross-team collaboration on an interface. This collaboration on the interface also ‘pays’ for mitigating the risk of friction at the boundaries of different parts of each app.
In this context, I’m thinking more about data-centric services (probably with a fairly generic and perhaps somewhat coarse-grained interface) rather than fine-grained RPC-style functions dressed up as a not-quite-RESTful JSON-over-HTTP interface. This should lead to increased stability (i.e. reduced volatility) of the interface and simplified dependencies (i.e. coarse-grained rather than fine-grained dependencies).
This is not “separate teams per software layer” — I think
So, I’m not — at least I don’t think I am — naïvely advocating for removing the UI layer from the application component, and thus advocating for a minimal form of separate teams per software layer. Instead, I view the different client apps and public APIs as individual products. I think that these products need to be product-managed. Similarly, I view these underlying functional services as products. The sum of their interfaces form an API (potentially, an internal API) which I view as another product. These products need — and deserve — to be product-managed, too.
What’s wrong with this?
And now, considering that this approach does not seem to be widely discussed, the Gretchenfrage: What am I missing? Why doesn’t this make sense? What would be a better principle for organizing teams in such a setting? Why is the team-by-feature approach superior?
I typically work for medium-sized to large companies building B2C, B2B or B2E products. Building significant features or functional capabilities typically requires collaboration and alignment with multiple groups within in the company. Such capabilities often depend on additional systems beyond the team’s control. YMMV.
As a bonus, the diagrams in this post show clearly that there is a difference between a visual designer and a graphic designer. Ah, well…