The Art of Open-Sourcing
Open-sourcing is a great way to collaboratively build and improve software for everyone to use. There is an art to creating good open-source software, as I learned in my journey to make PermissMe. I want to walk you through that journey to help you make more informed decisions when you decide to create your own open-source software.
PermissMe handles the “dangerous permissions” introduced with Runtime Permissions in the Android SDK level 23+ with no extra dependencies. It was meant to be for internal use only, but after some discussion with my manager, we agreed it would be helpful to others as well.
Develop on a Separate Repo or Module to Remove Dependencies on Your Main Product
Most open source projects stem from the need of the library in an existing project. It is better when starting development to create a separate module for the library, to allow for easy portability to your public repo when the time comes. If possible, start development on a separate repo all together. This way, there will be no accidental usage of convenience utils or dependencies on your existing project environment. You will be more aware of what dependencies you’re introducing for the purpose of the library and exactly which “utils” are required to get it functioning. Open source projects are an excellent exercise in practicing minimalism, which leads to the next point:
The more dependencies your library has, the bigger in size it will be when dropped into a project to use. Users and developers alike are not huge fans of bloating their app apk size. For example, if you need to do network calls, opt for using the java native API provided in java.net over dropping in a separate library, like Retrofit. However, if a user wants to be able to use an existing networking framework, you should add the flexibility to do so (we’ll come back to why this is important to do later).
Catch Bugs & Architecture Flaws by Integrating the Project During Development
The main goal the developer of any library should have is to ensure there are no bugs in the library. Writing tests is one way to catch bugs but another foolproof method is to simply put yourself into the shoes of the users. Integrate your library into different projects and features to make sure all code paths are tested . It’s hard to test every single use-case if you have just one project using your library in just one way, especially if you developed your library to be customizable and flexible. You need to test those use cases with other projects; real or demo!
As an aside: A bug I found right before making PermissMe public was discovered when I was using it in a hackathon project! The project followed a code path in PermissMe that was never hit in a production app that had it fully integrated for months!
Collect Feedback & Insights to Improve Quality
Getting feedback from coworkers or other developers during development and performing architecture reviews can help figure out which use cases are important for the initial release, and which ones are good for subsequent releases. This will validate your own assumptions, as well as result in higher code quality as you are essentially having it reviewed multiple times. Discussing high-level architecture and functionality is also beneficial for use cases you have possibly missed.
I was discussing PermissMe with a fellow developer, and they brought up the fact that user contact permissions on a specific device had given them trouble in the past and it would be great if PermissMe took care of that for him. I verified that I had accounted for his specific pain point and that PermissMe would indeed work for it. Having the insight of many is extremely valuable for a first release.
Design a Minimal Public API
A user of open-source software expects to be able to take advantage of all the new updates of each release without having any of the old functionality break. A library becomes unreliable when classes and members that were previously supported are marked Deprecated or don’t exist in newer releases. A minimal public API has the benefit of being able to change the inner workings of your library without affecting the interface. From Effective Java 2nd Edition by Joshua Bloch
“The single most important factor that distinguishes a well-designed module from a poorly designed one is the degree to which the module hides its internal data and other implementation details from other modules.”
This excerpt is specifically about good design patterns when creating classes and methods but also applies to creating a well designed open-source library.
Be aware and intentional when adding members, methods, and classes to your library’s public API. For your first release, create the public API with the mindset that you will not be able to modify it and will be stuck with it for a long time. Providing backwards compatibility with each update to your open-source library will make it a reliable candidate for users to integrate into their projects.
Be Pragmatic For the First Release
There is a long list of things that you’ll want to add into the first release — be pragmatic! There will always be things that could make your open source project better* in one way or another. Better demo apps, better plugins and more “flexibility” but it is okay to release an MVP and build on it after the first release.
*In this usage, by “better” I am not referring to code quality, but to providing more functionality or better UI with fancy animations. Code quality should always be a priority regardless of which release.
Know Your Users
During development, take into account the different types of users.
The three main types I identified:
- Users who want to just drop it in and have it work. They don’t want to fiddle with looking at the source code, or trying to understand the inner workings — they just want it to work.
- Users who want to be able to plug in their own components. Using their own instance of a networking library, caching library or image loading library etc. They might want to do this to be able to add custom pre/post processing, or analytics.
- Users who want to fork your project and build on top of it or change it however they please.
Each of these users are important.
Be Patient — it can be a long process
There are a lot of components to releasing a high quality open source library. Other than the core implementation, you also need good documentation, good tests, and a demo app that showcases various scenarios. Depending on the nature of your library and where you work, you might also require legal and security approval, and have to explain your code library to people who have no idea what it does, or are not familiar with the language or platform. You may also have to find time to work on it between other projects depending on your schedule.
I’m currently in the process of developing another library with the intention of open-sourcing it. Keeping in mind the points listed above has provided a framework for me to follow and makes a daunting task much more manageable. Open-sourcing is a great way to showcase cool things you’re working on, as well as learn from other contributors. It’s rewarding work that benefits the developer community at large, and I hope this post has provided an easier framework to follow.