I used asdf for a long time and recently switched over to rtx (https://github.com/jdxcode/rtx) and so far it's been a better experience for me. I must have screwed up something years ago in my dotfiles, but when I setup asdf two or so years ago, I kept running into odd issues - the wrong version of ruby being used for running rubocop/rspec, vim being unable to autofix styling, misc other tools not working as expected when maintaining several versions of them. I installed rtx as kind of a hail Mary and it's been much more smooth so far.
I'd like to offer https://github.com/jamesob/desk as an alternative to direnv. It's useful for also jumping to the project directory and doing other things like opening an editor.
I have to say I love editorconfig, I feel that once you start running code and managing tools it starts to get too much for me. At that point just spin up a VM or container so that the environment is yours.
I loathe pre-commit hooks. I often times just want to save work in progress or show someone what I have right now and they slow down my work or worse fail and lose my commit message and cause me to have to figure out how to disable them to continue. If you want to run checks for formatting or similar that is much better done in CI. I can get a reminder without breaking any dev workflows. Of course make fixing formatting a single command, and maybe an optional hook for those that prefer it. But when projects try to auto-install hooks it drives me crazy.
A compromise is to only enforce pre-commit rules when merging to main or some other important branch. Be as sloppy as you want on your own branches and make stuff proper when you're ready.
Imo the pre-receive or update hook should be used on the server. For trunk based development I‘d also only check for (e.g) formatting on the main branch.
By the time I realize I should have done that I have already been inconvinced. Also remember to copy .git/COMMIT_EDITMSG before you run it so that you don't loose your message.
Pre commit hooks that fail are trash, just absolutely the worst thing you can do to ruin your team's good practices of committing often & keeping flow high.
Any check that take more than 6 seconds can also go jump off a cliff as car as I'm concerned.
But I do greatly value fast fixing & feedback. Run format! (and don't print out unchanged things!) Run lint! Maybe run tests, if they're fast.
One of the constraints becomes that you are trying to make quick actionable easy to view data, and the output can become too long. We had some outside teams come in & deploy centralized & more updated lint & testing, and alas there's just multiple pages of yellow jest configuration warning as it starts, and it's just so much harder to quickly check status. These hooks need to be quick to read, as well as run. All of the hooks should run if they can, not stop on first problem.
Ideally the ci/CD system is a good fast way to see test results. Devs shouldn't even have to think about it, just commit & off board the running. I hear Facebook has very interesting systems where devs aren't even having to make commits for this, which sounds epic. Alas many ci/CD systems are doubly slow, which sucks: slow to start, slow execution speed, and most damming low caching, so they have to do a lot of from-scratch bring up that just takes a really long time versus what local dev has. Systems like nx in JS land are starting to change this more systematically, rather than being a lot of custom ci/CD tweaking.
Informational, not prescriptive! Use the tools to accelerate & guide. Right now we're all learning but tool heavy setups are for sure the way.
Good tools, but I disagree with the last one, which feels more like an outlier. The feat, docs, whatever style is highly opinionated, and I have yet to encounter a need for something like this in a professional setting
Somehow it doesn't seem to be such a big problem in Java land. I think there's some common baseline shared by basically everyone - I don't remember ever seeing Java classes which were not indented with 4 spaces for example.
People like to pooh pooh Java in the circles I hang out in, but I’m always quick to point out stuff like this, things that are just basically mostly solved in Java land and no one really wastes time on anymore because some pretty good decisions were made 20-25 years ago. How to handle a lot of aspects of dependencies is another classic example.
clang-format has so many useless options and yet it cannot do normal readable argument handling. At least not according to the documented options (as of a few versions back at least).
function(
arg,
arg
);
New line per argument, closing parenthesis on a new line. This is standard in most langauges, yet clang-format cannot handle it.
Then it also insists on aligning everything prettily. Most, but not all of it can be disabled though.
And lastly it doesn't do very well with tab indents. Most of it works perfectly, you just need to set both tab size and indent size, but then it decides to do its alignment thing and suddenly that line is all spaces, even the base indent.
Clang-format is honestly by far the worst formatter I've had the displeasure to fight. C/C++ still needs to be formatted manually
I think with this kind of stuff, it should be, give me a sane set of defaults and make me change it when they don’t make sense. Rather than go to make me search and configure and have to make 100 different decisions on minutiae and exhaust my brainpower on what I would consider important but relatively low impact work in the short term
Oooh, that's much closer. Not perfect, but so much better. Do you have a solution for this as well?
→(StructType){
→····.a = 1,
→····.b = 2,
→};
It's not just this scenario, but this is the worst one. It does it regardless of useTab and what's worse is that it's four spaces when both indent width and tab size are set to 8
Weirdly, initializer indentation is controlled by `ContinuationIndentWidth` rather than by `IndentWidth`. That one I would agree is a clang-format bug, or a mistaken policy decision.
I haven't myself worked on a tabbed code base during clang-format's existence. You might want to look at Linux's settings for ideas, although they clearly differ from your preferences in other ways. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
Seems like the point of this is to work across languages though. I'm not sure how I feel about it. Different languages have their own conventions. Often times there's a reason why one convention might be preferred in a language over a different convention in another
I really like the batteries included philosopy. I think golang really took the idea mainstream but deno, heavily inspired by go and that philosophy, also is a joy to use.
One of Haskell's most popular formatters, Formolu [1], is explicitly not opinionated and has custom whitespace as a goal:
> Let some whitespace be programmable. The layout of the input influences the layout choices in the output. This means that the choices between single-line/multi-line layouts in certain situations are made by the user, not by an algorithm. This makes the implementation simpler and leaves some control to the user while still guaranteeing that the formatted code is stylistically consistent.
Coq, Agda, etc. also don't have formatters either, partly because "user-defined layout", but also partly because their syntax is just so complicated and they have smaller ecosystems
I care whether experts can understand each others’ reviewed work, not whether they would use exactly the same amount of whitespace. Don’t reformat code you aren’t rewriting, and definitely not with a tool that doesn’t understand what a developer was communicating when he laid it out that way.
I would say everything in the codebase should be auto formatted to a consistent style. This reduces whitespace noise in pull requests. No room for egotistical developers to take ownership of files in a shared codebase and waste time on petty formatting arguments. It keeps everything professional and tidy.
When someone commits changes to an existing file, they auto format before committing. If existing parts of the file already contain weird non standard formatting this creates distracting whitespace noise in the pull request that could have been prevented. It's a waste of time to not use standard formatting.
Layout is semantic, just as names and comments are. I don't want a tool to blindly stomp any of these when it lacks understanding how they benefit readers.
The answer to dirty diffs is to not make them. Every change should be intentional, and a reviewer should agree that it's important. "Reformat this block I haphazardly edited" is fine, but don't make the change bigger for no reason.
> I don't want a tool to blindly stomp any of these when it lacks understanding how they benefit readers
Some dev will have 1 newline after a method ends, another dev will have two newlines, some might have 3 etc. Should you as a code reviewer be wasting time looking for such issues and putting comments tell the other to fix such issues?
It’s not my job to make you write exactly what I would have. I don’t care about an extra blank line, and I expect a reviewer to accept that it doesn’t matter. I draw the line at layout that is misleading about the code (e.g., dangling else that doesn’t parse the way it’s indented).
If it gets to a dozen I’d grumble about wanting to fit more code on screen, but this just isn’t a problem we’ve ever had. I think the urge to enforce complete uniformity is bad for a collegial high-trust team.
Yes layout is semantic and the automatic layout configuration should not be random nonsense. Configure a style that makes sense and apply it.
I've never seen that code that needed to be weirdly formatted with its own rules separate from other files in the codebase in order to make sense. That just sounds like a developer being a prima donna with their code style, not something that genuinely improves understanding and collaboration.
System.arraycopy(src, srcPos, // from
dest, destPos, len) // to
where I want to show the parallel relationships between src/srcPos and dest/destPos. Blind tools don’t know to do this, they either emit one long line or waste seven lines.
Tools also won’t know how to format a DSL well at all, which has already been a problem with Spark jobs in Scala.
Meh. That is so obvious to anyone who would use that function. Just put it on one line.
If your function has too many parameters then the code probably needs refactoring.
Yes agreed about DSL in Scala. Scala is complicated. I was a Scala dev for many years. We tried to avoid the more academic and overly abstract designs with that language.
Here we are in the current year and we still i/o source as raw form text. Personally, I’ve always hoped for standardized AST formats with comprehensive tooling, including source control. Many more problems vanish than are created with source as AST. For instance, this discussion.
48 comments
[ 4.3 ms ] story [ 114 ms ] threadOthers:
https://direnv.net/ -- when you cd to a directory, do things like set variables.
https://asdf-vm.com/ -- manage and use specific versions of software. Can work with direnv too!
https://pre-commit.com/ -- git hooks that I personally found easier to manage than Husky.
https://github.com/qoomon/git-conventional-commits -- enforce standard commit messages. Works with pre-commit!
I loathe pre-commit hooks. I often times just want to save work in progress or show someone what I have right now and they slow down my work or worse fail and lose my commit message and cause me to have to figure out how to disable them to continue. If you want to run checks for formatting or similar that is much better done in CI. I can get a reminder without breaking any dev workflows. Of course make fixing formatting a single command, and maybe an optional hook for those that prefer it. But when projects try to auto-install hooks it drives me crazy.
So you can go wild in your own branches and draft MRs but anything you want someone else to review has to pass.
Works wonders, but occasionally you screw up. To get out of screwup, use `git reflog` and `git reset --hard`.
Any check that take more than 6 seconds can also go jump off a cliff as car as I'm concerned.
But I do greatly value fast fixing & feedback. Run format! (and don't print out unchanged things!) Run lint! Maybe run tests, if they're fast.
One of the constraints becomes that you are trying to make quick actionable easy to view data, and the output can become too long. We had some outside teams come in & deploy centralized & more updated lint & testing, and alas there's just multiple pages of yellow jest configuration warning as it starts, and it's just so much harder to quickly check status. These hooks need to be quick to read, as well as run. All of the hooks should run if they can, not stop on first problem.
Ideally the ci/CD system is a good fast way to see test results. Devs shouldn't even have to think about it, just commit & off board the running. I hear Facebook has very interesting systems where devs aren't even having to make commits for this, which sounds epic. Alas many ci/CD systems are doubly slow, which sucks: slow to start, slow execution speed, and most damming low caching, so they have to do a lot of from-scratch bring up that just takes a really long time versus what local dev has. Systems like nx in JS land are starting to change this more systematically, rather than being a lot of custom ci/CD tweaking.
Informational, not prescriptive! Use the tools to accelerate & guide. Right now we're all learning but tool heavy setups are for sure the way.
- Pre-Commit hooks that fail to handle partial stages.
- Running CI as far away as possible to enlarge feedback time.
- Non-incremental builds.
But pre-commit hooks should fail fast.
Just use dotenv instead.
https://asdf-vm.com/ -- manage and use specific versions of software. Can work with direnv too!
May be useful in some cases, but adds a global dependency on asdf itself.
> https://pre-commit.com/ -- git hooks that I personally found easier to manage than Husky.
Git hooks are disturbing and slow down and/or break advanced git interactions.
> https://github.com/qoomon/git-conventional-commits -- enforce standard commit messages. Works with pre-commit!
Only if you want to be so pedantic about them. I find it mostly a waste of time to enforce commit message style.
While minor variations exist, virtually all Java code follows these conventions pretty closely.
Although I'll note it seems to get a bit more chaotic with regards to indenting newer constructions like streams and lambdas.
Then it also insists on aligning everything prettily. Most, but not all of it can be disabled though.
And lastly it doesn't do very well with tab indents. Most of it works perfectly, you just need to set both tab size and indent size, but then it decides to do its alignment thing and suddenly that line is all spaces, even the base indent.
Clang-format is honestly by far the worst formatter I've had the displeasure to fight. C/C++ still needs to be formatted manually
Oooh, that's much closer. Not perfect, but so much better. Do you have a solution for this as well?
It's not just this scenario, but this is the worst one. It does it regardless of useTab and what's worse is that it's four spaces when both indent width and tab size are set to 8I haven't myself worked on a tabbed code base during clang-format's existence. You might want to look at Linux's settings for ideas, although they clearly differ from your preferences in other ways. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
> Let some whitespace be programmable. The layout of the input influences the layout choices in the output. This means that the choices between single-line/multi-line layouts in certain situations are made by the user, not by an algorithm. This makes the implementation simpler and leaves some control to the user while still guaranteeing that the formatted code is stylistically consistent.
Coq, Agda, etc. also don't have formatters either, partly because "user-defined layout", but also partly because their syntax is just so complicated and they have smaller ecosystems
[1] https://hackage.haskell.org/package/fourmolu
When someone commits changes to an existing file, they auto format before committing. If existing parts of the file already contain weird non standard formatting this creates distracting whitespace noise in the pull request that could have been prevented. It's a waste of time to not use standard formatting.
The answer to dirty diffs is to not make them. Every change should be intentional, and a reviewer should agree that it's important. "Reformat this block I haphazardly edited" is fine, but don't make the change bigger for no reason.
Some dev will have 1 newline after a method ends, another dev will have two newlines, some might have 3 etc. Should you as a code reviewer be wasting time looking for such issues and putting comments tell the other to fix such issues?
You dont care about an extra blank line, what about 2 extra lines, what about three and so on. Do you see why there is a need for a consistent style?
exactly, which is why such rules should be part of the code, no need to trust if such conventions are followed if the rule will take care of it.
You should spend your time doing some meaningful not wasting it on such issues.
I've never seen that code that needed to be weirdly formatted with its own rules separate from other files in the codebase in order to make sense. That just sounds like a developer being a prima donna with their code style, not something that genuinely improves understanding and collaboration.
Tools also won’t know how to format a DSL well at all, which has already been a problem with Spark jobs in Scala.
If your function has too many parameters then the code probably needs refactoring.
Yes agreed about DSL in Scala. Scala is complicated. I was a Scala dev for many years. We tried to avoid the more academic and overly abstract designs with that language.