Update to swift package init templates

Perhaps this is because I'm an existing user but the argument that looking two directories deep is heavy doesn't resonate with me. The user is already invoking swift package init from the command line so they must be at least reasonably comfortable using the command line and navigating file hierarchies; navigating one level deeper to find source files doesn't seem like a big stretch.

As mentioned above (and by others) the issue with the current template for executables and tools make it difficult to add more targets. It biases too heavily towards new users at the expense of additional burden for existing users who are likely to add additional targets (it's common to start with an executable and end up with an executable depending on a library and tests for the library).

I think you're right to explore different layouts, so what if we inverted the target and purpose? For a library this would be:

.
├── Package.swift
└── SomeLibrary
    ├── Sources
    │   └── SomeLibrary.swift
    └── Tests
        └── SomeLibraryTests.swift

For executables and tools the template could elide the 'purpose' (i.e. Sources/Tests) and the entry point would be one-level deep. Adding new targets later would not add burden as they would be at the top-level.

.
├── Package.swift
├── SomeExecutable
│   └── main.swift
└── SomeLibrary
    ├── Sources
    │   └── SomeLibrary.swift
    └── Tests
        └── SomeLibraryTests.swift
1 Like

The Vapor Toolbox provides an interactive experience for creating new projects if you want to take a look at some inspiration!

3 Likes

Apologies for the slower reply - I wanted to step back a bit and do another round of self-evaluation on if I was reacting to "I don't like the suggested change because it's different" vs. "I don't like the suggested change because it's not as good for some reason". Which begs the question of what that reason is, if that's the case.

Partially, I'm right in line with @georgebarnett in my perception that two levels of directories makes for a burdensome concept for new developers, but since I've been programming for quite a few years, I have to acknowledge that I'm not anywhere near that starting point - either with programming in general, or with Swift.

But history is also something I don't think you can ignore - especially when new developers are (hopefully) going to be interacting with developers who've been here and while, and have that inherent expectation of structure. And along those lines, for better or worse, SwiftPM's fundamental structure is aligned quite strictly with targets. Because of that, making a simplified use case that hides that scenario (which your suggested change does, and quite nicely) I think is actually doing a disservice. But that's also partially based on my cost/reward evaluation that two directories isn't that much. What I see as the value is an implicit affordance that there is more complexity there. Because a template sets up the directories, you don't need to immediately engage with it other than to navigate down one more directory if you're clicking through folders, or opening another directory in a UI - although VSCode notably hides even that from you. In return, you're getting a clear hint that there's a bigger structure available here for when you want to expand, and its pattern is likewise clear.

I haven't seen ./Previews at the top level of such a structure myself, but I do have ./Snippets now that the feature is functionally available in 5.8 - so I end up with a directory structure for most of my work that looks like:

Package.swift
README (and other misc files)
Tests/
   ATarget/
Sources/
  ATarget/
Snippets/
  SnippetExample1
  SnippetExample2

It's not a far stretch to imagine this kind of layout once you've seen it for an expanded structure, but if you're only ever seeing the top level without anything else, it's not clear where you should expand. I would think it just as likely to see someone reach for the pattern of:

Package.swift
Sources/
OtherSources/
Tests/
OtherTests/

The structure of the directories ends up providing a sort of guard rails to where you're going to expand - at least in such a way that you don't get the "SwiftPM warnings you're holding it wrong" scenario, which I see as valuable.

Just to add more noise to the signal...

If the aim is to help people new to SPM, how about another, extra option:
swift package init --type tutorial

Which could generate a sample package which was even more heavily annotated with comments which explain exactly what each part does and how they interact. There could also be non-compilable files in the package explaining the folder layout. e.g.

/Sources/AboutTheSourcesFolder.txt 
/Tests/AboutTheTestsFolder.txt 
/Snippets/AboutTheSnippetsFolder.txt 
etc...

This example package would have a main executable target.

The executable would have a dependency from the internet (say the SPM 'Deck of Cards' example package.)

The package would also have a very simple library target (also a dependency of the main executable target) perhaps a library that vends card dealing functions.

Again, all heavily commented explaining that these elements are not compulsory but this is how it's done.

The package should have a good README, rather than a placeholder.

2 Likes

I know this is an old thread, but the new template is annoying. Personally, I program as a hobby. I'm not a beginner, but I'm not advanced. Over the past several months, I have been using the command line instead of Xcode for programming. I like the customizability, and I like NeoVim more than Xcode. I agree with prior statements that if a user is using the CLI to program, they are most definitely beyond the beginning stages of programming.

There is always a learning curve, but making things too simple does not help someone new to the language with more than creating the Package.swift file and a main.swift. Even for new users, the lack of a more full template becomes apparent really fast. Templates reduce manual input of boilerplate, but more importantly, they can be used to provide direction and expectation. New users want to know what is expected so they know what they can break, when they can break it, and why they should break it.

I like the idea of a tutorial, but instead of creating a separate command for it, why not make it part of the template in a README.md? First, it says README so you're already giving instructions to new users. After SwiftPM states the directories and files it created it could could also state, "Please look at the README if you're new to Swift". Second, a clear and concise "how-to" should remove the mystery of the file structure, instruct how to add more targets, and provide a brief overview of the various Package.swift options. This providers an excellent method of on-boarding for new users and reference for more advanced users. The current SwiftPM documentation page provides a lot of information, but it doesn't have a link to all of the possible SwiftPM options/Package.swift options.

Something else I noticed was running swift package init --type executable creates the following:

Package.swift
.gitignore
Sources/
    main.swift

Running swift package init to create a library gives you a Tests folder with an initial test file. Is there a reason executables don't do the same? I get not wanting to overwhelm a new user, but in this case the user is on the CLI so they're not that new. swift package init --executable creates such a lack-luster project currently - it's a let down. It "feels" better as a new user to put in a line of code (in this case a shell command) and get back something meaningful. It makes new users feel like they've already done something cool and all they did was create the project.

1 Like

Yeah, I agree that the executable template isn't really suited as scaffold for anything other than the simplest projects. And the removal of a tests target bugs me to no end - I think it sets a very bad example.

Anyway, adding tests and/or any further structure requires a lot of manual editing of Package.swift. I now know how to do it, but without the old example Package.swift files I'm not sure I would even have figured it out.

With the previous template a) tests were already available and b) adding an additional target is easier because you already see the intended structure reflected in Package.swift and the directory/file structure.

My recommendation would be to have a executable template that is more in line with what we had: typical structure with a target and tests (I call this the canonical SwiftPM project). And a minimal-executable template that only has the main.swift file in the Sources folder.