SDK 设计规则
One of my side projects involved designing a framework and sdk for 3rd party programmers (programmers that cannot easily get a quick answer from me). Engineering software for this situation was surprisingly more challenging than designing code that is always utilized by one company.
*Note: I will just refer to the design using the term sdk but these tips still apply to any kind of API.
While developing the architecture, I noticed that I had to consider 3 concepts continuously. I eventually began to think of them as the 3 ideals that governed my sdk design.
- Get design correct before a release
- Keep the visible sdk* small & focused
- Make the sdk easy to use
*For visible sdk, I’m referring to code in the sdk that other developers can access.
Points 1 and 2 are important because once a release is made, refactoring the visible sdk results in breaking changes. Point 3 is important if you want developers to use your sdk. It was pretty easy to accept that these rules made sense but it was very difficult to ensure that I was always adhering to their meaning. Fortunately, I put together some design tips during the process that helped me achieve the 3 ideals.
- Terminology & language design
- In my opinion, this is the most important step in getting an sdk right and requires much more time than the same step when designing an application.
- Language needs to be self evident to other developers
- Terms can’t easily be changed after a release
- Language & terms really help determine what objects and functionality need to be defined as code
- Don’t use terms that people need to look up
- Software design
- Big interfaces are your enemy
- Interfaces really tie you to your design because you can’t change an interface without breaking existing code
- Use interfaces for very specific tasks
- Interfaces should have only a few members (1 or 2 is best)
- Use interfaces in situations where you have a number of different types of classes that share only a small subset of specific functionality. If the classes share a large subset of functionality, you might want to consider using an abstract class.
- Abstract classes are your friend
- Abstract classes allow you to change how an object works without breaking code
- Members can be added/removed without breaking functionality of existing programs by using virtual functions
- You can even change the language by renaming a function (Basically create a new function, just remove the intellisense for the old one and depreciate by adding a virtual instance).
- Limit inherited classes
- Only expose absolutely necessary functions
- The template method design pattern is very useful for controlling the use of inherited classes
- Redesign often to remove functionality
- Omit features that *might* be useful in the future
- Design/build an application that uses the sdk while designing/building the sdk. You will be surprised at how much you change your original design.
- End user design
- Main ideas
- The less a programmer has to see, the easier it is to understand
- If your sdk is discoverable, then the importance of documentation is somewhat lessened
- As mentioned, correctly define the terms/language
- Design for intellisense even if you don’t use intellisense
- Hide undocumented public/protected functions from intellisense using attributes (Here is the attribute for Visual Studio)
-
Try to define namespaces based on how often a set of objects will be used
- Developers may use only 30% of your sdk 90% of the time
- Put this 30% in some core set of namespaces so that it is easily deciphered using intellisense
- Functions that are useful but not required should probably be in some sort of utility class or implemented asextension methods
- “Good enough” design
- The bar for “good enough” design is much higher than for an application
- For my first sdk, the bar was at least 3 times higher. I spent 3 times as much time on design as I would have on an application that my company has full control over.
- The law of diminishing returns is less significant with an sdk compared to an application
浙公网安备 33010602011771号