<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ishan Khanna</title>
    <description>The latest articles on DEV Community by Ishan Khanna (@droidchef).</description>
    <link>https://dev.to/droidchef</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F867541%2Fabb9f980-590e-4122-8a61-25f26255855a.png</url>
      <title>DEV Community: Ishan Khanna</title>
      <link>https://dev.to/droidchef</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/droidchef"/>
    <language>en</language>
    <item>
      <title>Mastering The Gradle Dependency Tree</title>
      <dc:creator>Ishan Khanna</dc:creator>
      <pubDate>Wed, 11 Jan 2023 23:09:51 +0000</pubDate>
      <link>https://dev.to/droidchef/mastering-the-gradle-dependency-tree-2jah</link>
      <guid>https://dev.to/droidchef/mastering-the-gradle-dependency-tree-2jah</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wQNrwKfz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/Mastering-The-Gradle-Dependency-Tree.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wQNrwKfz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/Mastering-The-Gradle-Dependency-Tree.png" alt="Mastering The Gradle Dependency Tree" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Gradle dependency tree is the backbone of your Gradle builds. Its representation can help you visualize the structure of all of the gradle dependencies in a project, as well as any transitive dependencies. Not so long ago I wrote a Twitter thread sharing some tips to debug your slow Gradle builds which led me into the journey of diving deeper into this topic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is a great question to refresh and revise what I have learned over the years from my ex-colleagues especially &lt;a href="https://twitter.com/inyaki_mwc?ref_src=twsrc%5Etfw"&gt;@inyaki_mwc&lt;/a&gt; &amp;amp; &lt;a href="https://twitter.com/jperezalv?ref_src=twsrc%5Etfw"&gt;@jperezalv&lt;/a&gt;&lt;br&gt;&lt;br&gt;
I'll try to summarize what usual suspects I can recall in the 🧵 &lt;a href="https://t.co/lgZDmeIKTn"&gt;https://t.co/lgZDmeIKTn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Ishan Khanna (&lt;a class="mentioned-user" href="https://dev.to/droidchef"&gt;@droidchef&lt;/a&gt;) &lt;a href="https://twitter.com/droidchef/status/1593302175383400451?ref_src=twsrc%5Etfw"&gt;November 17, 2022&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, I discuss&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are dependencies and transitive dependencies in Gradle?&lt;/li&gt;
&lt;li&gt;What is a dependency tree in Gradle?&lt;/li&gt;
&lt;li&gt;What are the different dependency configurations in Gradle?&lt;/li&gt;
&lt;li&gt;Five ways to generate a dependency tree in your Gradle project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By reading the whole article, you will&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have a solid understanding of Gradle dependency tree&lt;/li&gt;
&lt;li&gt;be equipped with the knowledge to generate a Gradle dependency tree using different ways for any project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started by covering some basics.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is a Dependency in Gradle?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A dependency in Gradle is a relationship between two elements that allow one to access the content, resources, or libraries of the other element. It can be between modules within a project or external dependencies from external sources such as &lt;strong&gt;Maven Central&lt;/strong&gt; and &lt;strong&gt;JCenter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A Gradle dependency establishes an association between the two elements by specifying the version of the dependency being used. When Gradle constructs a dependency tree, it takes into account both transitive and direct dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Transitive Dependency in Gradle?
&lt;/h3&gt;

&lt;p&gt;A transitive dependency in Gradle is a dependency that is implied by another dependency and thus pulled into the project from an external source.&lt;/p&gt;

&lt;p&gt;Transitive dependencies are resolved using the version of the library declared by the original dependency, and all of them for that library is then included in your project.&lt;/p&gt;

&lt;p&gt;This can lead to unnecessary bloat in your projects if you are not careful about managing your gradle dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different Types of Transitive Dependencies
&lt;/h3&gt;

&lt;p&gt;They can be both &lt;strong&gt;direct&lt;/strong&gt; and &lt;strong&gt;indirect&lt;/strong&gt; ; for example, if you declare a direct dependency on Library A, which has a transitive dependency on Library B, you will also end up with Library B included as a transitive dependency in your project.&lt;/p&gt;

&lt;p&gt;🧠&lt;/p&gt;

&lt;p&gt;Transitive dependencies can become complex when multiple modules have different versions of the same library; Gradle will attempt to resolve this by picking the newest version available.   &lt;/p&gt;

&lt;p&gt;It is important to manage these various versions carefully to avoid conflicts or other unexpected behavior in your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring Gradle Dependencies in a Gradle Project
&lt;/h3&gt;

&lt;p&gt;Gradle allows us the ability to group dependencies by specifying a dependency configuration. You may have seen words like &lt;code&gt;implementation&lt;/code&gt;, &lt;code&gt;androidTestImplementation&lt;/code&gt; or &lt;code&gt;testImplementation&lt;/code&gt; in your project’s &lt;code&gt;build.gradle&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;By default, a Gradle build doesn’t support any dependency configuration however they integrate with your build via plugins such as the &lt;strong&gt;Android&lt;/strong&gt; plugin, &lt;strong&gt;Kotlin&lt;/strong&gt; Plugin, or the &lt;strong&gt;Java&lt;/strong&gt; Plugin.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These configurations are used by Gradle to generate classpaths for building project for production or testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is important to know this before you generate your dependency tree as you might start wondering why are there multiple configurations in your build.&lt;/p&gt;

&lt;p&gt;With the basics out of the way, now it is time to actually start generating the dependency tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating A Gradle Dependency Tree
&lt;/h2&gt;

&lt;p&gt;There are five ways to generate the Gradle dependencies. The quickest way is to use the dependencies task. However, it may not always be suitable or give you the best results. So we will walk through all the different ways you can generate and visualize it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I personally don’t use or recommend using Android Studio for anything other than writing code, especially if you are working on a relatively large code base. However, I still do talk about it for anyone feeling adventurous.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;If you would like to follow the commands I run in the sections below. You can set up a lightweight &lt;a href="https://github.com/droidchef/dep-height-example"&gt;sample project&lt;/a&gt; I created to demonstrate &lt;a href="https://blog.droidchef.dev/impact-of-dependency-tree-depth-on-gradle-builds/"&gt;the impact of dependency tree depth on your gradle builds&lt;/a&gt; by completing the steps below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open your Terminal and Go to the directory where you save your projects, for me, it is &lt;code&gt;~/dev/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/dev/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Clone a sample root project like this
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:droidchef/dep-height-example.git

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Change the directory to the root project like this
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd dep-height-example

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you are ready to run all the commands mentioned in the steps below.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Using Dependencies Task in Command Line
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;easiest way to generate a dependency tree&lt;/strong&gt; for your project is to run the dependencies task at the root of your project and here is how you do it.&lt;/p&gt;

&lt;p&gt;In your terminal, Go to the root directory of your application and Run the following on the command line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew :{moduleName}:dependencies

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;{moduleName}&lt;/code&gt; should be replaced with the name of the module you want to want to view the dependency tree for.&lt;/p&gt;

&lt;p&gt;The sample which is a multi-module project has a module named &lt;code&gt;contractor&lt;/code&gt; and I will try to list the gradle dependencies for it by running the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew :contractor:dependencies

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is what the output looks like&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C_pJP3uc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-dependency-tree-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C_pJP3uc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-dependency-tree-example.png" alt="Mastering The Gradle Dependency Tree" width="880" height="947"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the output of the dependencies task is extremely verbose as it contains results for all configurations, classPaths, elements, and their respective metadata.&lt;/p&gt;

