Pay attention to interface design

For SDK, interface is the link between SDK and customer products, and the quality of interface design is an important indicator to measure the usability of SDK products. A poor SDK interface not only gives developers a subjective impression that it is difficult to use, but also increases customer development costs and even affects product quality. In the first few years of SDK development, the author did not pay attention to it, but gradually realized that excellent SDK interface design must consider the following points:

  1. A unified interface design style is not just about making a professional impression on developers. Furthermore, it can pass on to developers the design philosophy of the SDK. This stylistic hint makes it easier for developers to invoke SDK functions without making mistakes. For example, we can design the SDK to initialize all interfaces with init method and uninit method. Once developers accept this, they will subconsciously notice if uninit is called to release resources.

  2. Platform conventions The bottom layer of an SDK product is usually cross-platform implementation, and the upper layer is a layer of encapsulation for different platforms. The encapsulation layer should especially consider the development conventions of the platform. Because developers who interconnect with SDK usually focus on the development of a specific platform, which does not conform to the naming style of the interface of this platform, interface design conventions will bring them extra learning costs and increase the difficulty of interfacing.

  3. Upgrade extension Interface Design Consideration Upgrade extension is a fundamental requirement for every programmer responsible for a continuously iterative product. But for SDK products, this is especially important. The reason is that poor interface design can be remedied by later iterative refactoring, and once the SDK is released, it is costly for customers to modify the code to upgrade the SDK. If the interface compatibility is not good, customers will not be willing to upgrade, and the problem with that is that maintaining multiple versions puts a lot of support pressure on us.

  4. Comments and interfaces are two sides of the SDK and play an equally important role in the SDK as interfaces. No interface in the SDK is redundant, and no interface is allowed without comments. When we developed the SDK, we always assumed that developers would not look at our integration documentation. Therefore, it is only by making as many comments as possible that we can eliminate problems as much as possible before developers turn to the document or ask questions.

SDK interface design specification

Aiming at the above points, we formulated our own SDK interface design specification based on the general coding specification, platform naming specification and industry general convention. At present, it is not particularly perfect and detailed, but with a unified standard, I believe there will be a principle guidance for the future interface design. Our SDK is mainly aimed at mobile terminal iOS/ Android platform, and the language used is OC/Java. The design specifications of other platforms can be used for reference.

Class/interface

Classes/interfaces must be named using nouns.

  • The Android interface requires an I character to distinguish it.
// good case
public interface AliyunIRecorder;   // android; Interfaces are distinguished by I

// bad case
public interface AliyunIImport;     // android; Import is not a noun
Copy the code

Method/function

Method/function names are clear enough to understand that abbreviations should not be used except for industry-common proper nouns.

// good case
void setExposureCompensationRatio(float value); // android; The method name is the explanation


// bad case
- (int)removeTransitionAtIndex:(int)clipIdx;    // iOS; The parameter name should use the full name clipIndex
Copy the code

As few parameters as possible, more than 4 parameters need to consider using structure/class encapsulation.

In addition to reducing method length, the benefits of using structure/class encapsulation are more significant because future versions of interface functionality will only need to add configuration properties instead of providing a new interface.

// bad case
void setMusic(String path,long startTime,long duration);        // android; Use the Music class for encapsulation
Copy the code

If you can use synchronous interfaces, try not to use asynchrony. Asynchrony interfaces should be explained in comments.

While the behavior of designing synchronous interfaces is clear, designing asynchronous interfaces can lead developers to make false calls because they think the interface behavior is complete. Asynchronous interfaces must be highlighted and specify the corresponding callback method.

// bad case
int finishRecording(a);     // android; An asynchronous interface needs to describe the corresponding callback method
Copy the code

An interface does only one thing and is named doSomething.

// bad case
int editCompleted(a);            // android; StopEdit/finishEdit instead
Copy the code

The enumeration

  • iOS

    Using the platform convention hump nomenclature, usingtypedef NS_ENUM()Syntax definition.
// good case
typedef NS_ENUM(NSInteger.AVCaptureFlashMode) {
    AVCaptureFlashModeOff  = 0.AVCaptureFlashModeOn   = 1.AVCaptureFlashModeAuto = 2,}//iOS; System API naming

// bad case
typedef enum : NSUInteger {
    DIRECTION_LEFT = 0,
    DIRECTION_RIGHT = 1,
    DIRECTION_TOP = 2,
    DIRECTION_BOTTOM
} DIRECTION_TYPE;        //iOS; No hump naming, no enumeration value naming, no OC declaration specification
Copy the code
  • Android uses the platform convention of naming enumerators in all uppercase letters, separated by underscores.
// good case

public enum FormatStyle {
    FULL,
    LONG,
    MEDIUM,
    SHORT;
}              // android; System API naming method

