I have a few questions about this new approach... ...
# declarative-gradle
j
I have a few questions about this new approach... First of all, are there some more complex examples than the samples? I am most interested in the cases that then require you to write a plugin and how the plugin is integrated. The other part I am interested in is the problem of mixing imperative and declarative code. More specifically why it is a problem. I don't mean in terms of that it is harder to maintain, more in terms of why it is harder to maintain, if maintenance is one argument. And then the question of if this approach does mean you "extend" the DSL and if that will not lead to comparable problems as imperative code? And maybe finally... you can already write plugins right now, you are not too much forced to mix imperative and declarative, so people mix out of convenience? Or are you feeling forced? Or is this more about trying to force users to do something, that is better for the team in the end? I am really neutral about this atm, so I am not trying to say something is bad or good, also I am trying not to get hyped about this. I am just trying to understand the motivation and culture a bit better - the way of thinking. Thx
1
👀 2
a
Personally for me, I think by far the biggest reason for declarative gradle, that it unlocks fast IDE integration which doesn't require full project sync, it's a huge (pun not intended) problem for large multi module projects, when configuration can take a few minutes, but it required every time you change dependency, or add new module for IDE to work
I think hard separation of imperative and declarative is just a side effect of it, but it fits perfectly with recommended approach, for example we already have full separation of build logic and config separation, so nothing would change for us in terms of build.gradle files, just slighly different syntax of configuring type of module
j
@Andrey Mishchenko I guess now asking why the Kotlin DSL cannot do this would be for someone else to answer and based on the implementation of Gradle. But now I wonder how the new DSL is implemented. It sounds very much like this here means a move from internal DSL to external DSL.
a
Kotlin DSL cannot do this because it still based on imperative Gradle dsl, so to know about any change requires recompilation and full sync of project state after that
Not sure that I understand internal vs external part, but it's just more limited, DSL can be read reliably statically, without invoking full logic of your build
I see that potentially this fully declarative DSL could be done with Kotlin, but there are still problems: Kotlin doesn't limit imperative logic, so it potentially can read files, network etc. There was experiments to make limited Kotlin, so make similar language like Starlark for Python, but based on Kotlin Kotlin files have to be compiled, and in case build classpath change it required to recompile all of them (incremental build would help though)
j
An internal DSL is a DSL build as part of a programming language. Your DSL is essentially a normal program. Languages like Groovy, Scala and Kotlin (and many more) have some special constructs to allow for this. An external DSL is a DSL developed especially for the DSL and has no language constructs besides what is to be used for the DSL.
a
What you describe as internal dsl looks for me just that it a language feature which helps design API which looks as DSL
So yeah, no arguing here, I see what you are saying, yes it's external DSL, full DSL, not a part of programming language
j
The "old" build files for gradle are full programs. First Groovy, then Kotlin. Unless Gradle developed an interpreter I don't know of.
a
External DSL has those advantages, that it doesn't allow to use other language features and usually way cheaper to read and parse
Yes, "old" build files are full programs, limited only by classpath
Not only that it full program, but also that it has access to almost anything in the build (will be a bit more limited with isolated projects)
j
External DSLs being more easy to read and parse depends on the design of the language. More easy to read for a human does not always go with more easy to parse. As for limiting access, not impossible with interal DSLs, but surely more easy with an external one, yes. But then again the plugins will have that power, so not sure this is really a point. Or do you mean that if it is concentrated in the plugins it is more easy to deal with? That might be.
a
I'm taking about read for tools, IDE etc, not human readable
j
ah, well yes, as long as there is a parser giving the information required to the IDE there is no problem, be the syntax easy or difficult to parse.
a
But to be honest without programming language limitations you can make it more readable too, but not sure that it's top goal for declarative Gradle
be the syntax easy or difficult to parse.
A large part is not only syntax, but what this syntax represent, thanks to separation between declarative and imperative, IDE can get a lot of information from DSL alone and use it to represent project structure.
As for limiting access, not impossible with interal DSLs, but surely more easy with an external one
The only possible solution now (at least reliable one, which doesn't try to statically interpret programming language logic) is to run build scripts and do full project syncronization
Or do you mean that if it is concentrated in the plugins it is more easy to deal with? That might be.
Not sure that I understand. But the goal is that declaration allows plugins to describe behaviour, so IDE supports DSL editing, autocomplete and even partially understand project structure and features
t
I am on the fence undecided about the declarative gradle stuff. my only hope is if we are to adopt it in the bigger mature projects that they at least make sure we have a clean way to continue running with our existing suite of convention plugins. if the path to adoption is clean sort of how version catalogs went i'll probably be happy about it. just don't want to have to throw out all the mountains of work it was to get where we are already.
have really not looked at it though so entirely possibly my concerns are unfounded
a
my only hope is if we are to adopt it in the bigger mature projects that they at least make sure we have a clean way to continue running with our existing suite of convention plugins.
I think it would depends on how your convention plugins are implemented Declarative Gradle requires a single project type per project, so reactive convention plugins (when you apply them and they configure other plugins depending on what is applied) wouldn't work out of the box as I see, it would require to rewrite them, to have single plugin per project type and expose additional features as DSL. We are on the same boat here, but we plan to migrate I think if you have a single convention plugin or convention plugin per project type, should be easier to migrate Also build.gradle/build.gradle.kts is continue to be available, so you can just continue use it
of how version catalogs went
I think version catalog is way more less impactful comparing to decalrative gradle in terms of amout of potential changes.
t
Yeah so sounds like I am already half way there. Single convention plugin can apply additional plugins via declarative DSL yes? So currently we look roughly like this:
Copy code
// kotlin android project with: compose, dagger via ksp, moshi-codegen via ksp
plugins {
    id("com.aetna.android-library")
    id("org.jetbrains.kotlin.plugin.compose")
    id("com.aetna.dagger")
    id("com.aetna.moshi")
}
or this:
Copy code
// kotlin jvm with: // dagger via ksp, moshi-codegen via ksp
plugins {
    id("com.aetna.jvm-library")
    id("com.aetna.dagger")
    id("com.aetna.moshi")
}
Moshi plugin behaves identical on both project types so presumable I can lift that to a boolean in a DSL to have it also applied. Then the dagger plugin does the typical flow with pluginManager
Copy code
target.pluginManager.withPlugin("...") { ... }
So I would likely need to break that out to two different plugins one for each type plus the DSL toggle?
a
> Single convention plugin can apply additional plugins via declarative DSL yes Yes this how I understand overall setup, you apply plugins conditionally, but there is no special DSL for this (like for dependencies for example), it's more like you add a toggle to your DSL like
enableMoshi=true
. You still may have convention plugin to share logic, but it would be applied to your declarative gradle plugins with project type, not to module directly. And probably it would be declared like
id("com.aetna.moshi") apply false
in your project type convention > So I would likely need to break that out to two different plugins one for each type plus the DSL toggle I believe it's not necessary to break it as soon as dagger convention works for android and jvm projects, so you need DSL toggle to enable it, but the single plugin can be applied both to Android and JVM Just a disclaimer, I'm as new as everyone else to this, and also try understand how project setup will work with declarative gradle, so this is my limited understanding of current prototype
❤️ 1
t
thats even better. possibly just some additional declarative plugins that apply existing so I can then work behind the curtain with minimal churn on the DSL for teams
a
yes, I hope it will work for us too. Because we also have setup similar to your above, so we need an additional plugin to. combine all features available So folks who argued that a single entry point plugin for all project types and not combination of plugins as features, were actually correct and will make it even easier for them to migrate, like Slack in their gradle plugin: https://slackhq.github.io/slack-gradle-plugin/dsl/#dsl