photos from Unsplash for "pipeline"
General approach
Hello! I am starting a series of posts on pipelines in development and not only that help to verify the quality of mobile applications being developed. The main idea is to highlight all the approaches to mobile development that are relevant now: native development for Android and iOS, React Native, Xamarin and Flutter. I will start with Android, but first I would like to give a general idea of what this is all about.
Keep in mind that this is a general overview of tools and practices that can come in handy in the process of developing Android applications, and not a tutorial on setting up these tools.
What is it all for?
Let's start with the well-known truth: the later you find a defect in the application, the more expensive it is to fix it. Suppose that you have discovered a bug already in production. Your testers need to reproduce this bug locally, register it, prioritize it, pass it to the developers, and they, in turn, need to fix it, make a new assembly, pass it back to the testers so that they are convinced that everything is fixed, and then make the release build, and only then send the new version to users.
Many hours of work could be saved if you had mechanisms to prevent the appearance of bugs at the very beginning. I'm not saying that there is a silver bullet that eliminates all bugs - this is impossible. But what’s possible is to erect barriers (also known as quality gates) that increase the likelihood of catching bugs in your code as early as possible.
On the developer's computer
You as a developer always work on your machine with an IDE and command line tools. Let's see what exists for Android developers.
Android Studio
This is now the default option for the Android developer, and since it is based on the IntelliJ platform, there are many inspections for Java, Kotlin, and XML. I advise you to agree in a team about the specific rules that you want to use, configure them on one computer and upload the settings.jar file with these rules to your version control system or some kind of collaborative work tool (like Confluence).
Inspection Settings in Android Studio
AS also has quick fixes that you can apply to your code by pressing Alt + Enter.
Quick fix example from Android Studio
Android Lint
This is a static analysis tool specifically for Android development, out of the box with hundreds of rules, any of which you can use. Lint can also be launched from the Gradle task (task), and give prompts directly in Android Studio, and generate a report. It has many checks, divided into categories - security, internationalization, usability, performance ...
But the ability to add your own rules makes it especially powerful. For example, Room has its own set of rules, Timber logging library has its own. You can create rules for your team or project and be sure that no one makes certain typical mistakes. (By the way, soon at the Mobius conference there will be a report on this, explaining both the theoretical and practical aspects).
Android Lint Report Example
More static analysis
Of course, there are many static analysis tools designed not specifically for Android, but in general for Java and Kotlin : PMD , FindBugs (abandoned, use SpotBugs ), Checkstyle , Ktlink , Detekt and others. Choose to your liking, integrate it into your pipeline and ensure its real use (how exactly? Read on).
Report example from FindBugs
But it’s not enough to have a tool that provides data on what needs to be fixed. You will also find the following information useful:
- How does code coverage with tests change over time?
- How long will it take me to fix all the problems found?
- How much duplicate code is there in the project?
- How do I extend my rules to multiple teams?
And many others. At EPAM Systems we focus on quality, so we have chosen SonarQube as a tool to answer these questions. Find out more about SonarQube's benefits here .
Unit testing
Hopefully you don't need to reassure you again that your damn code needs unit tests for various reasons . It doesn’t matter if you follow the TDD, adhere to the principle of the testing pyramid or the new idea of the testing mushroom . It is not so important what level of coverage you set as your goal, in any case, your unit tests are a necessary component. So, you need to write and run them! Fortunately, over 11 years of evolution, we got a pretty convenient mechanism for running tests from the Gradle and Android Gradle plug-in.
In the Android greddle project, by default there is the testDebugUnitTest task (for you, of course, it may differ depending on the flavors), and it is she who runs the tests. Make sure you use it and that code coverage grows over time. The advantage of Java unit tests is that they work on the JVM workstation, and not on Dalvik / ART, which gives an advantage in speed.
In the case of android unit tests, there is one fundamental problem: dependence on the Android SDK. This is one of the reasons why all these approaches to the UI layer appeared like MVP, MVVM, MVI and other MV *. The specific problem depending on the class on Android is that unit tests simply fall due to the use of stubs of this Android itself, which simply throw an exception. Of course, there are a couple of options: either skip tests for this class, or extract part of the logic into other classes, or create interfaces for Android-dependent classes to test some high-level logic, or use Robolectric (which is far from ideal). Another option is to use instrumental tests that may be suitable for checking the behavior of an Activity, but the current trend is that Activity should not contain tests.
To the question of coverage: you want to know what it is at your moment and how it changes over time, so that you would need a tool for this as well. To my knowledge, jacoco is an industry standard for Java and it has Kotlin support.
Instrumented Tests
These tests run on the Android emulator, which allows them to use the Android Framework. Unfortunately, they are slow and unstable (due to some problems with the emulator), so most of the developers I personally know try to avoid them. But their support is in Gradle and Android Studio, so for you, they may be suitable.
Security audit
In addition to simple errors, typos, problems with copy-paste and the like, there is also a large category of problems that you should pay attention to: security. Of course, Android Lint already provides some relevant tips, but it’s better to take care of specialized tools specifically for this task. These tools can work in both static and dynamic modes; depending on your security requirements, you may want to use either of these modes, or both. You might want to start, for example, with the Mobile Security Framework , and later consider paid options.
Fortunately, there is a list of static analysis tools compiled directly by OWASP. For example, you can choose Find Security Bugs or use the OWASP SonarCube Project .
Verify Verifications
As I said, the shorter the feedback cycle, the less time and money you spend on fixing bugs. So I want to be sure that the code corresponds to the production quality even before it gets to the repository or even communicated locally. Of course, you can simply ask your developers to perform checks, but there is a much better option: Git hooks.
I suggest adding a pre-commit hook for all the checks we discussed above: Lint, static code analysis, and unit tests. An example of the setup process can be found here .
CI / CD Pipeline
It is very difficult to imagine an Android project without a CI / CD pipeline. Your goal is to repeat all the above checks at the assembly stage. There are several reasons for this:
- Git hooks can be easily circumvented with the `--no-verify 'option
- The code can successfully pass all checks locally, but introduce problems after merge
- Need test and coverage reports
Report example at bitrise.io
Fortunately, it’s enough for you to either mention these security checks directly in the Gradle build script, or to invoke the corresponding tasks in your CI / CD pipeline. If you have difficulty building a pipeline, recently at the DevOops conference I made a presentation on mobile DevOps in 2019.
Please also do the following:
- Run all the checks for pull requests. Do not let merge any request that violates any of the rules. This is very important: if the rule is not executed, then, in fact, it does not exist.
- Run all the checks during assembly and deployment. You do not want to lower your quality bar.
- If the build is broken, this is the first priority. The team should fix the problem immediately because it violates your continuous delivery practice and prevents the team from writing quality code.
And good luck improving your code!
If you liked this article, follow me on Twitter so you don't miss the following. And if you will be in Moscow in December or you can come, come to our Mobius conference and find out a lot of other things about development for Android (and iOS)!
PS Thanks to vixentael for approaching security issues, to Alexei Nikitin for review and comments, to Alexander Bakanov for proofreading.