developers

Guiding Principles for Building SDKs

How to create a better developer experience with SDKs that delight developers

Mar 12, 202414 min read

When it comes to building SDKs, particularly in authentication and identity management, it’s not just about the code; it’s about crafting an experience. This is critical for SDKs aimed at popular programming languages and frameworks like Swift, Kotlin, .NET, Ruby, PHP, Javascript, React, Angular, Vue, and NextJS. A delightful developer experience revolves around providing an intuitive, idiomatic experience that allows for seamless integration with minimal code.

At Auth0 by Okta, we have over 45 Auth0 open source SDK Libraries and 35+ Quickstarts with samples, and we support 12 programming languages. In NPM alone, we have over 90 Million package downloads a month!

Having been part of that journey for seven years in roles ranging from Engineer to Director, I’ve compiled some guiding principles we use to create a developer experience that allowed us to achieve that spectacular growth – and keep growing.

Understand the Developer's Mindset

Building a robust and powerful SDK is a good start, but it's far from the endgame. To truly support developers, you must deeply understand their perspectives, challenges, and aspirations. This level of empathy requires a nuanced approach, one that goes beyond engineering excellence to focus on delivering an intuitive and delightful user experience. Let's delve deeper into two essential aspects that help you connect better with developers: building empathy and applying contextual awareness.

Empathy Over Engineering

Engineering is about solving problems, but empathy is about understanding which problems matter to developers and why. This awareness is fundamental when your target audience includes developers who engage with complex issues and often have to juggle multiple tools and SDKs.

Knowing the community

To offer something truly valuable, spend time embedded in the communities around each target programming language and framework. For example, participate in forum discussions, attend developer events or webinars, or engage with online communities. These avenues provide a wealth of information on developer needs, wants, and dislikes. If you’re fortunate enough to have a Developer Relations team, they can be a great partner in helping you learn more about the developers using your SDKs.

The developer signal

Listening to your developer community will help give you insight into pain points you should be mindful of, such as:

  • Complex installation: Developers often dread complicated setup processes because they want to get started quickly.
  • Poor documentation: A lack of clear, well-written documentation can turn an otherwise good SDK into a developer's nightmare.
  • Non-idiomatic APIs: An API that does not conform to the common practices of a language can be challenging to work with.
  • Non-intuitive APIs: An API that uses a lot of domain-specific jargon and assumes the developer must be an expert creates unnecessary barriers to use.
  • Cryptic errors: Unclear errors make it difficult for the developer to troubleshoot issues effectively.
  • Lack of flexibility: SDKs that are rigid in their functionality can force developers into workarounds, creating unnecessary friction.
  • Inadequate support: Slow or non-responsive support channels can be a serious obstacle, especially when developers are under deadlines.
  • Security concerns: With authentication SDKs, unclear methods for handling tokens or encryption can generate distrust.

It’s important to acknowledge your pain points. We take a holistic approach to tackling the overall developer experience. We quickly fix issues while deliberately evolving each SDK to reflect on the previous version and move the needle with the next version.

Contextual awareness

It's easy to underestimate the importance of feeling "native" to a particular programming language or framework. Developers are often deeply connected to the languages they work with. Beyond appreciation, developers are already familiar with the idioms and patterns of their native language or framework, which they use daily. A library that does not speak that same "language" and uses different ways of doing things requires a higher cognitive load. Reduce the load and be idiomatic.

Adapting to language conventions

When working with one language, your SDK might employ higher-order functions and optional types to align with the focus on safety and expressiveness. In contrast, another language of the same SDK might prioritize asynchronous methods and leverage dynamic typing.

Design patterns

Understanding common design patterns in each language can guide the architecture of your SDK. For instance, the Observer pattern is prevalent in JavaScript frameworks, while we often see the Model-View-View Model (MVVM) in Swift and Android Kotlin.

Testing and tooling

Remember to provide tools and scripts familiar to developers in their environment. For example, integrating with popular tools like Webpack or Babel is almost a given if you're targeting Javascript ecosystems.

By applying contextual awareness, you show developers that you speak their language—literally. It fosters a sense of belonging and trust, key ingredients in turning users into advocates for your SDK.

Listen to developers. Don’t assume

Empathy and contextual awareness are not mere buzzwords but guiding principles for creating SDKs that resonate with developers. They bridge the gap between what is technically possible and genuinely useful, creating an environment where both the SDK and the developers can thrive.

Example: Authenticating and returning an access token

A typical scenario for mobile developers in identity is an end user authenticating and an Access Token being returned. It seems simple enough, so, in theory, it shouldn’t be a problem for the developer.

Let’s add another step: you want to authenticate once and forget with mobile. To achieve this, we use refresh tokens to retrieve a fresh access token. Okay, this seems simple enough and perhaps something the developer should do, shouldn’t they? I’m an identity developer, and it seems simple to me.

