When Klunky Component APIs Show in the UX
At various times, the behavior of Facebook reveals to me that it’s a loosely coupled system with long latencies in synchronizing its various data stores. Just today, the iOS app asked me to confirm a friend request. When I did so, it gave me a pretty generic error—something about not being able to do this action at this time. That’s when I realized that I’d already accepted that particular friend request, days ago. That tells me that there are often inconsistencies between the database used with one interaction, and the one used with another interaction on another interface.
It also tells me that there are likely teams working on components, rather than features. If it was a feature team, the need for an error message would have driven a different underlying implementation. A feature team would want to differentiate between not being able to accomplish an action because it was already done, and because some problem was blocking it. For the former, there’s no need to show an error at all.
Instead, I can imagine they’re using some sort of “friend accept” API written by another team. That code either performs the acceptance, or reports an error. From an implementation point of view, not being able to perform the acceptance because it’s already done seems very similar to not being able to do it because the request has gone away, or the database can’t be contacted, or any other reason. This is a common problem when looking at things from an implementation oriented point of view.
When one team is developing the whole implementation stack for a feature, they’re more likely change the interface to suit the needs of the user of the interface. This may be aligned with the interactions of a person, or it may be aligned with the needs of another component. In either case, the capabilities of a component should be provided in ways that make the most sense for consumers, not the provider. If this is not done well, the team developing the consumer code will likely reach for the Adapter Pattern or Mediator Pattern in order to make it look, as far as possible, as if the implementer team provided a consumer-oriented API. Such an adapter can isolate the consumer from idiosyncrasies of the provider and provide a cleaner, easier to use API, but it can’t make up for lack of information.
It may be that I’m reading too much into this, and the situation is different than I imagine. There are many ways to screw up the design of software such that the deficiencies are noticeable from the user interface. The observed facts are consistent with the problems I’ve seen internally to code that I’m not at liberty to reveal.
- Pay attention to the user experience, particularly in the face of error conditions.
- Evolve component APIs, as needed, to support the needs of client code.
- Try to develop full-stack features, rather than dividing up the work in component teams. Use a hybrid if you need component expertise.
- If you can’t do that, collaborate across teams to enhance existing APIs to better support the consumer’s needs.
- As a consumer, isolate your code from the implementation using an adapter if the implementation doesn’t provide an API tuned to your needs. This adapter can do the translation that’s necessary, even making multiple calls, if needed, to get the information to better report to the user.
There’s more to software development than writing instructions the computer can understand.