Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎠 Deprecate and eventually remove bare settings #6217

Closed
eed3si9n opened this issue Dec 19, 2020 · 29 comments
Closed

🎠 Deprecate and eventually remove bare settings #6217

eed3si9n opened this issue Dec 19, 2020 · 29 comments

Comments

@eed3si9n
Copy link
Member

https://twitter.com/tpolecat/status/1340380781538062341

steps

organization := "example"
scalaVersion := "2.13.4"
name := "hello"

lazy val root = (project in file("."))
lazy val core = (project in file("core"))
lazy val app = (project in file("app"))

problem

I've been trying to discourage people from using bare .sbt build definition, but people do and often it leads to confusion since they tend to assume that the scalaVersion above would carry over to the subprojects.

expectation

Now that the ecosystem has largely migrated to sbt 1.x, we can cut off the vestige of sbt 0.13 era and deprecate bare settings against implicit root subproject in the proper build.

@eed3si9n eed3si9n added the Bug label Dec 19, 2020
@dwijnand dwijnand removed the Bug label Dec 19, 2020
@dwijnand
Copy link
Member

dwijnand commented Dec 19, 2020

Presumably project/plugins.sbt would continue to work as it does today.

@eed3si9n
Copy link
Member Author

@dwijnand Yup.

implicit root subproject in the proper build.

That's why I specified "proper build" as opposed to metabuild

@SethTisue
Copy link
Member

If the implicit root project is the only project, would there still be a deprecation warning?

@eed3si9n
Copy link
Member Author

@SethTisue If we want to remove the idea of projectless settings altogether in sbt 2.x, I think it would make sense to warn even if it's the only subproject in the build.

@SethTisue
Copy link
Member

If we want to remove the idea of projectless settings altogether in sbt 2.x,

That's a pretty big if :-)

Here's what I would suggest:

For now, only issue a deprecation warning if there are actually any non-root projects.

That would maximize helpfulness (calling attention to inadvertent foot-shooting) and minimize annoyingness for users who aren't aware of the overall trajectory of planned future sbt changes. Users who just want to 1) build their thing, 2) following advice and examples and books widely available across the Internet for the past decade.

If sbt 2.x goes forward with making a fundamental change in this area, then once 2.x is actually out (or at least in RCs, say), then consider going back and having 1.x warn more broadly, perhaps only under some kind of migration flag.

@SethTisue
Copy link
Member

If we want to remove the idea of projectless settings altogether in sbt 2.x

(Is there a canonical ticket on this? I have some further thoughts about this, but I'm not sure whether to put them here, or have this ticket be more narrowly just about deprecation warnings in 1.x.)

@eed3si9n eed3si9n changed the title 🎠 Deprecate bare settings 🎠 Deprecate and eventually remove bare settings Dec 19, 2020
@eed3si9n
Copy link
Member Author

If we want to remove the idea of projectless settings altogether in sbt 2.x

Is there a canonical ticket on this?

This is issue is meant to express Rob's and my intent on doing so.

@SethTisue
Copy link
Member

SethTisue commented Dec 19, 2020

First, I'm totally on board with deprecating bare settings in multi-project builds, I see no downside there.

As for the broader deprecation/removal, well, you can probably guess that I like bare settings for single-project builds very very much. This won't be the first time we've gone back and forth about this :-), notably at scala/scala-seed.g8#2 and scala/scala-seed.g8#4 and scala/scala-seed.g8#9, tickets that anyone interested in this will probably want to review. I know software isn't a democracy, but there are a lot of people on those tickets arguing in favor of bare settings, with their thumbs and their words, and almost nobody taking the no-bare-settings position.

I've never been convinced by the "people are eventually going to need to have multiple projects in their builds, so we might as well teach them the multi-project style from day 1" argument. I suspect that it seems appealing because we're so used to Scala OSS builds, which typically sprout subprojects for all sorts of reasons, including for cross-building. But I strongly suspect that there is a large "silent majority" of sbt users out there with simple, single-project, JVM-only builds. We don't hear from them that, I suspect, because sbt is remarkably easy to use in that scenario. It Just Works (TM). And I think sbt should work hard to make that kind of simple, uncomplicated usage of sbt stay simple and uncomplicated. And I think bare settings do that very well.

As I wrote last year:

You can learn a lot of Scala, and get a lot of value out of sbt along the way, before ever wanting or needing to know anything about multi-project builds at all. (I used Scala and sbt myself for years without ever learning that.)

In the context of teaching Scala to newcomers, I think the move to a multi-project build is in the learner's distant future, so to prepare them for that move so early is simply a pedagogical mistake that 1) distracts the learner from more important issues at their stage of learning, and not incidentally 2) gives them an unnecessarily negative impression of sbt.

