banner
biuaxia

biuaxia

"万物皆有裂痕,那是光进来的地方。"
github
bilibili
tg_channel

[Reprint] Learned the SDK writing style from big companies!

title: 【Reprint】The SDK Writing Style of Big Companies, Learned It Stealthily!
date: 2021-09-09 10:13:00
comment: false
toc: true
category:

  • Java
    tags:
  • Reprint
  • Java
  • SDK
  • Writing Style
  • Big Companies
  • General
  • Work
  • Needs

This article is reprinted from: The SDK Writing Style of Big Companies, Learned It Stealthily! - Juejin


Sharing experiences and tips for writing SDKs by yourself

Hello everyone, I am Yupi.

Recently, due to work needs, I wrote some general SDKs for projects myself. During the writing process, I read and referenced many SDKs written by other big shots in various companies, and I summarized some experiences and tips for developing SDKs to share with everyone~

image

Before that, I must explain what an SDK is.

What is an SDK?#

SDK (Software Development Kit) is a Software Development Toolkit, which is a collection of tools that help us develop software, generally accompanied by documentation, examples, etc., in addition to code.

Generally, SDKs need to be imported into the project for use. For example, the JDK that friends learning Java first encounter is a toolkit for developing Java software, and when using it, you need to write syntax like import java.util.* to import it. In addition, most SDKs need to be downloaded to a specified path through manual or project management tools before they can be imported.

Import SDK

What are the benefits of using an SDK?#

For example, suppose the company has many systems that need to implement file upload functionality. Friends who have read my articles before should know that an excellent file upload function is not easy to make, as many points need to be considered, such as chunking, resumable uploads, instant uploads, file storage, file management, etc.

File upload design: mp.weixin.qq.com/s/3QXe4MSOb…

Clearly, we do not need to develop file uploads for each system; instead, we only need one team to step up and write a general file upload SDK, and then let the systems that need to implement the same functionality reference it, which greatly reduces the workload and improves development efficiency.

General SDK

It's a bit like the saying "the predecessors build the car, and the later generations enjoy it"~

Writing an SDK is also known as reinventing the wheel. A good wheel can not only help the team save time and effort but also reduce the differences in the same functionality across projects. Let’s not even mention that for the same functionality, Xiao Wang's implementation takes 1 second to run, while Xiao Li's takes 1 hour!

If each system were to develop the same functionality, that would be reinventing the wheel, which is not a wise choice in most cases.

Now that we understand what an SDK is, let's see how to write an excellent SDK~

Summary of Experiences in Writing SDKs#

A good SDK should have characteristics such as simplicity, ease of use, understandability, extensibility, efficiency, and stability.

Ease of Use#

Nowadays, there are too many ready-made wheels! How can you make your wheel stand out? You need to improve the ease of use of the SDK first.

When I choose technologies, I tend to prioritize simple and easy-to-use SDKs, preferably those that can be easily used with just a few lines of code, rather than having to read through a long document and then write dozens of lines of code to make it work.

Just like a product manual, if it's too complicated, it will directly discourage people.

image

We can improve ease of use through the following points:

Unified Invocation#

Encapsulate complex functionalities and provide a unified entry point for external calls, shielding some implementation details as much as possible, reducing the process of user calls and the understanding cost of parameters.

For example, here are two types of date processing functions. Users do not need to care about how they are implemented; they just need to know how to use them, what parameters to pass, and what return values to expect.

// Type 1: Needs to create an object
DateUtils dateUtils = new DateUtils();
dateUtils.setDate('2021-08-31');
Date date = dateUtils.parse();

// Type 2: Direct call
Date date = DateUtils.parse('2021-08-13');

Which one do you think is easier to use?

Centralized Configuration#

Make complex parameter configurations centralized, so users do not need to write parameters everywhere but can manage them through a configuration file.

The mainstream Java development framework SpringBoot is a typical example. If users want to change the port of the embedded server or the database connection address, they do not need to write code; they just need to modify a configuration file:

# Server configuration
server:
  port: 8081
# Database configuration
db:
  ip: 10.0.0.1

In addition, this also facilitates project maintenance and multi-environment implementation.

Good Naming#

When naming functions in the SDK, try to make them conform to user habits.

For example, a function with parsing capabilities can be called "parseXXX"; a function that checks for emptiness can be called "xx.isEmpty", etc. Ideally, users should be able to understand what the function does just by looking at its name and parameters without reading the documentation.

Good and Bad Naming

Therefore, to write a good SDK, you should first use and reference other SDKs more. Once you develop this habit, you will find that everyone tends to name things similarly.

But also pay attention to one point: if possible, try not to have class names (function names) in your SDK that are exactly the same as others, as this may confuse users: with so many functions of the same name, which one should I use? Which one is from your SDK?

Understandability#

Sometimes, users may not be satisfied with simply using your SDK; they may want to read your SDK source code to understand it better, which makes them feel more at ease.

Therefore, in addition to ease of use, your SDK should also be easy to understand and not just look good on the outside.

This is closely related to coding habits. Whether writing an SDK or working on a project, you should adhere to the following points:

Clear Structure#

Organize the code by functionality or category and place it in designated directories. Common practices include packaging and layering, making it easy to see the purpose of each file in each directory at a glance.

For example, the classic Java project structure below has a service directory for writing business logic, a constant directory for storing constants, a utils directory for storing utility classes, etc., all of which are very clear:

Java MVC Project Structure

Unified Style#

The goal of a unified style is simple: to make the project look like it was written by the same person.

For example, using 4 spaces for code indentation, naming in camel case, etc. Especially for similar functionalities, naming and usage must be consistent! For instance, if a function for parsing text is called "parseXXX" at one moment and then "jiexiXXX" at another, it will confuse users~

image

However, in actual team development, it is difficult to achieve this. That’s why a set of common coding standards is needed, and everyone should adhere to the standards to make the project easier to understand and maintain.

Writing Comments#

It is best to add comments at the beginning of each class and function in the SDK, so users can understand what it does and how to use it just by looking at the code comments, without needing to read the documentation.

If you randomly open a Java SDK or a well-known SDK online, you will generally see these comments, including descriptions of function capabilities, parameter meanings, return value meanings, etc.:

Adding Comments

Documentation#

In addition to comments, you should also write a documentation (user manual) that includes how to import the SDK, what functionalities it has, how to use it, etc. You can even add some key implementation details and a list of common issues.

This will greatly influence users' choices. Personally, I generally do not choose SDKs without documentation; if something goes wrong, who do I turn to?

image

Extensibility#

One of the major difficulties in writing an SDK is that you need to consider not only the common usage scenarios but also the customized needs of a small number of users.

Therefore, the extensibility of the SDK is very important, but how can we enhance it?

Lightweight Dependencies#

On one hand, we can try to minimize the SDK's dependencies on other libraries.

For example, if you want to create a very lightweight utility class that is only a few dozen KB, there is no need to introduce a dependency library that is several hundred KB, as it would not be worth it! Others would not want to use it either!

Lightweight dependencies can not only reduce the size of the SDK but, more importantly, can also reduce the possibility of dependency conflicts. I have encountered many awkward situations where introducing a utility class caused the entire project to fail to run!

image

Custom Implementation#

To improve the generality and flexibility of the SDK, in the design of the SDK, in addition to providing a default implementation, it is recommended to provide a common interface or abstract class for users to inherit and write their own implementation.

For example, suppose we want to write a date parsing class, and the default parsing rule is to split the string by hyphens:

// Split by '-'
date = DateUtils.parse('2021-01-18')

If we can only do this, then the SDK would be very rigid. Because users might want to parse according to colons or other rules.

How can we implement this?

We can allow users to pass in their own delimiter:

// Split by '-'
parseRule = ':'
date = DateUtils.parse('2021-01-18', parseRule)

We can also allow users to control the parsing method themselves:

// Custom parser
interface MyParser extends Parser {
  // Needs user implementation
  void doParse();
}
// Specify parser
date = DateUtils.parse('2021-01-18', MyParser.class);

These two methods are common in SDK design. Additionally, allowing users to write or specify configuration files can also enhance flexibility.

Efficiency and Stability#

In fact, developing an SDK, especially in a large company, is a very "tricky" job, and I believe those who have done it will resonate.

As more and more users use your SDK, you may encounter all kinds of inexplicable problems; moreover, as an underlying dependency, the impact of the SDK on users is immeasurable. Therefore, if you do not want to work overtime fixing bugs frequently, you must ensure the stability of your SDK.

We need to pay attention to the following points:

1. Testing#

To ensure that each function works correctly, we can write unit tests (UT) to cover the SDK's functionalities and code as much as possible.

Especially after each code change and before releasing a new version, you should run the tests completely again; do not be blindly confident.

Interface Test Report

Additionally, you can conduct stress tests to estimate the execution efficiency of the SDK, such as executing a maximum of 3 times per second, with each execution taking 500 milliseconds, etc. It is recommended to include this information in the documentation to give users some expectations. You can also try to optimize the SDK's performance through stress testing.

2. Compatibility#

Try to minimize changes to important functions and interfaces, especially function names, input parameters, and return values!

For example, when the SDK is at version 0.1, the function definition is as follows:

boolean isValid(String str)

Then suddenly in version 0.2, it changes to:

String checkValid(StringBuilder str)

This would leave users confused during the upgrade, wondering why a bunch of functions cannot be found!

image

Therefore, for significant changes, you can write a new function and mark the old function with a comment like @Deprecated, indicating that it is outdated and guiding users to use the new one.

Additionally, you can also play with version numbers; for minor changes, only change the minor version number, such as from 0.0.1 to 0.0.2; for major changes, change the major version number, such as from 1.0 to 2.0. This can give users an expectation: this change is significant and may be incompatible.

3. Exposing Exceptions#

You should make users aware of the exceptions that may be thrown by the SDK code and leave it to them to handle accordingly to prevent unexpected errors.

image

Moreover, the SDK should print logs reasonably, especially exception logs, so that when issues arise, the caller knows what went wrong, facilitating troubleshooting.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.