Proposal: Deprecation of other sbt styles outside of top level build.sbt file

SBT’s main drawback, in my personal opinion, is the different ways of building the exact same project with many different styles:

I’ve seen projects wherein there is both a top level and a build.sbt in each directory, on top level build.sbt file, one build.scala file in the top level project file… etc.

The fact two people experienced in sbt that learned different styles and different ways of achieving their projects scripting goals with sbt could go into eachother’s projects and feel completely lost says something about the overly broad way sbt approaches building, when neither way is a right way, just one more encouraged.

Even if build.scala is being deprecated in favor of the build.sbt file style, I still do believe it could be taken a step further, and deprecate all styles but the one the community converges on the most (ATM, I believe the top level build.sbt file for multi-module projects). The goal being a single, unified way of developing and building projects, therein lowering the barrier of entry and maintenance of docs for so many different styles that all achieve the same thing, while also helping the community pick up abandoned but potentially useful projects in a shorter amount of time build in this singular way.

5 Likes

This derives from a conversation that started in scala/scala (https://gitter.im/scala/scala?at=59495da802c480e67263e586) and then later in sbt/sbt (https://gitter.im/sbt/sbt?at=594a8820a44c60fa4c4b4b69).

Thank you @jmcardon for creating this thread. You propose deprecating a style that I don’t see too common in the (OSS) wild, so provided we cater for those that are using that style (deprecation warnings, opt-in/opt-out, migration guide, auto-rewrite) I think it’s very achievable.

For anyone interested initially you couldn’t define projects in sbt files, only settings. So the single, top-level file style that we promote nowadays wouldn’t have been possible at the beginning. It kind of grew organically into having multiple possible styles.

Note that with this change you would still be able to define multiple sbt files at the root of the project (for instance a .gitignore’d “local.sbt”) as well as multiple sbt files inside project - it’s just the recursing into other directories that would see deprecation/removal of support.

I agree with this. It would also be nice to deprecate the top-level project because basically all builds are multi-project and reconfiguring the top project to aggregate and/or do nothing ends up being confusing. Probably out of scope but thought I would mention it.

3 Likes

For most OSS projects maintained by a small team and/or have a handful of subprojects, I agree having a single top-level build.sbt makes sense, and that’s how I personally write all my builds.

However, this is also a good opportunity to think about medium sized teams (let’s say 5 to 10 person each) maintaining a bunch of modules/services. In those situations, it might make sense to be able to roll up the builds together so different directory structure can represent n jars (or targets in monorepo term).

In Maven there’s the notion of parent poms. For sbt that’s company plugins, so I am not sure if we can reconcile having a bunch of those from all the subdirs, but even one-level deep aggregation with source/binary/cache of builds could change the way sbt could be used in a work environment.

Hey @jmcardon, I’m happy to see community requests for sbt! Welcome :slight_smile:

Do you mean that developers may be interested in having different projects living in different repositories and then clone them one inside the other and having them built without further configuration? If not, can you elaborate @eed3si9n?

If you mean this, I think that we should not optimize for this case since it is pretty weird and uncommon. I think there are other ways in which you can make the same scenario work:

  1. Source dependencies; or
  2. Merging the sbt files and ensuring that the build definitions still work by adding the correct baseDirectory for every project.

However, your original scenario doesn’t really make sense to me. Why would developers want to do that and not use source dependencies?

That’s exactly what I’m talking about (although having different repositories or not could be optional).

If sbt supported “hierarchical” build out of the box (I’m avoiding the term recursive since it’s already taken), it could become more common. Essentially what I am talking already exists in the name of Dbuild, and its usefulness is fairly clear, at least to me.

We can get true continuous integration, meaning that in a pull request wen can try to validate the change to some API and all of its usages. Wiring this manually I don’t think will scale beyond small projects.

2 Likes

I think that would encourage people to use multi projects, which from a modularity point of view is out of question a best practice. Sounds like an interesting idea that I don’t see as off-topic.

I’m very much in favor of eliminating the “build.sbt’s in every sub module” pattern, with one exception. I think my exception is the same as what @eed3si9n suggests, in that I’d like to be able to reference sub-projects via sbt, much like source dependencies but fully integrated with the build so my IDE picks it up and sbt recompiles the entire stack in one go.

The use case is when you’re maintaining a local fork of some (potentially open source) library, aka “vendoring”. You want to make changes to both the fork and your application concurrently, perhaps even using IDE refactorings across the two. The default build.sbt “import” mechanism means that your application build gets polluted with a bunch of junk from the vendor fork, so you have to make a bunch of modifications to the vendored build.sbt just to get your combined build to work.

I would love if I could just do project.in("./vendor/cats") and have it build that sub-project and include it as if I’d included a snapshot dependency. Barring that, I’d still prefer the build.sbt to be ignored so I know I just have to configure the entire build in my root project instead of mucking with the build for my fork and keeping the changes out of any PR’s I make.

1 Like

I would very much like that … if it were not for the meta-builds. In the meta-build, it is extremely rare that you have more than the top-level project, and in that case you definitely want your top-level settings in project/build.sbt to apply to that top-level project.

Maybe we could deprecate the top-level project if there is at least one other project.

If I understand correctly you all advocate for having one build.sbt file for multiproject build, right? Its hard for me to imagine anything worse, because in large projects I’m rarely ever interested how all of the modules are built. I always try to have the modules as separate as possible with every one of them having almost independent build.sbt file, and my root build.sbt just list the subprojects…

Such scenario is quite hard already because to share anything you need Build.scala and plugins can be declared only in root project/plugins.sbt, but still IMHO it is much better than one file with hundreds of lines

You can have multiple build.sbt files @ the top level, or in your project folder, the problem would be one in each module.

The entire point of this is the convergence of styles. Also:

Its hard for me to imagine anything worse, because in large projects I’m rarely ever interested how all of the modules are built.

Agreed, but often enough one module depends on another and getting that to work is ugly, and also it’s easier to pass around common dependencies.

Such scenario is quite hard already because to share anything you need Build.scala and plugins can be declared only in root project/plugins.sbt

No, you do not need build.scala to share anything. That particular style is what people have been trying to deprecate I believe. The entire point of build.sbt is to share dependencies much more easily and converge on a style that makes it easier for community members to maintain collaborative projects without incurring the cost in the learning curve of each project using a wildly different style.

I have used LocalProject for these cases and I find it rather nice(the only problem that you need to keep modules names coherent)

In my approach if you have build.sbt in subdirs it is the only way I know.

In my approach if you have build.sbt in subdirs it is the only way I know.

I mean that’s part of what this proposal is trying to address! That disconnect between people using the same tool.

What you’ve said is the exact reason I posted this. What you’re addressing is the biggest reason why converging on a style is beneficial: everyone knows the same style. At the end, if the entire community is doing the same thing with builds, it makes it easier to collaborate for more complex tasks if more people follow the same style.