惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell
Latest news
Latest news
V
Visual Studio Blog
美团技术团队
博客园_首页
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 三生石上(FineUI控件)
C
Check Point Blog
NISL@THU
NISL@THU
博客园 - Franky
C
CXSECURITY Database RSS Feed - CXSecurity.com
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
K
Kaspersky official blog
P
Proofpoint News Feed
F
Full Disclosure
G
GRAHAM CLULEY
Cyberwarzone
Cyberwarzone
S
Schneier on Security
罗磊的独立博客
T
Threatpost
Scott Helme
Scott Helme
S
Securelist
The Hacker News
The Hacker News
T
Tor Project blog
Spread Privacy
Spread Privacy
WordPress大学
WordPress大学
A
Arctic Wolf
V
Vulnerabilities – Threatpost
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
有赞技术团队
有赞技术团队
Security Latest
Security Latest
Blog — PlanetScale
Blog — PlanetScale
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Jina AI
Jina AI
Cisco Talos Blog
Cisco Talos Blog
IT之家
IT之家
博客园 - 叶小钗
P
Privacy & Cybersecurity Law Blog
T
Tenable Blog
F
Fortinet All Blogs
I
Intezer
C
Cybersecurity and Infrastructure Security Agency CISA
U
Unit 42
阮一峰的网络日志
阮一峰的网络日志
T
The Exploit Database - CXSecurity.com

Dropbox Tech Blog

How we used DSPy to turn AI evaluations into better responses in Dash chat How Dropbox uses MCP and Dash to close the design-to-code security gap Beyond code generation: rethinking engineering productivity in the age of AI agents Introducing Nova, our internal platform for coding agents Improving storage efficiency in Magic Pocket, our immutable blob store Reducing our monorepo size to improve developer velocity How we optimized Dash's relevance judge with DSPy Using LLMs to amplify human labeling and improve Dash search relevance How low-bit inference enables efficient AI Insights from our executive roundtable on AI and engineering productivity Engineering VP Josh Clemm on how we use knowledge graphs, MCP, and DSPy in Dash Inside the feature store powering real-time AI in Dropbox Dash Building the future: highlights from Dropbox’s 2025 summer intern class Fighting the forces of clock skew when syncing password payloads Making camera uploads for Android faster and more reliable How Dropbox Replay keeps everyone in sync Why we built a custom Rust library for Capture Detecting memory leaks in Android applications How we sped up Dropbox Android app startup by 30% Why we chose Apache Superset as our data exploration platform Revamping the Android testing pipeline at Dropbox Our counterintuitive fix for Android path normalization JQuery to React: How we rewrote the HelloSign Editor How we ensure credible analytics on Dropbox mobile apps Engineering Dropbox Transfer: Making simple even simpler Speeding up a Git monorepo at Dropbox with <200 lines of code Building for reliability at HelloSign Store grand re-opening: loading Android data with coroutines Modernizing our Android build system: Part I, the planning Modernizing our Android build system: Part II, the execution Our journey to type checking 4 million lines of Python The (not so) hidden cost of sharing code between iOS and Android Redux with Code-Splitting and Type Checking The Programmer Mindset: Main Debug Loop On working with designers Incrementally migrating over one million lines of code from Python 2 to Python 3 Crash reporting in desktop Python applications What we learned at our first JS Guild Summit How we rolled out one of the largest Python 3 migrations ever Dropbox Paper: Emojis and Exformation Creating a culture of accessibility Adding IPv6 connectivity support to the Dropbox desktop client Accelerating Iteration Velocity on Dropbox’s Desktop Client, Part 2 Accelerating Iteration Velocity on Dropbox’s Desktop Client, Part 1 DropboxMacUpdate: Making automatic updates on macOS safer and more reliable Annotations on Document Previews Open Sourcing Pytest Tools Open Sourcing Zulip – a Dropbox Hack Week Project Building Carousel, Part III: Drawing Images on Screen The Tech Behind Dropbox’s New User Experience on Mobile (Part 2) Building Dropbox’s New User Experience for Mobile, Part 1 Building Carousel, Part II: Speeding Up the Data Model Building Carousel, Part I: How we made our networked mobile app feel fast and local Scaling MongoDB at Mailbox Welcome Guido! Dropbox dives into CoffeeScript Some love for JavaScript applications Plop: Low-overhead profiling for Python Using the Dropbox API from Haskell A Python Optimization Anecdote Translating Dropbox
Introducing Focus, a new open source Gradle plugin
Ryan Harter · 2022-03-29 · via Dropbox Tech Blog

Working with large projects in Gradle can be a pain. As a project grows larger over time, configuration and build times tend to grow with it. Breaking up large projects into lots of modules can help mitigate this, but unless you meticulously follow the seemingly ever-changing advice about project structure and build script configuration, it’s easy to end up with a build system that’s doing far more than it needs to. And while Gradle is doing that extra work, you have to sit and wait.

At Dropbox, like many companies, we use Gradle to build our Android apps. Our monorepo contains almost 600 projects, most of which aren’t used by our engineers on a day-to-day basis. This means that Android Studio has to load many more modules than required, and we waste time waiting for our tools.

When we’re working on features within large projects, our time is generally spent within a specific feature module. By using reasonable abstractions within our modules we are able to develop code and write tests without depending on most of the other projects in our monorepo. But wouldn’t it be great if we could easily tell Gradle exactly where we’re working and what dependencies we need, and have it ignore the rest?

