How we went about creating tooling to maintain high-quality code.
Within our team, we pride ourselves on producing great products for our clients. More than that though, we aim to produce great code.
We want our code to meet high standards of efficiency, speed and maintainability. This means we adhere to style guides and apply best practices wherever we can.
These standards even apply to our XML files.
We use peer code reviewing as a tool for maintaining high-quality code. We look for bugs, styling mistakes and any general improvements.
Since we are human, we cannot rely on code review as a safety net which will catch everything. Instead, its only one of the weapons in our armoury.
So what other tools do we use?
We use various automated tools for keeping our code quality high. Our favourites include Android Lint, ktlint & detekt. They help to ensure code style and catch obvious bugs.
Yet, they don't provide ways of enforcing a style within your XML files. It also appears that there aren't many tools for doing so within an Android context. So I set out to create one.
I wanted to build a tool which we can run to check our XML files. We want to ensure certain styles, and it needs to be able to run within an automated pipeline.
I decided to build a command line interface (CLI). My Kotlin skills are better practised than my Ruby or Bash, so I set out to create a CLI using Kotlin.
‘Clikt is a Kotlin library that makes writing command line interfaces simple and intuitive’. Ok, this is taken straight from the website, but as it turns out it's rather true.
Clikt provides a base class, CliktCommand, which allows you to override run(). This is where you place your code and voila, a CLI.
XMLCheck is composed of a few different key components. These components help to break down the tool, allowing us to maintain and grow it over time.
Rule
A rule represents a particular style we want to enforce.
AttrRule & ElementRule
These abstract classes help to ensure these rules get run safely and appropriately. It allows the implementor to target their rule towards an attribute or element.
Checker
The checker implements CliktCommand and is where the rules get run.
Firstly, I examine the path, supplied as an argument, to collect the XML files ready for inspection. Next, for each XML File I read it into an XML Document. Now it's time to examine all the nodes within the document (examineNodes()).
examineNodes() loops through all the nodes, looking for Element's, and examines them (examineElement()). Using the rules supplied (allElementRules, allAttrRules) I check that each node conforms to the given rule.
Options
So that the CLI is more widely applicable I added a couple of options. --exclude allows users to not run particular rules. --fail-on-empty defines whether supplying an empty path should be considered an error. This is particularly useful at the start of the project when you haven't added any XML files yet within some of your modules.
To implement XMLCheck I made some additions to our standard quality.gradle file.
https://gist.github.com/alistairsykes/0ef606f1e4af0525cf42132f382fe270
This gets applied at the top of each modules build.gradle
apply from: "$project.rootDir/quality/quality.gradle"
Now we can call ./gradlew xmlchecker or ./gradlew check as we did before and our XMLCheck CLI gets run.
Thanks to Clikt, writing a CLI tool in Kotlin to check our XML files was simple and easy for us to maintain in the future. This means we can continue to produce high-quality XML files and reduces the overhead for a code review.
We have made this project available for others to use and customise for their needs. We hope this will help others to improve the quality of their XML files.
Search over 400 blog posts from our team
Subscribe to our monthly digest of blogs to stay in the loop and come with us on our journey to make things better!