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

Started to add rationales #5681

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from

Conversation

mildm8nnered
Copy link
Collaborator

@mildm8nnered mildm8nnered commented Jul 20, 2024

Addresses #4811

The idea is to add a longer explanation of the purpose or motivation behind each rule.

You can now see the output via swiftlint rules rule_name

For example

% swiftlint.debug rules array_init
Array Init (array_init): Prefer using `Array(seq)` over `seq.map { $0 }` to convert a sequence into an Array

Rationale:

When converting the elements of a sequence directly into an `Array`, for clarity, prefer using the `Array` constructor over calling `map`. For example

    Array(foo)

rather than

    foo.↓map({ $0 })

If some processing of the elements is required, then using `map` is fine. For example

    foo.map { !$0 }

Constructs like

    enum MyError: Error {}
    let myResult: Result<String, MyError> = .success("")
    let result: Result<Any, MyError> = myResult.map { $0 }

may be picked up as false positives by the `array_init` rule. If your codebase contains constructs like this, consider using the `typesafe_array_init` analyzer rule instead.

Configuration (YAML):

  array_init:
    severity: warning

Triggering Examples (violations are marked with '↓'):

Example #1

    foo.↓map({ $0 })

Example #2

    foo.↓map { $0 }

Example #3

    foo.↓map { return $0 }

And when rendered via Jazzy:

Screenshot 2024-12-01 at 21 04 11

Rationales may contain MarkDown formatting.

When formatting for the console, any lines containing "```" will be stripped from the output, and any lines between them will be indented by four spaces - so in the raitionale definition, code samples should not be indented - no other formatting will be performed, so any MarkDown will appear as is.

When formatting for jazzy, line containing "```" that start a code block will be assumed to be swift code, and will have swift appended to them. If you want to format for a different language, then specify that explicitly when starting the code block.

This assures that any code samples in the rationale will be formatted in a very similar way to any examples that are provided for the rules - see output and screenshots above.

@SwiftLintBot
Copy link

SwiftLintBot commented Jul 20, 2024

2 Warnings
⚠️ If this is a user-facing change, please include a CHANGELOG entry to credit yourself!
You can find it at CHANGELOG.md.
⚠️ This PR may need tests.
17 Messages
📖 Linting Aerial with this PR took 0.96s vs 0.94s on main (2% slower)
📖 Linting Alamofire with this PR took 1.27s vs 1.27s on main (0% slower)
📖 Linting Brave with this PR took 7.25s vs 7.23s on main (0% slower)
📖 Linting DuckDuckGo with this PR took 5.35s vs 5.34s on main (0% slower)
📖 Linting Firefox with this PR took 10.8s vs 10.85s on main (0% faster)
📖 Linting Kickstarter with this PR took 10.26s vs 10.22s on main (0% slower)
📖 Linting Moya with this PR took 0.53s vs 0.53s on main (0% slower)
📖 Linting NetNewsWire with this PR took 2.92s vs 2.94s on main (0% faster)
📖 Linting Nimble with this PR took 0.77s vs 0.77s on main (0% slower)
📖 Linting PocketCasts with this PR took 8.65s vs 8.62s on main (0% slower)
📖 Linting Quick with this PR took 0.46s vs 0.45s on main (2% slower)
📖 Linting Realm with this PR took 4.51s vs 4.54s on main (0% faster)
📖 Linting Sourcery with this PR took 2.33s vs 2.32s on main (0% slower)
📖 Linting Swift with this PR took 4.54s vs 4.52s on main (0% slower)
📖 Linting VLC with this PR took 1.26s vs 1.26s on main (0% slower)
📖 Linting Wire with this PR took 18.08s vs 17.99s on main (0% slower)
📖 Linting WordPress with this PR took 11.48s vs 11.42s on main (0% slower)

Here's an example of your CHANGELOG entry:

* Started to add rationales.  
  [mildm8nnered](https://github.com/mildm8nnered)
  [#issue_number](https://github.com/realm/SwiftLint/issues/issue_number)

note: There are two invisible spaces after the entry's text.

Generated by 🚫 Danger

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-add-rationale branch 5 times, most recently from 2e234b3 to e9e38be Compare July 29, 2024 22:08
@SimplyDanny
Copy link
Collaborator

That's an ambitious plan with 238 existing rules. 😅 But I very much appreciate the effort. This definitely something helpful and can be extended over time with the infrastructure as a starting point.

A few thoughts from my side:

  • There are currently one description and sometimes additional more specific reasons per rule. Now, we would add another form of documentation with the rational. I wonder if we should rather extend the description and introduce something like a "default reason" or "violation reason".
  • Something similar has been on my ToDo list for rule configuration options for quite a while.
  • I think that the text should be entirely Markdown.

@mildm8nnered
Copy link
Collaborator Author

That's an ambitious plan with 238 existing rules. 😅 But I very much appreciate the effort. This definitely something helpful and can be extended over time with the infrastructure as a starting point.

238 is a lot yes, but I think definitely achievable. I've had a lot of fun writing the ones so far, and it's the kind of thing that you can knock some off on a rainy afternoon. Keep going, and before you know it you're done.

I think one think to talk about is "voice" - we could go for something very dry and technical, or somewhat more lighthearted, or even something a bit zany.

I think my take is that some kind of middle ground is good, but it would be nice to have some "character" to the rationale's, and to let them be a little bit opionated in places ("almost no-one enables this rule").

A few thoughts from my side:

  • There are currently one description and sometimes additional more specific reasons per rule. Now, we would add another form of documentation with the rational. I wonder if we should rather extend the description and introduce something like a "default reason" or "violation reason".

So I think description has a role, and it's short and widely used.

I kind of see rationale as more of a freeform piece of text, that might mention some original source of why X is bad/good, and/or also maybe give some tips about using the rule, or about configuration options that you might want to use, or that people commonly set.

"Why should I care about this rule/how should I get the most out of it", together with a bit more of a narrative explanation of what it actually is - sometimes the examples can be a little obtuse.

  • Something similar has been on my ToDo list for rule configuration options for quite a while.

Yep - I think it would be great to have something more formal for config options.

It's kind of a pain, because we probably have a lot, and someone has to write the text (see rationale's), but we could definitely do a better job of explaining what individual options do.

I think mentions of config options in rationale's are of the kind - "this option is one that you might want to use" rather than documenting the config options per se.

  • I think that the text should be entirely Markdown.

My kind of tacky solution was

  1. needs to look good in swiftlint rules rule_name output (would be so nice if that picked up the system pager, if set)
  2. needs to look good in Jazzy output

So strip "```" for the Terminal and add swift for Jazzy, and make sure you get your indentation right for the Terminal yourself.

I think the Terminal case is harder.

Adding swift to "```" I kind of saw a service to rationale authors - it's probably swift code, and I know we'll forget to add those manually.

@SimplyDanny
Copy link
Collaborator

That's an ambitious plan with 238 existing rules. 😅 But I very much appreciate the effort. This definitely something helpful and can be extended over time with the infrastructure as a starting point.

238 is a lot yes, but I think definitely achievable. I've had a lot of fun writing the ones so far, and it's the kind of thing that you can knock some off on a rainy afternoon. Keep going, and before you know it you're done.

Oh, perfect. Happy to learn you like writing documentation. 😉

I think one think to talk about is "voice" - we could go for something very dry and technical, or somewhat more lighthearted, or even something a bit zany.

I think my take is that some kind of middle ground is good, but it would be nice to have some "character" to the rationale's, and to let them be a little bit opionated in places ("almost no-one enables this rule").

I think all these styles are fine. And maybe even a mixture makes them interesting for readers. One consistent style throughout the whole set of rules is anyway almost impossible.

  • I think that the text should be entirely Markdown.

My kind of tacky solution was

  1. needs to look good in swiftlint rules rule_name output (would be so nice if that picked up the system pager, if set)
  2. needs to look good in Jazzy output

So strip "```" for the Terminal and add swift for Jazzy, and make sure you get your indentation right for the Terminal yourself.

I think the Terminal case is harder.

The thing is that without using Markdown, there is no good way to use different text styles and add links to other rules or further references. For the terminal output, all the styling modifiers could be removed afterwards.

Adding swift to "```" I kind of saw a service to rationale authors - it's probably swift code, and I know we'll forget to add those manually.

Important is that it allows to choose other languages as well.

@mildm8nnered
Copy link
Collaborator Author

That's an ambitious plan with 238 existing rules. 😅 But I very much appreciate the effort. This definitely something helpful and can be extended over time with the infrastructure as a starting point.

238 is a lot yes, but I think definitely achievable. I've had a lot of fun writing the ones so far, and it's the kind of thing that you can knock some off on a rainy afternoon. Keep going, and before you know it you're done.

Oh, perfect. Happy to learn you like writing documentation. 😉

:-)

I think one think to talk about is "voice" - we could go for something very dry and technical, or somewhat more lighthearted, or even something a bit zany.
I think my take is that some kind of middle ground is good, but it would be nice to have some "character" to the rationale's, and to let them be a little bit opionated in places ("almost no-one enables this rule").

I think all these styles are fine. And maybe even a mixture makes them interesting for readers. One consistent style throughout the whole set of rules is anyway almost impossible.

I hadn't thought of it like that, but actually I think that is absolutely the best approach. Nothing too prescriptive, and then we can catch anything that goes too far off-piste, or lacks clarity in individual CR.