&lt;p&gt;Fortunately, our amazing colleagues at Gradle have provided us with a mechanism to control the result to only show specific types of configurations and this is what you will be using most of the time during your investigations.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to filter dependencies by configuration?
&lt;/h3&gt;

&lt;p&gt;You can use the configuration parameter with the dependencies task in Gradle to view dependencies for a specific configuration type.&lt;/p&gt;

&lt;p&gt;This is how you would construct your gradle task&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew :{yourModuleName}:dependencies --configuration {yourConfigurationName}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is an example showing implementation dependencies for the &lt;code&gt;contractor&lt;/code&gt; module of the sample multi-module project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew :contractor:dependencies --configuration implementation

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the example result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T2Wy6Ivo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-dependency-tree-for-specific-configuration.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T2Wy6Ivo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-dependency-tree-for-specific-configuration.png" alt="Mastering The Gradle Dependency Tree" width="880" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  List of Supported Parameters for Configuration Task
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;configuration&lt;/code&gt; parameter supports the following inputs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;testCompile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;implementation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;testImplementation&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your root project is an Android project then you also have access to these along with the above-mentioned inputs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;androidTestCompile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;androidTestImplementation&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are the examples showing how you can use the above parameters&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew :{moduleName}:dependencies --configuration compile
./gradlew :{moduleName}:dependencies --configuration testCompile
./gradlew :{moduleName}:dependencies --configuration testImplementation
./gradlew :{moduleName}:dependencies --configuration androidTestCompile
./gradlew :{moduleName}:dependencies --configuration androidTestImplementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Using Project Report Plugin
&lt;/h2&gt;

&lt;p&gt;If you have a large project or a small screen you can also generate the dependencies report using a plugin. The plugin is called The Project Report Plugin. It will give you an HTML-based dependencies report that allows you to browse the whole dependency tree in your favorite browser.&lt;/p&gt;

&lt;p&gt;It is extremely easy to set up and here is how you do it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Integrate Project Report Plugin?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open the &lt;code&gt;build.gradle&lt;/code&gt; file in the root directory of your project.&lt;/li&gt;
&lt;li&gt;Add this to the top of the file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apply plugin: 'project-report'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugins {
    id 'project-report'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Sync the Project in your IDE ( &lt;strong&gt;&lt;u&gt;Optional&lt;/u&gt;&lt;/strong&gt; )&lt;/li&gt;
&lt;li&gt;Run the following command in your terminal
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew htmlDependencyReport

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Open the HTML Report generated by Gradle. The file path is usually &lt;code&gt;{project root}/build/reports/project/dependencies/index.html&lt;/code&gt; where &lt;code&gt;{project root}&lt;/code&gt; refers to the root directory of your project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZsynJFPM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-project-report-plugin-output-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZsynJFPM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-project-report-plugin-output-1.png" alt="Mastering The Gradle Dependency Tree" width="880" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also &lt;code&gt;Command (or Cmd) ⌘ + Click&lt;/code&gt; on this &lt;code&gt;file://&lt;/code&gt; path and it should open in your browser.&lt;/p&gt;

&lt;p&gt;When you open this report you will see the project for which the report was generated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MSBbgX5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/Screen-Shot-2023-01-02-at-12.30.33-PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MSBbgX5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/Screen-Shot-2023-01-02-at-12.30.33-PM.png" alt="Mastering The Gradle Dependency Tree" width="880" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the &lt;u&gt;root project&lt;/u&gt; URL to see the searchable dependency report&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--smiX2FQa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/Screen-Shot-2023-01-02-at-12.29.33-PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--smiX2FQa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/Screen-Shot-2023-01-02-at-12.29.33-PM.png" alt="Mastering The Gradle Dependency Tree" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click different dependency configurations to view the report in detail.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Using Gradle Dependency Graph Generator Plugin
&lt;/h2&gt;

&lt;p&gt;Now if you are really interested in digging deep into your project’s dependency structure. There exists a third-party Gradle plugin that is built primarily for this purpose. I personally find it useful when dealing with modularization or if I want a glance at the whole dependency tree at once.&lt;/p&gt;

&lt;p&gt;It is called &lt;a href="https://github.com/vanniktech/gradle-dependency-graph-generator-plugin"&gt;&lt;strong&gt;gradle-dependency-graph-generator-plugin&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;,&lt;/strong&gt; developed and maintained by &lt;a href="https://github.com/vanniktech"&gt;Niklas Baudy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can use it to generate a visual graph for your project’s dependencies in formats like png, SVG, and dot.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Integrate Gradle Dependency Graph Generator Plugin?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open the &lt;code&gt;build.gradle&lt;/code&gt; file of your root project&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You can also add it to a specific project or module and it will work fine&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Add the following to the Gradle file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.8.0"
  }
}

apply plugin: "com.vanniktech.dependency.graph.generator"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.8.0"
  }
}

