At Halodoc, we constantly aim to have a cleaner and understandable code, have lesser complexity in managing the dependencies as it is a multi module project.
All the config data, dependencies and project flavours are managed in a centralised Gradle file in all android projects. Handling multi-module projects with a convenient dependency system had become a challenge over time. This article helps us understand the problems faced in traditional dependency management and the solution we took to solve these issues.
The Traditional Approach
The app-level gradle file is the one where we place all our dependencies. It may be third-party dependencies or even our multi-module dependencies.
Consider a project with several internal module dependencies. Let’s call it the Main App, Module 1, Module 2, and Module 3. All these three modules along with the main app, use the below dependencies.
As we are defining these dependencies in all the modules, for any upgrade in the dependency, we need to individually go to these modules, make sure to change it to the latest version, and build it. Any mismatch between the app and the modules dependency version creates conflict issues and also might arise compile time/ run time errors.
What is buildSrc?
buildSrc is a directory at the project root level which contains the build info. We can use this directory to enable
kotlin-dsl and write logic related to custom configuration and share them across the project.
buildSrc is treated as an included build. Upon discovery of the directory, Gradle automatically compiles and tests this code and puts it in the classpath of the build script.
buildSrc is more often seen in multi-project builds simply because larger builds are more likely to implement their own custom tasks and plugins.
The buildSrc Approach
buildSrc can be treated as a repo and cloned in all the modules and project we develop. As it is a single source of information for all the dependencies and their versions, maintaining it would be easy.
Adding buildSrc to the project
In the project-level directory, create a new directory named as `buildSrc`. Sync the project to see a few temporary files which get generated.
buildSrc module behaves like any other Gradle module in the project, it does not require being registered in the project’s
settings.gradle file, nor does it need its own module-level
build.gradle file. But as we will be using Kotlin DSL for our gradle files in our project, we need to add the support. To enable this, we create a new
build.gradle file inside the
buildSrc directory. Adding the
kotlin-dsl plugin enables us to create Kotlin sources for our config files.
src directory in our
buildSrc directory. Here we can place all our config files. There are 3 files we created.
- Versions.kt - Contains all the versions of the dependencies we require for the particular project.
2. Dependencies.kt - File to define all our dependencies , plugins used in our project. It looks as below.
3. ConfigData.kt - We can have an additional config file which would define the build configuration related information.
Finally, we have the config in our
buildSrc directory. Though we can define our versions and dependencies in the same file, we prefer doing it in separate files as it looks more cleaner and understandable. We can use these configurations in our project and app level
build.gradle files. To make this directory available for all our modules, we have created a git repository for the
buildSrc directory and we clone this directory in all the modules. Changes in any of the library versions, is done in the
Versions.kt file and is pushed to the main branch.
- Apart from the config files, we can also create custom tasks in this
buildSrcdirectory. For example, we can create jacoco test reports, coverage check tasks in the directory and use it in our project gradle files. This would make our gradle scripts shorter and cleaner. Example of a custom task is as below.
2. In the traditional approach there is a chance that two modules use different versions of the libraries and hence there are two copies of the same library which contribute to the app size increase. This is avoided by using
buildSrc for multi-module project. We can make sure all modules use same versions of the libraries which would helps in app size restrictions.
Few other advantages include compile time error checking, auto completion and content assists. Also as the android code is mostly written in Kotlin these days, there would be consistency of using the same language across the application.
When we have a situation where we need different versions of a library for different modules/projects,
buildSrc would not quite fit in. It would be cumbersome to maintain multiple copies/branches of
buildSrc and use them for different modules. This would majorly occur in bigger projects with multiple modules.
buildSrc + Kotlin DSL is the best option for dependency management. As it is a class-level declaration it can be easily tested. The auto-suggestion support and code navigation would help in saving time. Using separate classes for each purpose would be easy for better reusability and easy maintenance.
Scalability, reliability and maintainability are the three pillars that govern what we build at Halodoc Tech. We are actively looking for engineers at all levels and if solving hard problems with challenging requirements is your forte, please reach out to us with your resumé at email@example.com.
Halodoc is the number 1 all around Healthcare application in Indonesia. Our mission is to simplify and bring quality healthcare across Indonesia, from Sabang to Merauke. We connect 20,000+ doctors with patients in need through our Tele-consultation service. We partner with 3500+ pharmacies in 100+ cities to bring medicine to your doorstep. We've also partnered with Indonesia's largest lab provider to provide lab home services, and to top it off we have recently launched a premium appointment service that partners with 500+ hospitals that allow patients to book a doctor appointment inside our application. We are extremely fortunate to be trusted by our investors, such as the Bill & Melinda Gates Foundation, Singtel, UOB Ventures, Allianz, GoJek, Astra, Temasek and many more. We recently closed our Series C round and In total have raised around USD$180 million for our mission. Our team works tirelessly to make sure that we create the best healthcare solution personalised for all of our patient's needs, and are continuously on a path to simplify healthcare for Indonesia.