I think comprehensibility to English as a second language speakers is important, so probably we wouldn't want rationale's in Yorkshire Dialect or Runyonese, sadly.

  • I think that the text should be entirely Markdown.

My kind of tacky solution was

  1. needs to look good in swiftlint rules rule_name output (would be so nice if that picked up the system pager, if set)
  2. needs to look good in Jazzy output

So strip "```" for the Terminal and add swift for Jazzy, and make sure you get your indentation right for the Terminal yourself.
I think the Terminal case is harder.

The thing is that without using Markdown, there is no good way to use different text styles and add links to other rules or further references. For the terminal output, all the styling modifiers could be removed afterwards.

Any tips for how you think we should go about the styling modifiers stripping? Not entirely keen on having a markdown parser just so that I can de-markdown it :-)

Adding swift to "```" I kind of saw a service to rationale authors - it's probably swift code, and I know we'll forget to add those manually.

Important is that it allows to choose other languages as well.

So the intention is to ignore any language code that's present, as an override.

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-add-rationale branch 2 times, most recently from 2db6532 to 7370528 Compare August 3, 2024 18:37
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-add-rationale branch from 7370528 to 72177c2 Compare August 9, 2024 21:39
@SimplyDanny
Copy link
Collaborator

I hadn't thought of it like that, but actually I think that is absolutely the best approach. Nothing too prescriptive, and then we can catch anything that goes too far off-piste, or lacks clarity in individual CR.

I think comprehensibility to English as a second language speakers is important, so probably we wouldn't want rationale's in Yorkshire Dialect or Runyonese, sadly.

Fully support that, especially the last part! 🫣

The thing is that without using Markdown, there is no good way to use different text styles and add links to other rules or further references. For the terminal output, all the styling modifiers could be removed afterwards.

Any tips for how you think we should go about the styling modifiers stripping? Not entirely keen on having a markdown parser just so that I can de-markdown it :-)

Well, there is swiftlang/swift-markdown from Apple which I had been playing around with a little at that time. A new dependency should be well thought of. As these rationales are going to provide such a huge benefit, that would be justified though I guess. Apart from removing any Markdown styling, it would also allow SwiftLint to check that the whole text is actually valid Markdown before rendering the docs in the build.

On the other hand, even unrendered Markdown is so well readable, that I wouldn't complain if we just print the text as is into the console (keeping also URLs). There are also console rendering tools available that could be used to prettify the output. That, however, oughtn't be SwiftLint's job then.

Adding swift to "```" I kind of saw a service to rationale authors - it's probably swift code, and I know we'll forget to add those manually.

Important is that it allows to choose other languages as well.

So the intention is to ignore any language code that's present, as an override.

👍

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-add-rationale branch 5 times, most recently from c53b70e to 6ec46a0 Compare August 25, 2024 12:25
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-add-rationale branch from 6ec46a0 to 1954f36 Compare August 31, 2024 13:04
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-add-rationale branch 3 times, most recently from 132d531 to 1d9eaf6 Compare September 8, 2024 13:24
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-add-rationale branch 3 times, most recently from cfe760a to a5087ac Compare September 21, 2024 18:46
@mildm8nnered
Copy link
Collaborator Author

Are these CI failures something that I'm doing @SimplyDanny ? - https://buildkite.com/swiftlint/swiftlint/builds/8753 - they all seem to be concurrency related, but it feels like they come and go at random

@SimplyDanny
Copy link
Collaborator

SimplyDanny commented Sep 21, 2024

Are these CI failures something that I'm doing @SimplyDanny ? - https://buildkite.com/swiftlint/swiftlint/builds/8753 - they all seem to be concurrency related, but it feels like they come and go at random

They fail randomly. It's annoying. A retrigger normally helps. I hope this gets fixed by having strict concurrency checking always on by default. But until then there's still a long way to go.

Optionally, we can disable warnings reported as errors in Bazel builds for the time being.

@mildm8nnered
Copy link
Collaborator Author

Are these CI failures something that I'm doing @SimplyDanny ? - https://buildkite.com/swiftlint/swiftlint/builds/8753 - they all seem to be concurrency related, but it feels like they come and go at random

They fail randomly. It's annoying. A retrigger normally helps. I hope this gets fixed by having strict concurrency checking always on by default. But until then there's still a long way to go.

Optionally, we can disable warnings reported as errors in Bazel builds for the time being.

It feel like mine always fail :-) Apart from pushing an empty commit, is there a better way to retrigger them?


Possibly you could refactor your closure code and extract some of it into a function.

Many installations, including SwiftLint's, increase the default warning value from \
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I remove this configuration related note @SimplyDanny ? I've removed most of the others, as per your comment that better configuration docs are coming

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-add-rationale branch from 1724a2e to 1ce8ea8 Compare December 12, 2024 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants