<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ gradle - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ gradle - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 27 Jul 2026 20:16:20 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/gradle/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to boost build time with CircleCI test parallelism ]]>
                </title>
                <description>
                    <![CDATA[ By Karel Rochelt Providing an error-free API for a heavily developed project is not an easy task. Likely, the first things that come to mind are tests. For a mid-sized API, you may write hundreds or even thousands of end-to-end tests. These tests sig... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-boost-build-time-with-circleci-test-parallelism-f89e5eab1397/</link>
                <guid isPermaLink="false">66c34f3a4f1fc448a367903e</guid>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ gradle ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 03 Dec 2018 17:21:59 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*Xw31bEh4xGoWbmx_.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Karel Rochelt</p>
<p>Providing an error-free API for a heavily developed project is not an easy task. Likely, the first things that come to mind are tests. For a mid-sized API, you may write hundreds or even thousands of end-to-end tests. These tests significantly prolong build times.</p>
<p>In this post, we will explain how we solved long build times with CircleCI test parallelism and Gradle/Grails for <a target="_blank" href="https://amio.io">Amio</a> main service.</p>
<h3 id="heading-circleci-setup">CircleCI setup</h3>
<p>CircleCI’s <a target="_blank" href="https://circleci.com/docs/2.0/parallelism-faster-jobs/">documentation</a> does a decent job of explaining how their <a target="_blank" href="https://circleci.com/docs/2.0/local-cli/">command line interface</a> (CLI) tool should be used to enable test parallelism. When I started looking into it for the first time, it wasn’t entirely obvious what the returned result would look like. I was asking myself, “So, I’ll run this command and it will magically start splitting my tests?” Well, of course not! The result is a list of test files that should be executed on a particular container.</p>
<p>Does that sound complicated? Let me explain in an example.</p>
<p>The first thing we have to do is to set the parallelism key in the <code>.circleci/config.yml</code> file. From the CircleCI docs:</p>
<blockquote>
<p>The <code>_parallelism_</code> key specifies how many independent executors will be set up to run the steps of a job.</p>
</blockquote>
<p>Any value greater than one will enable parallel execution, but for the sake of this example, let’s go with two. This way, every time a CircleCI job is started, it will spawn two containers which will both do the same tasks.</p>
<p>If we were to use the parallelism key with no additional configuration, it would just run all of our tests twice. That is not what we want. We want to split our tests between the containers.</p>
<p>That’s where the CircleCI CLI comes in. It offers two commands which, when used together, split our tests into equal portions across our two containers.</p>
<p>Let’s say these are the test files in our project:</p>
<pre><code>src/integration-test/groovy/com/package1/Test1.groovysrc/integration-test/groovy/com/package1/Test2.groovysrc/integration-test/groovy/com/package2/Test3.groovysrc/integration-test/groovy/com/package2/Test4.groovysrc/integration-test/groovy/com/package2/Test5.groovy
</code></pre><p>Naturally, we will have other source files in our project; not just our tests. They may be located in the same <code>src/integration-test/…</code> directory. To achieve our goal of test splitting, we need to select only the test files for the project. That is done by using the <a target="_blank" href="https://circleci.com/docs/2.0/parallelism-faster-jobs/#globbing-test-files">glob</a> command:</p>
<pre><code>circleci tests glob <span class="hljs-string">"src/integration-test/**/*.groovy"</span>
</code></pre><p>This command will output the list of our tests (all 5 of them). ? Now we use the split command to, well, s<a target="_blank" href="https://circleci.com/docs/2.0/parallelism-faster-jobs/#splitting-test-files">plit</a> them between containers:</p>
<pre><code>circleci tests glob <span class="hljs-string">"src/integration-test/**/*.groovy"</span> | circleci tests split --split-by=timings
</code></pre><p>The <code>split</code> command offers several strategies to split the tests but <code>timings</code> is my favorite. It uses the timings data that is collected by CircleCI (this has to be enabled via the <a target="_blank" href="https://circleci.com/docs/2.0/configuration-reference/#store_test_results">store_test_results</a> key) to split the tests into portions that take a similar time to execute. Container indexing is automatic. We can run the same command on every container. In our example, running the command on Container 0 might output:</p>
<pre><code>src/integration-test/groovy/com/package1/Test1.groovysrc/integration-test/groovy/com/package2/Test3.groovy
</code></pre><p>And on Container 1:</p>
<pre><code>src/integration-test/groovy/com/package1/Test2.groovysrc/integration-test/groovy/com/package2/Test4.groovysrc/integration-test/groovy/com/package2/Test5.groovy
</code></pre><p>I say “might” because the real result would depend on the timings data. As you can see, every container got its half of the tests.</p>
<h3 id="heading-gradle-setup">Gradle setup</h3>
<p>Splitting the tests in CircleCI was the easy part. The hard part is getting Gradle to execute just the tests that are in the result of the split command. If we were using JavaScript and Mocha, it would be much easier. Mocha accepts a list of files which should be executed. With Gradle 3, I had been using this command to run tests: <code>./gradlew check -i</code></p>
<p>Gradle’s <a target="_blank" href="https://docs.gradle.org/current/userguide/gradle_wrapper.html">documentation</a> isn’t really helpful. Just figuring out what the check task does is a pain. Thankfully, it is possible to pass our test list as a parameter to the Gradle task.</p>
<pre><code>./gradlew check -i -PtestFilter=<span class="hljs-string">"`circleci tests glob "</span>src/integration-test<span class="hljs-comment">/**/*.groovy" | circleci tests split --split-by=timings`"</span>
</code></pre><p>Now, when the <code>check</code> task is started, it has access to the <code>testFilter</code> parameter. To make everything work, we also need to add some code that can handle the parameter in our <strong>build.gradle</strong>:</p>
<pre><code>integrationTest {  <span class="hljs-keyword">if</span> (project.hasProperty(<span class="hljs-string">"testFilter"</span>)) {    List&lt;<span class="hljs-built_in">String</span>&gt; props = project.getProperties().get(<span class="hljs-string">"testFilter"</span>).split(<span class="hljs-string">"\\s+"</span>)    props.each {      include(it.replace(<span class="hljs-string">"src/integration-test/groovy/com/"</span>, <span class="hljs-string">"**/"</span>).replace(<span class="hljs-string">".groovy"</span>, <span class="hljs-string">".class"</span>))    }  }}
</code></pre><p>Note that the parameter was passed to the task as a single string. In the code block above, Line 3 contains logic to split it back into rows. Calling include will tell Gradle to execute only the tests that we include. Now we can include all the rows, and we’re good, right?</p>
<p>Nope. Gradle doesn’t know how to work with source files. It only understands classes. We need to pass the compiled class files to it.</p>
<p>There are two problems with that. First, the compiled classes are not in the same directory. Second, the suffix is not .groovy but .class.</p>
<p>To overcome the first problem, we replaced the common prefix with **/. This says, “Look in the root directory and all its subdirectories.” Of course, you could replace it with something like <code>build/classes/integrationTest/com</code>. That is cleaner, but not necessary. This should be safe as long as the test classes names are unique. Line 5 in the code block above includes logic that solves both of these problems.</p>
<p>In the end, your <code>.circleci/config.yml</code> should look something like this (just the relevant part):</p>
<pre><code>- run:    # This is just <span class="hljs-keyword">for</span> debugging purposes, you can omit <span class="hljs-built_in">this</span> step    name: test splitting output    command: circleci tests glob “src/integration-test<span class="hljs-comment">/**/*.groovy” | circleci tests split --split-by=timings | xargs -n 1 echo</span>
</code></pre><pre><code>- run:    name: test    command: ./gradlew check -i -PtestFilter=<span class="hljs-string">"`circleci tests glob “src/integration-test/**/*.groovy” | circleci tests split --split-by=timings`"</span>
</code></pre><h3 id="heading-conclusion">Conclusion</h3>
<p>And that’s it! Easy, right? Well, it was a bit more work than it should have been. Having our test times cut nearly in half was definitely worth it! Applying test parallelism, we’ve decreased the build time from around 15 minutes to 9 minutes.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/5Pn6DOPH8BS02ki3faCRXcsui9ZE1x9jRnp4" alt="Image" width="800" height="414" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How modularization can speed up your Android app’s built time ]]>
                </title>
                <description>
                    <![CDATA[ By Nikita Kozlov Developers will continue to add new features throughout an application’s lifetime. More code means not only longer build times — it means longer incremental build time. For teams with big projects, waiting for new builds could eventu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-modularisation-affects-build-time-of-an-android-application-43a984ce9968/</link>
                <guid isPermaLink="false">66c34e7c4f7405e6476b0204</guid>
                
                    <category>
                        <![CDATA[ Android ]]>
                    </category>
                
                    <category>
                        <![CDATA[ android app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ androiddev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ gradle ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 20 Jan 2017 16:48:47 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*J-1MC3QGbIuwq4tb-yr-iA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nikita Kozlov</p>
<p>Developers will continue to add new features throughout an application’s lifetime. More code means not only longer build times — it means longer <em>incremental</em> build time.</p>
<p>For teams with big projects, waiting for new builds could eventually take up 10-15% of their workday. This not only wastes precious developer time — it also makes test-driven development extremely tedious, which hurts overall code quality.</p>
<p>Splitting an application into modules could be a solution to this problem. I was tempted to just split our codebase by feature, by layer, or in some other quick and obvious way. But first, I decided to create an experiment and collect some data, so I could make a better-informed decision. This article will explore the results I collected and my findings.</p>
<p>Before we dive into my experiment, I’d like to talk about the theory behind all this, and explain how we can decrease incremental build time.</p>
<h3 id="heading-a-bit-of-theory">A bit of theory</h3>
<p>When you create an Android application you have to have at least one <em>application</em> module, it is a module that applied the Gradle application plugin in his <em>build.gradle</em> file:</p>
<pre><code>apply plugin: <span class="hljs-string">'com.android.application'</span>
</code></pre><p>As a result of building this module you will get an .APK file.</p>
<p>One <em>application</em> module cannot depend on another. It can only depend on a <em>library.</em> It is the module that applied the Gradle library plugin:</p>
<pre><code>apply plugin: <span class="hljs-string">'com.android.library'</span>
</code></pre><p>As a result of publishing such a module you will get an .AAR file (Android Archive Library). Comparing to .JAR file .AAR has some Android-related things, for example, resources and Manifest.</p>
<p>Building process for any library or application module can be <em>roughly</em> split into five phases, that could be represented with a certain Gradle tasks:</p>
<ol>
<li><strong>Preparation of dependencies.</strong> During this phase Gradle check that all libraries this module depends on are ready. If this module depends on another one, that module would be built as well.</li>
<li><strong>Merging resources and processing Manifest.</strong> After this phase resources and Manifest are ready to be packaged in the result file.</li>
<li><strong>Compiling.</strong> This phase started with Annotation Processors, in case you use them. Then source code is compiled into byte code. If you are using AspectJ, weaving also happens here.</li>
<li><strong>Postprocessing.</strong> All Gradle tasks with a “transform” prefix are part of this phase. Most important ones are: <code>transformClassesWithMultidexlist</code> and <code>transformClassesWithDex</code><em>.</em> They produce .DEX files.</li>
<li><strong>Packaging and publishing.</strong> For libraries this stage means creating an .AAR file in the end, for applications — .APK.</li>
</ol>
<p>As I mentioned, our goal is to minimize incremental build time. It’s difficult to speed up all the phases in one experiment, so I decided to focus on the longest ones. For a project with a single module, those were the compiling and postprocessing phases. The merging resources and processing manifest phase can also sometimes be time-consuming, but if the Java code is untouched, than incremental build is quite fast.</p>
<p>We all know, that Gradle runs task in consequent builds only if input isn’t the same. It also doesn’t rebuild a module if it wasn’t changed. That leads to the following hypothesis:</p>
<blockquote>
<p>“The Incremental build time for a project with multiple modules is faster than for a single-module project, because only modified modules are recompiled.”</p>
</blockquote>
<p>All right, lets find out whether this is true!</p>
<h3 id="heading-experiment-setup">Experiment Setup</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/m8SaIngTlbZkpYa4eqzV1F8hdi26pco4kVfE" alt="Image" width="720" height="585" loading="lazy"></p>
<p>Project uses Gradle plugins v2.2.2. Minimal Android SDK is 15, that covers most of the devices according to <a target="_blank" href="https://developer.android.com/about/dashboards/index.html">API level dashboard</a>. All modules have a dependency on <em>Butterknife</em>, to make project a bit more “alive”, since all projects has external dependencies.</p>
<p>In all variants application module is called <em>“app”</em>, while library modules are called <em>“app2”</em>, <em>“app3”</em> and so on.</p>
<p>Each variant has in total around 100 packages 15,000 classes 90,000 methods. Assembled that is two DEX files, almost three. Generated code is dummy, to keep all the methods in the .APK file, minifying and shrinking were disabled.</p>
<p>All measurements was done with Gradle build-in profiler. To use it you just need to add “--profile” in the end of the command, like this:</p>
<pre><code>./gradlew assembleDebug --profile
</code></pre><p>As a result you will get a .HTML file with measurements.</p>
<p>For each setup I repeated each measurement 4 to 15 times, to make sure that my results were reproducible.</p>
<h4 id="heading-java-code-generator">Java Code Generator</h4>
<p>Writing all 15,000 classes by hand is time consuming, so I wrote a simple code generator in Python. It is available in <a target="_blank" href="https://gist.github.com/NikitaKozlov/ff9d8e65d9d880a2f35e1cac58a84990">Gist</a>. Below you can find a schema of the code it generates.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/OMOMY0Ji9nNhHYvfyKBdTcPmeC8fVujWWVYv" alt="Image" width="800" height="494" loading="lazy"></p>
<p>As you can see, every next generated method called the previous one, and every first method of the next class called the last method of the previous class. That makes code more coupled, and increased compilation time.</p>
<h4 id="heading-pure-java-modules">Pure Java modules</h4>
<p>I didn’t make a special experiments for pure Java modules. But I played with them a bit, and I can say that usually they are faster then Android ones. That happens because during build less tasks are executed, for example, there is no resources to merge.</p>
<p>If you’re interested in results for pure Java modules, please write a comment. Or you can clone the project from <a target="_blank" href="https://github.com/NikitaKozlov/GradleBuildExperiment">GitHub</a> and modify it according to your needs. But don’t forget that actual results depend on hardware. To be able to compare your results, please repeat some experiments in your environment as well.</p>
<h4 id="heading-small-losses-here-and-there">Small losses here and there</h4>
<p>It’s no surprise that doing something in parallel does slow down the build. Even having a second project open in Android Studio can make build 5–10% slower. Listening to music, watching YouTube, or browsing the internet increases the build time a lot! I personally saw a speeding up of a build process by up to 30% after just closing everything except Android Studio.</p>
<p>All experiments were done with only necessary browser tabs and a single Android Studio project open.</p>
<h3 id="heading-lets-do-the-experiment">Let’s do the experiment</h3>
<h4 id="heading-initial-state">Initial State</h4>
<p>As a starting point I took a project with a single module that contains all 15 000 classes. For this setup incremental build time is <em>1m 10s</em>.</p>
<h4 id="heading-3-modules">3 Modules</h4>
<p>First step is splitting one module into three: one application module and two library ones. Application module depends on libraries, but library modules are independent from one another. Each module has about 5 000 classes and 30 000 methods.</p>
<p>If changes are made only in application module, then build time is about 35 seconds. Almost 30 seconds win compare to initial state. But when one of library module is changed, even if application module is untouched, incremental build time grows to <em>1m 50s</em>. 40 seconds longer!</p>
<p>Let’s take a look into profile report and see what took so long:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/haPhcC7iI9R6lMmNaSTWm-sEQ3LzTZg8hI41" alt="Image" width="800" height="327" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/4RI8AzAfrQCPVsDjVRt009zHjGdaUPo30Rbk" alt="Image" width="800" height="112" loading="lazy">
<em>Profile report of an incremental build with changes in library module (“:app2”). Since application module (“:app”) depends on the library one, it is also recompiled.</em></p>
<p>In the screenshots above, you can see that most of the time was spent on building the library module. You might also notice that for library modules, both debug and release tasks were executed. Gradle wasted time executing two sets of tasks instead of one! This is why it took an extra 40 seconds longer than the single-module project.</p>
<p>We can avoid this and make this build even faster than our initial <em>1m 10s</em> by splitting our code into modules.</p>
<p>But that’s not the only problem. Let’s look into <em>how</em> our application module depends on library modules:</p>
<pre><code>dependencies {    compile project(path: <span class="hljs-string">':app2'</span>)    compile project(path: <span class="hljs-string">':app3'</span>)}
</code></pre><p>There’s an important problem in the code above: if a library is added like this, then the application always depends on the <em>release</em> variant, independent of it’s own build type. It also doesn’t matter which variant is chosen in Android Studio. Here’s what the <a target="_blank" href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-Publication">Gradle Plugin User Guide</a> says about all this:</p>
<blockquote>
<p>By default a library only publishes its <em>release</em> variant. This variant will be used by all projects referencing the library, no matter which variant they build themselves. This is a temporary limitation due to Gradle limitations that we are working towards removing.</p>
</blockquote>
<p>Luckily, it’s possible to change the variant our application depends on.</p>
<p>First, add the following code to libraries’ <em>build.gradle</em> file. It will allow library to publish <em>debug</em> variant as well:</p>
<pre><code>android {    defaultConfig {        defaultPublishConfig <span class="hljs-string">'release'</span>        publishNonDefault <span class="hljs-literal">true</span>    }}
</code></pre><p>Second, application module should depend on library ones like this:</p>
<pre><code>dependencies {    debugCompile project(path: <span class="hljs-string">':app2'</span>, <span class="hljs-attr">configuration</span>: <span class="hljs-string">"debug"</span>)    releaseCompile project(path: <span class="hljs-string">':app2'</span>, <span class="hljs-attr">configuration</span>: <span class="hljs-string">"release"</span>)    debugCompile project(path: <span class="hljs-string">':app3'</span>, <span class="hljs-attr">configuration</span>: <span class="hljs-string">"debug"</span>)    releaseCompile project(path: <span class="hljs-string">':app3'</span>, <span class="hljs-attr">configuration</span>: <span class="hljs-string">"release"</span>)}
</code></pre><p>Now the debug variant of our application depends on the debug variant of the libraries, and its release depends on their release. So lets make some changes to the module <em>app2</em> and rebuild it. After these changes, we can check our profile report again:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/khyDy7gT4Hd8SiCz7rfoDlarUfRyGRCINpXs" alt="Image" width="800" height="285" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/D-udP9Ns1gkbTFHdcLh0AE7MDlkYoNb3jJ66" alt="Image" width="800" height="110" loading="lazy"></p>
<p>The most significant difference is the absence of <em>:app2:packageReleaseJarArtifact,</em> which saves us about 15 seconds. In addition, the time is reshuffled a bit between rest of the tasks, and we end up with <em>1m 32s</em>. That is 18 seconds faster then before, but still 22 seconds slower then our initial configuration. For changes only in the application module, build time stays almost the same — <em>36 seconds</em> vs <em>35 seconds</em> in our previous configuration.</p>
<p>Unfortunately I didn’t found a proper explanation for why it builds both flavors. I hope that once this Gradle limitation is resolved, then this problem will just go away as well. The same issue is discussed in <a target="_blank" href="https://code.google.com/p/android/issues/detail?id=52962">AOSP Issue Tracker</a>.</p>
<p>I’m also planning to spend some time experimenting with Gradle tasks to find a workaround for this problem. One possible way is to exclude all release tasks for debug builds.</p>
<h4 id="heading-5-modules">5 Modules</h4>
<p>Obviously, build time depends on the amount of code. If you reduce amount of code by half then the build should also be roughly two times faster. If instead of 3 modules project is split in 5, then build time should be approximately 40% faster.</p>
<p>It is almost true.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/JsR7H3b6U9J49HLLY6rV5BCsNnuCQIT0O4rx" alt="Image" width="800" height="277" loading="lazy"></p>
<p>If changes are made only in application module then incremental build time is approximately 24<em>s.</em> For changes in a library module incremental build takes <em>50s</em>. Compare to initial <em>1m 10s</em> that is already a win. But I have a few more tricks at my disposal.</p>
<h4 id="heading-reduce-size-of-the-application-module">Reduce Size of The Application Module</h4>
<p>Independently of what module is changed, application module will be recompiled every time. So reducing it’s size makes total sense. Ideally, it should just assemble whole application from a separate modules and might also provide a splash screen, because splash screen often depends on lots of features.</p>
<p>That is how idea about <em>3+1</em> and <em>5+1</em> configurations was born. In both cases project has a small application module that depends on 3 and 5 library modules accordingly. All library modules are independent from one another and has equal sizes. Let’s see what that gives us:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/e5AZF2lz4WsblcBuK1WA94CRadMgF7lPrjr-" alt="Image" width="800" height="405" loading="lazy"></p>
<p>We can observe further drop in incremental build time. Even with changes in library module <em>5+1</em> configuration is build almost twice as fast as an initial single-module project. This is a decent progress.</p>
<h4 id="heading-why-does-project-actually-depends-on-butterknife">Why does project actually depends on Butterknife?</h4>
<p>This is a point where I have to make a confession. There was one very strong reason to add a dependency on <em>Butterknife</em>.</p>
<p>In the initial configuration incremental compilation takes <em>45s</em> out of <em>1m 10s</em>, but if <em>Butterknife</em> is removed then project is compiled in <em>15s</em> only! Three times faster! Whole incremental build without Butterknife is <em>40s</em>.</p>
<p>Is it a problem in the library?</p>
<p>As it appeared — no. Without <em>Butterknife</em> project compiles so fast because of actual Java incremental compilation, which is disabled for projects that use Annotation processors. You can find related issues in <a target="_blank" href="https://issues.gradle.org/browse/GRADLE-3259">Gradle Jira</a>, in <a target="_blank" href="https://code.google.com/p/android/issues/detail?id=200043">AOSP Issue Tracker</a>, it is also tracked in Gradle <a target="_blank" href="https://github.com/gradle/gradle/blob/master/design-docs/incremental-java-compilation.md">design docs</a>. If you will take a closer look into the issue from ASOP Issue Tracker, one of the comment says:</p>
<blockquote>
<p><em>“Annotation processors is not yet supported with incremental java compilation. It will depend on changes in Gradle.</em></p>
<p><em>We disabled it for project that apply com.neenbedankt.android-apt, so it's no longer a significant issue.”</em></p>
</blockquote>
<p>That is why build just becomes slower without a notification.</p>
<p>Personally I won’t remove Annotation processors from the whole project. I find libraries like <em>Dagger</em> and <em>Butterknife</em> useful. But having a couple of modules without them could be a good idea, that would make their builds so much faster!</p>
<h4 id="heading-one-more-trick-rump-up-api-level">One More Trick — Rump Up API Level</h4>
<p>Compilation is not the only thing that slows down build process. Producing .DEX files could also be time consuming. Especially if an application is above DEX Limit. Using multidex configuration increases build time, build system need to decided which classes go to which .DEX file. With introduction of Android Runtime the way how Android OS works with application that has multiple DEX files has changed. This is what <a target="_blank" href="https://developer.android.com/studio/build/multidex.html#mdex-on-l">Android Studio documentation</a> says about it:</p>
<blockquote>
<p><em>“Android 5.0 (API level 21) and higher uses a runtime called ART which natively supports loading multiple DEX files from APK files. ART performs pre-compilation at app install time which scans for <code>classesN.dex</code> files and compiles them into a single <code>.oat</code> file for execution by the Android device.”</em></p>
</blockquote>
<p>That leads to decrease in build time. The reason is that each module produces its own DEX files, that are included into APK without modification. If you take a look into the tasks that run during build, you will notice that <code>transformClassesWithMultidexlist</code> is no longer executed. Also compilation itself became faster. You can find more information and instructions how to make a flavor that uses API 21 <a target="_blank" href="https://developer.android.com/studio/build/multidex.html#dev-build">here</a>.</p>
<h4 id="heading-fastest-build-configuration-achieved">Fastest Build Configuration Achieved.</h4>
<p>Using API 21 for debug is an easy gain for every project. I tried it for <em>5+1</em> configuration and results were amazing:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/odoCUKJg-NQm9vl4yJKfZfh7jLCsxqEPqRAS" alt="Image" width="800" height="279" loading="lazy"></p>
<p>Even for changes in library module incremental build time was only <em>17 seconds</em>! But take into account that all modules are independent from one another. Once dependency between modules is introduced, build time increases from <em>17s</em> to <em>42s</em> (last row in the table above)!</p>
<h4 id="heading-developing-library-module-in-a-test-driven-way">Developing Library Module in a Test Driven Way</h4>
<p>One of the main reasons why test-driven development (TDD) is difficult for single-module project is build time. TDD encourage to run test often. Running tests multiple times in a minute is a normal practice. But when build takes a minute or two, working in Test Driven way couldn’t be very productive.</p>
<p>With introduction of modules that problem is automagically resolved. Building a single module in the last configuration took only <em>9s</em>! It make possible to run tests as often as needed.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/8hhEYND4vfQGxgZ-NOcL8YVohRxBHLHqjm3G" alt="Image" width="720" height="675" loading="lazy"></p>
<p>First and most important, the hypothesis was correct, modularizing project can significantly speed up build process, but not for all configurations.</p>
<p>Second, if splitting is done in a wrong way, then build time will be drastically increased, because Gradle build both, release and debug version of library modules.</p>
<p>Third, working in test-driven way is much easier for a project with multiple modules, because building a small library module is way faster then the whole project.</p>
<p>Forth, doing many things in parallel slows down the build. So having more powerful hardware is a good idea.</p>
<p>Below you can find results of all experiments described in this article:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/hxYQoAIaUGfb-dIVjjBmZVtiDyiPmpGyOOkw" alt="Image" width="800" height="601" loading="lazy"></p>
<p>Please vote for mentioned issues. Resolving any of those would be a huge step towards faster builds. Below you can find all links:</p>
<ul>
<li><a target="_blank" href="https://code.google.com/p/android/issues/detail?id=52962">https://code.google.com/p/android/issues/detail?id=52962</a></li>
<li><a target="_blank" href="https://issues.gradle.org/browse/GRADLE-3259"><em>https://issues.gradle.org/browse/GRADLE-3259</em></a></li>
<li><a target="_blank" href="https://code.google.com/p/android/issues/detail?id=200043">https://code.google.com/p/android/issues/detail?id=200043</a></li>
</ul>
<p>All code is published on <a target="_blank" href="https://github.com/NikitaKozlov/GradleBuildExperiment">GitHub</a>.</p>
<p><a target="_blank" href="https://twitter.com/Nikita_E_Kozlov"><strong>Nikita Kozlov (@Nikita_E_Kozlov) | Twitter</strong></a><br><a target="_blank" href="https://twitter.com/Nikita_E_Kozlov">_The latest Tweets from Nikita Kozlov (@Nikita_E_Kozlov): “https://t.co/wmGSJ7snW1"_twitter.com</a></p>
<p><em>Thank you for you time reading this article. If you like it, don’t forget to click the</em> ? <em>below.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
