Anatomy of Nokee Plugins
The Nokee plugins follow a strong model. In this chapter, we will look at the established plugin capability convention. We will discuss the three dimensions forming the plugin identification triplet: implementation language, runtime and entry point. We will also cover exceptions and base plugins.
Gradle requires all plugins to include a prefix known as the plugin namespace. What follows the namespace is known as the plugin name. Together, they form the fully qualified plugin name:
We reference non-Gradle core plugins via their fully qualified name.
Core Gradle plugins are implicitly part of the
org.gradle namespace and can be referenced name only.
The rather flat naming scheme does not provide the necessary information to understand what capability a plugin offers as well as how plugins can mix. The Nokee plugins further divide the plugin name into capability dimensions, which forms the plugin identification triplet.
At its core, Gradle plugins provide additional capabilities to a project. We can group the project capabilities into three major dimensions: the entry point, the runtime, and the implementation language. The plugin identification triplet allows us to represent these three dimensions and imply specific rules when mixing plugins.
As we explain each dimension of the triplet, let’s consider the plugin
dev.nokee.objective-c-ios-application and its breakdown:
The entry point represents how a component will be used, for example, as an application, library or device driver. Each entry point provides some opinion on what can be achieved by the project. For example, an application can run. However, it cannot be dependent upon in the context of providing an API to a consumer project. A device driver would be loadable instead of runnable. It would provide restriction for which kernel it can load into versus an application would be imposing a limitation at the runtime level. In general, there should only be one entry point per project.
The runtime represents where a component will be executed, for example, iOS, Android, Windows. Each runtime provides a specific model for configuring the target runtime requirements. In native, we often talk about the architecture, operating system, instruction sets, etc. These examples are on the lower spec of the abstraction. Runtime plugins could provide a higher level of abstraction. For example, iOS runtime would provide the model for targeting Apple devices. The higher level of abstraction helps prevent invalid configuration, such as compiling an iPhone application targeting the Itanium architecture.
The implementation language represents what the component is implemented with, for example, Objective-C, Swift, C++. In general, we can mix native languages. However, some languages have special requirements when mixing them with others. For example, Swift requires additional runtime libraries to be included inside an application bundle. This dimension ensures we met those requirements.
Dimensional plugins represent plugins that only specify a single dimension.
dev.nokee.cpp-language provides only the C++ implementation language capability.
It would need to be applied with a runtime and entry point plugin to produce anything meaningful.
Those dimensional plugins are offering less convenience than an entirely opinionated plugin.
For example appling plugin
dev.nokee.application-entry-point wouldn’t necessarily be the equivalent to
The latter would provide more convenience than all the individual dimensional plugins together.
The more a plugin knows before hands, the better the modelling can be.
A plugin can have no opinion on a dimension.
The dimension will then be considered unset.
It allows additional plugins to be applied to fill the dimension requirements.
For example, the
dev.nokee.jni-library plugin has no opinion on the implementation plugins and allows language plugins to be applied.
Thanks to the plugin identification triplet, we can assume what capability is provided by a plugin. It allows for a more natural understanding without having to open the documentation. As the development of the Nokee plugins moves forward, the convention will become more apparent and easier to understand.
It exists exceptional entry points that don’t follow the rules of one entry point per project. They are test suites and IDE integrations.
It’s a good engineering practice to tests the code of the project’s main entry point. Test suites provide additional entry points for this specific need. Another testing trend is to separate the tests into various buckets such as unit tests, integration tests and functional tests. We often model them as separate entry points. In the Java world, testing resolve mostly around the JUnit testing framework. However, in the native world, there are a considerable amount of testing frameworks. There is a need to differentiate tests written for each testing runtime. For this reason, test suites are special entry points.
IDE integration is also unique as it provides a capability that is often opinion-based. Some developers like to use Xcode, while others prefer Visual Studio Code. The IDE integration plugins should be applied as requested. However, Gradle doesn’t expose an auto applying plugin API. For this reason, build authors has to apply individual IDE plugins their developers require.
The final plugin types to mention are base plugins.
We can identify them by the
These plugins offer capabilities in an unopinionated manner.
It provides all the convenience and configuration rules without actually creating any components such as tasks, extensions, etc.
For example, the
java-base plugins offer all the configuration for compiling Java code but don’t create any source set.
java plugin is opinionated and creates a
test source set.