We more often than not re-use code when developing software. For code to be reused when working in Java, we can package it into classes, packages, modules (read gradle-modules), or an artifact.
In Java, we call these artifacts JARs while in Android they become a bit more complicated and independent to become AARs. AARs contain drawables, strings, layouts, values, assets and even the
AndroidManifest.xml. However, to truly re-use the code in an AAR we need to know:
- What the code does
- How to call it
- What to pass to it
The aim of this blog post is to outline how to develop and support Android libraries that are usable by other developers. The fact is that there are a lot of libraries developed that achieve what we want. However, the difficulty of using these libraries — often they are challenging to import, let alone use — deters developers from taking advantage of them.
To develop a usable Android library we can look towards consumer devices, like a smartphone, to know how to better structure our libraries for the programmers who will be our users. A smartphone has a lot of settings that one can tweak to achieve what they want. However, it comes with the best defaults for date/time format, text size, screen timeout, wallpaper, ringtone, and even basic apps to get you started. This however does not limit how much you can customise it to achieve what you want. We also have hidden apps and features that are still used to customise and diagnose issues. The hidden apps and features are hidden from the average user due to the technical and contextual knowledge required to use them. We should build our Android libraries following the same strategies.
I will try and simplify the standards that I believe a developer should follow for a library to be easy to use. This will be a 3-part series for easy reading:
- Part 1: Make the library conventional
- Part 2: Common mistakes to avoid when developing a library
- Part 3: Technical details on how to write and expose APIs
Make the library conventional
1. The documentation location should be conventional
Different platforms and languages have standard documentation locations. For Golang, library documentation is stored in pkg.go.dev and godoc.org. In addition to library documentation, we still need the basic starting and setup documentation in the code repository readme.
For Android, we generally have the instructions in a README.MD. Depending on the nature of the content, and company policy, links to external documentation are added here. These external documentation locations often include:
- Github wikis
- Atlassian pages
- Company documentation sites
- Javadocs sites
Here are some examples of libraries with great documentation:
To refer viewers back to the source code, make sure to add a link to the Github repo from the external documentation.
2. Make the setup steps conventional
Adding the library to a project should be as simple as adding the dependency in the module’s
If it requires adding the repository, classpath or applying a plugin, make sure that this is clear with examples and the specific locations of where it should be added.
3. The setup should be as minimal as possible
It should require little, and ideally no, effort for the developer to simply plug-and-play. This gives the developer quick feedback that they are doing it correctly. You can achieve this by:
- Providing default implementations of interfaces
- Providing default values
- Making whatever is not mandatory optional 😞
- It may sound easy but this means making params nullable or providing overloaded methods
- Providing sample implementations in a sample/demo app
- Developers tend to copy code for faster feedback, this will get them going quickly 😃
4. You should have a sample app module that can be easily run and modified
Having a sample app allows the developer to easily debug their code by comparing with this or running their implementations on the sample app. This also
- Shows them how to do an actual setup in running code,
- Provides customization code that developers can copy,
- Enables the developer to easily test the features and customizability without setting up their own project, and
- Shows different ways the library can be used.
5. Add a frequent asked questions (FAQ) section
This is optional but is straight-forward to add and valuable as a quick reference and a place to add to as you receive feedback from developers using your library.
6. Add a brief troubleshooting section
There are many ways of providing support for the library and this is one of them. If you have used the library yourself, troubleshooting the steps as well as providing examples of problems and solutions will guide users through common challenges that are not explicitly solved by the library or addressed by other parts of your documentation.
This section will provide insight into:
- Compatibility issues,
- Troubleshooting information for specific use-cases,
- Uncommon but obvious information, e.g. Java compatibility, gradle compatibility, and support version issues.
Beyond the steps above, other strategies for providing support are:
- Encouraging the creation of issues (e.g. via Bitbucket, Github, Gitlab or wherever your code is stored) where discussions and problem details can be easily provided. Issues are indexed by search engines and can also be searched on the repo.
- Providing tags for StackOverflow where problems can be posted and answered. Again, StackOverflow issues are indexed by search engines and the developers can find the solution and problem definition.
Github issues provide more flexibility because it is easy to figure out if the issue was fixed, on which library version, and by which commit and pull request.