We got feedback that it wasn’t as simple as we thought. Developers were creating solutions that may not be high-performing and, worse, lacked security best practices.

We hadn’t set our developers up for success because we assumed a certain level of identity knowledge. Why should our developers have to know about identity? They shouldn’t.

To simplify the process, I created a utility class as an experiment and bundled it with the SDK to take care of the Token Management life cycle and securely store all tokens. All the developer had to do was say, “Give me an AT (Access Token),” and have confidence in returning a valid AT without being concerned with what was happening under the hood.

This experiment became one of our most beloved SDK features because it addressed developer pain points.

Create Quickstart Guides and Boilerplate Code

Create Quickstart Guides and Boilerplate Code

When it comes to working with SDKs, common pain points for developers include:

  • Having to sift through poorly organized or overly verbose documentation.
  • Being overwhelmed with options and ending up with analysis paralysis.
  • Encountering inconsistencies in guides, code examples, or SDK interfaces.

Quickstart guides and easy-to-follow code samples can help address these pain points and create a positive developer experience.

A quick start guide serves as a brief, focused introduction to your SDK. It aims to take developers from zero to their first successful authentication call as swiftly as possible. You should create specific guides for each programming language and framework your SDK supports.

How to craft a successful quick start guide

Here are a few points to consider when creating tutorial content:

  • Provide language-specific instructions: Tailor your guide to the idioms and best practices of the target programming language.
  • Create step-by-step walkthroughs: Break down the process into easy-to-follow steps, preferably accompanied by screenshots or GIFs.
  • Include boilerplate code: Provide snippets of functional code that the developer can copy-paste to see immediate results.
  • Validate, don’t assume: Test the quick start guide in real-world conditions. Ask for feedback from internal developers or, even better, from external community members. You are not your customer.

Sample code: Your SDK's first impression

Sample code is usually the first interaction a developer has with your SDK. It should be:

  • Minimal: Only the essentials to get started.
  • Functional: It should compile and run without errors.
  • Commented: Brief comments explaining each line or section can be invaluable.

When thoughtfully crafted and easy to use, sample code can reduce the time it takes developers to learn how to integrate your SDK and use it effectively.

Simplify Dependency Management

It’s essential to ensure easy access to your SDK with a simple entry point.

When working with dependencies, common challenges that developers face include:

  • Complex installation processes involving multiple steps.
  • Dependency conflicts with existing libraries or versions.
  • Unclear or outdated instructions for package management.

Here are some tips to simplify dependency management:

  • Leverage native package managers: Native package managers such as CocoaPods for Swift, npm for JavaScript, or NuGet for .NET resolve dependencies automatically and are familiar tools for developers.
  • Use simple import statements: Initializing your SDK should be as straightforward as importing a single line of code once installed.
  • Use clear version management: Make it easy to switch between different versions of the SDK – clearly state which versions are stable, in beta, or deprecated.

By tackling these pain points head-on and simplifying the entry point to your SDK, you'll delight developers and foster faster adoption and more meaningful engagement with your product. After all, a happy developer is a productive developer, so aim to make their life easier from the start.

Minimize Friction through Excellent Documentation

Minimize Friction through Excellent Documentation

Well-crafted documentation effectively reduces the learning curve, enabling developers at all levels to integrate the library into their projects with greater ease and efficiency.

Well-documented methods and functions

While self-explanatory code is essential, having well-documented methods and functions elevates an SDK's usability, especially in the sensitive authentication realm. Documentation should go beyond mere comments in the code. Each method and function should be clearly described in the official documentation, outlining its purpose, parameters, return values, and possible exceptions or errors. This level of instruction provides developers with a comprehensive understanding of how to best utilize each piece of the SDK, ensuring functional and secure implementations.

Comprehensive API documentation within the SDK

Rather than relying solely on external resources, integrate high-quality API documentation directly within the SDK itself. This documentation should be easily accessible and navigable, allowing developers to quickly find relevant information without having to switch contexts. Features could include examples of API requests and responses. By embedding this level of detail into the SDK, you offer developers a one-stop shop for all the knowledge they need to integrate and troubleshoot effectively, enhancing their overall experience and productivity.

Leverage the Power of the Community

The community around an SDK can be as critical as the SDK itself. You can optimize this symbiotic relationship for everyone's benefit.

Open Source contributions

Creating an SDK that delights developers is a technical challenge and a community-building exercise. By simplifying the entry point and actively involving the community, you make your SDK more robust and user-friendly and cultivate a loyal following that can last for years. The result is a continuously refined product, widely adopted and highly respected.