plugins {
 id 'com.vanniktech.dependency.graph.generator' version '0.8.0'
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Sync with gradle in your IDE and Run this task in your terminal
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew generateDependencyGraph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generate the gradle dependencies graph in this directory &lt;code&gt;build/reports/dependency-graph/&lt;/code&gt; that looks like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q3dbbila--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/dependency-graph-sample-image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q3dbbila--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/dependency-graph-sample-image.png" alt="Mastering The Gradle Dependency Tree" width="880" height="674"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Using Gradle Build Scan
&lt;/h2&gt;

&lt;p&gt;Gradle build scans are like an X-ray for your Gradle and Maven builds.&lt;/p&gt;

&lt;p&gt;If you are using build scans in your Gradle project. You get access to the project dependencies for free. If you have never generated a Gradle build scan before, you can generate one right now for free in &lt;strong&gt;under two minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The only thing you need is the &lt;code&gt;--scan&lt;/code&gt; parameter at the end of any Gradle command you run in your terminal.&lt;/p&gt;

&lt;p&gt;Let’s use a simple command to list the tasks of the project to generate a build scan.&lt;/p&gt;

&lt;p&gt;Go ahead and run this command in the root directory of your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew tasks --scan

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the build ends, you will be prompted for a confirmation to generate the build scan. This is because Gradle will be collecting build information and information about your hardware and sending it to their servers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fYMO39Mt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-prompting-for-consent.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fYMO39Mt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-prompting-for-consent.png" alt="Mastering The Gradle Dependency Tree" width="880" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are okay with this, type &lt;code&gt;yes&lt;/code&gt; and hit &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B79A0KAB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-consented.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B79A0KAB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-consented.png" alt="Mastering The Gradle Dependency Tree" width="880" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you’ll see a link to your personal build scan access page in your terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KllPB2KO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-url-output.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KllPB2KO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-url-output.png" alt="Mastering The Gradle Dependency Tree" width="880" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open that URL in your browser and this is what you will see.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H1mr7oK3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-page.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H1mr7oK3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-page.png" alt="Mastering The Gradle Dependency Tree" width="880" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now to get information about your dependencies click on the &lt;strong&gt;Dependencies&lt;/strong&gt; item in the left menu navigation menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--te27m4eU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-dependencies-page.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--te27m4eU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-build-scan-dependencies-page.png" alt="Mastering The Gradle Dependency Tree" width="880" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will show you an interactive searchable dependency report in which&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can search for dependencies.&lt;/li&gt;
&lt;li&gt;You can see dependencies for different configurations.&lt;/li&gt;
&lt;li&gt;You can find out which library or module or project uses this dependency.&lt;/li&gt;
&lt;li&gt;You can even see which repository they come from.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to this, there is a lot more information you have access to in this build scan report. However, this is out of the scope of this article.&lt;/p&gt;

&lt;p&gt;Finally, let’s look at the most straightforward way to generate the dependency tree for your project using android studio.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Using Android Studio's Gradle Plugin
&lt;/h2&gt;

&lt;p&gt;You can use Android Studio’s Gradle plugin to generate and view the structure of gradle dependencies. This might seem like the easiest way. However, I &lt;em&gt;do not recommend&lt;/em&gt; this for &lt;strong&gt;large-scale projects&lt;/strong&gt; since it can &lt;strong&gt;slow you down&lt;/strong&gt; significantly. This is the reason, I am discussing this approach as the last one.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to generate Gradle Dependency Tree with Android Studio?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;First open your Android Studio and Click on the Gradle Tab.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m4iudFVq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-tab-module-list-in-android-studio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m4iudFVq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/gradle-tab-module-list-in-android-studio.png" alt="Mastering The Gradle Dependency Tree" width="880" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For an Android Project&lt;/strong&gt;
Then expand &lt;code&gt;:yourmodule&lt;/code&gt; -&amp;gt; &lt;code&gt;Tasks&lt;/code&gt; -&amp;gt; &lt;code&gt;android&lt;/code&gt; . Finally, double click on &lt;code&gt;androidDependencies&lt;/code&gt; to execute the task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For a Java or Kotlin Project&lt;/strong&gt;
Then expand &lt;code&gt;:yourmodule&lt;/code&gt; -&amp;gt; &lt;code&gt;Tasks&lt;/code&gt; -&amp;gt; &lt;code&gt;help&lt;/code&gt; . Finally, double click on &lt;code&gt;dependencies&lt;/code&gt; to execute the task.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mCXJ2Dxy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/dependencies-task-in-gradle-project-android-studio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mCXJ2Dxy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/dependencies-task-in-gradle-project-android-studio.png" alt="Mastering The Gradle Dependency Tree" width="880" height="948"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Android Studio Showing Dependency Generation Task in Gradle Project&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After this task finishes executing it will print the whole dependency tree report in the console of Android Studio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LjH1zcbe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/dependencies-output-android-studio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LjH1zcbe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.droidchef.dev/content/images/2023/01/dependencies-output-android-studio.png" alt="Mastering The Gradle Dependency Tree" width="880" height="308"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Output of Dependencies Task in Android Studio Console.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What are Omitted Dependencies?
&lt;/h2&gt;

&lt;p&gt;You might have come accross a message in the output that says&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(*) - dependencies omitted (listed previously)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It means gradle removes duplicate sections from your dependencie tree to keep the output concise. It doesn't actually affect your real dependency graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Failed Dependencies?
&lt;/h2&gt;

&lt;p&gt;In the output of your dependency tree if any dependency is marked as &lt;code&gt;FAILED&lt;/code&gt; then it means that Gradle could not locate it in any of your configured repositories.&lt;/p&gt;

&lt;p&gt;It could be due to many reasons including but not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incorrect versioning&lt;/li&gt;
&lt;li&gt;Connectivity Issues&lt;/li&gt;
&lt;li&gt;Proxy Concerns on your machine&lt;/li&gt;
&lt;li&gt;Misspelled dependency name&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Dependency Configuration Inheritance?
&lt;/h2&gt;

&lt;p&gt;As you might have seen in the screenshots above Dependency Configurations support inheritance. When a dependency configuration inherits from another configuration, it automatically gets access to all the dependencies of its parent.&lt;/p&gt;

&lt;p&gt;For example, consider an Android project. The app's &lt;code&gt;build.gradle&lt;/code&gt; file will have its own dependencies, such as the Android Support Library and any third-party libraries that the project uses.&lt;/p&gt;

&lt;p&gt;However, these dependencies can also be inherited from other scopes, such as a library module or even your organization’s internal repository of pre-packaged libraries. This allows you to easily keep your project up-to-date with the latest libraries and also simplifies maintenance.&lt;/p&gt;

&lt;p&gt;Gradle dependency configuration inheritance makes it easy to manage complex projects and keep them organized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By reading this post, you should now have a solid understanding of Gradle dependency tree and are now equipped with the knowledge to generate a Gradle dependency tree using different ways for any project. Please share this article on LinkedIn and Twitter.&lt;/p&gt;

&lt;p&gt;If you have any doubts regarding this, feel free to leave a comment below!&lt;/p&gt;

</description>
      <category>gradle</category>
      <category>android</category>
    </item>
    <item>
      <title>Flutter vs Jetpack Compose: The Battle of the Decade</title>
      <dc:creator>Ishan Khanna</dc:creator>
      <pubDate>Wed, 16 Nov 2022 03:38:11 +0000</pubDate>
      <link>https://dev.to/droidchef/flutter-vs-jetpack-compose-the-battle-of-the-decade-5fbj</link>
      <guid>https://dev.to/droidchef/flutter-vs-jetpack-compose-the-battle-of-the-decade-5fbj</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D67iPmCg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/Flutter-vs-Jetpack-Compose-Header--2-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D67iPmCg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/Flutter-vs-Jetpack-Compose-Header--2-.png" alt="Flutter vs Jetpack Compose: The Battle of the Decade" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the blue corner, we have Flutter. In the red corner, we have Jetpack Compose. These two titans have been locked in an epic struggle for supremacy ever since Google first announced Jetpack Compose in 2018. But who will come out on top? Let's find out!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Blade Runner Scenario
&lt;/h2&gt;

&lt;p&gt;In the original Blade Runner movie from 1982, humanity has developed a form of synthetically-created life that is so realistic, it's difficult to tell them apart from humans. These "replicants" are used for dangerous or otherwise undesirable jobs, and when they start rebelling against their human masters, a special type of police officer known as a "blade runner" is tasked with hunting them down and retiring them.&lt;/p&gt;

&lt;p&gt;Similarly, in the world of mobile app development, there are two types of developers: those who use &lt;strong&gt;&lt;a href="https://flutter.dev/"&gt;Flutter&lt;/a&gt;&lt;/strong&gt;, and those who use &lt;strong&gt;&lt;a href="https://developer.android.com/jetpack/compose"&gt;Jetpack Compose&lt;/a&gt;&lt;/strong&gt;. When Google first announced Jetpack Compose, many thought it would be the end of Flutter. After all, why use a cross-platform framework when you can just use the native tools provided by Google?&lt;/p&gt;

&lt;p&gt;But just like the replicants in Blade Runner, Flutter refused to go down without a fight. And in the two years since Jetpack Compose was first announced, Flutter has only become more popular. So what gives? Let's pit these two frameworks against each other in a head-to-head battle to see which one comes out on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Language
&lt;/h2&gt;

&lt;p&gt;Flutter uses &lt;a href="https://dart.dev/"&gt;Dart&lt;/a&gt;—an object-oriented language created by Google—while Jetpack Compose uses &lt;a href="https://kotlinlang.org/"&gt;Kotlin&lt;/a&gt;, a statically typed programming language created by JetBrains. Both languages have their pros and cons, but we're going to give this round to Dart because it is easier to learn for beginners and because it performs better than Kotlin when it comes to runtime speed and memory usage.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I personally found Dart easier to learn when I was &lt;a href="https://dev.to/droidchef/flutter-add-to-app-in-production-a-war-story-296i-temp-slug-7802304"&gt;Flirting with Flutter at Getaround&lt;/a&gt; a few years back.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Community Support
&lt;/h2&gt;

&lt;p&gt;When it comes to community support, there is no clear winner when comparing Flutter vs Jetpack compose.&lt;/p&gt;

&lt;p&gt;Flutter has a large and active community of developers who are constantly creating new plugins, sharing tips and tricks, and helping each other out. Jetpack Compose also has a strong community of developers, although it is not quite as large as the Flutter community.&lt;/p&gt;

&lt;p&gt;However, what Jetpack Compose lacks in community size, it makes up for in quality—the Jetpack Compose team is very responsive to issues raised on the GitHub repository and they are always working on new features and improvements.&lt;/p&gt;

&lt;p&gt;One surprising thing I found during my research was that when you compare the trends for both frameworks on Stackoverflow, Jetpack Compose is nowhere close to Flutter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://insights.stackoverflow.com/trends?tags=flutter%2Candroid-jetpack-compose"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f3Z9J2F0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/Screen-Shot-2022-11-08-at-9.42.48-AM.png" alt="Flutter vs Jetpack Compose: The Battle of the Decade" width="880" height="663"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Comparison of % of Flutter vs Jetpack Compose Stack Overflow questions monthly (as of November 11, 2022)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I believe this because Flutter works cross platform and so often times people are just looking for the same thing on multiple platforms and that contributes significantly to the question bank.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Documentation and Resources
&lt;/h2&gt;

&lt;p&gt;Both Flutter and Jetpack Compose have excellent documentation that is easy to follow and packed with plenty of code examples. In addition, both frameworks have a wealth of resources available online, including video tutorials, blog posts, articles, and more. We're going to call this one a tie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ease of Use
&lt;/h2&gt;

&lt;p&gt;Jetpack Compose wins this round hands down. While both frameworks are relatively easy to use, Jetpack Compose takes the cake when it comes to ease of use thanks to its declarative UI approach.&lt;/p&gt;

&lt;p&gt;This means that you can build your UI using simple Kotlin code instead of having to worry about all the underlying complexity.&lt;/p&gt;

&lt;p&gt;I know and understand that Flutter is also declarative, however it is not straightforward to access OS-level components directly without a bridging logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Systems
&lt;/h2&gt;

&lt;p&gt;Flutter uses its own custom Dart tooling to compile code ahead-of-time into native ARM assembly code for iOS and Android.&lt;/p&gt;

&lt;p&gt;On the other hand, Jetpack Compose uses the standard Kotlin compiler to build your app's UI.&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;misconception&lt;/em&gt; I had for a long time was that &lt;code&gt;@Composable&lt;/code&gt; uses an annotation processor, which is &lt;em&gt;NOT&lt;/em&gt; true!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compose works with the aid of a Kotlin compiler plugin in the type checking and code generation phases of Kotlin: there is no annotation processor needed in order to use compose. – &lt;strong&gt;&lt;a href="https://medium.com/androiddevelopers/under-the-hood-of-jetpack-compose-part-2-of-2-37b2c20c6cdd"&gt;Under the hood of Jetpack Compose — part 2 of 2&lt;/a&gt; by&lt;/strong&gt; &lt;a href="https://twitter.com/intelligibabble"&gt;Leland Richardson&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When comparing the addition of Flutter vs Jetpack Compose to existing applications, both bring a significant warm-up overhead and slow down the app that isn't entirely built with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Marketing &amp;amp; Brand Perception
&lt;/h2&gt;

&lt;p&gt;To better understand how teams at Google are supporting their respective frameworks I found that they aren't leaving any stone unturned to attract developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Marketing
&lt;/h3&gt;

&lt;p&gt;When comparing the marketing of Flutter vs Jetpack Compose both teams have their ads running on Google.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MDrXbzZp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/flutter-vs-jetpack-compose-ad-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MDrXbzZp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/flutter-vs-jetpack-compose-ad-1.png" alt="Flutter vs Jetpack Compose: The Battle of the Decade" width="880" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PqbAH9U2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/flutter-vs-jetpack-compose-flutter-ad-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PqbAH9U2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/flutter-vs-jetpack-compose-flutter-ad-1.png" alt="Flutter vs Jetpack Compose: The Battle of the Decade" width="880" height="703"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Flutter vs Jetpack Compose Google Ads Comparison&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Trends
&lt;/h3&gt;

&lt;p&gt;I also compared search trends for Flutter vs Jetpack and the results are quite shocking.&lt;/p&gt;

&lt;p&gt;The search interest for Flutter is almost double that of Compose as you can see in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C3Gf_Iax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/flutter-vs-jetpack-compose-google-search-trends.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C3Gf_Iax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/flutter-vs-jetpack-compose-google-search-trends.png" alt="Flutter vs Jetpack Compose: The Battle of the Decade" width="880" height="446"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Comparison of Google Search Trends for Flutter vs Jetpack Compose&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In fact, you can even compare the breakdown by region to see developers in which countries are heavily invested in Flutter vs Jetpack Compose.&lt;/p&gt;

&lt;p&gt;Excluding Canada, France, Spain, and the Philippines, Flutter dominates the search trends all over the world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cSS2sO3Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/flutter-vs-jetpack-compose-country-wise-breakdown-google-search-trends.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cSS2sO3Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/flutter-vs-jetpack-compose-country-wise-breakdown-google-search-trends.png" alt="Flutter vs Jetpack Compose: The Battle of the Decade" width="880" height="358"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Google Search Trends for Flutter vs Jetpack Compose by Region&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Frankly, I am surprised to see this result given how the brand perception and adoption feels like in the industry based on social media.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Adoption
&lt;/h3&gt;

&lt;p&gt;In order to understand how companies and individuals are perceiving the benefits, ease of use, and impact of Jetpack Compose for their Android projects I used a proxy metric to see how many talks were presented at Droidcon(s) in the last five years about both the topics and the results looked like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XMqfHSc9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/talks-at-droidcon-flutter-vs-jetpack-compose-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XMqfHSc9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/talks-at-droidcon-flutter-vs-jetpack-compose-1.png" alt="Flutter vs Jetpack Compose: The Battle of the Decade" width="880" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--21I7oEjM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/talks-at-droidcon-flutter-vs-jetpack-compose-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--21I7oEjM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/11/talks-at-droidcon-flutter-vs-jetpack-compose-2.png" alt="Flutter vs Jetpack Compose: The Battle of the Decade" width="880" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To plot the charts above, I looked at all the videos posted on Droidcon.com and looked for specific keywords in their titles. The keywords I looked for in the beginning were "Flutter" and "Jetpack Compose" and it resulted in the chart on the left-hand side.&lt;/p&gt;

&lt;p&gt;However, I realized a lot of talks used the word "Compose" in their title and so I ran my analysis again to find an astounding result that shows how popular "Compose" has been at Droidcon events in the last few years with the interest only growing over time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I know Flutter community organises their own separate events as well so this might not feel like an apples to apples comparison but it serves as a decent data point to predict the trends and inclination of the Android community at the very least.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Flutter vs Jetpack Compose: A Developer's Perspective
&lt;/h2&gt;

&lt;p&gt;As a developer who has used both frameworks, I can say without hesitation that Jetpack Compose is a joy to use. It's so much easier to create beautiful user interfaces with Jetpack Compose than it is with Flutter—and that's not even taking into account the fact that you can also use Kotlin instead of Dart with Jetpack Compose (although Dart is a perfectly fine language).&lt;/p&gt;

&lt;p&gt;However, there are still some things that Flutter does better than Jetpack Compose. For one thing, the hot reload feature in Flutter is indispensable when you're trying to rapidly prototype an app idea. And although Jetpack Compose has made great strides in recent months, it's tooling still isn't quite as good as Flutter's—which is something that Google will need to address if it wants Jetpack Compose to truly succeed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;So there you have it—a head-to-head comparison of Flutter and Jetpack Compose. While both frameworks have their own strengths and weaknesses, we think that overall Jetpack Compose comes out on top thanks to its ease of use and strong community support. However, ultimately the best framework for you will depend on your own specific needs and preferences.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>jetpackcompose</category>
    </item>
    <item>
      <title>Four Ways to Remove Duplicates From an Array in Kotlin</title>
      <dc:creator>Ishan Khanna</dc:creator>
      <pubDate>Sun, 23 Oct 2022 02:29:26 +0000</pubDate>
      <link>https://dev.to/droidchef/four-ways-to-remove-duplicates-from-an-array-in-kotlin-5f3o</link>
      <guid>https://dev.to/droidchef/four-ways-to-remove-duplicates-from-an-array-in-kotlin-5f3o</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;There are a few ways to remove duplicates from an array in kotlin:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using the &lt;code&gt;toSet()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;toHashSet()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;toMutableSet()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;distinct()&lt;/code&gt; function&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To understand the usage of each function let us consider the following example:&lt;/p&gt;

&lt;p&gt;You have a &lt;code&gt;data&lt;/code&gt; class called &lt;code&gt;Node&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Node(val id: Int, val fullyQualifiedName: String)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and, an &lt;code&gt;array&lt;/code&gt; of &lt;code&gt;Nodes&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val nodes = arrayOf(
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(2, "dev.droidchef.usecase.DeleteAllNodes"),
    Node(3, "dev.droidchef.usecase.SetAllNodes"),
    Node(4, "dev.droidchef.usecase.GetAllNodes"),
    Node(5, "dev.droidchef.usecase.WipeAllNodes")
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the toSet() function
&lt;/h2&gt;

&lt;p&gt;This function will create a new Set (which is a data structure that doesn't allow duplicate entries) from the given array. This is the simplest and the best way to remove duplicates from an array in kotlin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Points To Remember
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Return type of &lt;code&gt;toSet()&lt;/code&gt; is a &lt;code&gt;Set&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internally it calls &lt;code&gt;toCollection()&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;guarantees&lt;/strong&gt; the preservation of the iteration order of the elements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Sample
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Node(val id: Int, val fullyQualifiedName: String)

val nodes = arrayOf(
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(2, "dev.droidchef.usecase.DeleteAllNodes"),
    Node(3, "dev.droidchef.usecase.SetAllNodes"),
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(4, "dev.droidchef.usecase.WipeAllNodes")
)

val deDupedNodes = nodes.toSet()
deDupedNodes.forEach {
    println(it)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node(id=1, fullyQualifiedName=dev.droidchef.usecase.GetAllNodes)
Node(id=2, fullyQualifiedName=dev.droidchef.usecase.DeleteAllNodes)
Node(id=3, fullyQualifiedName=dev.droidchef.usecase.SetAllNodes)
Node(id=4, fullyQualifiedName=dev.droidchef.usecase.WipeAllNodes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the toHashSet() function
&lt;/h2&gt;

&lt;p&gt;This function will create a new HashSet (which is a data structure that doesn't allow duplicate entries) from the given array.&lt;/p&gt;

&lt;h3&gt;
  
  
  Points To Remember
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Return type of &lt;code&gt;toHashSet()&lt;/code&gt; is a &lt;code&gt;HashSet&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internally it calls &lt;code&gt;toCollection()&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;does not guarantee&lt;/strong&gt; the preservation of the iteration order of the elements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Sample
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Node(val id: Int, val fullyQualifiedName: String)

val nodes = arrayOf(
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(2, "dev.droidchef.usecase.DeleteAllNodes"),
    Node(3, "dev.droidchef.usecase.SetAllNodes"),
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(4, "dev.droidchef.usecase.WipeAllNodes")
)

val deDupedNodes = nodes.toHashSet()
deDupedNodes.forEach {
    println(it)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node(id=1, fullyQualifiedName=dev.droidchef.usecase.GetAllNodes)
Node(id=2, fullyQualifiedName=dev.droidchef.usecase.DeleteAllNodes)
Node(id=3, fullyQualifiedName=dev.droidchef.usecase.SetAllNodes)
Node(id=4, fullyQualifiedName=dev.droidchef.usecase.WipeAllNodes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the toMutableSet() function
&lt;/h2&gt;

&lt;p&gt;This function will create a new MutableSet (which is a data structure that doesn't allow duplicate entries) from the given array.&lt;/p&gt;

&lt;h3&gt;
  
  
  Points To Remember
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Return type of &lt;code&gt;toMutableSet()&lt;/code&gt; is a &lt;code&gt;MutableSet&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internally it calls &lt;code&gt;toCollection()&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;preserves&lt;/strong&gt; the iteration order of the elements as it uses &lt;code&gt;LinkedHashSet&amp;lt;T&amp;gt;&lt;/code&gt; implementation of a &lt;code&gt;MutableSet&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Sample
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Node(val id: Int, val fullyQualifiedName: String)

val nodes = arrayOf(
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(2, "dev.droidchef.usecase.DeleteAllNodes"),
    Node(3, "dev.droidchef.usecase.SetAllNodes"),
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(4, "dev.droidchef.usecase.WipeAllNodes")
)

val deDupedNodes = nodes.toMutableSet()
deDupedNodes.forEach {
    println(it)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node(id=1, fullyQualifiedName=dev.droidchef.usecase.GetAllNodes)
Node(id=2, fullyQualifiedName=dev.droidchef.usecase.DeleteAllNodes)
Node(id=3, fullyQualifiedName=dev.droidchef.usecase.SetAllNodes)
Node(id=4, fullyQualifiedName=dev.droidchef.usecase.WipeAllNodes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the distinct() function
&lt;/h2&gt;

&lt;p&gt;This function will return a new array that contains only the unique elements from the given array. This is the most flexible way to remove duplicates, as you can still use the original array if you need to. However, it is not the most efficient one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Points To Remember
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Return type of &lt;code&gt;distinct()&lt;/code&gt; is an &lt;code&gt;Array&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internally it calls &lt;code&gt;toMutableSet()&lt;/code&gt; followed by &lt;code&gt;toList()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Only use this &lt;strong&gt;if&lt;/strong&gt; you want your return type to be an &lt;code&gt;Array&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;does not guarantee&lt;/strong&gt; the preservation of the iteration order of the elements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Sample
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Node(val id: Int, val fullyQualifiedName: String)

val nodes = arrayOf(
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(2, "dev.droidchef.usecase.DeleteAllNodes"),
    Node(3, "dev.droidchef.usecase.SetAllNodes"),
    Node(1, "dev.droidchef.usecase.GetAllNodes"),
    Node(4, "dev.droidchef.usecase.WipeAllNodes")
)

val deDupedNodes = nodes.distinct()
deDupedNodes.forEach {
    println(it)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node(id=1, fullyQualifiedName=dev.droidchef.usecase.GetAllNodes)
Node(id=2, fullyQualifiedName=dev.droidchef.usecase.DeleteAllNodes)
Node(id=3, fullyQualifiedName=dev.droidchef.usecase.SetAllNodes)
Node(id=4, fullyQualifiedName=dev.droidchef.usecase.WipeAllNodes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Challenges with Removing Duplicates from An Array in Kotlin
&lt;/h2&gt;

&lt;p&gt;One of the common challenges people have when trying to remove duplicates from an array is not knowing which method to use. There are a few different ways to do it, and each has its own benefits and drawbacks. Another challenge is efficiency - if you're working with a large array, you need to make sure that the method you're using is efficient enough to handle it. Otherwise, you could end up with a very slow process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There are a few different ways to remove duplicates from an array in kotlin, each with its own benefits and drawbacks. The best way to choose which method to use depends on your specific needs. If you're working with a large array, you need to make sure that the method you're using is efficient enough to handle it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q: What is the best way to remove duplicates from an array in kotlin?
&lt;/h3&gt;

&lt;p&gt;A:  The best way to remove duplicates from an array in kotlin is to use the &lt;code&gt;toSet()&lt;/code&gt; method if you don't mind working with a &lt;code&gt;Set&amp;lt;T&amp;gt;&lt;/code&gt; and it also preserves the iteration order. If you don't care about the order and only want to have an &lt;code&gt;Array&amp;lt;T&amp;gt;&lt;/code&gt; as the return type then you should use &lt;code&gt;distinct()&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Q: What are some of the challenges people face when trying to remove duplicates from an array?
&lt;/h3&gt;

&lt;p&gt;A: Some of the challenges people face when trying to remove duplicates from an array include not knowing which method to use and efficiency. If you're working with a large array, you need to make sure that the method you're using is efficient enough to handle it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q: What is the most efficient way to remove duplicates from an array in kotlin?
&lt;/h3&gt;

&lt;p&gt;A: The most efficient way to remove duplicates from an array in kotlin is to use the &lt;code&gt;toSetOf()&lt;/code&gt; function. This function will create a new &lt;code&gt;Set&amp;lt;T&amp;gt;&lt;/code&gt; (which is a data structure that doesn't allow duplicate entries) from the given array. It uses a hashing algorithm to store the elements in the set, so it's very efficient.&lt;/p&gt;

&lt;p&gt;Don't forget to checkout my website for more tutorials about &lt;a href="https://www.droidchef.dev"&gt;Android &amp;amp; Kotlin Tutorials and Mobile Career Development Tips&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>array</category>
      <category>set</category>
    </item>
    <item>
      <title>Five Costs Engineers Don’t Know About Breaking A Critical Path In The App</title>
      <dc:creator>Ishan Khanna</dc:creator>
      <pubDate>Sat, 22 Oct 2022 05:12:08 +0000</pubDate>
      <link>https://dev.to/droidchef/five-costs-engineers-dont-know-about-breaking-a-critical-path-in-the-app-1hil</link>
      <guid>https://dev.to/droidchef/five-costs-engineers-dont-know-about-breaking-a-critical-path-in-the-app-1hil</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cjwNxQ3d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/10/five-costs-engineers-dont-know-about-breaking-a-critical-path-in-the-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cjwNxQ3d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.droidchef.dev/content/images/2022/10/five-costs-engineers-dont-know-about-breaking-a-critical-path-in-the-app.png" alt="Five Costs Engineers Don’t Know About Breaking A Critical Path In The App" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you break an app in production, the first thing leaders are interested to know is the estimated impact.&lt;/p&gt;

&lt;p&gt;The impact is what largely decides what course of action you take thereafter. If you perform retrospectives or postmortems you’d try to be more accurate with your estimates, however, based on my personal experience, most developers fail to see impact beyond direct revenue or crashes.&lt;/p&gt;

&lt;p&gt;In this post, I will discuss five different types of costs you incur when you break an app in production.&lt;/p&gt;

&lt;p&gt;The five types of costs associated with breaking a flow in your app are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explicit Loss of Revenue&lt;/li&gt;
&lt;li&gt;Collateral Damage to the Business&lt;/li&gt;
&lt;li&gt;Cost of Investigation&lt;/li&gt;
&lt;li&gt;Cost of Fixing&lt;/li&gt;
&lt;li&gt;Cost of Remediation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s look at each one of them in a little more detail.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cost 1: Explicit Loss of Revenue
&lt;/h1&gt;

&lt;p&gt;When you break a critical path in your app, this leads to a loss in revenue.&lt;/p&gt;

&lt;p&gt;Depending on the business model you operate under, the revenue loss could be immediate or lagging. For example, if you are selling goods or items that a user will consume, you could notice a drop in revenue soon enough, provided you have sufficient monitoring in place. On the other hand, if you are selling subscriptions, you could lose out on your subscribers in the subsequent cycle which could be a lagging indicator or you would fail to convert users into paying customers.&lt;/p&gt;

&lt;p&gt;This is what most people are able to figure out since this is what the bottom lines are made up of.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cost 2: Collateral Damage to The Business
&lt;/h1&gt;

&lt;p&gt;Apart from losing out on sales and conversion for certain items or subscriptions. You also end up hurting various other aspects of your business when you break a critical path in your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Brand Perception
&lt;/h2&gt;

&lt;p&gt;A lot of apps today depend on some form of organic growth. A dent in the brand perception can hurt the business significantly. Since brand perception is not something that you can measure easily. Its effects show up on the charts over months and sometimes even quarters.&lt;/p&gt;

&lt;h2&gt;
  
  
  App Ratings
&lt;/h2&gt;

&lt;p&gt;Another thing that can easily get affected here is the overall ratings in various app stores. Users that are savvy and care about app ratings can easily pick your competitor over you just because of that number.&lt;/p&gt;

&lt;h2&gt;
  
  
  User Retention and Engagement
&lt;/h2&gt;

&lt;p&gt;An app or an experience that doesn’t work for a user will eventually lead to them leaving your app sooner than you’d expect them to. Driving users out of your app will bring the overall retention and engagement numbers down. This hurts a lot of businesses that rely on a network of how many active users exist on their app at any given point in time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customer Acquisition Cost
&lt;/h2&gt;

&lt;p&gt;The more users you acquire over time, the harder it becomes to target the relevant people with the ads for your product. This leads to a rise in customer acquisition cost. The users that have installed your app either organically or through a paid ad, contribute to this if they leave the ecosystem due to a bad experience.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cost 3: Cost of Investigation
&lt;/h1&gt;

&lt;p&gt;Depending on the nature of the fire and its impact, you’d start investigating the issues.&lt;/p&gt;

&lt;p&gt;Needless to say this is one of the things engineers enjoy the most. However, pulling people away from their regular tasks to deal with fires has a huge impact on productivity since it requires context switching. You also need people who have domain knowledge and technical understanding of the areas that are currently dealing with fire. That kind of expertise may not always be available.&lt;/p&gt;

&lt;p&gt;In addition to engineering resources, you would also end up involving Quality Assurance to ensure the fix works as expected and product managers to plan a proper course of action whenever needed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cost 4: Cost of Fixing
&lt;/h1&gt;

&lt;p&gt;Once the investigation is complete and you have isolated the issue. The process to fix the issue starts.&lt;/p&gt;

&lt;p&gt;Here someone would either commit a new change or revert an old commit, run the tests, and ensure everything works fine. Wait for your continuous integration to pass. Cherry-pick the commit into a new branch. Generate the artifacts, run your regression tests, and eventually submit the builds to the relevant stores.&lt;/p&gt;

&lt;p&gt;All of this again, costs time and effort. None of which is free.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cost 5: Cost of Remediation
&lt;/h1&gt;

&lt;p&gt;Often times when you break the app, product and engineering are not the only ones that are dealing with the fire.&lt;/p&gt;

&lt;p&gt;Remember the times when you had to take to social media to get the attention of a business you were frustrated with? Yeah, that happens too and that’s where your marketing and communications teams come in. They have to deal with any negative PR that gets generated due to this issue. In addition to this, your customers could also start flooding your customer service teams.&lt;/p&gt;

&lt;p&gt;An increase in customer service inbound leads to either an increased backlog of tickets your team has to deal with or some additional expense your company has to bear by adding more representatives to cater to this issue.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I speak from years of experience working on apps operating in very different industries and teams of all sizes big and small. It is not common to come across engineers who think about these things before shipping their next feature, fix, or a refactor.&lt;/p&gt;

&lt;p&gt;Before you make a change be it a feature or a fix, ask yourself. What can go wrong and if there is a way I can either prevent it from happening today or I can immediately mitigate the crash/problem by guarding my change behind a feature flag? It will always be appreciated by your teammates and your managers.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>How does Anonymous Feedback Impact Engineering Teams?</title>
      <dc:creator>Ishan Khanna</dc:creator>
      <pubDate>Thu, 08 Sep 2022 15:59:56 +0000</pubDate>
      <link>https://dev.to/droidchef/how-does-anonymous-feedback-impact-engineering-teams-4lm8</link>
      <guid>https://dev.to/droidchef/how-does-anonymous-feedback-impact-engineering-teams-4lm8</guid>
      <description>&lt;h2&gt;
  
  
  What is anonymous feedback?
&lt;/h2&gt;

&lt;p&gt;When you provide someone feedback without your name associated with it, it is called anonymous feedback. For example, you could provide feedback to someone's manager asking them not to reveal your identity when they pass it on to the person who this feedback is about.&lt;/p&gt;

&lt;p&gt;Many tools like Impraise, Lattice, and, Workday that companies use for employee and performance management provide an option for giving anonymous feedback nowadays.&lt;/p&gt;

&lt;p&gt;Even though the manager can see, who gave what feedback to whom. The receiver cannot see the sender's name.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Expectation vs The Reality
&lt;/h2&gt;

&lt;p&gt;The number one expectation a team, an organization, or a company has from an anonymous feedback culture is an increase in the feedback that people can get about themselves and or their work.&lt;/p&gt;

&lt;p&gt;It is almost never the case. I say almost because I am sure someone somewhere in some way might have proven in a study that anonymous feedback works for certain teams.&lt;/p&gt;

&lt;p&gt;Let's discuss the following reasons to understand why I feel the reality is completely different.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lack of Accountability
&lt;/h3&gt;

&lt;p&gt;My first and foremost issue with anonymous feedback is the lack of accountability.&lt;/p&gt;

&lt;p&gt;Try to think about the answers to the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When trying to submit your work to your peers, say a pull request for code review or a proposal for an idea. Do you ensure that your work is of good quality?&lt;/li&gt;
&lt;li&gt;Ever wanted to write a blog post or ended up writing one but didn't publish, telling yourself this isn't your best work?&lt;/li&gt;
&lt;li&gt;Made a cool library or project but didn't have the courage to open source it, thinking about all the criticism you'd expose yourself and your project to?&lt;/li&gt;
&lt;li&gt;We've all been there and we'll always think about these things. For one and only one reason, accountability. If something can be tied back to you, you are accountable for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most people are never taught how to give proper feedback that matters, until very late in their lives. Add to this, the power dynamics of the company's hierarchy, the office politics, and the cultural diversity to the mix. Anonymity makes it easier to deliver sub-par feedback.&lt;/p&gt;

&lt;p&gt;As long as a certain quantity of feedback gets passed around in the organization, the management can just use those statistics to demonstrate a "so-called-healthy culture of feedback". However, it is not really helping anyone. Neither the provider nor the receiver and definitely not the organization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Delusion of Transparency
&lt;/h3&gt;

&lt;p&gt;Another common misconception among the masses is the fact that anonymous feedback can promote more transparency. To a certain extent, this is true, however, more often than not. People mistake the cloak of anonymity as a weapon for vendetta.&lt;/p&gt;

&lt;p&gt;The receiver, even if they know who gave them the feedback, can't really confront the provider. They have no chance of improvement as a lot of the anonymous constructive feedback is mostly rants or venting letters.&lt;/p&gt;

&lt;p&gt;To be clear confrontation here should not be taken in the literal sense. I'll explain to you why, in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Negligible Scope of Improvement
&lt;/h3&gt;

&lt;p&gt;Obviously, who doesn't like to be praised? But it isn't the praise that makes us better, it is the criticism. Constructive feedback, marinated with empathy and thoughtfulness, layered with X, and seasoned with actionable opportunities is what brings the best out of people who want to rise and shine.&lt;/p&gt;

&lt;p&gt;But this is hard, and anonymity makes it even harder to go the extra mile and deliver feedback that is easy to process, contextualize, understand, and act upon. Hence, anonymous feedback usually offers little to no scope for improvement.&lt;/p&gt;

&lt;p&gt;Now you must be wondering if there are so many issues with anonymous feedback, why do companies allow it?&lt;/p&gt;

&lt;p&gt;I am sure an experienced human resource professional could give you a thousand more reasons however, based on my personal experience and research here are three reasons why organizations do it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reason 1: Anonymity will increase the quantity of feedback
&lt;/h3&gt;

&lt;p&gt;As I mentioned above, for organizations, it is mostly about the numbers. As long as they can broadcast these numbers in presentations and company-wide meetings. It helps them with their narrative of claiming that we have great feedback or an open or transparent culture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reason 2: Anonymity makes certain employees feel safer
&lt;/h3&gt;

&lt;p&gt;This is absolutely true, there are certain sections of employees in every organization who would always feel more comfortable providing anonymous feedback. These could be people from underrepresented or marginalized populations. People early on in their careers or people who are shy in general or people who don't have the best communication skills in the common language of the org. They could also be people who fear retaliation in any way, shape, or form.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reason 3: Anonymity could lead to higher engagement
&lt;/h3&gt;

&lt;p&gt;This is somewhat synonymous with reason number one, however, it more relates to the feedback being given to the leadership or the organization as opposed to the feedback being shared among peers.&lt;/p&gt;

&lt;p&gt;So what can be done to fix this? Well, nothing can replace good actionable feedback. It does not matter if it is anonymous or not, as long as it is actionable.&lt;/p&gt;

&lt;p&gt;However, as discussed above, not everyone knows how to provide good feedback, and sometimes it is just hard to provide feedback even if you know how to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invest in Feedback Training
&lt;/h2&gt;

&lt;p&gt;The first step in improving the quality of feedback for your teams should be to provide them ample training on what is considered good feedback, and when and how to provide it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What here translates to Actionable&lt;/li&gt;
&lt;li&gt;When here translates to Immediately&lt;/li&gt;
&lt;li&gt;How here translates to a framework that people can use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a simple framework that you can start using today to provide feedback to people that actually helps them.&lt;/p&gt;

&lt;p&gt;I learnt about it while working at Booking a few years ago. It is called the BIO Feedback model.&lt;/p&gt;

&lt;p&gt;BIO is an acronym for Behavior, Impact, and Opportunity and it focuses on a fluent approach that asks you to point out behavior you observed in someone, the impact it has in that situation, and the opportunity or options the person has to make improvements and grow.&lt;/p&gt;

&lt;p&gt;Let me illustrate it with an example:&lt;/p&gt;

&lt;p&gt;Situation: Your product manager never scheduled a single retrospective in the whole quarter and you want to provide feedback on this.&lt;/p&gt;

&lt;p&gt;Here is one way how I would approach them.&lt;/p&gt;

&lt;p&gt;Hey $_product_manager_name, I noticed that we have been working throughout the quarter without doing any retrospectives on our team (The Behavior). I believe the team is not thoroughly aware of the things that are going well and the things that can be improved to ensure high productivity, impact, and happiness of the team (The Impact). I would suggest scheduling an hour in the coming sprint or week to do a retrospective on the team's performance and processes for this past quarter. We will use this opportunity to highlight our wins and make sure we keep doing what is working well for us. Also, we'll try to find out what hasn't worked well for us this past quarter and find out ways to improve in the upcoming quarters (The Opportunity).&lt;/p&gt;

&lt;p&gt;As you can see, the product manager now has ample context around why this feedback was delivered. They have been made aware of the impact some teammates might be having due to this. Lastly, you've provided them with an opportunity to improve and grow themselves.&lt;/p&gt;

&lt;p&gt;This is just an illustrative example, I am not of the belief that it is solely a Product Manager's or Engineering Manager's responsibility to organize retrospectives. If you feel something is not working well, just raise your hand, take the lead and organize a retrospective.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deanonymysing Feedbacks
&lt;/h2&gt;

&lt;p&gt;Once your teams get into the habit of providing good, actionable feedback to one another. This will happen automatically. Once I realized I had started providing actionable feedback, even in the tools that by default anonymize my feedback, I started adding my name at the end of the feedback.&lt;/p&gt;

&lt;p&gt;This allows the receiver to reach out to me, to ask for clarifications in case there is a misunderstanding or they need more context or any support from me in terms of the opportunity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In the end, I'd like to say, feedback is a very critical part of your growth journey. No one that has climbed any ladder of success has done so without feedback. If you're not getting good feedback from your teammates, manager, customers, or anyone that matters to you, you should proactively ask for it.&lt;/p&gt;

&lt;p&gt;It is not easy, it is not comfortable and it makes you vulnerable. But if you get past those feelings, there is an abundance of growth waiting for you.&lt;/p&gt;

&lt;p&gt;Before you go, &lt;a href="https://twitter.com/droidchef"&gt;let's connect with each other on Twitter!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>beginners</category>
      <category>softskills</category>
      <category>communication</category>
    </item>
    <item>
      <title>Conditional Provisioning with Dagger</title>
      <dc:creator>Ishan Khanna</dc:creator>
      <pubDate>Wed, 25 May 2022 06:30:34 +0000</pubDate>
      <link>https://dev.to/droidchef/conditional-provisioning-with-dagger-51m</link>
      <guid>https://dev.to/droidchef/conditional-provisioning-with-dagger-51m</guid>
      <description>&lt;p&gt;In this article, you’ll learn how to use Dagger for conditionally provisioning (providing) your dependencies without adding stress to your memory.&lt;/p&gt;

&lt;p&gt;As your product grows. You often start trying out new things with it. Since we don’t always know what’ll work best for the users, we often try multiple strategies to solve a problem. This is done through some sort of an A/B test. However, this comes at a cost. The cost is that two distinct solutions exist in the same version of the app, to solve one customer pain point. Let’s try to see it through a lens of an image editing application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing the Sample App
&lt;/h3&gt;

&lt;p&gt;Imagine you have an app that allows users to edit photos and share them. For editing photos, we use a library called &lt;code&gt;SimplePhotoEditor&lt;/code&gt;. This library could be your in-house implementation, a third-party proprietary solution, or even an open-source project that you are using, but that is irrelevant and I wanted to get that out of the way.&lt;/p&gt;

&lt;p&gt;Now you come across a library called &lt;code&gt;ComplexPhotoEditor&lt;/code&gt; which offers you better photo editing capabilities and promises higher performance when compared to its alternatives in the market.&lt;/p&gt;

&lt;p&gt;As you are a very dedicated and passionate engineer, you decide that you want to give this new library a try in your app and see if your users find your app to be more useful, robust, and whatnot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the Sample Use Case
&lt;/h3&gt;

&lt;p&gt;Both the libraries require a lot of memory as soon as they are initialized and want to hold on to a significant amount of it, throughout their lifetime during the app’s session. Not going to comment on the design of the library :]&lt;/p&gt;

&lt;p&gt;So as soon as someone initializes an object of either of the two libraries we’d see a significant spike in resource allocation. Since we need at least one of the two libraries at all given times, we’ll have to live with that overhead, however, having both of them taking up their fair share of resources doesn’t really make sense. So in the next section, we’ll look into implementing this behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing the Use Case
&lt;/h3&gt;

&lt;p&gt;Let’s say we have an interface called ImageManipulationStrategy which has a method to manipulate the input and return an output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface ImageManipulationStrategy { 
 fun manipulate(image: Image): Image 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to support both the libraries, we have their respective implementations in our app, that look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SimpleImageManipulationStrategy(
 private val SimpleImageEditor: simpleImageEditor
    ): ImageManipulationStrategy {

     override fun manipulate(image: Image): Image {
         // manipulate with simpleImageEditor
     }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ComplexImageManipulationStrategy(
 private val ComplexImageEditor: complexImageEditor
    ): ImageManipulationStrategy {

     override fun manipulate(image: Image): Image {
         // manipulate with complexImageEditor
     }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when using these strategies in other classes we can easily swap them in our Dagger Module like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Provides
fun imageManipulationStrategy(
  simpleImageManipulationStrategy:SimpleImageManipulationStrategy,
  complexImageManipulationStrategy:ComplexImageManipulationStrategy,
) : ImageManipulationStrategy {
    // provide the desired strategy
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this works fine, there is a problem with providing the dependency this way and we’ll see that in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the Problem
&lt;/h3&gt;

&lt;p&gt;As we can see Dagger at Runtime will not know which dependency we actually might get in our method, so it’ll initialize both of them. So that whichever one we need, is readily available at our disposal in the method.&lt;/p&gt;

&lt;p&gt;Having both of them initialized when we only know one is going to be needed, is the problem here. Now, this can occur in any case, where initializing a class is expensive and you might have to choose between those implementations, wasting resources on at least one of them.&lt;/p&gt;

&lt;p&gt;The solution to this problem is pretty simple and we’ll see that in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the Solution
&lt;/h3&gt;

&lt;p&gt;Dagger exposes the &lt;code&gt;Provider&amp;lt;T&amp;gt;&lt;/code&gt; class to us. So instead of using the default mechanism of providing the dependencies, we can defer the initialization by using this class.&lt;/p&gt;

&lt;p&gt;The way it works is that Dagger will provide you the &lt;code&gt;Provider&amp;lt;T&amp;gt;&lt;/code&gt; object and you can use it to &lt;code&gt;get()&lt;/code&gt; the actual dependency.&lt;/p&gt;

&lt;p&gt;Here is how it’d look in practice&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Provides
fun imageManipulationStrategy(
    simpleProvider: Provider&amp;lt;SimpleImageManipulationStrategy&amp;gt;,
    complexProvider: Provider&amp;lt;ComplexImageManipulationStrategy&amp;gt;,
) : ImageManipulationStrategy {
    return if (myConditionIsMet) {
        simpleProvider.get()
    } else {
        complexProvider.get()
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and this will ensure that Dagger doesn’t initialize a dependency unnecessarily when we don’t need it to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You don’t always want to rely on Dagger to provision dependencies for you directly.&lt;/li&gt;
&lt;li&gt;You should always assess if any of your dependencies are hungry for resources.&lt;/li&gt;
&lt;li&gt;It is possible to conditionally provision dependencies in your graph at runtime, with Dagger.&lt;/li&gt;
&lt;li&gt;Dagger exposes a class called &lt;code&gt;Provider&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;When using an object of &lt;code&gt;Provider&amp;lt;T&amp;gt;&lt;/code&gt;, Dagger won't initialize the dependency unless the &lt;code&gt;get()&lt;/code&gt; method on this object is called.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originally published at &lt;a href="https://www.droidchef.dev"&gt;https://www.droidchef.dev&lt;/a&gt; on April 2, 2022.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
