Guide, Product Updates, SaaS

From Struggle to Victory: Overcoming 5 Game-Changing Challenges in SDK Development

The Frontend SDK team I lead at Frontegg has the mission of creating an open-source library for easy integration of Frontegg components into developers’ applications. We provide dedicated SDKs for various frameworks, such as frontegg/react, which is widely adopted by both B2B and B2C frontend developers with 10,000 weekly downloads. Our SDKs include an embedded login box and a robust admin portal, offering extensive user management capabilities on top of our frontend APIs.

The adventure of creating open-source libraries is an endeavor that is distinct from developing applications. In this blog, I will shed light on the challenges that resonate with my daily experience, and which I believe every SDK developer can relate to:

  1. Backward Compatibility vs. Breaking Changes
  2. One Size Fits All vs. Tailored Tech
  3. Customization vs. Out-of-the-Box Excellence
  4. Simplify SDK Infrastructure for Seamless Feature Development
  5. Mastering Quality Assurance and Release Pipelines

I’ll be sharing valuable tips and real-world examples along the way. Feel free to dive into the one that piques your curiosity the most. Let’s jump right in:

Challenge #1. Backward Compatibility vs. Breaking Changes

Creating an excellent SDK is like juggling. You need to keep everything working as before while making constant improvements.

Now, let’s be honest, developers have tight schedules. Asking them to embark on an adventure to upgrade your libraries and actively rework their code is not a great idea. What they truly appreciate is seamless delivery of bug fixes, new features, and slick improvements  This approach, while developer-friendly, poses a unique set of challenges for us.

  1. Strive for the best while keeping the old
    SDK developers are committed to enhancing the user experience by identifying opportunities for codebase improvements, which may include critical changes, or restructuring efforts to optimize the SDK. When such improvements are recognized, developers face the dilemma of either compromising on a single solution or introducing a new one while retaining support for the previous version.
  2. Avoid code proliferation
    To address the initial challenge, we sometimes introduce a new configuration option that accommodates both the new and old systems, ensuring backward compatibility. However, managing multiple code versions can be impractical for several reasons:
  • Dev velocity – Slows down development, as developers must handle multiple codebases.
  • Code quality – The codebase becomes convoluted and challenging to maintain, leading to spaghetti code.
  • Expertise – Over time, maintaining legacy code interferes with developers’ expertise in the product.
  1. Dual thinking—backward and forward
    Being an SDK developer requires thinking both backwards and forward. Achieving 100% backward compatibility upon release is essential, but developers must also anticipate how their work today can avoid future breaking changes.

Balancing these factors and managing a single, coherent codebase is crucial for the success of open-source SDK projects. Lets jump to some practical tips to achieve this:

Practical Tips

1.Keep it generic and object-oriented

No! (Don’t do this)

Try this instead.

2. Think ten features ahead – Always envision what future enhancements might look like for your interface. Consider scalability and potential additions, so your users won’t be caught off guard when new features roll out.

3. Graceful deprecation with configurations – When necessary, introduce dedicated configurations to support both forward and backward compatibility. Mark the previous support as @deprecated and provide clear instructions on transitioning to the new implementation.

4. “Turn Off” option – Offer your customers a simple way to disable a change if they struggle to integrate a new API seamlessly.

5. Release breaking changes selectively – Only resort to breaking changes when absolutely necessary, and when you do, accompany them with a clear and comprehensive migration guide. Ensure users can smoothly transition to the new version. Encourage users to upgrade to major new versions by offering compelling incentives and rewards.

6. Keep a breaking changes wishlist – Maintain a list of potential breaking changes you’d like to introduce when the opportunity arises. This allows you to plan and communicate these changes proactively.

7. Streamline your code – Have a central location where you align the API to the latest version. Collect backward-compatible APIs and convert them to the latest format, ensuring that your business logic remains readable and adaptable.

Challenge #2. One Size Fits All vs. Tailored Tech

Do you focus on delivering top-notch SDKs for specific frameworks, ensuring an exceptional user experience? Or do you compromise to make your product accessible to a broader customer base?

While some libraries target specific frameworks, achieving framework agnosticism is a significant challenge. Let’s explore a tailored solution by looking at our Angular SDK. Our aim was to empower developers to restrict sections of their application to entitled users.

We’ve streamlined the Angular developer experience for our feature, but it requires dedicated testing, ongoing support, and a deep understanding of Angular.

To tackle the challenge of balancing generic SDK features with framework-specific ones, consider applying these strategies:

Responsible decisions

  • Leverage framework usage data for informed decisions.
  • Provide clear effort estimates.
  • Prioritize making key features easy to integrate.

Smooth delivery

  • Offer workarounds for tailored support, including example projects.
  • Begin with an MVP and iterate based on feedback from design partners and developers.

Cultivate expertise

  • Focus on high-impact frameworks and invest time in mastering them.
  • Equip SDK developers with basic framework knowledge and designate experts for more complex frameworks.

Architectural Considerations

  • Implement slim adapters containing only essential components.
  • Invest in infrastructure for automated adaptation of basic APIs to different frameworks.

Challenge #3. Customization vs. Out-of-the-Box Excellence

