Easy-to-use Toss Front SDK
The post argues that an SDK’s stability depends not only on its internal implementation but also on how safely users can interact with it. Low-level APIs may expose every operation clearly, yet still allow human errors such as missing event handlers or cleanup. The recommended solution is an intent-driven Facade interface that simplifies common workflows, prevents misuse, and still provides low-level escape hatches for advanced cases. ## Designing an SDK That Is Easy to Use - Toss Place develops an external SDK for Toss Front payment terminals. - The SDK allows third-party developers to build plugin apps that integrate with Toss services and run on the terminal. - A simple-looking server API might require users to: - Open a server. - Register connection, message, and error handlers. - Remove handlers. - Close the server. - This approach exposes implicit responsibilities to SDK users: - A message callback might never be registered after a connection. - Handlers might not be removed before shutdown. - Improper cleanup can cause memory leaks and operational issues. - Therefore, third-party implementation mistakes can directly affect platform reliability. - A safer interface hides unnecessary internal steps: ```ts const server = await sdk.start({ onConnection, onMessage }); await server.stop(); ``` ## Facade as an Intent-Driven Interface - The Facade pattern is commonly described as wrapping a complex subsystem with a simpler interface. - In SDK design, its deeper purpose is to reorganize complexity around user intent rather than merely hide functionality. - Users should express goals such as: - “Start a server” - “Upload a file” - “Request a payment” - Internal concerns—including authentication, retries, state management, listener registration, and cleanup—should be handled by the SDK. - AWS CDK illustrates this distinction: - **L1 constructs** closely represent raw CloudFormation resources and provide fine-grained control. - **L2 constructs** provide intent-based APIs, such as creating a versioned S3 bucket with `versioned: true`, while handling the underlying configuration automatically. - The goal of a Facade is to reduce cognitive load and coupling, not simply to conceal every lower-level capability. ## Combining High-Level and Low-Level APIs - A well-designed SDK should provide both abstraction levels: - **High-level Facade:** Handles the roughly 80% of common use cases through complete workflows. - **Low-level APIs:** Serve as escape hatches for the roughly 20% of specialized cases requiring precise control. - In the example: - The Facade’s `start()` method opens the server, registers listeners, coordinates connections, and returns a unified server handle. - Low-level APIs separately expose operations such as `open`, `close`, `send`, `disconnect`, and event listeners. - This layered design improves immediate developer experience while preserving long-term compatibility and extensibility. ## Trade-offs and Escape Hatches - Higher-level abstractions inevitably reduce some flexibility. - Specialized requirements—such as keeping one connection while closing others—may not fit the Facade workflow. - As orchestration becomes more sophisticated, the SDK maintainers inherit additional implementation and maintenance costs. - Low-level escape hatches are therefore essential: users should be able to bypass the Facade when they need detailed control. ## Practical Recommendation Design SDK APIs around user intent and automate error-prone lifecycle management wherever possible. Offer a concise Facade for common workflows, but retain well-defined low-level interfaces so advanced users are not blocked by the abstraction.
Read original(opens in new tab)