Also, a lesser concern, but: it seems rather strange to me to allow bare settings in projects/plugins.sbt but prohibit them in root build.sbt. What's the argument for introducing that inconsistency? If bare settings continued to be allowed in metabuilds, then it seems to me like you aren't enabling any simplifications either in the codebase or in one's mental model of how sbt works.

cc @tpolecat

@eed3si9n
Copy link
Member Author

eed3si9n commented Dec 20, 2020

I'll try to explore my take on this topic, but I just want to preface that I don't want to come off as high-horse preachy. Certain things are facts, but mostly these are my subjective opinions.

In sbt meetings, one of the phrases I use a lot is "cognitive load". Often people feel the sense of disorientation / lostness looking at unfamiliar build tools and languages. Gradually the users gain footing by memorizing basic patterns, making a few variations, and confirming that the outcome matches the expectation. Years ago when I started out as an enthusiastic plugin author, sbt was notorious for its difficulty in learning, and people making heads or tails by looking at the build files.

At least in terms of the build.sbt syntax, the history of sbt post-2014 is the history of unification in the hopes of reducing the cognitive load:

At each juncture, there were certain tradeoff that we had to make either in terms of migration cost, code complexity, performance, or usability of some use cases. For example, <project>/<config>:<intask>::task might perform better for tab-completion if the users could ever remember how to interpret the shell syntax.

Among the above changes, the most highly contested probably was the deprecation and eventual removal of project/Build.scala. It's totally understandable because being actual *.scala gave users the footing to feel less-lost about what is going on in the build. I have zero regrets on removing this in sbt 1.x:

  • build.sbt DSL requires its own understanding regardless of the file extension, so the warm feeling that comes from project/Build.scala is mostly false sense of security.
  • All plugins in sbt 1.x are AutoPlugin that automatically generate import clause in build.sbt. Using project/Build.scala requires hand-rolling the import clause.

But ultimately the biggest reason is having 3 ways to express the same thing (subproject) adds needless cognitive load to the new and experienced users alike. The 3 ways were:

  1. Multi-project build.sbt
  2. Bare-style build.sbt
  3. Build.scala build definition

We are down to 2.

I've never been convinced by the "people are eventually going to need to have multiple projects in their builds, so we might as well teach them the multi-project style from day 1" argument.

So my reasoning is not because the new users will eventually need multiple projects. Instead my reasoning is: as a maintainer, I want to reduce the freedom of how the builds are written so I (or future maintainers) won't have to answer questions about them, and because bare style cannot replace multi-project style today, but multi-project style can subsume the bare style.

@dwijnand
Copy link
Member

The build.sbt, core/build.sbt, & app/build.sbt style is still possible and not deprecated (recently encountered in a support case). Perhaps that still comes under your bare-style build.sbt way. (That includes, btw, the project/foo.sbt, project/bar.sbt, etc, setup, which I was never a fan of.) I'm more in favour of deprecating and removing that, while I'm more on the fence on root project bare settings (I see the value of both arguments...). I should've written down what I'd discovered while trying to study #2899 as I don't remember any more...

@eed3si9n
Copy link
Member Author

The build.sbt, core/build.sbt, & app/build.sbt style is still possible and not deprecated (recently encountered in a support case). Perhaps that still comes under your bare-style build.sbt way. (That includes, btw, the project/foo.sbt, project/bar.sbt, etc, setup, which I was never a fan of.)

Yea. That makes sense.

Part of me want to hold on to the idea of decentralized *.sbt files because being able to define build definitions in a nested directory structure is actually a useful feature, especially if the sub-graph can act as an independent build. Maven does this the best using parent POMs, and Bazel works somewhat like that with BUILD file created per target (although subdirectories cannot function as a standalone build).

If we want to evolve sbt into supporting this kind of build of multiple builds usage, using source dependencies like sbt-sriracha would probably be the way to go, so overall I'm in agreement with the deprecation of decentralized bare-style *.sbt.

@hmemcpy
Copy link
Contributor

hmemcpy commented Dec 21, 2020

Thank you for starting the discussion, I recently stumbled on this myself (rather, this was reported as a bug in one of the IntelliJ plugins I maintain). It was surprising to me to find that top level settings don't behave as you'd expect. Since IntelliJ is also guilty of generating its default "sbt project template" with just the top level settings, I imagine this is a common pitfall. I opened a request for emitting a warning for this in #6224, but @eed3si9n beat me to it!

Anything that would make it easier to "do the right thing" is an automatic +1 from me!

@bjornregnell
Copy link

bjornregnell commented Mar 22, 2021

@eed3si9n Does this mean that a simple build.sbt for a single-project build (such as most projects of my beginner programmer students) will go away? I really love to say that they can start with just

scalaVersion := "3.0.0"

and then we might add some compiler settings to get warnings and initialCommand with an import for the console as we continue... All this lazy val root stuff and ThisBuild slash is not so good for beginners with only single-project builds....

@nafg
Copy link
Contributor

nafg commented Jun 30, 2021

