I think a more ideal solution would be to achieve the flexibility of elastic TabStops without having to actually change the way it's represented under the hood.
My conviction from personal experience is that your personal tools need to be adaptable to fit any organization. This splits largely along tech stack culture lines. Our shop was originally Ruby before we started moving to NodeJS, we all use spaces for indentation.
So unless I want to force my whole team to start using tabs, I can't use elastic tabstops.
This isn't a viable improvement until it can accommodate the existing state of affairs. The other obstacle in the way is code linters. I have to make a case to turn off linter rules at my shop and if the only objection I have is that it makes a workflow I haven't even tried yet difficult to implement, it's not going to be taken seriously if it requires work from the whole team.
The way I usually accomplish workflow improvement objectives is to find a way to accommodate both my needs and the status quo while thinking deeply about the underlying context creating the obstacle.
Environment managers get gnarly when you have to commit .env files to the codebase. Every time someone changes the .env file and commits, on pull the expected behavior of the system changes. Not having a .env file committed to the codebase caused issues with the insufficient handling of environment by our CI process.
So I use .env-local for overriding the environment and one line in the codebase overrides the .env file in case .env-local exists. That way I don't have to care about what's in .env and I won't get surprising behavior upon pulling the repo.
One year later I got around to eliminating the 12 factor violation. One month after that we decided to replatform. -_-
Nowadays with prettier, gofmt and similar, there's almost no languages remaining without high quality, fast formatters which can run on save. So changing from spaces to tabs should be as simple as updating to tabs:true in prettier config.
Which is half of why this is an insoluble problem. There's no solution that doesn't impose some workflow or wetware overhead on introduction.
Installing "Tabs for indentation, spaces for alignment" on wetware is probably the best solution in terms of maximizing utility for minimized development/workflow costs. But even that is going present a wetware tax for some developers, and it's not superior in terms of utility to the article's proposal.
We don't know that there's no solution. One of your siblings suggested having the editor just use space alignment. I can't see any reason why that wouldn't work either and was the idea I had in mind.
But installing ideas onto wetware is perhaps the most expensive thing that can ever be considered. Because it often involves fighting a war.
We've got a git hook that prettifies and runs unit tests on commit. Works very nicely. Formatting is one flame war, another is code style. We've automated that too with sticking to airbnb. If there are any warning a commit does not pass.
For compatibility, it's feasible to represent elastic tabs with spaces. All we care about is the new behavior. The editor can parse for aligned columns.
Unless I'm missing something it doesn't solve the main issue with tabs vs. space which is that most people and editors don't do it right, that is indent with tabs and align with spaces. How does Elastic TabStops deal with that? For instance in code like:
int main() {
printf("%s, %s, %d",
somevariable,
somefunction(),
42);
}
Because beyond that I personally (and very subjectively) consider that adding comments on the same line as the code is usually a bad idea when you can put them on the previous line and it's both better suited to long comments and easier to match the comment with the line. In the example from the gif in the article consider the distance between the `x();` code and the matching comment all the way to the right. Putting it on the line before would make more sense IMO. Most decent code editors will also be able to wrap the comment more easily that way. That being said I'm anal about enforcing 80 columns in my code so maybe I'm just a weirdo.
Why not always do this? Once you stop using column alignment/align with opening delimiter, and use hanging indent, these issues go away:
int someLongFunctionNameThatWillBeRefactored(int foo,
int bar);
someLongFunctionNameThatWillBeRefactored(longVariableName1,
longVariableName2);
and do
int someLongFunctionNameThatWillBeRefactored(
int foo,
int bar);
someLongFunctionNameThatWillBeRefactored(
longVariableName1,
longVariableName2);
or even
int someLongFunctionNameThatWillBeRefactored(
int foo, int bar);
Now tabs work fine. Spaces work fine. Elastic TabStops? Ironic that he mentions "Keep it simple, stupid!" and then overengineers this thing and every editor along the way.
Anyway, this will probably not go down well since everybody has been trained to use the former style, and now people "prefer" it, out of what seems to me to be habit.
I don't think scare quotes are warranted, I do prefer the former style, I find that it makes it easier to match the arguments to the function at a glance. Of course it's purely subjective.
I do note that even your proposition doesn't really solve the problem of using Elastic TabStops, because if you imagine a comment spanning all three lines:
someLongFunctionCall(⇥ /* This function call */
⇥ longVariableName1,⇥ /* is really cool *
⇥ longVariableName2);⇥ /* and stuff */
You have an additional tab at the beginning of the two last lines which means (as far as I understand it) that the first comment line won't necessarily line up with the two others. Of course that showcases a potential issue with Elastic TabStops, not your particular coding style.
Block comments interleaved with code are rare in most codebases I've worked on, because it's almost always easier to put them on their own lines, above the statement:
/* This function call is really cool and stuff */
someLongFunctionNameThatWillBeRefactored(
longVariableName1,
longVariableName2);
So I sort of dismissed that use-case as a toy example. But yes, if you did that elastic tabstops would be useful... except the contents of the block comment doesn't get reflowed when the tabstop width changes. Which I'm sure we could do, but then we're getting into interesting territory w.r.t edge cases/usability for sure.
One (extremely minor) advantage of putting the closing paren on the next line (in languages that allow trailing commas, like Python) is that when adding or deleting an argument, the diff only touches that one line (you never have to move the paren)
Because at least for me, the closing paren pulls my mind back to the correct indentation after the end of the block. Without it, I typically do a quick side-to-side and top-to-bottom scan to ensure the next block is at the level I'm expecting.
Python is especially bad for me here, despite having used it everyday for years, because "if" and "while" and etc don't even have those closing markers.
That's my preference, as well. My rationale is that you should pick one or the other: indentation can entirely eschew dangling closing brackets as in LISP, or closing brackets always track nesting. Otherwise it looks asymmetric and ugly.
The idea seems to be: add a tab between printf( and "%s in order to get a result that looks like your example.
Elastic tabstops are great for making table like code, not just for aligning comments. But for me, the cons outweighs the pros. The biggest problem is that it requires a specific interpretation of the tab character that is uncommon and nonstandard.
Oh that's quite clever actually. But I agree, overall it seems like an interesting idea but it's not good enough to warrant modifying and/or replacing all existing tools who deal with displaying and editing code.
Not about to participate in any side of this flame war. I just wanted to point out how nice the presentation is on this site. And the whole site is less than 1MB!
Most languages don't have ASTs that work well in "degenerate" cases like unfinished/work in progress/sample code. These are things you often want to have in source control. There are also very few AST standards between languages making for a lot more language-dependent work for an SCM.
(For what it is worth, I toyed with what I think to be a useful compromise to the idea, which is to use syntax highlighting tokenizers, which perform well and interoperate well with character-based diffs: https://github.com/WorldMaker/tokdiff)
I agree that degenerate cases are one of the major problems with trying to move to higher-level editing abstractions (and it's one of the big issues I faced with my own application), but I don't see how it's a problem here.
If it doesn't have a valid AST, then it's not a valid program, either. If you're using a formatting program (like prettier or gofmt) and pass it an invalid program, you're either going to get an error, or undefined behavior. And anyone else opening it in a different editor is going to have their language-mode interpret the invalid program differently than yours, too. Source code tools like structured search won't work predictably, either.
This sounds to me like saying "An XML structure editor? But what if I want to put an invalid XML structure in a file called foo.xml and commit it to the repository?" Or my first boss complaining that visual text editors didn't let you see every byte. Or Mel needing to know drum addresses so he could use them for constants.
As time goes by, we move to higher level abstractions, and (thanks to tools like gofmt) we're already at the point where you probably shouldn't be pushing source code which doesn't even have a valid AST, and expect all your tools to work perfectly. There's plenty of ways to write and commit WIP code without needing an invalid AST on disk.
I thought similarly for many years. What's the use of code in source control that doesn't compile anyway?
Then I started paying attention to all the reasons why we naturally might want to check in "invalid" code.
All the cases where I'm never going to finish an entire refactor in a single commit, and the whole refactor makes far more sense in documented steps where many of the intermediate steps will never compile.
All the cases where sending broken code to a source control server at the end of the day is both the best way to back it up and the easiest way to get fresh eyeballs on it in the morning. Even with CI systems in place, sometimes the errors that the CI bot can tell you are as useful as the ones your own machine's build environment can tell you. (Especially in those weird cases where it turns out to be that maybe its the build environment on your own machine that's the problem and you've been beating yourself up over a bad install of something that should be unrelated, and the build errors on the remote machine lead you to the real problem.)
All the cases where I might build tests first, and the compiler is a test, especially in a static typed language, before working backwards to make the tests pass/run/compile.
A lot of people like to think of programming code as some purely logical construct, but good code is poetry, even in its mistakes. Sometimes we need drafts to tell our stories right. Sometimes we need bad poetry in source control as a warning to others to help them realize what good poetry can be.
It's interesting to want code editors to keep us from ever writing bad poetry to disk, but it's also somewhat inhumane. People write bad poetry all the time, it's a natural skill. Saving bad poetry for posterity is sometimes the only way we get better poetry.
I once saw a phd thesis that argued that the best way to go was to use AST diffing at the top level (classes, method definitions, etc) but line-based diffing for the inner parts (method bodies, etc).
Small textual changes can lead to large changes in the AST, which results in confusing diffs. Merging is also non-trivial.
On the other hand, for top level structures following the AST keeps things saner.
It's also similar to the thought path that lead me to trying a Tokenizer for diffs. The tool as is essentially gives you character-based diffing everywhere which keeps the inner parts sane/mergeable.
One of the things that I never got around to doing was exploring the higher-level opportunities, but they are there. Just as the tokenizer is the first pass in AST building, tokenized diffs should contain enough information that if you wanted to try to do higher level diff analysis you could do some interesting things.
Storing the AST works for a class of problems, namely whitespace issues, but a refactoring as simple as renaming a token still makes merges a mess. (And if you store a whitespace / comment decorated AST, you can still have a messy merge.)
That said, you could address that and other issues, you're just working with something several steps removed from an AST. Or you could call an AST the 90% solution.
And how do you decide, given two versions of a source file, if the token was renamed or it was a new one?
This looks "trivial" for trivial cases, but I can imagine lots of difficult corner cases there. Depending on how you define what constitutes a "rename", this may even be undecidable.
Actually, even basic AST-aware diffing algorithm would be a nice thing. I write a lot of Lisp code - Lisp source is, quite literally, AST serialized to text - and regular diffs in SCMs are really annoying. Like, I remove some AST node in the middle, and git diff will think most of the function changed, just because indentation shifted a bit.
Only for a tiny, tiny portion of what constitutes a coding style (indentation depth) and only if the original code used tabs for indentation and spaces everywhere else consistently otherwise everything looks like crap when you change the tab width. In my experience most tab-indented projects end up mandating a tab width in their coding style and using anything else leads to chaos. See the Linux kernel for example. Besides if you really value this flexible tab width you can no longer impose a maximum line length since it's tab-dependent.
Beyond that it's quite weird to make tab width configurable but nothing else. What if I prefer to have opening { on the same line as the function prototype? What if I prefer my identifiers to be in CamelCase? What if I prefer not having spaces around arithmetic operators? All that could be done relatively easily if code was stored as an abstract AST and formatted on demand.
Tab indentation is theoretically superior to spaces if used correctly but in practice it's probably not worth the trouble. At least as far as I'm concerned I gave up on tabs a long time ago.
It's less ridiculous than fighting over this stuff in code review.
It's usually teams or projects agreeing on a coding standard, and those standards dictate everything other trivial detail. As a developer, you are an author, and you're writing with a "voice." On a team, it's a courtesy to the reader to write with the team's voice rather than your own.
Doesn't work as well in languages where indentation is significant. But even in languages where indentation is insignificant you'll run into issues doing things like line splitting.
Doesn't work as well in languages where indentation is significant.
The point is that the code on disk needs to work when it's compiled. That's all. You could write an editor that displays the code in a circle so long as it writes properly indented code when you save. Nothing about the IDE is actually important.
FWIW Black ( https://github.com/ambv/black ) is a disciplined Python formatter that's reasonably successful, so I'm not convinced that the "significant indentation" thing actually matters too much; it probably just means that formatters need to be more careful to not introduce bugs, but the same principle of code -> AST -> code seems just as valid.
What line splitting issues are you referring to? I've been pretty happy with the approach used by Prettier (and I believe Black) of fitting it on one line if possible, and doing one per line otherwise. I'd say that's my favorite part of Prettier: I don't need to think about wrapping anymore, it figures it out, so it's sad to see that gofmt doesn't do that (from my testing just now).
I think you're only considering a one-way transform, what's being proposed above is two-way. i.e. Store the output of Black as the 'canonical' version, but translate it back into your preferred style when looking at the code in your editor.
> but the same principle of code -> AST -> code seems just as valid
The question is really the reversibility of the transform in a reasonable way. If you are translating all your source to an AST there is technically no reason multiple programmers even need to be working in the same language. However in practice, even within a single language, there are many possible transforms from an AST back into code. Some will make sense, some will be nearly indecipherable. In practice you either limit the allowed transforms such that there is little benefit over a simple linting tool or the problem explodes in complexity.
> Doesn't work as well in languages where indentation is significant.
Store the bytecode, indents and dedents are present as <indent> and <dedent> token which are no different than e.g. <brace, open> and <brace, closed>.
Well technically those are in the tokeniser, the AST or bytecode would reify the structures they delimit, and if you stored the AST or bytecode the separator would be reified from there.
But the point is that for the machine indentation is no different than any other token (in fact Haskell is defined using braces and semi-colons, the common indentation-based version is an augmentation of the base language which semantically just inserts braces and semicolons)
The typesetting is used to convey information though. I use indentation to convey information about connected concepts. The indentation of my in code comments conveys how important they are and whether we're at the start of a new paragraph.
Im more explicit than most but everyone does this to some degree. The most basic example is indenting code blocks.
Generally I find it harder to debug auto formatted code. I lose information of who the author(s) were and it makes it harder to see where breaks in ideas can happen.
Back when I was in Excel every section had its own style and unwritten rules - inevitable with 30 year software. Once the code is auto formatted all information about those unwritten rules is lost.
Good point; some meaningful typesetting may be lost. Then again, if such a system were used, programmers would avoid writing code that made significant use of non-syntactically-relevant aspects of code. Furthermore, it might influence language designers to make documentation part of the language syntax.
its not really documentation per se. It's flaws programmers are prone to. Everyone has their own set. Knowing the author in an abstract sense speeds up the process.
isn't it currently the case? colors and style are not saved in the code, but are applied by the syntax highlighting when displayed.. the display of elastic tabs could probably fit in there somewhere.
Not if you make documentation part of the syntax (which is often sort-of the case today to make it easier to generate doc from code). It would force you to fix the documentation format though, but that wouldn't necessarily be a bad thing.
There are tools to take a well defined format and generate pretty documentation from code. What happens in real life is that people write the bare minimum that describes the interface for the function, but not how it works or how to use it beyond a few words. And then you end up with very pretty autogenerated docs that don't help you at all.
Okay but that's kind of a different problem isn't it? If people can't be bothered to comment their code properly I doubt they're going to write high quality LaTeX documentation on the side.
I find that Rust deals with that mostly well, the doc format is part of the language, the documentation generation part of the toolchain. You can even validate example code from the comments. You can enable warnings for missing documentation on methods. In my experience documentation for Rust crate is generally at least okay-ish, it generally saves me a trip into the code itself. That being said Rust prototypes are also a lot more expressive than their C counterparts (no questions about "should I free that pointer?") so that probably helps as well.
My point is that the harder you make it for people to comment their code, the less useful comments you'll get. Freeform text (where you can even whip up a ghetto table or graph with a fixed size font in a few minutes) gives you the best chance of meaningful comments.
I'm not convinced, I don't find the Rust format particularly hard to grok, it's Markdown so it looks mostly fine when viewed as plaintext. A Markdown table is pretty ghetto but on top of that it'll display nicely in the generated HTML. Also if you really want to do ascii art you can always use ``` to escape everything: https://github.com/simias/pars/blob/ce820b5af0be3091d47104cf...
I guess it does add a little bit of friction but if somebody tells me they don't write docstrings because they don't want to bother with the Markdown syntax I'd reply I'm going to assume that they're just looking for excuses at this point.
Seems to me text would not be an issue at all, examples might be. And you could integrate the documentation format with the language itself such that code examples in the host language can be recognised and properly formatted by the editor or renderer.
Alas it seems much like A.I., flying cars, and human immortality, reconciling tabs vs spaces is one of those technological dreams that must remain a dream.
Like the debate of creation vs evolution, or vi vs emacs, or which color to pain the bike shed, these problems are unfortunately too complicated for a human to ever pretend solving
Specifically, the space there after ( . Syntax-aware editors already handle this formatting situation fine.
The remaining use case for this elastic business is aligning reams of comments on the right side.
The best solution solution is not to write those. They are never needed in code, but sometimes they can be beneficial in data structure declarations.
The elastic effect shown can be a achieved without tabs. The text editor simply recognizes that multiple lines have aligned comments, and maintains that with spaces. However, that still leaves the version problem/infelicity that semantic changes to one line trigger surrounding whitespace changes.
The best solution is to leave enough space for the longest declaration you would ever use. Anything longer is then split into multiple lines.
struct foo {
int magic; /* magic number */
int x, y; /* coordinates in bar space */
void (*sudden_big_decl)(struct foo *, /* Phew, That was close! */
int, int, /* Good thing we left all that room. */
double);
};
The tabs vs. spaces debate has to be one of the biggest wastes of time in all of programming. Not to be uncivil but it's a bit depressing to see human creativity lavished on it once again.
One of the first things I do when starting a new project is to adopt a code formatting standard enforced by automated tools like Eclipse formatting for Java or Pep8 for Python, then move on. I really don't care what the format is as long as it's consistent and readable, hence usually let the team decide in return for adhering to the choice. And I've stopped working with teams that cannot get past obsession over tabs vs. spaces. It's a warning signal that there's an unhealthy lack of focus on things that really matter to users like clean interfaces.
this page shows up here about once a year. "This page was first uploaded on 2006-07-02 and last updated on 2017-11-18." afaik there are a couple of plugins for various IDEs, but (as oftenwrong said) go's semi-forced autoformatter seems to be the more practical/successful solution.
We're using Prettier for formatting our JavaScript and I totally agree with you that the right answer here is to "stop thinking about formatting" and just let the tools deal with it.
Dupes with comments aren’t always dupes, it turns out. I hadn’t seen this before, so I’m glad there were comments on it to keep it from being duped! Thanks for saying something.
Well, you still have to install lots of things: a source code editor, a way to download the code, a compiler to compiler it, libraries it needs to run, etc.
Having to install software or set a tab-stop correctly would be just one of those things.
Gedit, the one program I have used in the past, in the small list of set a tab-stop correctly programs:
My original Gedit plugin (no longer compatible with Gedit's changed API)
This seems broken, not because it's not a good idea. A lot of things that I don't use and don't want are already installed (and somewhat broken.) If I use the 'cat' command on a source code file formatted this way, how is that going to work? A new shell or new Terminal program that will set a tab-stop correctly, or a set a tab-stop correctly plug-in for bash or the Terminal program? The default eight spaces in the shell for tabs isn't very pretty, so maybe you're onto something.
As I mostly blindly click "Install", libraries that had vulnerabilities are updated or maybe newly installed. I didn't ask for these libraries, I try to remove them and the package manager reports that they are not installed. I guess I've got bigger problems to deal with, and will bump along using tabs and/or spaces. There must be a better way.
So you want each of the maintainers of every text editor, text processing tool (e.g. diff, grep, sed, awk, git, etc.), IDE, and web app (gitlab, github, etc) to implement this standard? You’re going to be waiting a long time...
I wasn't going to jump into this because arguing tabs vs spaces feels like a parody at this point, but I think you're correct.
I started using spaces for indentation just because I worked with people who did that. I kind of forgot I was even doing it because vim's auto-indent did a lot of the work, but after some time I realized spaces don't make sense.
The familiar arguments for tabs:
* Clean mapping between the concept of scope depth to a single character
* Configurable display of indentation width, everyone can see what they want
Tabs have problems only when people use them for alignment, which breaks when tabwidth is changed.
Actually can someone try to change my mind? I know tabs-vs-spaces is an eternal war, yet I feel the problem is completely solved, hence I must be ignorant of the counter arguments.
(The only thing more logical than using tabs might be using no whitespace at all and having the editor determine presentation. But that wouldn't work well with line-oriented tools.)
It's only even a problem if tabs and spaces are mixed; if EVERY level of indent were denoted by a tab then it wouldn't really matter if the default editor width were 2, 4, or 8 or any other number as it would still be consistent in that editor.
Spaces are only used for alignment at the very end, so the alignment should be consistent even when tab sizes are different because the base alignment, which is done with tabs, is the only thing that changes.
If you're trying to align text, then even 2 would fail when the thing you're trying to align with is an odd number of characters (name of a method, etc).
Absolute alignment and level of indent dependent code are two separate tasks.
The former is a pre-formatted fixed-width character document that can only be viewed one way.
The latter is a document which is easily processed; editors should show the intended logical representation of the information according to user preferences for conveying such meanings (though for terminal compatibility they often default to either 8 or 4 fixed width spaces in less powerful editors; still the meaning is conveyed clearly).
What I like about this is that this would end up all fights about how to display tables with raw text formatting... just use tabs to delimit table values...
Here's a crazy idea I just had. What if there were multiple kinds of tab characters so that you could encode your intent more explicitly? i.e. a "one level of indent" tab, an "align with with the first instance of this character on preceding line" tab, "indent to one more level than previous" tab, "indent to one less level than previous" tabl, etc.
I like this idea. I feel like today’s landscape may be making it somewhat irrelevant, everyone seems to be moving to automated lint-formatting, but I might have to try this.
Having written a code auto-alignment tool, I like the idea of elastic tabstops because it makes the alignment explicit. Thinking of it as a grid and having an explicit separator between columns would be nice, it gives me control over what gets aligned. Auto alignment is tricky and always has corner cases as well as missing features, things you wish it would align but it doesn’t.
I don’t buy the argument mentioned several times here that elastic tab stops have to degrade gracefully; tabs already don’t do that. From my point of view, one of the larger downsides is it wouldn’t help with situations that call for right-align, e.g. numbers. And since formatting requires look ahead, I’m curious if the command line tool (“etst”) is enough to make command line workflows good, e.g., ssh, grep, sed, perl, etc.
The only way this gets adopted is if it degrades gracefully to existing editors and tooling.
This only works, obviously, with a well-behaved whitespace model: pure spaces or 8-spaced tabs.
I can see a few ways to do this:
1. The editor deduces elastic tabs by observing where text lines up.
2. Augment #1 with knowledge of the lexical structure (same complexity as a syntax highlighter) to deduce where it ought to line up.
3. Use invisible characters to identify tab-stops. (Repurpose vertical tab, maybe? Or a zero-width char?)
4. Use an external file to store tab-stops. (At which point you can name your tab stops.)
5. A 'prettifier' utility can use parsing knowledge to generate 3 or 4.
Neat! I'm interested in visual programming languages, the semi-textual intermediaries like forced indentation in Python and frame-based editing [1] are fascinating, so I'm surprised I'd never heard of this. The first issue I see is there are some styles and languages where things are more naturally right-aligned within their "cells" (e.g. alignment against the left side of a column of :s), which starts to complicate things.
Yeah. Their UX in Microsoft Word is a bit PITA, and it took me much longer than I'm willing to admit before I understood how they're supposed to work, but themselves they're a really good idea.
I didn't make the connection with aligning source code before - but mostly because "source code" is in the "plaintext" bucket in my head, as opposed to "rich formats" - that is, I expect to read and edit streams of bytes, the way they're saved in memory, with no invisible, hidden metadata that could get silently corrupted. While the word processor style tabs seem brilliant, I have mixed feelings here, as I wouldn't want source code to stop being raw plaintext.
Like a lot of things for this kind of software it required both culture (tab stops were a legacy from physical typewriter) and RTFM to understand how Microsoft designed the ergonomics under Word. As a noob I need only a simplified version of it (static tabs) and the full fledged caused a lot of reflex behavior from Word that threw me off. Not helped by the fact that word tables (another alignment trick) was random as ..
Due to the way vim was written, it’s been an incredible pita trying to get support for elastic tabs going there. It’s funny: it’s easier to code elastic tabs for dozens of closed source IDEs and editors with only basic plugin functionality than it is to add it to the most hacked editor of all time.
(On phone. Will link GitHub PR when I’m on a desktop and can use the internet with proficiency somewhat greater than that of a caveman.)
> It's not hard to imagine new conventions evolving in a new environment where proportional fonts are possible and text always stays lined up properly.
This is only one of the reasons why I use a proportional font. The other, and arguably more important reason, is that monospaced fonts make it easier to see if I've made a mistake in repetitive code because it acts like a visual "checksum" of the line.
We prefer spaces over tabs because the ident style requires it.
Anyway, the solution is simple: agree on one style and stick with it. Code is made to be read many times more than it's modified (open close, you know), therefore one shouldn't read a code line more than once to understand it.
It's your job to deal with the company style and adopt, otherwise you're not professional.
In the times of standard code formatters for every language, isn't this just a display problem?
For JavaScript, you could simply force the code to be saved as prettier formatted without any config.
If you display it, however, you can let your editor apply whatever format you like. So you would have one source of truth in the repo and whatever you like in your editor.
monospaced typefaces are "real", and I would hate to live in a world where someone thought it was a good idea to write software, represented in columns and lines, in anything other than monospaced font
I've always assumed the obsession with monospaced fonts in coding comes from terminals, which are monospaced for traditional reasons.
I code in non-monospsaced fonts sometimes. I enjoy it. There are (for me) basically no downsides except occasional other coders wanting things "lined up" vertically, which I don't care about but enforce using a code formatter.
It would be great if the terminal did this, so tab-separated value would "just work" and commands with tabular output (ls, ps) wouldn't need to worry about alignment at all.
There were N different ways to handle tabs, and now there are N+1 ways. The solution to the problem isn't to add more ways to implement tabs but to reduce the number of ways to implement tabs.
My conviction from personal experience is that your personal tools need to be adaptable to fit any organization. This splits largely along tech stack culture lines. Our shop was originally Ruby before we started moving to NodeJS, we all use spaces for indentation.
So unless I want to force my whole team to start using tabs, I can't use elastic tabstops.
This isn't a viable improvement until it can accommodate the existing state of affairs. The other obstacle in the way is code linters. I have to make a case to turn off linter rules at my shop and if the only objection I have is that it makes a workflow I haven't even tried yet difficult to implement, it's not going to be taken seriously if it requires work from the whole team.
The way I usually accomplish workflow improvement objectives is to find a way to accommodate both my needs and the status quo while thinking deeply about the underlying context creating the obstacle.
Environment managers get gnarly when you have to commit .env files to the codebase. Every time someone changes the .env file and commits, on pull the expected behavior of the system changes. Not having a .env file committed to the codebase caused issues with the insufficient handling of environment by our CI process.
So I use .env-local for overriding the environment and one line in the codebase overrides the .env file in case .env-local exists. That way I don't have to care about what's in .env and I won't get surprising behavior upon pulling the repo.
One year later I got around to eliminating the 12 factor violation. One month after that we decided to replatform. -_-