Infrastructure work has recently been doing, in the face of the more than 30 completely no specification components, gas I play a direct lightning five whip, but work goes on, so wants to establish a set of specifications, these components to reduce the cost of enough, use, maintenance and evasive to white piao an online, are some basic code found in the specification, Not very useful, so according to their own work experience, summed up a set of norms/agreements, I hope to throw off a brick to attract jade, you big guy a lot of advice and supplement ~

The specification itself is a contract between developers, there is no most authoritative, only the most suitable.

Version of the specification

To ensure the compatibility of components in each project, the agreed component development versions are as follows:

AndroidSdk version

MinSdkVersion: 21

28 targetSdkVersion:

The language environment

Development language: Kotlin

Kotlin version: 1.4.x

JDK version: 1.8

Other Recommended versions

AndroidStuido: 4.2

Gradle tools: 4.1 x

Gradle: 6.7 x

Component naming conventions

There are three types of convention components, depending on their function:

Based on the component

Component libraries that provide business-neutral basic support for projects, such as lib_basic for MVVM architecture and lib_basic_koin for dependency injection, are collectively named lib_basic_xxx. These base components can also be relied upon by tool components and business components, not just projects.

Tool components

A library of components that encapsulate common business-independent functionality in a project, such as Dialog pop-ups, photo album selections, is uniformly named lib_util_xxx.

The business component

Functions that appear in the requirements of A project may also be used in other projects are encapsulated, such as scanning and photographing in A salesman edition is also useful in A business edition, so they are separately encapsulated as A business component for management, and such components are collectively named lib_tool_xxx.

GroupId

GroupId for all components is unified as com.any.android for easy indexing and management in Maven repository.

The version number

For the iteration version number, there is no mandatory requirement, only reasonable upgrade, but special attention should be paid to the following conditions:

1. For the uploaded development version, it should be reflected in the version, such as 1.0-dev02, to distinguish it from the official version, and merge it into the main iteration version after verifying that there is no risk in the project.

2. Temporary release for emergency repair of problems in project A shall be reflected in the release, such as 1.0-Hotfix-a. This modification shall be merged into the main iteration version after it is verified without risk in other used projects.

Development principles

The open closed principle

When upgrading a component, it should be open for new changes and closed for changes, that is, adding without subtracting, in order to ensure the compatibility of calling older versions of the API in the project. Apis that are no longer recommended should be annotated with the @deprecated annotation and replaced with a new proposed API, rather than simply removing the old API. After several iterations of a stable release, all component consumers can discuss removing the older API.

Backward compatibility principle

Version iterations for all components must be backward compatible, that is, version 1.2.0 must be compatible with version 1.1.0, without changing the business layer code after the consumer upgrades the version.

If the business code must be modified in the upgrade due to the unreasonable design of the component in the early stage, the component developer shall discuss the technical implementation plan with all the component users to see whether the upgrade of the component can be completed with minimal changes. After the development of the component function, the component developer shall inform the user in written form and provide a complete upgrade document.

Principle of tripartite segregation

When we encapsulate components, it is inevitable to use third-party dependencies. In order to avoid the impact caused by replacing third-party dependencies or upgrading dependencies, we need to encapsulate third-party dependencies twice to avoid direct use. For example, if we want to use The Glide framework to load pictures, we can create a proxy class to proxy The Function of Glide, and use the proxy class in the business code instead of calling Glide directly. This way, when we replace the Glide framework in the future, we can make minimal changes to the business code.

Of course, not all tripartite libraries (retrofit, RxJava, etc.) are isolated by proxy mode, after all, our isolation principle is for easier iterations in the future, not for trouble.

Principle of least dependence

In order to reduce dependent libraries in a project, components should be split when they are encapsulated in the following situations:

Lib_util_imageloader is a new image loading library for Glide and Picasso. Since the two libraries provide similar functions, only one image loading framework can be used to meet business needs. There is no need to rely on both image loading frameworks. So lib_util_imageloader should be split into the following structure:

Lib_util_imageloader_core: image-loading core library abstracts the way images are loaded as an interface, project-oriented and not implemented.

Lib_util_imageloader_glide: Encapsulates glide twice to implement the interface in core.

Lib_util_imageloader_picasso: Secondary encapsulates Picasso to implement the interface in core.

When a project uses an image loading library, it only needs to choose a Glide or Picasso, in addition to core, which it must rely on, so that it does not pack unnecessary libraries into the project.

Another advantage of this approach is that it is easy to expand. If I wanted to use Fresco, ALL I had to do was add a lib_util_imageloader_fresco and implement the core interface. When I switched components, I just changed the dependencies in the Gradle file. I didn’t have to change the business code because the business code was based on the core components.

Least visible principle

Components should expose as few classes, interfaces, methods, and so on as possible. You can provide a unified API to the user through the appearance pattern, making it easier for the user to understand.

Support development mode

The component should be reserved for developer mode, which can be turned on or off by users themselves.

Enable developer mode: Logs are generated on key nodes of component running for easy debugging. Exceptions can be thrown during running.

Disable the developer mode: The component does not output logs with the Error level or lower. Exceptions and ANR cannot be thrown when the component is running. If exceptions occur, you need to capture them in the component and report them to users through Error callback or printing Error level logs.

Can expand sex

Some of the components (most of which, as the case may be, are wrapped components of a tripartite library) should be extensible enough to allow a user-defined implementation to override the default implementation.

For example, the Dialog library has a default popover style and needs to support user-defined popovers rather than just selecting from the default styles. The same logic applies to the image loading framework.

The development of specification

Package specification

In order to avoid unintended package name conflicts, it is agreed that the package name of the component is level 4. The latter two levels can be named according to the specific function of the component and have good readability, except that the com.company of the first two levels is fixed.

Resource specification

To avoid packaging problems caused by resource conflicts, add the following code under the Android node of the Gradle file to enforce resource name prefix check:

android{
  resourcePrefix = "${your_component_name}_"
}
Copy the code

Code specification

You should follow the Java development code specification, which is not covered here.

Visibility domain specification

In Kotlin, the new keyword internal can be used to modify class names, method names and member variable names, limiting the visibility of the modified object module, and reducing the visibility of classes, methods and variables that do not need to be exposed externally.

Inline function

Kotlin added the keyword inline modifier to reduce the number of methods pushed into the method stack. Use inline when encapsulating components to improve efficiency.

A memory leak

All components must be tested for memory leaks before they are released. Components with memory leaks are forbidden to come online, and all leaks should be fixed during development.

confusion

Component developers need to verify that their components work properly after packaging obfuscation, such as using runtime annotations, reflection, Json conversion, etc., and declare obfuscation avoidance rules in access documents.

The document

The access, use, upgrade, and precautions of components must be clearly reflected in the development documents. No access documents or incomplete documents shall pass the acceptance.

Demo

The component had better have the supporting demonstration project, which is used to most intuitively reflect the function provided by the component, and also convenient for users to refer to.

The last

At present, I can only think of so much, and I will continue to add new ones in the future.

Standardize good customization, but it is difficult to implement, the road is long, come on, workers!