Threads for carlmjohnson

    1. 9

      Lots of “jokes” here but read the Aaronson piece if you haven’t, it’s fun and informative.


        Thanks for the tip, that was a charming piece of writing.

    2. 18

      Is this an argument? Mobile editing is dog shit. It’s just awful top to bottom. I can’t believe we’re 15 years into iOS, and they still don’t have frigging arrow keys let alone actually useable text editing. Almost daily, I try to edit a URL in the mobile Safari and I mutter that every UX engineer at Apple should be fired.

      1. 9

        You know the UX engineers on the Safari team would just love to not have to expose the URL at all…

        1. 9

          I don’t really know why you’re singling out Safari, when Google/Chrome have a long history of actually trying to get rid of displaying URLs. And it’s been driven not by “UX engineers”, but primarily by their security team.

          For example:

          (and to be perfectly honest, they’re right that URLs are an awful and confusing abstraction which cause tons of issues, including security problems, and that it would be nice to replace them… the problem is that none of the potential replacements are good enough to fill in)

        2. 5

          Shrug! Android Play Store, the app, does this. Terrifying! It breaks the chain of trust: Reputable app makers link to an url (thankfully, it’s still a website), but you have to use the app anyway to install anything, which has nowhere to paste the url, let alone see it, so you can’t see if you are installing the legit thing or not. Other than trust their search ranking, the best you can do is compare the content by eye with the website (which doesn’t actually look the same).


            I’m reluctant to install third-party apps in general, but, when I do, preserving a chain of trust seems possible for me: if I click a link to, say, on Android, it opens in the Play Store app; and, if I open such a URL in a Web browser (and I’m signed in to Google), there’s a button to have my Android device install the app. Does either of those work for you?


              Wow! That did not work in Firefox just one month ago (when I had to install Ruter on my new phone). Now it does. I tried Vivaldi too, and it doesn’t even ask whether I want to open it in Google Play.

              Browser devs to the rescue, I guess, but as long as the app isn’t doing their part – linking to the website – the trust only goes one way.

      2. 8

        The upside: it reduces the amount of time you want to use your phone, which, for most people, is a good thing.


          Does it though? I mean, you’ll spend much longer fiddling to get the text right!

          If you think “oh this’ll just be a quick reply” and then end up actually typing more than you thought you would, it makes sense to finish the job you started on mobile, which then actually takes more time. Especially when you’re on the go and you have no laptop with you.

      3. 6

        I don’t miss arrow keys with iOS Trackpad Mode[1]. The regular text selection method is crap, but it works well enough doing it via Trackpad Mode.

        I think part of the problem with the iOS Safari URL bar is that Apple tries to be “smart” and modifies the autocorrect behavior while editing the URL, which in my case, ends up backfiring a whole lot. There’s no option to shut it off, though.


          Wow, I had no idea this existed! Apple’s iOS discoverability is atrocious.


            Apple’s iOS discoverability is atrocious

            Agreed. Just the other day I found the on screen keyboard on my iPad was floating and I couldn’t figure out how to make it full size again without closing the app. A few days later I had the thought to try to “zoom” out on the keyboard with two fingers and it snapped back into place!

            As someone more comfortable with a keyboard and mouse, I often look for a button or menu. When I step back and think about how something might be designed touch first, the iOS UX often makes sense. I just wish I had fewer “how did I not know that before!” moments.


          The other problem I encounter near daily is not being about to edit the title of a Lobsters post on the phone. It really sucks.


            The far more frustrating thing on is that the Apple on-screen keyboard has no back-tick button. On a ‘pro’ device (iPad Pro), they have an emoji button but not the thing I need for editing Markdown. I end up having to copy and paste it from the ‘Markdown formatting available’ link. I wish would detect iOS clients and add a button to insert a backtick into the comment field next to the {post,preview,cancel} set.


              Long-press on the single-quote key and you should get a popup with grave, acute etc accents. I use the grave accent (the one on the far left) for the backtick character.

              Edit testing if this actually works. It does!


                Thank you! As someone else pointed out in this thread, iOS is not great for discovery. I tried searching the web for this and all of the advice I found involved copying and pasting.


                  This is a general mechanism used to (among other things) input non english letters:


                    Oddly enough, I knew about it for entering non-English letters and have used it to enter accents. It never occurred to me that backtick would be hidden under single quote.


              You can make a backtick by holding down on single quote until backtick pops up, but it’s pretty slow going.


          This seems super useful, but I’ve spent the last ten minutes trying to get it to

          1. Enter selection mode using 3D touch
          2. Get the trackpad to not start jittering upward or downwards

          It seems either that my phone’s touchscreen is old and inaccurate or I am just really dang bad at using these “newfangled” features.

          I agree with your other reply - discoverability is atrocious. I learned that you can double/triple tap the back of your phone to engage an option which blew my mind. I wonder what I’m missing out on by not ever using 3D touch…

      4. 5

        Samesies. The funniest bit, at least for me, is that I’m usually just trying to remove levels of the path, or just get back to the raw domain (usually because autocomplete is bizarre sometimes). This would be SUCH an easy affordance to provide since URLs already have structure built-in!


        I find the trick of pressing down on spacebar to move the cursor works pretty well.


          It’s okay but it’s still not as good as digital input for precision.


        The problem is that Apple phones don’t have buttons.


          No phones do anymore, it seems…


            Arthur C Clarke predicted this in The City And The Stars. In its insanely-far-future society there is a dictum that “no machine shall have any moving parts.”


        It’s hidden, but… tap url bar, then hold down space and move cursor to where you want to edit. Now normal actions work ( e.g. double tap to select a word).

        That said I agree with your second sentence.


          The trackpad mode works very poorly on the iPhone SE because you can’t move down since there’s no buffer under the space key, unlike the newer phone types. It doesn’t work well for URLs because the text goes off screen to the right, and it moves very slowly. Ironically I’m on an iPad and I just tried to insert “well” into the last sentence and the trackpad mode put the cursor into the wrong place just as I released my tap. It just sucks. This is not a viable text editing method.

    3. 40

      In a large part because, at GitHub’s size, I worry much less about private equity enshittifying it.

      I would argue that the little ad for Copilot that now appears on GitHub file pages is the first step of the enshittification cycle. “We need to maximize engagement with Copilot. How do we do it? Oh, I know, we can add a CTA to the content pages…” is the first step on the road to ruin. Hell, the whole homepage is just another social media feed at this point.

      1. 12

        Hell, the whole homepage is just another social media feed at this point.

        Yeah, this has driven me nuts – I was a regular user of the homepage to track relevant activity (people I follow, people doing things to my own repos), and the new feed design has more or less taken that away.

      2. 9

        Reminds me of how the windows widgets have a news feed you can’t disable, and they recently updated it to show fewer widgets and more of the news feed.

      3. 8

        Self-plug: I’m maintaining a filter list to hide Microsoft GitHub’s UI garbage if you’d like it to be less shitty.


        I don’t know how or why this exists, but a slightly wonky variant of the old linear feed can be viewed at

    4. 14

      Debugging like I’m 15 again

      Lol, perfect description of how every new workflow file gets created.


      Why make the comparison if you recommend TOML for the things YAML is usually used for?


        It’s a little bit apples and oranges, but the thinking is something like

        • They are both file formats that people complain about
        • They both have serious problems with implementation security
        • They both are sometimes used for config files
        • Neither is a good choice for a config file
        • Neither is a good choice for an RPC API, which people did with XML (SOAP) and mostly haven’t done with YAML
        • XML is a good choice for a document format, ie a book or legal markup, and not bad for UI layout, ie JSX and XUL
        • There’s not really usecase where YAML is the best choice

        So adding it all up, but both flawed, but XML is “better” than YAML because it has some pros, whereas YAML is all cons.


          Thanks! Makes a more sense to me now.

          TOML and Nickel look interesting, but it’s an academic matter for me as I’m usually on the receiving end of config file format choices. I will say this, though. If anyone out there is using ESLint and is considering using YAML instead of JSON, I’ve tried this and I can tell you it is not good!

    6. 1

      I’m having trouble understanding the code. How does this work?

              old_value = result[y, x]
              if old_value < 0:
                  new_value = 0
              elif old_value > 255:
                  new_value = 255

      Isn’t the old_value always going to be a between 0 and 255 because it’s a uint8 that is stored in a int16 memory slot?

      1. 2

        Thanks for asking, this is helpful.

        The diffused error gets accumulated in result (in the next few lines of the function). So the first pixel you ever look at will never be negative, but later on the error diffused from previous pixels can push the values above or below 255.

        1. 1
          1. 2

            I will probably for the final version in the book rename result to staging or something and adds some explanatory comments, so thank you again for asking.

    7. 1

      Honestly, it seems like the only people who are complaining about YAML are those that are overusing it, or using tech that overuses it. Every single complaint I’ve heard personally comes from people writing absurd configurations for Ansible or some other devops tech which should have been scripted instead. (Seriously, loops in YAML? Get out of here.)

      This article itself is a complaint about what is likely a floating-point rvalue, which it correctly rounds. Version numbers are strings and not numbers. You wouldn’t expect a scripting language to interpret 1.20 as "1.20", nor should you expect YAML to do so as well. (This assumes you have a basic understanding of YAML parsing.) Last I checked, XML won’t even solve this problem as it’s going to be dependent on your schema.

      1. 3

        I understand that 1.20 != "1.20" is operator error. The thing is on the podcast, my cohost, who likes YAML, laughed because he had the same bug. In this comments section, Simon Willison said he had the same bug. I’m pretty sure I also had the same bug when Python 3.10 came out, although it’s been a while, and maybe I’m misremembering. But I feel like that’s why when the bug hit I figured it out relatively quickly. If you look around, you can find a lot of people experiencing variations of this same bug.

        If operator error is extremely common, maybe the operators aren’t at fault?


          Yep, i’ve had the same bug in TOML too. it’s not a YAML problem, and making me use JSON/XML and wrap every value in redundant quotes, braces and chevrons isn’t going to fix it.


            Really? I thought TOML requires all strings to be quoted, which would make the difference a lot more obvious.


            Perhaps the compounding problem is that the tools that process the Yaml/JSON/TOML/whatever are accepting any data type and coercing to string. This, combined with Yaml autoquoting sometimes working produces a laxness that causes a lot of headaches.

            Ideally, both tools should be stricter: The config syntax you’re using shouldn’t yield strings or numbers depending on how something is written (ie, autoquoting is evil), and the tool that consumes the config document should not be accepting floating-point numbers where a string is expected. Pervasive permissiveness (aka “sloppiness”, but often misinterpreted as “convenience” or even “ergonomics”) is a scourge on our industry.


          YAML is a superset of JSON. If people struggle, they should keep this in mind, and maybe choose to use JSON syntax instead until they learn more YAML. (In the case of numbers/strings, you’ll have the same issue in JSON.)

      1. 1

        I made an endless honeypot once. I don’t think it actually stopped any spammers, but it made me happy.

    8. 21

      I agree with the author, and would summarize it like this.

      XML is a markup language like HTML, and YAML is a data exchange format like JSON.

      Markup languages are good for (surprise) marking up text. You start with text, and then layer structure and annotations on top of it with markup syntax. The markup syntax is verbose because it gives primacy to plain text, which is the default and requires no ceremony apart from escaping a few characters.

      Markup languages are bad for configuration; data exchange languages are good for configuration. It just so happens that YAML is a bad data exchange format. It has many human-friendly do-what-I-mean features but they backfire when you actually mean something else (e.g. NO for Norway, not false).

      1. 15

        How dare you RTFA and summarize it better than I made it. I am deeply offended by this breach of commenting etiquette. 😉

        1. 1

          A little off topic, but: I think your site sets the main text content’s foreground color (something dark), but neglects to set its background color, letting my browser’s personal fallback settings for unspecified styles take over.

          For unstyled sites, I have my fallback colors set to light-on-dark, so this half-enforced styling comes out as dark-on-dark.

          1. 2

            I’m just a guest blogger, but I’ll pass it along.

      2. 5

        Markup languages are bad for configuration; data exchange languages are good for configuration

        Mostly agree, but I would go further and say

        • XML/HTML are for documents, JSON is for records / “objects”, and CSV / TSV are for tables.

        However, JSON is a pretty good data exchange language, but it’s not good for configuration because the syntax it too fiddly (comments, quoting, commas)

        YAML is definitely not good for data exchange, and it has big flaws as a config language, but there’s no doubt that many people use it successfully as a config language.

        So config languages != interchange formats in my mind. Interchange formats are mostly for two programs to communicate (although being plain text helps humans too, so it’s a bit fuzzy.)

        The space of config languages is very large, AND it blends into programming languages. Whereas JSON is clearly not a programming language (though it was derived from one)

        1. 3

          Yeah that makes sense, config language deserves its own category. I guess I’d say I prefer JSON over XML if those are your only two options (and I find it works well enough in VS Code for example, though they allow comments and trailing commas I think).

      3. 3

        I think YAML is not suitable for data exchange, because of its complexity and shaky security record. Better to stick to JSON if you need text, or CBOR or protobufs etc. if you prefer binary. Good data exchange languages are bad config languages.

        YAML is barely tolerable as a data input or configuration language, but there are better options such as json5. TOML is ugly and confusing but still better than YAML.

        1. 3

          I wish more things would adopt UCL for configuration. Like YAML, it is a representation of the JSON object model but it also has a number of features that make it more useful as a configuration language:

          • Macros.
          • Include files.
          • Explicit merging rules for includes (replace objects, add properties to objects).
          • Cryptographic signing of includes, so you can use semi-trusted transports for them.
          • Syntactic sugar for units

            While I like UCL, it can turn into its own kind of hell. rspamd, for instance, is a fantastic piece of software, but the complex mass of includes and macros can make the configuration hard to reason about. Mind you, this isn’t UCL’s fault, just something it enables.


              The macros can be a bit exciting but I like the fact that rspamd doesn’t have any defaults in the program, they’re all visible in the config file directory that’s included with the lowest priority.

    9. 7

      I think these kinds of countermeasures are more pleasurable for the implementor than they are effective, but it is fun.

      1. 3

        It was fun to read, too.

    10. 6

      This rant seems limited to issues of semantic interpretation. However in practice there are many more concerns to weigh. The security track record of XML parsers is much, much worse than the track record of YAML parsers. This is especially true for the most recent versions of each.

      I’m not talking here about application choices of how to use either format. e.g. the famous issues with web frameworks blindly calling into code objects decoded from the format isn’t the fault of the format. I’m talking about the risk you incur simply by passing untrusted input to the parser.

      1. 6

        If you use a real YAML parser, you get the same billion laughs problem as XML. I don’t see much difference in terms of difficulty. YAML has also tags, which no one uses but are basically as bad as namespaces in terms of causing unexpected bugs.

        1. 4

          YAML’s tags have caused some slapstick security failures, but I think most implementations have stopped using them to instantiate application objects by default.

          On the other hand XML still has problems with external entities which can cause hilarious firewall bypasses. And XML’s data model is a really bad match for the usual data structures.

          Really, they are both terrible, and both should be avoided. It’s better to spend time pointing people at actually good alternatives, such as json5.

        2. 3

          Yes, they do have some security concerns in common. Recursive issues in the spec are disappointing on both sides of the ledger. However, a simple review of vulnerabilities for the canonical implementations reveals the difference in how well each format can be practically implemented without introducing vulnerabilities specific to the implementation. XML has been stable for nearly two decades and we’re still suffering from serious vulnerabilities in libxml2.

    11. 10

      Hm what’s the exact example where 1.20 gets interpreted as 1.2? I would have thought if you have quotes it doesn’t do that

      That said, I mostly agree with “there’s always something better than YAML”.

      I divided such languages into 5 categories here, which may help frame discussions / choices: (feel free to add missing languages)

      I’m not sure XML really competes with YAML or JSON though. It doesn’t have data types, and the data model for documents doesn’t conveniently map to struct/array or record/list data types in languages – it maps to the DOM, which is probably not what you want.

      Although I can see XML being used as a test file format – you can have <prog></prog> and <expectedStdout> sections. But most people seem to write their own file formats for there

      I wrote my own, and there was some article about the Go test framework that does that – it’s plain text, not XML (maybe someone remembers the link)

      Main problem with embedding code in XML is that <>& have to be manually escaped, and basically all languages use those chars. I guess you can use CDATA but I can’t remember how to do that …

      1. 11

        The problem is that 1.20.1 doesn’t need quotes, so you don’t think to add it to 1.20.

        1. 18

          I learned this one using GitHub Actions, where my [3.7, 3.8, 3.9] list of a Python versions to try broke when Python 3.10 came out. I had to switch to ["3.7", "3.8", "3.9", "3.10"]

          1. 4

            That example would have bit you in any type-aware config language. :) You’re passing in floating point numbers, not strings.

            1. 14

              This is true, but autoquoting strings encourages the problem. In YAML, 3.10 doesn’t “look” wrong. It looks just like all the things which work correctly. In JSON, it would be more obvious that you were doing the wrong thing because [3.9, 3.10] would “look” wrong. It’s a psychological problem more than anything else.

            2. 8

              This is an argument in favor of properlytyped configuration languages.

        2. 9

          Yeah 1.20.1 not requiring quotes is bad. In my head I call that the “else-whatever” or “else-me-no-care” anti-pattern

          The language author just writes the if statement (“happy path”), and then they don’t care what happens in the else statement

          1. if it looks like 1.20, then it’s a float
          2. if it looks like "1.20", it’s a string
          3. else me no care

          Shell has this all over the place.

          Valid Brace expansion:

          $ echo {foo,bar}


          You can just leave off one char and then things are broken. Now your own source code is data that flows through the system:

          $ echo {foo,

          YSH detects that at parse time, not at runtime:

            echo {foo,
          [ -c flag ]:1: Word has unbalanced { }.  Maybe add a space or quote it like \{

          Although I think we can even stricter, and say not just that {} should be balanced, but that they should always be quoted.

          Same with

          • globs that don’t match anything – you have to opt into nullglob or failglob options to fix that
          • tilde expansion for a user that’s not real
          • history expansion

          YSH addresses all these things

          So then you can use it reliably as a config file format!

          $ cat _tmp/h
          hay define Package
          Package foo {
            version = 1.2.0
          $ bin/ysh _tmp/h
              version = 1.2.0
          '_tmp/h':4: Syntax error in expression (near Id.Expr_DecInt)

          So it has typed data just like Python or JS, and you get a dictionary when it’s valid … This still needs some work (and documentation), but I think it’s better than YAML for sure, and more flexible than JSON.

          And it’s all in your shell, so you don’t have to switch to a new language – it’s all parsed as one language. Most YAML embeds shell these days

          Hay Ain’t YAML -

        3. 2

          Sure, but the way to avoid that is to use a subset of YAML. If you are willing to use the full set of XML capabilities then you run into a lot of similar alternative representation issues and human intuition mistakes. Both formats are usable if you stick to a very restricted subset and neither format is usable in full.

      2. 1

        I’ve suggested this before, but NestedText would be a good addition to your string data category.

    12. 3

      Tsk tsk, we’ve hit a dead end!

      It’s not a total dead end. You can get the output you want by having your Parent struct declare a method that unmarshals into struct{ Child *Child, C *string, D *string }{ &p.Child, &p.C, &p.D }.

    13. 13

      This reminds me of when I was a child learning BASIC. I drew a circle to the screen and thought “so this is it. A perfect circle. Wow. It’s a little blockier than I thought, but it’s on a computer, so it must be perfect, right?”

      1. 7

        I distinctly remember the moment, when I was 12, that I realised that the opposite of such things was true.

        I wrote a BASIC program to repeatedly take the square root of a number, and graph it. Eventually, that result became zero, as opposed to doing what I expected it to do - approach zero. I was deeply confused at the time.

        Edited: I was surprised to find as I aged that some of my most vivid memories of childhood are confusion and discovery. And how many of them relate to computers :)

        1. 8

          For me, it was logo. We were taught to write programs to draw equilateral triangles and squares and told to draw regular polygons with 5, 6, and 7 sides. After a few tries (I was 7 at the time and had only been programming for a few hours), I wrote a program that generated an n-sides regular polygon. I tried it with 500 and it (very slowly!) drew a circle. I knew about pixels, so I knew it wasn’t really a circle, but realised that a circle was an infinity-sided regular polygon, which felt like a major revelation. It wasn’t until I was about double that age that I learned the maths that explains why that’s an interesting conclusion.

        2. 3

          A computer can certainly represent a perfect circle (though it cannot display it). It can also represent the square root of a number, taken as many times as you would like.

          On the flip side of the coin, we can formalise what computers do when they do approximate; the computer is then a perfect or near-perfect rendition of these formalisations.

          1. 4

            Ah, yes. That was almost my first experience with Common Lisp, and it convinced me to persist with learning the system.

            * (/ 3 2)

            That right there is a language doing the right thing ;)

        3. 1

          I was upset when I took a summer class that taught us C and the instructor told us about bit precision. It’s a computer, what do you mean it can’t just store all the bits in 0.1!

      2. 1

        Yeah. As a kid, it took me a while to understand the difference between the discrete world of digital machines and the continuous world of some mathematical concepts. I heard the term “discretization” a lot but I only truly grasped it after I had more programming experience. The instant feedback of modern programming really accelerates learning.

    14. 6

      Yikes, and no CW :P

      1. 1

        What does CW mean in this context?

        1. 5

          Usually it means “content warning.” Maybe the implication is that DHH related projects need to be flagged?

          1. 1

            I’m very confused

    15. 1

      Is there a tool for detecting if this affects you? I don’t write Go, but I imagine that I’d want to immediately apply this to all my code, but also it’s too hard to verify that it won’t cause a subtle yet significant bug somewhere in 30K lines of code.

      1. 5

        The best Go projects use a metalinter to run 100s of various code checks. Mine will fail the test suite if there’s a lint error and I’m guessing the loopclosure lint is in there somewhere.

        1. 2

          golangci-lint has quite a lot of linters. What would be recommended settings for small and mid-size projects?

          1. 2

            Here is the CI workflow I’ve landed on after an enormous amount of trial and error and iteration. In order:

            Notably, and deliberately, no golangci-lint.

      2. 5

        Is there a tool for detecting if this affects you?

        from the article:

        Tools have been written to identify these mistakes, but it is hard to analyze whether references to a variable outlive its iteration or not. These tools must choose between false negatives and false positives. The loopclosure analyzer used by go vet and gopls opts for false negatives, only reporting when it is sure there is a problem but missing others. Other checkers opt for false positives, accusing correct code of being incorrect. We ran an analysis of commits adding x := x lines in open-source Go code, expecting to find bug fixes. Instead we found many unnecessary lines being added, suggesting instead that popular checkers have significant false positive rates, but developers add the lines anyway to keep the checkers happy.

      3. 4

        Yes, it can output a debug line for every place where the code it emits would be different.

      4. 2

        I maintain a daily job at work that builds go from tip and runs all unit tests against the latest go head. Today I added GOEXPERIMENT=loopvar to it, thankfully(?) no tests failed. We did have a host of these capture problems, some bugs, some not really of consequence, at some point that were discovered by the recently added vet lint.

    16. 2

      We included a special case with the same effect in the point releases Go 1.20.8 and Go 1.19.13, so when Go 1.22 is released, code written depending on the new semantics will never be compiled with the old semantics, unless people are using very old, unsupported Go versions.

      Are it not exactly these very old Go versions that need protection from the new semantics?

      1. 14

        I don’t think there’s ever been a promise that old Go tools work forever. Just old Go code.

      2. 7

        When they say very old, it means versions from before the Go version directive was added to go.mod files.

    17. 3
      body {
        min-height: 100vh;

      What’s the purpose of this? The author only says that it “is pretty handy too, especially if you’re gonna be setting decorative elements,” which tells me nothing.

      1. 3

        I wouldn’t want it in a reset because it’s an opinionated choice, but it’s useful for when you have short pages (potentially not a whole screenful) and you want the footer to be at the bottom of the screen without any blank space under it. The alternative is the footer is in the middle of the screen and followed by blank space, which can be ugly.

        Most sites however can fill a screen between just the header and the footer so it’s not always necessary. Also, and this is niche but it comes up a lot in the news industry, if you try to make a seamless iframe, it screws up the page height detection.

        1. 1

          To get a footer stick to the bottom of the body, you need a lot more CSS.

          To me this rule alone is just asking for trouble with unwanted scrollbars (there’s a half dozen different definitions of viewport height depending on toolbars, keyboard, dead areas, etc.)

          1. 1

            To be clear, it’s not for sticky footers, just growing the content area until the footer is at the viewport bottom. But I agree, it’s mostly unnecessary and it can be wrong if you need dvh or whatever instead.

    18. 3

      An atomic change can only affect one service, because there’s no way to make cross-repo commits. In some way, this might be one of the biggest benefits I’ve come across so far, because I know how tempting it is to bunch a couple of unrelated changes into the same commit.

      Hmm, if true then using a monorepo undoes some of the benefit of microservices.

      1. 8

        you’ll probably have different owners for different parts of a monorepo, and those owners all need to approve a commit that touches their portion

        you can make a commit that spans multiple parts of the codebase, but there’s enough bureaucratic friction involved that people tend to do so sparingly

        (it is technically possible, though, which is one of the benefits of having a monorepo)

    19. 8
      *::after {
        box-sizing: border-box;

      This has not been the best practice for like a decade.

      *::after {
         box-sizing: inherit;
      :root { /* or html or body */
         box-sizing: border-box;

      is what you want for things to inherit as expected else you need to override each instance.

      ¿Removing link color by default unless there is a class? So much for accessibility & default styles. Those with poor vision generally appreciate the colors and you have the default color: LinkText. Use that unless you have a serious design reason to mess with the defaults (meaning it shouldn’t be a default).

      I understand the difference between reset vs. normalize, but setting everything to zero & then overriding seems wasteful versus nudging browsers in who are straying from the other back to a default one would expect if no CSS were added by the user. Generally I suggest vendoring if you want a modern normalize …tho its maintenance seems to lead toward abandoned with old, open merge requests.

      Design of the site tho: ::highlight background color being the same as the code blocks means you can’t see what you are selecting. Uses JavaScript for syntax highlighting of static content when you shouldn’t. With blue generally signifying links in body copy, it’s weird being used as inline code element coloring (I would argue most body copy shouldn’t be monospace so it’s clearer to stylistically tell the difference, but devs seem to like it as a stylistic choice for one reason or another). I don’t generally know why the base paragraph size is using clamp() & scales up with the screen size–a bigger viewport does not mean you should try to fill up more of that space & unless you have a good reason, it should almost always be the default 1rem set by the user agent to respect the user’s settings. I can understand some headings getting some different treatment, but don’t mess with the body size as users who need bigger type on a bigger screen probably already adjusted it with an OS or user agent setting.

      1. 2

        ¿Removing link color by default unless there is a class? So much for accessibility & default styles. Those with poor vision generally appreciate the colors and you have the default color: LinkText. Use that unless you have a serious design reason to mess with the defaults (meaning it shouldn’t be a default).

        I disagree pretty strongly with this. Yes, all links should get some color or something to show what they are, but unless you’re talking about a content well (which is its own thing and has its own rules for how to style it), you should be setting that color on a per-component basis. Otherwise you have to jump through crazy hoops when you have some card which can be wrapped in a link and now all the text inside the card is blue and underlined and you’re adding !important to try to reset it to normal.

        If there’s some section of the page where arbitrary rich text is going to be dropped, then you need to mark that as a content well to ensure all the links inside are styled, but you also have to do a lot of other things, like make sure bullet lists will work and whatnot. I think a lot of the disagreements about CSS are from people who only ever style content wells and then they wonder why the rest of us are always banging on about BEM and atomic CSS and whatnot. Content wells are special and the normal rules don’t apply.

        The “does this link have a class tag on it?” rule strikes me as a good compromise: if you’re not styling the link yourself, you get the default style, but once you touch the link, you own it and are responsible for styling it correctly.

        1. 5

          To be clear, I’m not suggesting a { color: LinkText } but rather don’t touch the default color in many cases unless you have a specific design to be follow. I was pointing out that there is a <system-color> value that’s meant to be used for links & link-like things such as { color: LinkText }. In body copy, a lot of folks should be respecting the user agent for a11y or user customization concerns.

          I can see your (and probably the author’s) use case tho now so thanks for explaining–I was locked in thinking about designing blogs. In the context of a blog/text-heavy design then I could see something like .Content a { color: revert } or unset to go back to the defaults in the actual post content but let other supporting UI elements do the inherit color.