Here are some tips to increase developer engagement:

  • Use an easily accessible repository: Your GitHub or GitLab repository should be easy to find, fork, and contribute to. Well-structured README files and documentation should guide newcomers.
  • Create clear contributor guidelines: Explain how developers can contribute, what coding standards to follow, and how pull requests are reviewed.
  • Implement a robust review process: This ensures the quality of community contributions while providing educational value back to the community. Effective code reviews can become learning opportunities for everyone involved.
  • Be curious: If a developer raises an issue, get curious and figure out the problem they are trying to solve. Is someone doing something unexpected? That could be a gap in documentation vs presuming developer error.

Streamline Developer Onboarding

When you invest time and resources into understanding your developer audience's sources of frustration, you can use that knowledge to build a better SDK onboarding experience for them that avoids common pitfalls.

Exception handling and debugging

Developers expect to deal with error messages and debugging. Giving them the information and context to do something with the error messages makes debugging significantly easier and more intuitive.

Common Pain Points

  • Cryptic error messages: Obscure, generic, or overly technical error messages are frustrating and can hinder debugging efforts
  • Lack of debugging information: Often, error logs don’t provide enough contextual data, making it difficult for developers to identify the root cause.
  • Inconsistent exception types: Different types of exceptions thrown for similar kinds of errors can be confusing.

The Opportunity

  • Descriptive error messages: Provide a human-readable and explicit error message whenever an exception is thrown. For example, instead of saying "Authentication failed," say "Authentication failed: Invalid OAuth token."
  • Contextual information: Along with the error message, provide additional details like which function or API call caused the exception, relevant IDs, timestamps, etc. This context can help developers debug issues much faster.
  • Exception handling guidelines: Maintain consistent exceptions and document them thoroughly. Include examples showing how to catch and handle these exceptions in various programming languages.

Code Modularity and Flexibility

  • Modular design: Structure the SDK to enable selective import of modules, reducing bloat and optimizing performance.
  • Loose coupling: Architect components to minimize dependencies, simplifying updates and maintenance.
  • Extensibility: Design the SDK for adaptability, with hooks and interfaces for developers to customize and extend functionalities, aligning with specific project needs.

In essence, the effectiveness of an SDK is significantly enhanced by focusing on accessible, real-world tutorials and by designing for modularity and flexibility, catering to the diverse needs of the developer community and fostering an environment of innovation and efficiency.

Developer Experience is Worth the Investment

Developer Experience is Worth the Investment

The concept of "delighting" developers is not merely an aesthetic or superficial goal. A well-crafted SDK becomes a significant strategic asset in a landscape where developer attention and mindshare are increasingly valuable commodities. Investing in a delightful developer experience is mutually beneficial and impactful for developers and businesses.

Builds brand ambassadors

A delighted developer is more likely to share their positive experience within their network. In a community where word-of-mouth has tremendous value, these developers become natural ambassadors for your SDK and, by extension, your brand. A recommendation from a trusted peer can often have a more significant impact than any marketing strategy.

Facilitates rapid adoption and innovation

A well-designed, intuitive SDK accelerates the onboarding process, allowing developers to go from discovery to integration swiftly. This saves time and makes it easier for developers to innovate, fueling a faster development and deployment cycle. The quicker developers integrate and deploy, the faster they can respond to market demands and opportunities, giving businesses a competitive edge.

Decreases support costs

A clear, intuitive developer experience minimizes errors, leading to fewer support tickets and reduced burden on customer service. Comprehensive documentation and community engagement further alleviate these costs. With developers able to find answers quickly on their own or through community channels, the business can allocate support resources to more complex, high-priority issues.

Improves SDK quality and lifecycle

Being open source means developers can actively contribute to your SDK, pointing out flaws, suggesting enhancements, and even fixing bugs. This crowdsourced approach to quality assurance can be incredibly beneficial. The developer community becomes an extension of your QA team, resulting in a more robust and reliable product over time.

Attracts and retains talent

If your SDK gains a reputation for its excellent developer experience, it will also reflect positively on your organization. Talented engineers are more likely to want to work for a company that clearly values high-quality code and a user-centric approach, which will help you attract and retain top talent in the long run. It’s one of the reasons I joined Auth0 7 years ago.

Drives revenue and growth

While an SDK might be open source and free to use, it can often be a gateway to other monetizable services and features. A user-friendly SDK can be a compelling entry point for developers who may transition to using your company's other premium or enterprise-level offerings.

Investing in a delightful developer experience is not just about making a good impression; it's about forging lasting relationships with the developer community. By providing an SDK that meets developers on their terms — intuitive, idiomatic, and integrated — you're creating a robust ecosystem that makes developers' lives easier and contributes directly to your business objectives. The aim is to create a win-win situation where developers are empowered and the business thrives — a compelling reason to make your SDK as delightful as possible.