To answer that question, we recently set out to find an easy way for our engineers to specify the module in which they’re working, and let Gradle and Android Studio ignore the rest.   

The manual way

In the past, we’ve been able to trim the number of projects that Gradle loads by manually adjusting the projects that are included in the settings.gradle.kts file. The quick and dirty way is to simply comment out the projects that you don’t need:

include(":sample:app1")
//include(":sample:app2")
include(":sample:lib1a")
include(":sample:lib1b")
//include(":sample:lib2a")
//include(":sample:lib2b")
//include(":sample:lib2c")
include(":sample:lib-shared")

include(":sample:moved")
project(":sample:moved").projectDir = File("sample/lib-moved")

However, this approach quickly becomes unwieldy as a project grows, and the interdependency of your modules grows more complex.

Another approach is to extract all of those include("...") statements into a separate file. This way, you can more easily switch between modules by simply choosing which files you want to apply:

//apply(from = File("project-1.settings.gradle.kts")
//apply(from = File("project-2.settings.gradle.kts")
//apply(from = File("project-3.settings.gradle.kts")
apply(from = File("settings-all.gradle.kts"))

But with all of the possible permutations, it’s easy for this to become unmanageable too. On top of that, making sure those extra settings files stay in sync can be a nightmare.

Since Gradle already knows about the dependency tree of your project, wouldn’t it be great if there was an easy way to have Gradle create these files for you?

Enter Focus

Focus allows you to do just that. Our Focus Gradle Plugin evaluates your project configuration and creates a unique settings.gradle file for the module you want to focus on. This file only includes the project dependencies that a specific module requires, allowing you to easily ignore the rest. The plugin also creates a .focus file which identifies which module should currently be focused. 

With these files in place, Gradle will only configure the modules you need when you sync your project. Deleting the .focus file—which can be done manually, or by using the clearFocus task—will revert to including all of your modules.

For example, while working on design systems at Dropbox, the Focus plugin allows us to easily focus on our UI Components Playground project (a sample app in our monorepo for working on design system components). This reduces the IDE sync time from 1 minute to 15 seconds. 

To start, we simply run the following command:

./gradlew :applications:uicomponents_playground:focus

This creates a focus.settings.gradle file in the module’s build directory—which only includes the projects that are required to build the uicomponents_playground module—and a .focus file at the root of the project which points to the newly created Gradle settings file. Clicking the Sync Elephant icon in Android Studio will only load the required modules, improving the performance of both the IDE and Gradle.

If we want to spend some time in a different module—perhaps a dependency that needs updating—we can simply focus on that other module and sync.

./gradlew :dsys:components:focus

This way, we’re easily able to trim the number of modules loaded in the IDE and configured by Gradle. When we’re ready to go back to building the entire project, we can simply remove the .focus file in the root directory of the project, or run the following Gradle task:

./gradlew clearFocus

With Focus, our engineers are able to iterate faster throughout the day, allowing them to spend more time focused on the quality of the code they’re developing, and less time waiting for their tools to sync.

Adding the Focus plugin

Focus is a settings plugin, so it should be applied in your settings.gradle(.kts) file. Since we currently publish the plugin to Maven Central, you’ll have to add that as a repository in your pluginsManagement block:


// settings.gradle(.kts)
pluginsManagement {
  repositories {
    mavenCentral()
    gradlePluginPortal()
  }
}

plugins {
  id("com.dropbox.focus") version "0.4.0"
}

Next, move all of your include statements into a settings-all.gradle file:


// settings-all.gradle(.kts)
include ':sample:app2'
include ':sample:lib2c'
include ':sample:lib-shared'
// ...

include ':sample:moved'
project(':sample:moved').projectDir = new File("sample/lib-moved")

Optionally, you can configure the plugin within your settings.gradle.kts file:


// settings.gradle(.kts)
focus {
  // The name of the settings file
  allSettingsFileName = "settings-all.gradle" // Default
  // The name of the pointer file that tells Focus which module to focus on
  // This should be added to your .gitignore file.
  focusFileName = ".focus"  // Default
}

Lastly, don’t forget to add your Focus file—.focus by default—to your .gitignore file.

Once those steps are complete, you can use the focus Gradle tasks in each subproject to reduce the amount of time you have to sit around and wait.

Open source at Dropbox

Dropboxers who have been using the Focus plugin are incredibly happy with the results. Our Android engineers have seen significant improvements in Android Studio and Gradle performance—in some cases reducing the time it takes Android Studio to sync with Gradle from 2 minutes down to 20 seconds. We’re excited by these improvements in our build performance, and are even more excited to share these improvements with the Open Source community.

On a personal note: I’ve been involved with the Open Source community for many years, both developing and contributing to open source libraries. When I was considering where I wanted to work next, it was important to me to be a part of a company that not only values but actively participates in the open source community. One of the things that excited me about Dropbox was learning how much the company supports the use of open source libraries and also encourages Dropboxers to contribute back to the community. (If that’s something that excites you too, we’re hiring!)

When I prototyped Focus and proposed that it could become a general use plugin, Dropbox encouraged me to take the time to build it and share it with the community. While Focus isn’t quite ready for 1.0, we invite you to give it a try and let us know how it works for you. And if you run into any issues, please let us know.