Customers typically expect features to integrate seamlessly with their specific requirements, including matching their application’s styling, brand identity, and user experience. Some customers may prefer extensive customization options to tailor the feature precisely to their unique needs.

At the same time, there are users who value simplicity and efficiency. They trust in best practices and appreciate easy, out-of-the-box solutions. Like all software vendors focused on user experience and their ROI, we contend with this tradeoff on a daily basis. 

For example, here is our signup form, a built-in component that we provide.

We decided to keep our main component unified, without maintaining a fully dynamic and generic form, while still letting all of our customers have a proper solution for their needs, and even be ready to add additional configurations pretty easily on demand. As a result of these choices:

  • We provide a comprehensive form built adhering to industry best practices. 
  • We offer a set of predefined configurations for controlling the layout and form structure. 
  • Full styling customization is also available for every component. 
  • For unique needs, we provide detailed documentation on how to implement a fully customized form using our APIs only.

This is how it looks like using easy customization in our SDK:

Practical Tips

  1. Always share the building blocks – Share the core elements of your feature, assuming that your APIs are ready for use. This ensures you have a workaround ready when needed.
  2. Delve into user experience – Invest in extensive research to find the best user experience solutions for various use cases. If your default UX meets users’ criteria, they might not need customization at all, and will trust your approach and recommendations. This makes deployment and maintenance easier, and avoiding successive rounds of customization requests makes the SDK owner’s life easier, as well. .
  3. Expose common customization – Offer the most common customization as built-in options and ensure your documentation covers all of them to make life easier for users.
  4. Prepare for future configuration – Anticipate potential requests and make your infrastructure ready for future configurations. Be prepared, so you can easily add customization options as needed, keeping it flexible and adaptable.

Challenge #4. Simplify SDK Infrastructure for Seamless Feature Development

Introducing a new SDK feature goes much more smoothly if it works in many configurations and is very flexible, so many users can quickly adapt it to their unique situations.. 

If the most general requirements of the SDK infrastructure are automatically implemented without the developer having to actively set them up, many headaches of implementing SDK (backward compatibility, for example) go away. This streamlines development, reduces errors, saves time, encourages collaboration, and facilitates contributions. In addition, this approach frees up developers to concentrate on crafting and enhancing functionality without the burden of managing foundational concerns.

To achieve all this, here are two best practices we rely on, followed by some practical tips.

  1. Create a robust shared library of components for customization
    We maintain a versatile shared components library to support our customers’ customization preferences. To streamline this process without offering custom support for each feature, we’ve devised a robust mechanism. This mechanism ensures that every component effortlessly adheres to our predefined themes, inheriting styling, color palettes, breakpoints, and more from customer-provided configurations. By integrating these shared components into each new feature, we facilitate full customization without requiring additional support.
  2. Create automated API adapters
    We’ve implemented a mechanism in every framework wrapper to transform our APIs written with Redux sagas from our core package into actions in the relevant framework’s store. With this approach, developers can create new APIs without additional steps, ensuring a smoother development experience. For example, here is how we do it for Vue.js customers:

Practical Tips

  1. Regression testing – Maintain a robust suite of regression tests for your features. This safeguards against accidental breakages, as not every developer is intimately familiar with your system’s logic and requirements.
  2. GitHub PR template – Make GitHub PR template includes a checklist that guides developers through the steps necessary for successful integration.

Centralized backward compatibility management – Establish a centralized approach to managing backward compatibility, and simplify the process of ensuring that previous implementations remain supported alongside newer versions.

Challenge #5. Mastering Quality Assurance and Release Pipelines

Building an SDK, especially an open-source one, means that your code can impact millions of end users across various applications. The responsibility of releasing new code to production is immense, as it directly affects your vast user base. To tackle this challenge effectively, you must prioritize quality and reliability in your release pipelines. 

Practical Tips

  1. Maintain a detailed changelog – Developers should be required to include changelog information with their commits. Therefore, you should create a dedicated automated process for managing changelog entries, to ensure that each commit has a proper title and changelog selection.
  2. Multi-stage release pipelines – Start by releasing your core business logic internally. Gradually release it to the public source code, with a separate pipeline to ensure code quality. Consider releasing an alpha version, which can be tested by customers when necessary or by QA teams. Only after thorough testing and validation should you manually release a new npm version.
  3. Effective communication – Create a dedicated internal Slack channel to report and track every new version being released. 

Ensure that support teams are informed and aligned with the release process, keeping them fully aware of what’s happening.

  1. Support for hot fixes – Establish a dedicated pipeline for handling hot fixes promptly, and to address critical issues efficiently.
  2. Comprehensive E2E testing – Maintain a comprehensive end-to-end testing pipeline to thoroughly assess the functionality and reliability of your packages.
  3. Manual sanity checks – Conduct manual sanity checks for your packages, both on a clean integration setup and on existing installations. This ensures that everything continues to work as expected.

Congratulations on making it this far! 

We’ve navigated through five pivotal challenges in the realm of open-source SDKs. By embracing these recommendations and best practices, you not only ensure faster and more reliable releases, but also fortify the security of your user base. Watch as your SDK development transforms into a sleek, efficient, and effortlessly maintainable powerhouse. I’m eager to hear about your team’s experiences with these recommendations, so don’t hesitate to share your feedback and suggestions with me.