What we learned building Koan’s MS Teams integration
When the dust settled in 2020, MS Teams wound up sitting somewhere near the top. Microsoft’s collaboration tool was a smash hit with remote teams and a massive opportunity for developers — including our own team at Koan.
Maybe you’re building your own integration. Maybe you’re just starting to think it over. Wherever you’re at on the journey, here are the most important lessons we took home from integrating Koan with MS Teams.
Work happens where it happens
Ever lost track of a goal?
If there’s one thing we’ve learned building Koan, it’s that goals require transparency and engagement. Goals that get lost aren’t achieved. It’s as simple as that.
Koan’s original user interface is a React.js web app. It’s still the platform’s most fully-feature UI, but there’s a catch: for team members engaging with one another’s progress, finding the right tab in a busy browser bar is one more obstacle to engagement — and bad news for a startup built around product-led growth.
Recognizing this, one of the first integrations we built uses rich messages and Dialogs to connect Koan to Slack. The feedback from teams using it has been almost universally positive. Integrating status updates with the natural flow of conversation builds alignment and helps keep everyone informed.
Why integrate with MS Teams?
Not every team uses Slack, however. For organizations already invested in the Microsoft stack, for instance, MS Teams is a natural alternative.
Though we had long planned to mirror our Slack integration in MS Teams, the early days of the COVID-19 pandemic gave the project new urgency. Customer requests for new integration ticked up. Our roadmap shifted to make way. We just needed to figure out how to build it.
Many roads lead to Redmond
From a development perspective, Slack and MS Teams have much in common. Both provide basic chat and video-calling functionality. Both expose public, event-driven APIs. Both have toolkits for more elaborate forms and custom interfaces. But while Slack’s API has its nooks and crannies, Teams is loaded with different paths towards similar ends. That means:
- Many different tools for building UIs
- Many different layers of permissions (and obtaining them)
- Many different IDs/references, sometimes for similar objects, across both MS Teams and the Graph API
Consider authorization. Koan’s entire strategy as a product-led startup relies on lowering barriers to entry. Asking a new user for a wall of permissions sits somewhere between “bad form” and “a complete non-starter” — but obtaining permissions progressively means handling different state of authorization and adds considerable complexity to the installation process. Even our relatively simple case required us to:
- Use the
/.default
scope to obtain an administrator's blessing to send notifications proactively (outside of conversations initiated by MS Teams users). - Obtain a team lead’s blessing to list the Teams and Channels (
Channel.ReadBasic.All
andTeam.ReadBasic.All
) Koan could integrate with.
Implementing additional behaviors means obtaining more permissions and adding more complexity to the mix — and we haven’t even started building the application yet!
On one hand, options mean flexibility. On the other, identifying the functionality we needed to implement (typically more than we wanted to implement, but less than we could have) proved a recurring challenge throughout the integration project.
Simplifying Development
Perhaps the biggest challenge building for MS Teams, however, lay in translating our Slack-inspired mental model into MS Teams’ terminology. While our day-to-day work continued in Slack, preparing for the project involved spinning up a test channel, inviting our team, and spending hours poring over Microsoft’s documentation. But an abstract understanding of an API is no replacement for practical experience, and we quickly turned to the implementation.
#1 Prototype first, commit later
“In the beginner’s mind there are many possibilities, in the expert’s mind there are few.” — Shunryu Suzuki
Building for the ages in an unfamiliar problem-space is a recipe for disaster. As with most of our projects at Koan, our very first goal was to walk the “happy path” from setup to activation, ensuring customers could onboard with as few surprises as possible.
The result was about as far from a fully-featured app as it gets. Hard-coded IDs and OAuth tokens? Callback hell? You name it, we did it.
We didn’t get invested, at least not in the beginning. We proved the concepts we needed to prove and learned as we went. Then we threw it out and started over.
#2 Listen for everything
Conversational APIs are — sorry — chatty. From our experience with Slack, however, we knew that studying the chatter coming over the wire during manual exploration would help us get the hang of the API’s ebbs and flows. While most of the incoming messages amounted to interesting trivia, certain types of messages included the user IDs, conversation handles, and cues needed to implement subsequent actions.
Our integration didn’t need to handle every inbound message, but during development verbose logging was enormously helpful.
#3 Study, code, debug, repeat
When we built our Slack integration, we followed the time-honored formula for Building Against Someone Else’s HTTP API: study, mock, test, repeat. Minimizing the manual cycles of setting and resetting permissions, roles, and data in service of different test scenarios enabled much faster iterations — and left us with a confidence-inspiring test suite, to boot.
Our work over, through, under, and around the various layers of abstraction in MS Teams’ libraries and SDKs complicated this approach, however. The vast majority of project time came down to learning how to use Microsoft’s Bot Framework SDK; learning the concepts beneath it; and making sure that real-world experience aligned with the claims made by the various type declarations, reference code and documentation we were able to find.
As one example, we were excited to use the Graph API’s TypeScript type declarations to simplify development of identity and profile features. Koan’s platform has benefited greatly from TypeScript, but we were surprised to discover material drift between the documented types and the real-world behavior of the API. No harm, no foul — documentation always lags reality — but the lack of reliable types meant more time studying and verifying behavior.
Ultimately, the indirection made (admittedly painful) manual testing more attractive than spending time automating scenarios we didn’t yet understand.
That’s learning for you, though. Sometimes it hurts.
#4 Adapt to the platform (and not the other way around)
“Give us courage to change what must be altered, serenity to accept what cannot be helped, and the insight to know the one from the other.” — Reinhold Niebuhr
Software interfaces separate different philosophies and design principles. This is particularly true when integrating between platforms — Koan, say, which we have some agency over, and MS Teams, which we don’t. We came into the project intending to build an integration roughly equivalent to what we had with Slack, but found considerable divergence (and complexity) integrating with Microsoft’s APIs.
One example of this came from the product requirement to send proactive messages when our integration was installed. The good news is that it’s possible, and we did. The bad news is that we sunk a lot of time into functionality that in some ways swum upstream against the main flow of the platform.
Conclusion
Like every development project, parts of the integration came together more smoothly than others. While our past experience working with Slack and our own applications provided some helpful context, MS Teams is a distinct service that took some time to understand — but now an excellent way to engage with Koan!