// bad case
public enum AlivcLogLevel {
    AlivcLogLevelDebug(0),
    AlivcLogLevelInfo(1),
    AlivcLogLevelWarn(2),
    AlivcLogLevelError(3),
    AlivcLogLevelFatal(4);
}              // android; Enumeration values are not properly named
Copy the code

Member variables/attributes

  • IOS exposes properties only when getter/setter methods are also required, otherwise methods are used instead. Use oc base datatypes, not C/C ++ base datatypes.

  • Instead of exposing properties directly, Android provides getter/setter methods. A Param class must have a constructor.

// bad case
public int videoWidth;                          // android; Provide getter/setter methods
@property (nonatomic.assign) int bitrate;      // iOS; Use NSInteger instead of int
Copy the code

Naming conventions

Get existing objects using get names.

// bad case
AliyunICanvasController obtainCanvasController(Context var1, int var2, int var3);  // android; Use get instead of obtain
Copy the code

The new object that gets a new is named create.

Create can indicate to the developer that the resource is being created.

// good case
public static AliyunIEditor createAliyunEditor(a);  // android; The factory method creates a new instance using create

// bad case
AnimPlayerView newPasterPlayer(a);              // android; Use create instead of new
Copy the code

Class/structure names require a purpose declaration, ending with Param.

Suffixes can be Config,Setting, and so on, and once determined all interfaces need to be consistent.

// good case
public class AliyunVideoParam;    // android; Naming conforms to specifications

// bad case
public class CropParam;         // android; Without a prefix
public class MediaInfo;         // android; There is no declaration that it is a recording parameter and no end in Param
Copy the code

Set effect: setXxx, remove effect: clearXxx

// bad case
int addAnimationFilter(EffectFilter var1);                  // android; Nonconformity to specification
- (void)deletePaster:(AliyunEffectPaster *)paster;          // iOS; Nonconformity to specification
Copy the code

Added: addXxx, deleted: removeXxx, Cleared: clearXxx

// good case
int addMediaClip(AliyunClip clip);        // android; Replace with clearPartList

// bad case
void deletePart(a);                        // android; Replace with removePart
void deleteAllPart(a);                     // android; Replace with clearPartList
Copy the code

Array/Dictionary named using the variable name + List/Map/Array/Dictionary

The main reason for not defining variable names in plural forms is that our development team doesn’t have a deep understanding of plural nouns. Instead of naming unprofessional variable names, it’s more intuitive.

// good case
public List<Frame> getFrameList();         // android; Conforms to naming conventions

// bad case
@property (nonatomic.copy) NSArray<AliyunFrameItem *> *frameItems;  // iOS; Replace with frameItemArray
Copy the code

The callback

Callback methods Unless otherwise required, the callback interface comment must specify which thread to call in.

Ensuring that all of the developer’s interface calls are executed on the main thread can avoid many threading problems. Some callbacks need to be commented out in specific threads such as render callbacks.

  • IOS callback classes invariably end in Delegate. The callback method starts with the name of the callback class +Did. Each callback corresponds to a Delegate property.

  • Android Callback classes always end with Callback, and the Callback method starts with on+ Callback class name.

// bad case
@protocol AliyunIPlayerCallback 

@end                              //iOS; You cannot use callback endings
Copy the code

Initialization/uninitialization

The main module must be initialized using the init method with the Param configuration parameter.

Uniform initialization allows developers to quickly become familiar with SDK calls.

  • The iOS OC class should not provide a de-initialization method. If possible, try to construct and destruct native resources at specific locations according to the following priorities:
  1. The native resource is constructed when the key method is called, and the native resource is destructed internally after the callback is completed. For example, the transcode method is called to construct the resource, and transcode completes the callback to destruct the resource.

  2. The construction and destruction of native resources are provided externally by paired methods. For example: startPreview vs. stopPreview, startEdit vs. stopEdit, Open vs. Close.

  3. If none of the above is appropriate, consider destructing native resources internally at dealloc.

// bad case
- (void)destroyRecorder;              // iOS; Consider whether it can be avoided by 1, 2, and 3
Copy the code
  • android

    The main module class must be presentreleaseMethod,releaseDelete the underlying resource with the Same Java life cycle.
// bad case
void dispose(a);             // android; Release () is not used
Copy the code

The prefix

Class, interface, structure, enumeration values must be prefixed.

Java does have package names to distinguish between classes, but prefixes are recommended to make it easier for developers to distinguish SDK interfaces.

The package name

All ANDROID SDK interfaces must be in the same package name.

annotation

Use /** */ comments for external interfaces, not // comments.

Many interfaces require more than one line of comment to make it clear, so it is used uniformly here.

Source: this article is reproduced by the third party, if there is infringement, please contact xiaobian to delete.