I don't see how this change reduces load. You have a whole background about reducing cognitive load for users and then stated this change will result in fewer questions. But it means the metabuild has different rules than the build, and once you go down that path the cognitive model is more complicated.

Seth suggested detecting if it's a multi-project build but I have a different suggestion.

If there's a val that's a project in(file(".)) that's when you should warn.

The warning should say instead of putting the settings at the top level put them into the settings of that project, or prefix them with ThisBuild /

@bjornregnell
Copy link

bjornregnell commented Jun 30, 2021

@nafg If your solution proposal still allows (?) bare bone settings without ceremony in simple builds then I'm all for it. All my students just love ❤️ bare bone settings and exactly all of our student projects are single-project builds.

@ekrich
Copy link
Contributor

ekrich commented Jul 1, 2021

Maybe sbt new (no template) should just generate a skeleton build with everything you need with the latest Scala version. Maybe if you don't have the latest sbt it could offer to update that too if you don't have a build.properties.

I am totally in favor of reducing the variation in build styles. I wish there was just one way to format code too. So much less to think or reason about.

@bjornregnell
Copy link

bjornregnell commented Jul 1, 2021

@ekrich Yes I agree, but sometimes we just can't have the cake and eat it at the same time and some variablity will be needed for the very different use cases of a simple single-project build and a complex multi-project OSS build to publish on maven central etc., I guess. And all tools in the ecosystem should have a very simple getting-started thing; for sbt the simplest thing is scalaVersion := "3.0.0" and no other ceremony. I like the idea of a simpler sbt new very much; just filed this: #6574

@eed3si9n
Copy link
Member Author

A few weeks ago, I conducted an informal survey on GitHub using code search for "scalaVersion :=" whose extension is .sbt, sorted by recently index. The search is specific enough to list out mostly build.sbt files, and I sampled the first 100 results. The result is Survey of sbt build styles: 2021-07.

  • (pure) multi project style: 41
  • hybrid style: 13
  • (pure) bare style: 46

I am a bit surprised by the prevalence of the bare style, and many of them separated with blank lines like 2014 never happened. But in general, completely removing the bare style might be an uphill battle.

As Seth suggested as

First, I'm totally on board with deprecating bare settings in multi-project builds, I see no downside there.

maybe I should first go after the hybrid cases since that's the confusing case.

@eed3si9n
Copy link
Member Author

Since I titled this issue originally as 'Deprecate bare settings', I'll close this issue and maybe open a new issue specifically about deprecating hybrid cases.

@bjornregnell
Copy link

I really like that the bare style is kept for single-project projects! Really great that you base this on empirical evidence. And now I don't have to rewrite my teaching material for beginner programmers and can continue to show them how easy it is to get going with sbt 🥰

@ekrich
Copy link
Contributor

ekrich commented Aug 3, 2021

Could it be possible to have sbt to convert from a bare style to a multi-project style for people wishing to convert and then add to their projects?

@eed3si9n
Copy link
Member Author

eed3si9n commented Aug 3, 2021

That might give me a good excuse to bring nocomma { ... } into the canon. With it I can pretty much translate from bare style to multi-project style mechanically.

@SethTisue
Copy link
Member

SethTisue commented Jan 31, 2022

This is in the Scala FAQ now: https://docs.scala-lang.org/tutorials/FAQ/index.html#i-set-a-setting-in-sbt-but-nothing-happened-why

I still think it would be excellent to deprecate, or at least issue some kind of warning on, the use of a bare setting (either in build.sbt or interactively) if the build is multi-project.

@hmemcpy
Copy link
Contributor

hmemcpy commented Jan 31, 2022

@SethTisue that's great! I would omit the word "simply" from it, per the style guide I'm sure you have somewhere ;)

@SethTisue
Copy link
Member

@hmemcpy done: scala/docs.scala-lang@7ec4bd8

@bjornregnell
Copy link

I still think it would be excellent to deprecate, or at least issue some kind of warning on, the use of a bare setting (either in build.sbt or interactively) if the build is multi-project.

As long as it is allowed without "beginner-strange" warnings in single-project builds, I'm all for deprecation of multi-project bare-bone settings.

@som-snytt
Copy link
Contributor

Contributing to scala faq that ThisBuild / name doesn't work for single project case. Uniformity of treatment would have resulted in less cognitive load for us cargo cultists.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 11, 2023
@SethTisue
Copy link
Member

Since I titled this issue originally as 'Deprecate bare settings', I'll close this issue and maybe open a new issue specifically about deprecating hybrid cases.

@eed3si9n does that ticket exist?

@eed3si9n
Copy link
Member Author

eed3si9n commented Feb 3, 2024

It's subsumed by https://eed3si9n.com/simplifying-sbt-with-common-settings/, where I propose that hybrid usage will be allowed, and sort of act similar to ThisBuild-like way in sbt 2.x.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants