-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #508 from RBusarow/release_0.15.0
create release 0.15.0
- Loading branch information
Showing
16 changed files
with
1,346 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
--- | ||
id: benchmarks | ||
|
||
sidebar_label: Benchmarks | ||
|
||
title: Benchmarks | ||
--- | ||
|
||
The Tangle project has the ability to generate test projects and run synthetic benchmarks against | ||
it, using [Gradle-Profiler](https://github.com/gradle/gradle-profiler). | ||
|
||
For the time being, the intent of these benchmarks is to provide a hermetic comparison between Hilt | ||
and Tangle's build times, with as few variables as possible. | ||
|
||
The generated test projects represent best-case scenarios, in that no library module depends upon | ||
any other library module, and each library module only has a single empty `Fragment` and | ||
empty `ViewModel`. The build speed percentage gain from using Tangle is most likely higher than | ||
anything which could be observed in a real world application. | ||
|
||
To run these tests yourself, [check out the Tangle project](https://github.com/RBusarow/tangle) and | ||
run `./gradlew profile`. The generated code is in `$rootDir/build/benchmark-project`. | ||
|
||
The generated benchmark project is also hosted on | ||
GitHub [here](https://github.com/RBusarow/tangle-benchmark-project), with different branches for | ||
different project sizes. | ||
|
||
## The results | ||
|
||
These tests were all run on a water-cooled 12-core 4.3GHz hackintosh with 32GB of ram. I chose that | ||
machine because it has excellent cooling. A MacBook Pro will start overheating and thermal | ||
throttling during prolonged benchmarking, skewing the results. | ||
|
||
### 100 modules | ||
|
||
Tangle's mean execution time was a 20.23% reduction from Hilt's mean. | ||
|
||
[full results from Gradle Profile here](@site/static/benchmark/benchmark_100.html) | ||
|
||
![Hilt vs Tangle results, 100 modules](/img/benchmark_100.png "Hilt vs Tangle results, 100 modules") | ||
|
||
### 10 modules | ||
|
||
Tangle's mean execution time was an 11.67% reduction from Hilt's mean. This is less significant | ||
because the Tangle test project still needs to generate a Component using Kapt/Dagger, and that cost | ||
is relatively static regardless of benchmark size. It's also comparable to the static cost of | ||
component generation in a Hilt project. In a real world project with a much more complicated Dagger | ||
graph, component generation should take longer. | ||
|
||
It's also worth noting that an "11.67% reduction" in this case really just means that the build took | ||
18 seconds instead of 20 seconds. For a project of this size, it's safe to say that the decision | ||
should be made based upon API surface rather than build performance. | ||
|
||
[full results from Gradle Profile here](@site/static/benchmark/benchmark_10.html) | ||
|
||
![Hilt vs Tangle results, 10 modules](/img/benchmark_10.png "Hilt vs Tangle results, 100 modules") |
129 changes: 129 additions & 0 deletions
129
website/versioned_docs/version-0.15.0/configuration.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
--- | ||
id: configuration | ||
sidebar_label: Configuration | ||
title: Configuration | ||
|
||
--- | ||
|
||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
|
||
## Gradle | ||
|
||
The simple way to apply Tangle is to just [apply the Gradle plugin](gradle-plugin). | ||
|
||
You can also just add dependencies yourself, without applying the plugin: | ||
|
||
<Tabs groupId="language" | ||
defaultValue="Kotlin Dependencies" | ||
values={[ | ||
{label: 'Kotlin Dependencies', value: 'Kotlin Dependencies'}, | ||
{label: 'Groovy Dependencies', value: 'Groovy Dependencies'}, | ||
]}> | ||
|
||
<TabItem value="Kotlin Dependencies"> | ||
|
||
```kotlin | ||
// any Android module's build.gradle.kts | ||
|
||
plugins { | ||
id("android-library") // or application, etc. | ||
kotlin("android") | ||
id("com.squareup.anvil") | ||
} | ||
|
||
dependencies { | ||
|
||
// Fragments | ||
api("com.rickbusarow.tangle:tangle-fragment-api:0.15.0-SNAPSHOT") | ||
anvil("com.rickbusarow.tangle:tangle-fragment-compiler:0.15.0-SNAPSHOT") | ||
|
||
// ViewModels | ||
api("com.rickbusarow.tangle:tangle-viewmodel-api:0.15.0-SNAPSHOT") | ||
anvil("com.rickbusarow.tangle:tangle-viewmodel-compiler:0.15.0-SNAPSHOT") | ||
|
||
// optional Activity ViewModel support | ||
implementation("com.rickbusarow.tangle:tangle-viewmodel-activity:0.15.0-SNAPSHOT") | ||
|
||
// optional Compose ViewModel support | ||
implementation("com.rickbusarow.tangle:tangle-viewmodel-compose:0.15.0-SNAPSHOT") | ||
|
||
// optional Fragment ViewModel support | ||
implementation("com.rickbusarow.tangle:tangle-viewmodel-fragment:0.15.0-SNAPSHOT") | ||
|
||
// WorkManager | ||
api("com.rickbusarow.tangle:tangle-work-api:0.15.0-SNAPSHOT") | ||
anvil("com.rickbusarow.tangle:tangle-work-compiler:0.15.0-SNAPSHOT") | ||
} | ||
``` | ||
|
||
</TabItem> | ||
|
||
<TabItem value="Groovy Dependencies"> | ||
|
||
```groovy | ||
// any Android module's build.gradle | ||
plugins { | ||
id 'android-library' // or application, etc. | ||
kotlin("android") | ||
id 'com.squareup.anvil' | ||
} | ||
dependencies { | ||
// Fragments | ||
api 'com.rickbusarow.tangle:tangle-fragment-api:0.15.0-SNAPSHOT' | ||
anvil 'com.rickbusarow.tangle:tangle-fragment-compiler:0.15.0-SNAPSHOT' | ||
// ViewModels | ||
api 'com.rickbusarow.tangle:tangle-viewmodel-api:0.15.0-SNAPSHOT' | ||
anvil 'com.rickbusarow.tangle:tangle-viewmodel-compiler:0.15.0-SNAPSHOT' | ||
// optional Activity ViewModel support | ||
implementation 'com.rickbusarow.tangle:tangle-viewmodel-activity:0.15.0-SNAPSHOT' | ||
// optional Compose ViewModel support | ||
implementation 'com.rickbusarow.tangle:tangle-viewmodel-compose:0.15.0-SNAPSHOT' | ||
// optional Fragment ViewModel support | ||
implementation 'com.rickbusarow.tangle:tangle-viewmodel-fragment:0.15.0-SNAPSHOT' | ||
// WorkManager | ||
api 'com.rickbusarow.tangle:tangle-work-api:0.15.0-SNAPSHOT' | ||
anvil 'com.rickbusarow.tangle:tangle-work-compiler:0.15.0-SNAPSHOT' | ||
} | ||
``` | ||
</TabItem> | ||
|
||
</Tabs> | ||
|
||
## Setting up the Tangle graph | ||
|
||
In order to connect Tangle to your application-scoped Dagger component, | ||
call `TangleGraph.add(...)` immediately after creating the component. | ||
|
||
```kotlin | ||
import android.app.Application | ||
import tangle.inject.TangleGraph | ||
|
||
class MyApplication : Application() { | ||
|
||
override fun onCreate() { | ||
super.onCreate() | ||
|
||
val myAppComponent = DaggerMyAppComponent.factory() | ||
.create(this) | ||
|
||
TangleGraph.add(myAppComponent) | ||
} | ||
} | ||
``` | ||
## Next steps | ||
|
||
Tangle is now able to generate its code and hook in to Dagger. | ||
|
||
Check out these features to start using Tangle in your project: | ||
- [Fragments](fragments/fragments.mdx) | ||
- [ViewModels](viewModels/viewModels.md) | ||
- [WorkManager](workManager/workManager.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
--- | ||
id: extending-anvil | ||
|
||
sidebar_label: Extending Anvil | ||
|
||
title: Extending Anvil | ||
--- | ||
|
||
[Anvil] is a Kotlin compiler plugin which simplifies how we use [Dagger]. Anvil's documentation is | ||
definitely worth a read. Its benefits can be broken down into three categories: | ||
|
||
1. It can dramatically simplify Dagger development by automating most of the "plumbing". | ||
2. It can **reduce build times** by [generating dagger factories], meaning that you can remove | ||
the `dagger-compiler` kapt dependency (and probably remove kapt entirely) from most of your | ||
project. | ||
3. It allows us to write our own code generators. This is what Tangle does. We're able to generate | ||
our own code, which is then integrated into the final graph by Anvil. | ||
|
||
## Generating code from generated code | ||
|
||
Some of the code generated by Tangle requires additional processing. | ||
|
||
For instance, given this human-written code: | ||
|
||
```kotlin | ||
class MyViewModel @VMInject constructor( | ||
@TangleParam("name") | ||
val name: String | ||
) : ViewModel() | ||
``` | ||
|
||
Tangle will generate this: | ||
|
||
```kotlin | ||
// generated by Tangle | ||
public class MyViewModel_Factory @Inject constructor( | ||
internal val savedStateHandleProvider: Provider<SavedStateHandle> | ||
) { | ||
public fun create(): MyViewModel { | ||
val name = savedStateHandleProvider.get().get<String>("name") | ||
checkNotNull(name) { | ||
"Required parameter with name `name` and type `kotlin.String` is missing from SavedStateHandle." | ||
} | ||
return MyViewModel(name) | ||
} | ||
} | ||
``` | ||
|
||
Notice that it uses `@Inject constructor`. This code was created *after* compilation started, but it | ||
needs to be analyzed as part of the overall Kotlin compilation task. | ||
|
||
This is trivial if the project is using Dagger to generate dagger factories, because the kapt | ||
compilation stage hasn't started yet. When kapt starts, it will scan the files and see the generated | ||
MyViewModel_Factory.kt as though it's just another human-written file. | ||
|
||
For Anvil, however, things are more difficult. The Kotlin compiler scans files once and passes that | ||
collection of files to the Anvil plugin. So in order for Anvil to generate code for Tangle, the two | ||
libraries need to be able to talk to one another. As Tangle creates new files, those files are | ||
passed along to Anvil for additional processing. For the MyViewModel_Factory.kt file above, Anvil | ||
will generate the following: | ||
|
||
```kotlin | ||
// generated by Anvil | ||
public class MyViewModel_Factory_Factory( | ||
private val param0: Provider<@JvmSuppressWildcards SavedStateHandle> | ||
) : Factory<MyViewModel_Factory> { | ||
public override fun `get`(): MyViewModel_Factory = newInstance(param0) | ||
|
||
public companion object { | ||
@JvmStatic | ||
public fun create(param0: Provider<@JvmSuppressWildcards SavedStateHandle>): | ||
MyViewModel_Factory_Factory = MyViewModel_Factory_Factory(param0) | ||
|
||
@JvmStatic | ||
public fun newInstance(param0: Provider<@JvmSuppressWildcards SavedStateHandle>): | ||
MyViewModel_Factory = MyViewModel_Factory(param0) | ||
} | ||
} | ||
``` | ||
|
||
[Anvil]: https://github.com/square/anvil | ||
|
||
[compiler-api]: https://github.com/square/anvil/tree/main/compiler-api | ||
|
||
[Dagger]: https://dagger.dev | ||
|
||
[generating dagger factories]: https://github.com/square/anvil#dagger-factory-generation |
Oops, something went wrong.