The interesting thing here is using several fonts in the same document. They show docstrings, TODO comments, and Copilot suggestions all being different fonts, which is cool and makes sense.
It’s always interesting to see which ligatures are considered important. It’s gotta be based on what appear in the most-used languages, right? Like if TLA+ was more popular there might be a ligature to turn [] into □, and if Prolog was more popular you’d see a :- ligature. So what language inspired ligatures for <~~ and :<? The ..< is for Rust, right?
Ligatures aren’t important. You could argue it breaks intent for ligatures, is riddled with false positives, & confuses readers using your setup (in-person pairing, presentations/demos). If you want a ⇒, then type a ⇒.
I love ligatures for general text, but for code, they break the “what you type is what you see” guarantee. It can be hard to make out the component letters of a ligature. Monaspace/s </ and /> ligatures are especially egregious.
Many of my favorites do. We should fix our languages so you can clearly mean what you mean as we haven’t been beholden to ASCII for a long while. Minus greater than, isn’t an arrow; → is. How am I not supposed to think <= isn’t ⇐ but actually means ≤? It’s a mess that APL had right.
And when a language can’t support, I prefer Vim’s conceals to the representative character over the quagmire of ligature abuse.
I’m pretty sure the Go, Python and JS maintainers would not accept a change to add a bunch of obscure unicode characters you can’t even type on most keyboards as operators. It’s a nice idea but just won’t happen in reality. Ligatures may not be “important” but they’re nice, I like them, not everyone does but I can do what I want with my editor, I can make it yellow comic sans if that helps me read it!
Do you know how many keyboards don’t have a $ despite how many languages rely on it and honestly a lot of symbols not present on many keyboards? It’s an arbitrary line no matter how you slice it for what could or could not be considered keyboard-friendly and ≤ is hardly an “obscure” symbol when almost all of us learned it in math(s) class as ≤ before having approached needing it for progamming.
It’s not arbitrary. You could argue that the extensive use of a symbol only used in some cultures, the $, is a poor choice, but it was used because it was available on the keyboard of the language designers. =>, which I’m not gonna try to use the symbol for as I’m on my phone (and to not undermine my point), is not.
I was in the ligature camp for a little while… Ultimately what is important is that we are all working in the same language if we are working together. If you google around for “Chinese keyboard” you will see the $ right there where you expect (with a great selection of additional characters. If you want to add some more symbols to your programming, might I suggest starting with a few of those before you reach for some APL bs.)
It’s just one more accident of history, like so many others.
With ฿ being the currency I use most regularly, I should invent a programming language that uses it to get it added to every keyboard. Would make my life easier.
Yeah I get that, my keyboard doesn’t my own country’s symbol for currency on it, but I’m willing to bet many more keyboards in the world have a dollar sign on (which I’ve always felt is a weird token to use for languages and tools but that’s another topic)
Point stands, <= is pretty accessible, some obscure symbol isn’t. And I don’t think keyboard manufacturers are going to start adding all the math symbols! We’d end up with an emoji keyboard 😂
Ah, but which arrow do you want? And how do you type it out? Do you need charmap open at all times just to edit code and hope you selected the correct glyph from the “arrow” search?
I wish there was a limit on citations of this article. Are there any others on the internet?
Have you actually experienced in-person sharing and them being confused? I’ve used ligatures for who knows how many years, and I don’t remember someone experiencing that. The common experience is “oh this is cool, how do I get this?”.
Whenever I see people on HN or Lobsters complaining about people liking ligatures, it reminds me of people saying that desire paths are wrong.
I’m happy that ligatures exist and make people happy but I get thrown off when I’m pairing with someone who uses them. In languages I’m proficient in, ligatures conflict with the familiar structures I type. In language I’m unfamiliar with they obscure what I need to type to replicate a result. I spend most of a session like that mentally translating to the byte-representation I expect.
I also find the transition to and from ligatures jarring and distracting when I’m watching someone edit code.
Every presentation/talk I’ve ever went to where the writer didn’t consider the audience always had someone ask about it. Base symbols are the lingua franca.
It’s often cited because it expresses many folks’ thoughts more consicely & from the authority of a typographer.
Getting serious now. Keyboards came from typewriters (d’uh!). If I’m using a typewriter, I can type a ‘<’, then hit backspace and type ‘_’ to get the ‘≤’ symbol. I could even hit the ‘=’ key, backspace, then ‘/’ to get ‘≠’. It’s unclear if the designers of ASCII (back in the 60s) deliberately wanted to emulate this behavior with the definition of BS (backspace, character 8). It’s definition doesn’t state that the previous character be erased, just the cursor moved back one space without erasing. I often think it would be nice if an editor (or system) could do this, and just know I realized that maybe this is what the ‘AltGr’ key (which, being an ignorant American, don’t have on my keyboard) does (even if conceptually).
I can hold < on my phone’s keyboard to get a ≤. The touchscreen keyboards arguably make it even easier to add symbols assuming your keyboard is open source so you can fix the issues in it.
I’ve never used any of the weirder characters that lurk beneath the Option and Shift keys on the Mac, I just know they’re there. Unfortunately every time I need to type °C I’m on another platform.
I use ± fairly often and, if I’m entering anything non-English, the accent-modifier keys (option-i, option u, and so on) are great. I tried typing Étoilé on a Windows keyboard a couple of years ago and was amazed at how hard it is (on Mac, it’s option-e E t o i l option-e e). Oh, and I type dæmon if I’m feeling particularly smug.
Agree that ligatures are awful. I have to get used to it and/or always second guess what the actual characters are that somebody has written on the screen.
I find reading it clearer and easier to skim with conceal on than trying to remember each of these languages specific notions of these ASCII combos (while using the expected, basic math symbols I can use in those languages that do support ≠), the proper Unicode symbol is used so no looong equals or ambiguity issue, there are no false positives, & when working on a line the true input is always displayed (which sometimes helps jog my memory on how language X represent symbol Y.
Usually I’ll disable it for any long pairing sessions.
The dedicated copilont font thing is even cooler than that: they propose leaving code produced by copilot in the different font, so you retain that information after the fact. Font family as metadata. It’s genius!
Hey azeemba! As I read it, they are saying it as “this is a cool thing that becomes possible now”, because they really go out of the way to say “after the fact”:
What if […] you could see which parts of your code it suggested after the fact?
But it is in a section titled “What if” and you are right that it requires collaboration on the part of the code editor, so it’s not coming soon to a terminal near you. But it might be something for GitHub codespaces themselves, or the collaborative editor discussed at https://lobste.rs/s/s4mdxb/github_next_realtime_github .
It’s been about 20 years since I looked, but I seem to recall this being one of the early features of D. I can’t remember if it was RTF or HTML, but the idea was that you’d have rich text for comments and be able to embed images, cross-references, and so on directly in the source files. A lot of D has changed beyond all recognition back then, so they probably gave in to the tyranny of git diff.
It wouldn’t need to; you could easily insert a preprocessor that converts RTF (or whatever) to plain text. (Vaguely similar to Knuth’s “weave” utility for literate programming.)
I’m not necessarily arguing this is a good idea; just a thought experiment.
ligatures in programming fonts i think got more popular with hasklig, then it branched out to other programming languages with unsavory effects. ones that don’t change the look of the original ascii drastically are not terrible, but they are still irritating to the eyes. In other cases they just plainly look nasty and draw attention, which is the opposite of what one wants. They are based on static rules and just guaranteed to be wrong in so many programming languages that it doesn’t make sense to ponder what ligatures are required, and where they are suitable.
Pity that using multiple fonts for different document elements in VSCode is such a kludge. Requires a third party extension that must be re-enabled after every editor update.
You should be able to style them through settings.json, no? I customize token styling and colors with semanticTokenColorCustomizations for example, I thought fontFamily would be supported there, too.
Ruby doesn’t have semantic syntax highlighting so I’m using the editor.tokenColorCustomizations version, but it seems like foreground and fontStyle might be the only css attributes supported.
Using at least something like staticjinja is not going to hurt you. You can keep using plain HTML and only make use of template inheritance and includes to at least move the unimportant parts of the pages away from the content in a way that makes it easy to come back to them and change things without going through multiple files and repeating the edits.
I would personally probably also add a way to use Markdown, because I find writing plain HTML tedious and distracting. Good when I need it’s power, bad when I need to &, " and <strong> constantly. I suffer from ADHD, which means that any accidental complexity will make it easier to procrastinate. Also </strong>.
You can setup your css so <b> can be synonymous with <strong>
Yea, typing & is annoying, I suggest typing and instead and using regular quotes than " - maybe there’s some other solution to this that isn’t immediately obvious to me :p
Looks like zero? Especially if you just used it from the command line.
Yea, typing & is annoying, I suggest typing and instead and using regular quotes than " - maybe there’s some other solution to this that isn’t immediately obvious to me :p
Quoting MDN:
If you have to display reserved characters such as <, >, &, and “ within the <pre> tag, the characters must be escaped using their respective HTML entity.
The problem I have with using a form of text markup (like Markup) is properly escaping asterisks when I really want an asterisk (which isn’t often, but does happen from time to time). It’s especially bad when it happens in code I’m posing. Then I have to go back and fix the post. Yes, this happened recently, and it affected the output of the code to render it useless.
nav, header, footer. cp template.html todays_post.html. If you need extremely basic templating, template.html.sh > todays_post.html.
Why do you need breadcrumbs? If we’re talking beyond blogs, you probably shouldn’t write any static site generator and use what exists, because others will need to come along to maintain it…
Writing raw HTML is also a matter of your editor. If your editor supports snippets and smart expansion, you can write just plain HTML pretty quick. There’s some great vim plugins like emmet.
I’ve wanted to go to an SSG for years but the simplicity of HTML for such a simple and rarely updated personal site is unmatched. I dealt with Wordpress for a decade more than a decade ago and I’m glad I got away from it because I spent more time upgrading and hardening it than I did blogging on it.
A few thoughts about this beautiful piece of writing -
My grandfather is a farmer, something I am immensely proud of. It holds tremendous dignity, providing food for others, something we all need to live, what sustains our life force. He’d grind rice in his hands to de-husk the grains. He’d make a rope bed, each strand out of the plastic fibers in fertilizer bags. The townspeople would entrust their cash to him for safe-keeping, and they’d come to him for medical emergencies. He gave generously to the town’s temple, and even land to those of other faiths, so they can build their own house of worship. You can ask people in a dozen towns around and they’d know him. He assiduously labored at our land for seven decades - and his children and grandchildren are well-taken care of. What’s all this? Care - caring for his family, for his land, for the well-being of others. It’s not saintly austerity or total alturism, but a balance between the private and the public.
At work, I am a software engineer - I work on an infrastructure service. It’s used by hundreds of millions of people. What does caring look for me? It’s gently tending to the system, improving every thing I touch, knowing my small changes will ripple through the years and the decades. It’s working assiduously, paying attention to small details - that’s where the devil lies. It’s generously sharing tools and tips and advice, making others reach their potential, saving them wasted time. It’s being dependable, someone you can trust to do the right thing. It’s being a good example through good conduct. These are all human things, social things, ways of relating to your craft and to the people around you.
I think caring is at the root of craft, of a vocation. How else can you possibly spend your life?
I always find complex joins like this hard to read.
Here’s an alternative approach using a cascade of where … in expressions:
select CustomerID, Name
from Customers
where CustomerID in (
select CustomerID
from Orders
where OrderID in (
select OrderID
from OrderDetails
where ProductID in (
select ProductID
from Products
where CategoryID in (
select CategoryID
from Categories
where Name = 'Beauty'
))))
I actually think this is easier to follow.
I’d be interested to compare query plans and see if this can be as efficient as the solution proposed in this article.
Part of this is cultural I think. Joins feel more “relational” and more “correct” than a cascade. I also don’t think you see as many examples of cascade queries as you learn SQL, which most people do in an ad-hoc way. Joins also work everywhere, and some databases might have limitations with cascades (I can’t think of one but I don’t know - is it ANSI SQL?)
I found my enjoyment of writing SQL improved substantially after I gave myself permission to lean more on tricks like this rather than try to figure out the right joins for everything.
It’s definitely a “try it and look at the query plan” thing, but I’ve run into cases where PostgreSQL’s optimizer did a worse job on “in (subquery)” than on an equivalent join.
I think in theory the optimizer should have enough information to be able to detect when the two styles are semantically equivalent, but in practice, it has a limited CPU budget and can’t cover every possible case. (Or maybe it’s just that nobody happens to have added the detection logic to the optimizer yet.)
Yeah, I really like CTEs for making this kind of thing easier to follow.
with category_ids as (
select CategoryID
from Categories
where Name = 'Beauty'
),
product_ids as (
select ProductID
from Products
where CategoryID in (select CategoryID from category_ids)
),
order_ids as (
select OrderID
from OrderDetails
where ProductID in (select ProductID from product_ids)
),
customer_ids as (
select CustomerID
from Orders
where OrderID in (select OrderID from order_ids)
)
select CustomerID, Name
from Customers
where CustomerID in (
select CustomerID from customer_ids
);
My understanding is that in most database engines views and CTEs are effectively the same thing under the hood - or at least they result in identical query plans.
One way of thinking about CTEs is that they are way of defining a view that exists only for the duration of the current query.
I love these little tools. They present a new way of creating something, and make it easy to try things out, even if you aren’t “trained” as a visual artist or musician.
The real killer feature for these tiny apps is being able to share creations via URLs. You can encode the state as a base64 value in the URL itself.
I can’t actually find the really tiny ones, but these ones I like none-the-less:
Bitsy - a 1-bit pixel art game maker for little adventure games
PuzzleScript is a domain-specific language for making sliding-block puzzles
I’ve also made a few things like this myself; they don’t encode programs in URLs, but either provide the ability to download a self-contained single-file html export, include a built-in pastebin service, or both:
These are fantastic - especially Octo - I just went down a Chip-8 rabbit hole. It seems feasible to make a Chip-8 emulator for the Arduboy I bought recently.
EDIT: ah, the Chip-8 requires more buttons (basically a num-pad) than the Arduboy has (more like a Gameboy).
Or they simply are not real-time applications. ¯\(ツ)/¯
David Harel made the following distinction, which has been widely adopted:
transformational systems
interactive systems
reactive systems
(The term Reactive Programming comes from this third definition, though it has become almost completely mangled in the process).
UI Applications are interactive systems, which means that their environment can wait for them. And it can. I don’t die if I see a SPOD, and in fact it can be exactly the correct information: the program is busy with a task I just gave it, and it will be responsive again once it is done.
In many cases, this is vastly superior to alternative behaviours. For example, if I save a document and it takes a while, I would rather not be able to terminate the program while the save is in progress. Or a program remains theoretically active, but grays out all its UI elements. Technically no SPOD, but not useful either. And more difficult to get right, so you more often get issues like the program not reactivating its UI. Just block normally and let the OS figure it out! Don’t be deceptive by claiming you are active when there is little or nothing useful to do.
I love this! Excited for more work on Rust on CLR.
Additionally, Rust will allocate only unmanaged heap memory
but eventually I guess returning some heap object back to C# will involve putting it in managed memory (or else it won’t ever be dropped). I guess you can achieve this with just a wrapper object that has a finalizer that asks Rust to drop the internal object and then the impl Drop can run and you get it all for free
Finalizers in .net are pretty slow, if I remember correctly, since they don’t work nicely with the generational GC. So it might not all be free, but it would still work :)
But if you’re already writing a custom rust compiler, you might not even need an additional wrapper, just compile the Drop trait as the IDisposable implementation?
Isn’t the .NET equivalent the IDisposable interface? That can be used to manage the lifetime of COM objects, which should be somewhat similar (single owner, no reference counting, explicit destruction, wrap them in a .NET object if you need multiple owners).
Thanks for the link. I don’t have time to watch the video now, but I am interested in this space.
We repeatedly see the tension between code and configuration. Tools like Chef and Puppet used a Ruby DSL, so a limited subset of a full language. Then everyone started stuffing logic into YAML, with tools like Ansible and Salt. Invariably, they “evolve” loops and conditions. Now we have tools like Terraform that use HCL, which is just an abstraction over JSON, to also do loops and conditions and templating and so on. Tools like Pulumi take the other approach again of using a full programming language used in a specialized way, and a lot of the newer stacks from AWS and Terraform similarly use JSII to bring-your-own-programming-language for their CDK platforms.
We keep going back and forth on this and the churn feels really stupid and a waste of lifetimes of human potential. Clearly we desire a more constrained way to write more constrained domains of code, but the more we constrain the more we need to break out of the constraints!
The language I’m most interested in as a reasonable compromise between a “full” language and a “configuration” language is https://cuelang.org/. It’s got an interesting use of types, among other things. I’m not so familiar with Dhall. Would you please give a quick comparison between the two?
I don’t think a simple config language is tenable for IAAS configuration. Modern infrastructure is replicated, so a simple language will require tons of repetition if a new block is to be copied per server or per region. It’s also common to have duplication with slight changes. For example. nonprod envs are usually the same as prod envs but with different dependencies and names, most parameters won’t need to change. (In fact, you want minimal changes so testing can happen in an env that’s very similar to prod.)
So, very quickly, you end up with ways to increase repetition with variation (loops over a list) reduce duplication (inheritance, mixins, includes).
I think what people do want is to be able to diff two versions of a simple language. The input language can be complex, and, in the limit, might as well be a regular programming language, as Pulumi does it. But it is easier to review a diff using the final, expanded, simple output language.
You can end up in the middle tar-pit, like GCL at Google. It’s a super complex language with lots of gotchas. It actually is Turing-complete in a terrible way. It’s simple to just use something like a restricted Python - and there has been a general switch to that at the company, as well.
It’s simple to just use something like a restricted Python - and there has been a general switch to that at the company, as well.
Which leads to another sub-optimal endpoint: now every tool you use has a slightly different interpreter which has cherry picked different language features to support. Now you get to play Python feature roulette every time you edit a configuration file!
Starlark seems pretty nicely designed, tho there aren’t many implementations - there’s a golang one and a java one (part of bazel). But I really hope it doesn’t suffer from multiple dialects.
Modern infrastructure is replicated, so a simple language will require tons of repetition if a new block is to be copied per server or per region.
As a software dev, Terraform HCL drove me absolutely nuts. So much copy and paste. “There are patterns here, can I make a function?” “You can create an HCL module”. Ugh.
I also think Cue is very interesting! I haven’t looked at it very much, so I don’t think I can do a proper comparison with Dhall. Generally my understanding is that you use Cue together with .yaml, and cue defines the validations etc.
With Dhall you just use Dhall. You can convert it to json/yaml, but you can also use it directly.
Also, Dhall mostly does typing, as in you just say “this is a number” and “this is a string”, while cue does more validation like “this is a number that is larger than this other number”. You can do that in Dhall as well, but it’s more clunky. Dhall feels more like a “Json for Haskell”, and CUE I guess is more of an “TLA+ for yaml” or something.
For cloud stuffs I have used the AWS CDK, and I think it’s probably the best approach there. I should try Pulumi at some point. :)
I like Cue’s types because in practice types are not “this is an integer” but “this is an IP address” or “this is a number in the range of…” and so on. I don’t think Cue is at all dependent on YAML, my understanding is it’s both the configuration format itself, as well as the language in which you define the types/constraints on top of your data fields. So it’s got a neat consistency “all the way down”.
In practice types are not “this is an integer” but “this is an IP address” or “this is a number in the range of…” and so on
Yes, that’s what I was trying to say.
It’s not bound to .yaml, but it seems very cleary advertised as validation for .yaml, .json and other text. The home page of CUE shows a video of it validating .yaml on the top.
We repeatedly see the tension between code and configuration. Tools like Chef and Puppet used a Ruby DSL, so a limited subset of a full language. Then everyone started stuffing logic into YAML, with tools like Ansible and Salt.
There is a third way - Pulumi (and I think AWS CDK) let you use a full programming language with no restrictions. With CDK it’s Typescript, and in Pulumi’s case you can use “any JVM language (Java, Scala, Kotlin, Clojure), .NET (C#, F#, PowerShell), Node.js (JavaScript, TypeScript), Go, Python”.
I’ve been using Pulumi with Typescript and it’s been great. My last exposure to DevOps had been with Chef, which I really disliked using.
I wouldn’t call myself a DevOps engineer or SRE, more just a fullstack engineer who ended up needed to deploy and manage a bunch of infrastructure on AWS.
I cover Pulumi and AWS/Terraform CDK in my comment. I’m glad to hear your experience with Pulumi has been good, It’s the product I’m most interested to try next time I need to do IaC.
This sounds like a bad idea to me. One of the main benefits of Dhall is that it is a total programming language giving you guarantees about program termination. I don’t want my infrastructure deployment blowing up because I got too cute with recursion in javascript or whatever.
I can’t remember the last time I managed to crash a JavaScript interpreter. I’m pretty sure that in practice this is not a problem anyone has (it would be recoverable, at least with Pulumi). Anyway it’s always possible that any tool could experience eg a network or power outage so they all need to be able to recover from that kind of thing.
I’m still at a loss why anyone would knowingly use the Chrome browser. It was created with exactly one purpose: To help Google track you better. Oh wait, it wasn’t Google wanting to “give something back” or “donate something for free out of the kindness of their hearts”? Nope. It was created as a response to browsers like Firefox and Safari that were slowly improving their privacy settings, and thus reducing Google’s ability to violate your privacy for a fee.
And if you’re curious, Google didn’t create and give away fonts out of the kindness of their hearts, either. If you’re using Google fonts, you aren’t anonymous. Anywhere. Ever. Private mode via a VPN? Google knows who you are. Suckers. Seriously: How TF do you think they do perfect fingerprinting when everyone is using only a few browsers on relatively small number of hardware devices?
TLDR - Google dropped the “do no evil” slogan for a reason.
To be fair, they also wanted their web apps to run better. They went with Google Chrome rather than making Gmail and Docs into desktop apps. If the owner of the platform I make my apps on is a direct competitor (Microsoft Office vs Google Docs), I wouldn’t be happy. Especially when that competitor platform sucks. Now that Chrome holds the majority of market share, Google can rest easy knowing that their stuff runs how they want for most users. Chrome also pushed the envelope for browser features they directly wanted to use in their apps.
The tracking and privacy thing is a LOT more pronounced now than it was in 2008 when Chrome came out. That’s definitely an issue that’s relevant today, but you can’t really pretend it was the sole driving force of the original release of Google Chrome.
I knew that Google was building Chrome for the purpose of tracking back when it was still in development, based on private comments from friends at Google. I don’t know if that was 2008, but it was somewhere in that time period. Yes, they needed a better browser experience to support some of their product goals, but Google’s overwhelmingly-critical product is tracking users, and protecting that one cash cow is important enough to give away gmail and browsers and fonts and phone OSs (and a thousand other things) for free.
Google loses money on pretty much everything, except advertising. And despite whatever the execs say in public, they’re actually quite content with that situation, because the advertising dollars are insane.
“If you’re not paying for the product, then you are the product.”
To be fair, they also wanted their web apps to run better.
They could have done that by funding development in Firefox.
It would have been hard to work within an existing technical framework, especially considering that Firefox in 2008 or whatever was probably saddled with more tech debt than it is today, but it’d certainly be an option.
You can’t strong-arm the web into adopting the features you want by simply funding or contributing to Firefox.
And it’s not clear to me that Google would’ve been able to get Mozilla to take the necessary steps, such as killing XUL (which Mozilla eventually did many many years later, to compete with Chrome). And sandboxing each tab into its own process is probably also the kind of major rework that’s incredibly hard to pull off when you’re just an outsider contributing code with no say in the project management.
I get why Google wanted their own browser. I think they did a lot of good work to push performance and security forwards, plus some more shady work in dictating the web standards, in ways that would’ve been really hard if they didn’t have their own browser.
I still feel a bit bitter about the retirement of XUL. Back in the mid-2000 you could get a native-looking UI running with advanced controls within days. Haven’t seen anything that would get close to that in speed of development so far, maybe except VisualBasic?
Yeah, which I’m sure very conveniently prevents them from attracting too much anti-trust attention, the same way that Intel or NVidia don’t just buy AMD. But I doubt they pay any developers directly to contribute to Firefox, the way that for example AMD contributes to Mesa, Valve contributes to WINE, Apple contributes to LLVM, etc.
There’s a difference between not crushing something because its continued existence is useful to you, and actually contributing to it.
On one hand, you’re totally right. Throwing cash at keeping other browsers alive keeps their ass away from the anti-trust party.
On the other hand, again, between 75% to 95% of [Mozilla’s] entire yearly budget comes from Google. At that volume of financial contributions, I don’t think it matters that they’re not paying Google employees to contribute to Firefox—they’re literally bankrolling the entire organization around Firefox, and by extension basically its paid developers.
They pretty much were back then. At the time Google weren’t happy with the uptake of Firefox vs IE, despite promoting FF on their own platforms, and wanted to pursue the option of their own browser. Mozilla weren’t particularly well known for being accepting of large contributions or changes to their codebase from third parties. There was no real embedding story either which prevented Google from going with Gecko (the Firefox browser engine) as the base instead of WebKit.
I’m still at a loss why anyone would knowingly use the Chrome browser.
Chrome was the first browser to sandbox Flash and put Java behind a ‘click to play’. This was an extreme game changer for security.
Expanding on that, Chrome was the first browser to build sandboxing into the product from day 1. This was an extreme game changer for security.
Between (1) and (2) the threat landscape changed radically. We went from PoisonIvy and BlackHole exploits absolutely running rampant with 0 or 1 click code execution to having to nothing in a few years - the browser exploit market, in that form, literally died because of Chrome.
Continuing on,
Firefox had tons of annoying bugs that Chrome didn’t. “Firefox is already running” - remember that? Chrome had bugs but ultimately crashes were far less problematic, only impacting a tab. Back then that really mattered.
Chrome integrates with GSuite extremely well. Context Aware Access and browser management are why every company is moving to enforce use of Chrome - the security wins you get from CAA are incredible, it’s like jumping 10 years into the future of security just by choosing a different browser.
To help Google track you better.
Whether that’s true or not, the reality is that for most of Chrome’s lifetime, certainly at least until very recently, there were very very few meaningful privacy issues (read: none, depending on your point of view) with the browser. Almost everything people talked about online was just a red herring - people would talk about how Chrome would send out LLMNR traffic like it was some horrible thing and not just a mitigation against attacks, or they’d complain about the numerous ways Chrome might talk to Google that could just be disabled and were often even part of the prompts during installation.
I don’t see why it’s hard to believe that Google wanted more control over the development of the major browser because they are a ‘web’ company and controlling web standards is a massive competitive edge + they get to save hundreds of millions of dollars by not paying Firefox for google.com to be the homepage.
Chrome has been publishing whitepapers around its features for a long time. I don’t keep up anymore and things may have changed in the last few years but there was really nothing nearly as serious as what people were saying.
If you’re using Google fonts, you aren’t anonymous. Anywhere. Ever.
Just to be clear, what you’re talking about is, I assume, the fact that if a website loads content (such as fonts) from a CDN then your browser makes requests to that CDN. Google discusses this here, although I’m not sure why this behavior is surprising:
Is there some other aspect of Google Fonts that you’re referring to? Because I’ve really lost my ability to give statements like “Google Fonts tracks you” any benefit of the doubt after a decade of people misunderstanding things like “yes, a CDN can see your IP address”.
Seriously: How TF do you think they do perfect fingerprinting when everyone is using only a few browsers on relatively small number of hardware devices?
Who says they do perfect fingerprinting? Also since when are there a relatively small number of hardware devices? An IP, useragent, and basic device fingerprinting (“how big is the window”) is plenty to identify a lot of people.
Infosec people love Chrome for architectural reasons. Which just goes to show that privacy and security are separate concerns that only marginally overlap.
I agree, Privacy is totally separate from Security. That said, I do not believe Chrome has represented a privacy concern since its inception - at least until recently, which I only say because I no longer care to follow such things.
*$font,third-party slap this bad boy in your uBlock Origin config & you won’t be downloading any fonts from third-party sites.
…But do be warned that laggards are still using icon fonts (even on contemporary sites!) despite it not being the best practice for icons for over a decade.
I’m still at a loss why anyone would knowingly use the Chrome browser.
I use it because (among other reasons) I want protection against viruses more than against Google. The last thing I heard about Firefox security (I don’t follow it actively) was Patrick Walton commenting that they have made significant improvements but still have never caught up to Chrome on security. I want Chrome’s security for lunch, there is no free lunch, and I’m okay with paying for that lunch in ad targetting data. With JavaScript disabled by default (for security), I never even see many of the ads that they might spend that data on targetting.
Your attitude is a good one: You’re conscious about what they’re probably trying to do with data about you, and you accept the trade-off for the services provided, and you do so consciously.
If Google were above-board in what they’re doing, I’d be 100% thumbs up for their behavior. But they’re not.
A major financial reason for Chrome is to save the cost of paying browser vendors to make Google the default search engine. Google pays Apple like $10 billion a year for this purpose on Safari. This is why Microsoft aggressively promoting Edge is such a threat to Google - fewer users using Google.
When I looked at this many years ago, I obviously had the same exact question, but I don’t actually have an answer. The same browser version (stock) with the same config (stock) on the same OS and OS version (stock) on the same hardware (stock) with the “same” Google fonts apparently generates a different Google fingerprint, apparently even in private browsing mode through the same VPN IP. Drop the Google fonts, and the fingerprint is apparently identical. It’s been a decade since I looked at any of this, so my memory is pretty fuzzy at this point. And of course Google doesn’t provide any hints as to how they are unveiling users’ identities; this is a super closely guarded trade secret and no one I knew at Google even gave me any hints. (My guess is that they are all completely unaware of how Google does it, since the easiest way to maintain secrets is to not tell all of your employees what the secret is.)
The Google fingerprinting does a render on a hidden canvas (including rendering text using fonts) and then sends Google a hash of that render. Somehow the use of Google fonts (note: specifically when downloaded from Google, which is what most web sites do) appears to give different users their own relatively unique hash. If I had to guess (WAG WARNING!!!), I’d suggest that at least one of the most widely distributed fonts is altered ever-so-imperceptibly per download – but nothing you can see unless you render large and compare every pixel (which is what their fingerprint algo is doing). Fonts get cached for a year, so if (!!!) this is their approach, they basically get a unique ID that lasts for the term of one year, per human being on the planet.
If you examine their legalese, you’ll see that they carefully carve out this possible exception. For example: “The Google Fonts API is designed to limit the collection, storage, and use of end-user data to what is needed to serve fonts efficiently.” Right. They don’t need to collect or store anything from the Fonts API. Because your browser would be doing the work for them. Similarly, “requests for fonts are separate from and do not contain any credentials you send to google.com while using other Google services that are authenticated, such as Gmail.” So they went out of their way to provide the appearance of privacy, yet somehow their fingerprinting is able to defeat that privacy.
The only thing that I know for certain is that Google hires tons of super smart people explicitly to figure out how to work around privacy-protecting features on other companies’ web browsers, and their answer was to give away fonts for free. 🤷♂️
I’m not normally accused of being a conspiracy theorist, but damn, writing this up I sure as hell feel like one now. You’re welcome to call me crazy, because if I read this shit from anyone else, I’d think that they were nuts.
That’s really ingenious, if true. To go along with supporting your theory, there is a bug open since 2016 for enabling Subresource Integrity for Google Fonts that still isn’t enabled.
I’m a bit sceptical about the concept, that seems like it comes with an enormous cost of downsides - fonts are not light objects, and really do benefit from caching. Whereas merely having the Referer tag of the font request in addition to timing information & what is sent with the original request (IP addr, User agent, etc) seem perfectly sufficient in granularity to track a user.
This feels too easy to detect for it not to have been noticed by now - someone would have attempted to add the SRI hash themselves and noticed it break for random users, instead of the expected failure case of “everyone, everywhere, all at once”.
The fonts are constantly updated on Google fonts at the behest of the font owners, so the SRI hash issue being marked as WONTFIX isn’t very exciting, as I wouldn’t be surprised at it being legally easier for Google to host one version of the font (as Google is often not the holder of the Reserved Font Name), as the Open Font License seems to be very particular about referring to fonts by name. Reading through the OFL FAQ (https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL-FAQ_web), if I were a font distributor I would be hesitant to host old conflicting versions of the font amongst each other. Plus, easier to cache a single file than multiple, and lower effort on the side of a font foundry, as it means they do not need to have some versioning system set up for their font families (because they’re not just one weight, type, etc).
The fonts not being versioned goes beyond the SRI hash benefits, fonts often have breaking changes[0] in them e.g. https://github.com/JulietaUla/Montserrat/issues/60 so a designer being to know future font changes wouldn’t result in any changes in the page. So in my mind, it really feels like it’s the foundry who’s wanting there to be a single authoritative version of the font.
0: I suppose a semver major version bump in the font world would be character width changes.
Even if cpurdy’s version is true, I’m sure they use every normal and not so normal trick in the book to track as well. If your singular goal is identifying users uniquely, you would be stupid to rely on only 1 method. You would want 100 different methods, and you would want to deploy every single one. So if a competing browser vendor or unique edge case happens to break a single method, you don’t really care.
I agree caching of fonts is useful, but the browser would cache the most common fonts locally anyway. It would behoove Google to set the cache lifetime of the font file as long as practically possible, even if they were not using it to track you.
I agree, fingerprinting is a breadth of signals game, but I just can’t believe this vector, it feels way too technically complicated for comparable methods available within the same context - the idea was minute changes in font to result in different canvas render hashes, but a user already has a lot of signals within JS & canvas (system fonts, available APIs, etc) that are much quicker to test.
Fonts are cached per site by the browsers as a means of avoiding fingerprinting the cross-domain timing effects - Safari & Chrome call it partitioned cache; Firefox, first party isolation. So Google can tell you’ve visited a site as the referer gets sent on first load, unless they set Referrer-Policy: no-referrer, of course
I agree it’s technically complicated, but I imagine they want a variety of hard and not very hard methods. Assuming they do it, perhaps they only run it when they can’t figure out who you are from some other, easier method.
I always have a degoogled Chrome fork installed as a backup browser, in case I have website compatibility problems with Firefox. Some of my problems might be caused by my Firefox extensions, but it’s easier to switch browsers than to start disabling extensions and debugging.
On desktop I use Ungoogled Chromium. On Android I use Bromite and Vanadium. My Android fork is GrapheneOS, which is fully degoogled by default. I am grateful that Google created Android Open Source to counteract iOS, it is an excellent basis for distros like Graphene. I use F-Droid for apps.
Also, I have the Google Noto fonts installed as a debian package (fonts-noto). It’s a great font that eliminates tofu, and I thank Google for creating it. I don’t think Google is spying on my debian installed package list. If I don’t connect to google servers, they can’t see the fonts used by my browser.
I primarily rely on Ublock Origin for blocking spyware and malware, including Google spying. It’s not perfect. I can always use Tor if I feel really paranoid. The internet isn’t anonymous for web browsers if you are connecting with your real IP address (or using the kind of VPN that you warned about). Google isn’t the only surveillance capitalist on the web; I expect the majority of sites spy on you. Even Tor is probably not anonymous if state actors are targeting you. I wouldn’t use the internet at all if I was concerned about that.
Chrome initially came out in late 2008, when Firefox and Safari were actually doing OK, and IE8 was just around the corner, its betas were already out on Chrome’s release date. Chrome wasn’t even a serious player* until about 2010 or 2011, by which time IE9 was out and IE 6 was really quite dead. This article from June 2010 has a chart: https://www.neowin.net/news/ie6-market-share-drops-6-ie8-still-in-top-spot/
You can see IE8 and Firefox 3.5 were the major players, with Safari on the rise (probably mostly thanks to the iphone’s growing popularity).
i remember when Chrome’s marketshare was big enough that I had to start working with its annoying bugs. I tried to ignore it at first hoping it would die, but once the boss himself started pushing it, the pain kept coming. But there was a period there I didn’t hate - IE8 and Firefox 3.5 actually both worked pretty well.
Firefox was the #2 browser (behind only IE*) when Chrome was introduced, and at the time it was still growing its market share year after year, mostly at the expense of IE.
After its release, Chrome quickly overtook Safari (then #3), and proceeded to eat almost all of IE’s and Firefox’s market share. It is now the #1 browser, by a significant margin.
Interestingly, Safari did not yield market share to Chrome, and continued to grow its market share, albeit at a much lower rate than Chrome did. I assume that this growth is based on the growth of iPhone market share, and relatively few iPhone users install Chrome. Today, Safari is now solidly the #2 browser behind Chrome.
Edge (the new IE) is #3.
Firefox has dropped to the #4 position, in a three-way tie with Opera and Samsung.
Agreed. I’m not sure if IE7 was a thing until after chrome. Also when Chrome first came out it was a breath of fresh air because at the time you either had to use Firefox or Opera, both of which had the issue of sites breaking that were made with IE in mind or the whole browser locking up because one site was hung. While I won’t speculate that tracking was a primary goal of Chrome development let’s not pretend that it wasn’t leaps and bounds ahead of what else was available at the time on the IE6 centric web.
Chrome was definitely aimed directly at IE, most likely because they couldn’t bribe MS to default to Google search and because its outdated tech made the push to web apps much harder - consider the fact that early versions didn’t run on anything other than Windows (about 6 months between 1.0 and previews for Mac and Linux), and the lengths they went to get sandboxing to work on WinXP.
I think it’s fair to say that Firefox did have an impact - but it wasn’t that Chrome was created as a response, rather that Firefox defeated the truism that nothing could dethrone IE because it was built into Windows.
I’m still at a loss why anyone would knowingly use the Chrome browser.
I generally don’t like when technology companies use their product to push some ideological agenda, so I would probably choose Chrome over Firefox if I would have to choose between only those two. Also the new Firefox tabs waste a lot of screen space, and they didn’t give any official way to return to the previous look, so that’s another argument (last time I’ve used FF I had to hack through some CSS, which stopped working few updates later). The only thing I miss from FF are tab containers, but that’s about it.
But still, I use Vivaldi, which runs on Blink, so I’m not sure if I match your criteria, since your question is about “Chrome browser” not “Chrome engine”.
My work uses Google apps heavily and so I maintain a personal/work distinction in browsing by routing everything for work to Chrome. Privacy is a technical dead letter.
Yeah, I obviously have to use Chrome a bit, too. Because as a developer, ignoring the #1 browser seems stupid, any way you look at it. And a few sites only work on Chrome (not even on Safari or Firefox). I try to avoid Edge except for testing stuff, because the nag level is indescribable. “Are you super double extra sure that you didn’t want me to not be not your not default web browser? Choose one: [ Make Edge the default browser ] [ Use Microsoft suggested defaults for your web browser choice]” followed by “It’s been over three minutes since you signed in to your Microsoft cloud-like-thingy user account that we tied to your Windows installation despite your many protestations. Please sign in again, and this time we’ll use seven factor authentication. Also, you can’t not do this right now.” And so on.
I abhor and abjure the modern web, but we all have to live in it. On my Mac I use an app called ‘Choosy’ which lets me reroute URLs to arbitrary browsers, so I can use Safari without worry, given that I send all the garbage to either Chrome or a SSB.
My issue is that 99.99% of the time I’m mindlessly using a tiny fraction of git - clone, branch, add, commit, push. So 99.99% of the time I don’t need to understand git, think about how it works, or remember the rest of its capabilities. If I only ever use the first page of the manual, why would I have a refresher read of the remaining 300 pages every six months on the off chance I need to do something out of the ordinary? There should be two tools: everyday-git, and chaos-git.
Git was designed to for a whole most engineers don’t inhabit. One of the core goals is to allow distributed, peer-to-peer sharing of commits. This makes sense when you work on the Linux kernel. In that world, they routinely test WIP patches shared via a mailing list. But that’s not the world most of us live in. Usually, you just want to make some changes, have them reviewed, and merge them. Merging is a pain no matter what system you use since you have to choose how to do the operation. That’s why it’s common for people to hold off on making big changes if they know another colleague is working on the same files.
So Git makes possible what most of us don’t care about (distributed/peer-to-peer sharing of commits), and can’t help with what makes version control complicated (merging) because it’s just essential complexity.
It would be useful if someone made a system where merging was made as simple as possible - perhaps by tracking edits from the editor itself, chunking them logically (instead of “mine or theirs”, “keep these extra logs I added but keep their changes to add retries”).
It doesn’t help that the most popular OSS repository, GitHub, is so tied to this technology.
Throughout the code of both GitLab, Gitaly, and all related components, we assume and very much require Git. Blaming a file operates on the assumption we use Git, merge requests use Git related operations for merging, rebasing, etc, and the list goes on. If we wanted to support Mercurial, we would effectively end up duplicating substantial portions of the codebase. Gitaly helps a bit, but it’s not some kind of silver bullet that magically allows us to also support Mercurial, SVN, CVS, etc. It’s not the intended goal, and never will (or at least should) be. Instead, the goal of Gitaly was to allow us to centralize Git operations, and to shard the repositories across multiple hosts, allowing us to eventually get rid of NFS.
(This quote was in the context of why adding Mercurial support would be difficult and expensive.)
In my team’s health checks, we go down the tree of classes and take all the locks in reader mode. This catches deadlocks quickly and is a good proxy for the task being productive.
I agree with the article that your health checks shouldn’t check dependencies as well. But not for the author’s stated reason of ensuring partial availability if not all of them are degraded/down. It’s simply so the health check is simpler to understand and so gives you a clear signal for what’s not working.
nearly every professional programmer works in some sort of specialized domain. Most programmers think that the domain they work in is representative of programming in its entirety, and they’re usually wrong. An example of a specialized domain is “stateless http servers”. If most of your work is in stateless http servers, most of your opinions about programming are actually opinions about programming stateless http servers, which is a smaller and more specific topic. If most of your work is in game engine programming, most of your opinions about programming are actually opinions about game engine programming, which is a smaller and more specific topic.
Nearly every topic involving Casey Muratori and Jonathan Blow boils down to this:
Casey and Jon Blow work in the specialized domain of games. They’re both good at these things.
They think that what is true of their domain is universal.
Techniques that make sense for programming http servers that do not make sense for game engines or game rendering they say are “wrong”.
They present this to a community of people who largely program stateless http servers, who proceed to lose their minds. Both sides are, in a sense, correct, but both sides see the other side as being wrong, because both sides believe they’re talking about the same topic when they are actually talking about different topics.
Repeat ad infinitum.
That’s not to defend Clean Code specifically though, that book is pretty bad.
Well said. I’m often baffled by the choices made in new versions of C++, but that’s because I have no idea how people use the language in embedded, real-time, or low-latency systems.
I do think, though, they proselytize principles that cut across domains. Primarily: actually understanding what a computer is doing, actually caring about performance, actually molding your tool set to your domain. This isn’t all bad.
Well said. I’m often baffled by the choices made in new versions of C++, but that’s because I have no idea how people use the language in embedded, real-time, or low-latency systems.
How do you mean? I think the only place I routinely see C++ performance being worse than C is iostreams, which to me is more a byproduct of the era than C++ itself.
I think what GP was saying was not “these features are slow” but instead “The design of the API has decisions that I find questionable but assume makes sense in other contexts”
I think you could characterize this as a dynamic we have observed, although I think you’re selling a lot of folks in the general programmer community short by generalizing it to “nearly every” or “most” and by saying they themselves over-generalize from their limited frame. Maybe, maybe not. It’s a vast community. As a stateless http server programmer by trade but a “person who likes to understand how things work” by disposition, I always get a lot of value out of hearing from the wisdom of experts in adjacent domains. It doesn’t always have to be relevant to my job for me to get that value from it. It’s not as if I come back to my team hollering that we have to implement a HTTP handler in assembly, but it does help form mental models that from time to time break through the layers of abstraction at which my code sits, increasing opportunities to pattern-match and make improvements that otherwise would have been hard for me to conceptualize.
Relatedly, the creator of Zig recently drew on some of the same performance-oriented learning from the games community to restructure his language’s compiler and dramatically speed it up. Seems like he applied good judgment to determine these seemingly disparate areas could benefit each other.
Sure, sure, but I think that you touched on a really interesting point, right? I think we could make the credible argument that we don’t have “general” programmers and instead have a (large) cluster of web programmers, an even larger cluster of folks who use SQL and Excel, another cluster of embedded programmers who mostly do C and assembly, another of game developers, and so on and so forth. All of those clusters experience the act of programming very differently.
Anyways, I think you were on to something or at absolute worst had kicked off a really interesting idea. :)
yeah, “the general programmer community” is about as substantive of a concept as “the general hammering community”. It puts the focus on the hammer instead of the blow. It’s a great way to get people to avoid thinking about the consequences of their work, which is really useful if what you want people to focus on is “I went from using Java to Rust” instead of “I am building systems that violate the consent and boundaries of a large number of people and cause harm to society”.
It would be a community of moving things around in memory for its own sake and nothing else. Even memtest86 would be too much. “I made a list of things and no one ever used it.” “I printed hello world to /dev/null”. An isolated unapplied spikes-only meetup.
Not parent, but I have read the book, and have an opinion: avoid. Much of it teaches fairly bad habits, shows the wrong heuristics, and the code examples range from “meh” to downright awful.
Strictly speaking the book is not all bad. Much of it is fairly reasonable, and some of its advice, as far as I recall, is actually good. Problem is, the only people capable of distinguishing the good from the bad are people who don’t need the book in the first place. The rest are condemned to take the whole thing at face value, and in the end we get SOLID zealots that blindly follow principles that makes their programs 3 to 5 times bigger than they could have been (not even an exaggeration).
Unless you’re a historian, I would advise you to read A Philosophy of Software Design by John Ousterhout instead. Here’s a teaser.
I like this article on the subject of Clean Code. In particular, the code examples that have been taken straight from the book just show the kind of havoc that following all the advice blindly can cause. For example, the prime generator example at the end of the article is 70 lines long and requires 7 functions with “readable” names such as smallestOddNthMultipleNotLessThanCandidate. By comparison, a simple sieve of Eratosthenes function takes roughly 20 lines of code and does not needlessly split the logic into unnecessary auxiliary functions.
The function names you mention were put into an example of refactoring another example source code (in the book). I pick Bob’s exploded version with long names over the original source code every day. It’s not that I like the name. I prefer it to the original, because the original is obfuscated in some places.
Honestly, I really have an impression that most people criticizing the book didn’t read it. There is a lot of good advice in the book, and maybe some shitty details. But those shitty details shouldn’t invalidate the good advice and I think that most of people think that it should. I’m really happy I haven’t followed the advice that the book shouldn’t be read.
Even within a single game there are lots of modules with varied constraints. include rendering, sound, gameplay, controls, platform compatibility, tools… Some of it needs top performance, some of it needs top flexibility… from the outside I would guess expertise acquired when developing indie games as significant as Braid and The Witness is very likely to be relevant in many other domains. Perhaps even most.
The Witness took seven years to develop, was privately funded off of a prior success, uses a custom engine, has very sophisticated optics and rendering, and has no combat, no networking, and no skeletal animations. Even in games, The Witness itself is highly irregular in terms of development. Most people don’t have seven years and $800k to make a puzzle game with a fine-grained attention to rendering and no combat. It’s an extremely specific context. The other thing I find so weird is that on HN and Lobsters people constantly bring up The Witness, but working in games, it’s not a game I hear talked about often.
Before The Witness there’s this success you mention: Braid. So it’s not just the one game, and he worked on other things before.
Many things go into the development of a single game. Especially if you do most of those things yourself. The game may be specific, but the development required to achieve it… not so much.
The other thing I find so weird is that on HN and Lobsters people constantly bring up The Witness, […]
This is a link involving Casey Muratori, and a comment thread mentioning one of his closest peers, Jonathan Blow. Of course The Witness was gonna come up.
Really well said. It’s hard, because on the one hand I’d like to think that there are some universal truths about software. And maybe there are. But, so much is context-dependent.
Sometimes. I’ve owned a computer with a sound chip soldered to the motherboard and also a plug in sound card with exactly the same chip on it (same drivers, etc). The one on the motherboard had faint but audible noise (like squeaking sounds when the hard drive motor was busy). The one on the card had a noise floor not noticeably higher than the quantisation noise floor.
The electrical power for a chip on a motherboard tends to be very noisy. The power the chip on the card was was being fed via the PCI pins was much cleaner. :)
A good motherboard will feed clean power to its sound chip. IME mediocre ones don’t and you’ll get better sound out of a $5 USB sound card since it gets the advantage of cleaner power.
I think this is even more noticeable with USB mics sounding nicer because mic input is even more sensitive than speaker output?
One big win from a lot of the early cards was having a big MIDI sample bank. This became pointless first when CPU speeds and RAM were fast enough to handle the MIDI synthesis and then more so when RAM got big enough that games used recorded (or even procedurally generated) music. Beyond that, they offered buffering and low-latency mixing. This was important because a CPU would often be interrupted at a time and leave a buffer empty (or, since they were rings, leave the card replaying the same sample instead of moving to the next), being able to DMA from a few ring buffers in memory and mix meant that the CPU could have a lot of jitter without causing audio artefacts. By the time CPUs were 100 MHz or so, this was less important. Then they got DSPs for dynamic effects and positional audio. By the time CPUs were a few hundred MHz, you could do most of this on a CPU.
These days, the only thing that the audio interface is doing that’s really useful is the digital to audio conversion. Higher-quality DACs make a noticeable difference (or, more accurately, low quality ones do. Modern DACs have such ridiculously high tolerances that they can be way above what a human can perceive, but that doesn’t stop people putting absolutely terrible ones in some systems). More commonly, decent electrical isolation makes a difference. After the DAC, you have analogue signals flowing to an amplifier / speaker and these will easily pick up interference. This is why a lot of setups have an optical connection between the digital source and the DAC / amplifier. Using an external USB audio device can give better quality for a similar reason: moving the DAC away from the case can make a big difference.
There’s also some complexity in synchronisation. Audio is often carried over HDMI now so that latency from HDMI encoding and decoding is the same for the audio and video signals. Doing this moves the DAC out of the computer, though not all displays have decent electrical isolation and so this can make the signal very bad.
Let’s rewind to 2017. I grew up at the tail end of the Jabber era; my happiest memories of computer-aided socialization involve being signed in to Facebook, Google, and two other XMPP providers from one piece of software at the same time, while chatting about Supernatural.
So true! I remember installing Pidgin on any computer I could. I’d talk to friends on AIM, Google Talk, and Facebook Messenger at once. It was simple and fast. It even had a good plug-in ecosystem. I recall one that enabled “psychic mode”, which opened a chat window as soon as the person on the other end started typing. I’d send a message quicker than them and freak them out. Now my social life is on a bunch of apps that don’t talk to each other. It certainly isn’t in their interest to.
The system also integrates with their source control. It supports portable snapshots which preserve a timeline of app state + graphical state + a source control snapshot.
The future is impossible to predict, but perhaps the next level is something like computing as in the novel Permutation City - many providers vying for business on a generic MIPS exchange, with computations paused, their state captured, then seamlessly restarted from the same state on a computer somewhere else. It’s a neat thought although this level of interoperability is anathema to cloud provider profits. Competition is expensive; monopoly/oligopoly with vendor lock-in is where the real money is. Beyond those political/economic concerns I’d say data transfer bandwidth is the main technical hurdle to this vision becoming reality.
Interestingly I got it from a very pro-capitalist man, Peter Thiel. This is a prominent thesis in his book Zero to One: the purpose of a firm is to achieve monopoly.
This is a very interesting subject in economics. Are you familiar with the paper from Ronald coast on why firms exist? It is pretty short, readable and changed the whole field. And the whole monopoly thing appears as empire building in governance and information economics. If you like the subject, you will like the texts :)
The problem is data gravity. With a bit of leg-work, moving container load around multiple clouds is already possible. Kubernetes allows multi-cloud deployments with some effort, for example. But if you rely on DBs or data warehouses in a particular region/cloud, the compute cost savings need to be massive to justify hopping over the egress cost wall.
There’s also latency requirements for online services. If you need to be in US-central, you’re constrained by the ambient costs of that area - land prices, wages, electricity costs. You can’t just pack up and move to Taiwan.
Chances are that future infrastructure will be affected by laws and regulations more than by technical limitations.
We may end up in a future where countries have sovereign segments of the network with strict rules regarding data storage and transport.
Maybe this will drive enthusiasts to find refuge in an alternative to internet - small private mesh networks that are integrated with each-other.
I find that possibility quite compelling, but your wording confuses me. The internet is already a “network of networks” - how is what you’re describing different?
Data residency requirements are already here. Every government/health usage is being constrained this way. The only thing you get is physical presence. It’s just as easy to exfiltrate data if storage is connected to the network. And it prevents you front taking advantage of the cheapest prices, wherever they might be world-wide. And yet, governments forge on ahead.
Hopefully next is some degree of ops-conservatism going mainstream. The current situation is only bearable for very large organizations and IMO we have just gotten better at “throw it over the wall”.
We are now at a point where we are really bad at anything but kilo-core/TB-ram clusters because at less than that the cost of ops eclipse the hardware. Continuity from development, small deployments to “web-scale” has been largely sacrificed.
The other main branch in the tree is “own-nothing” of specialized cloud offerings where you have to use mock implementations to even do testing.
Containerization was a significant improvement for the “works on my machine”-problem, but it has been terrible for deployment performance and artifact management. It’s proof we failed to package and distribute our services.
Similarly the overlay-network based mesh is an indication that the network layers and OS integration doesn’t match how we think about connectivity between services.
My hope is that we do more to resolve these basic issues at the OS level and then rethink k8s etc, how would they work if the OS solved networking and process isolation?
The container abstraction is so shallow that once you start trying to debug multiple containers working in concert, it only works for everyone using the same operating system. It essentially only “solved” disk snapshotting and distribution of snapshots. Engineers working on macos vs linux vs windows (even WSL) are working as diffrerently as a cloud engineer deploying on ECS vs EKS vs AKS. We’ve just shifted the character of the differences between machines.
The RPC nature is a big part of the issue. The networking options around containers are very different across operating systems. The ability of containers to interact with the host is a big area of difference. The Docker Engine approach of running containers in a VM limits those containers in ways they would not be limited when deployed (in most cases). This is particularly true on MacOS where the interactions between containers and the host depends (at least at one point ~2017) on whether you were using a wired or wireless connection to your network.
So move to SOA and RPC, partially spurred on by containerization, pushes the differences to the area of maximum difference. The reaction most people have is to try to push everything into a network managed by Docker Engine. That can make debugging tests completely unrepresentative of the relationships between applications when they are deployed. The ability to mock external dependencies has been very important in my debugging work.
The MacOS wired vs wifi case is extreme but I’ve been bit by this in my work. I was debugging a call to an external API. I had the application running locally, working against a containerized version of the external API (the connections may have done in the other direction, this was a long time ago). I was making progress debugging it. I had to leave the office to catch a flight. While on the plane I could no longer reproduce the issue because the host application could no longer connect to the container. Worse than “works on my machine” because it was the same machine!
ggplot is so good for defining plots, it more than justifies using R. It is so freeing to be able to map data variables directly to plot aesthetics like x-position, y-position, stroke colour, fill colour, opacity, stroke width, shape, whisker length, ribbon width, etc. without needing to manually construct a vector of colour names or what have you.
tidyr and dplyr are so good for tidying and then wrangling data: either of these, too, justifies using R. Both have a deep understanding of their problem domain’s inputs, actions, and outputs; a small core of orthogonal verbs that ninety percent of the time suffices on its own; and a wide selection of variant verbs that come in useful the other ninety percent of the time.
NB: Pandas is a killer library in the opposite sense: its is so painful for interactive data analysis that it justifies avoiding Python. I especially want to single out three of its design decisions. First, “the index is not a normal column” leads to no end of special cases. Second, “you can’t index by (row numbers, column names)” completely ignores how people usually indicate rows and columns in a table. Thirdly, its API is insanely large, because once you start method chaining everybody expects their function to become a method, too.
Yeah I agree – Pandas is not really a killer library for Python, because
it’s not that good compared to tidyverse, and
Plenty of people use Python for other reasons.
I use Python for almost everything, but I don’t use Pandas.
It seems to me like NumPy / SciPy / machine learning frameworks attract more people to Python than Pandas.
On the other hand, I think ggplot2/tidyverse are a major reason that many people use R. (The other reason is that it’s taught in stats courses in colleges.)
It seems to me like NumPy / SciPy / machine learning frameworks attract more people to Python than Pandas.
Ya, and you can also add scikit-learn to that list.
I think ggplot2/tidyverse are a major reason that many people use R. (The other reason is that it’s taught in stats courses in colleges.)
If you work in statistics, especially for the life and behavioural sciences, there’s a third reason: most new models are published as R packages, as are many domain-specific models and datasets. A quick look at the last four days of CRAN’s recent[ly updated] packages turns up this interesting bunch. (The real list is 10-times as long, so I’ve picked a few raisins from the pudding).
OptimaRegion: Confidence Regions for Optima of Response Surfaces
fastqcr: Quality Control of Sequencing Data
dogesr: Work with the Venetian Doges/Dogaresse Dataset
eiPack: Ecological Inference and Higher-Dimension Data Management
convergEU: Monitoring Convergence of EU Countries
blindreview: Blind Review Using Forward Search Procedures
allomr: Removing Allometric Effects of Body Size in Morphological Analysis
imputeMulti: Imputation Methods for Multivariate Multinomial Data
scMappR: Single Cell Mapper
birdscanR: Migration Traffic Rate Calculation Package for ‘Birdscan MR1’ Radars
cornet: Elastic Net with Dichotomised Outcomes
I imagine that for the right specialist, any of these can be a killer library. Or, given that they are used by end users, you could call R a platform and these its killer applications.
Thirdly, its API is insanely large, because once you start method chaining everybody expects their function to become a method, too.
A C# language feature, extension methods, solves this. “Extension methods enable you to “add” methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.”
You can have one type and import whichever set of extension methods for that type. This allows modular and fluent interfaces.
The interesting thing here is using several fonts in the same document. They show docstrings, TODO comments, and Copilot suggestions all being different fonts, which is cool and makes sense.
It’s always interesting to see which ligatures are considered important. It’s gotta be based on what appear in the most-used languages, right? Like if TLA+ was more popular there might be a ligature to turn
[]
into□
, and if Prolog was more popular you’d see a:-
ligature. So what language inspired ligatures for<~~
and:<
? The..<
is for Rust, right?Ligatures aren’t important. You could argue it breaks intent for ligatures, is riddled with false positives, & confuses readers using your setup (in-person pairing, presentations/demos). If you want a
⇒
, then type a⇒
.I love ligatures for general text, but for code, they break the “what you type is what you see” guarantee. It can be hard to make out the component letters of a ligature. Monaspace/s
</
and/>
ligatures are especially egregious.Right!? They look like some sort of Biblical hieroglyphics meant to represent the fetching and disbursing of water from a well.
Most languages won’t accept
⇒
in place of=>
.Many of my favorites do. We should fix our languages so you can clearly mean what you mean as we haven’t been beholden to ASCII for a long while. Minus greater than, isn’t an arrow;
→
is. How am I not supposed to think<=
isn’t⇐
but actually means≤
? It’s a mess that APL had right.And when a language can’t support, I prefer Vim’s conceals to the representative character over the quagmire of ligature abuse.
I’m pretty sure the Go, Python and JS maintainers would not accept a change to add a bunch of obscure unicode characters you can’t even type on most keyboards as operators. It’s a nice idea but just won’t happen in reality. Ligatures may not be “important” but they’re nice, I like them, not everyone does but I can do what I want with my editor, I can make it yellow comic sans if that helps me read it!
Do you know how many keyboards don’t have a
$
despite how many languages rely on it and honestly a lot of symbols not present on many keyboards? It’s an arbitrary line no matter how you slice it for what could or could not be considered keyboard-friendly and≤
is hardly an “obscure” symbol when almost all of us learned it in math(s) class as ≤ before having approached needing it for progamming.It’s not arbitrary. You could argue that the extensive use of a symbol only used in some cultures, the $, is a poor choice, but it was used because it was available on the keyboard of the language designers. =>, which I’m not gonna try to use the symbol for as I’m on my phone (and to not undermine my point), is not.
Strong argument for putting $ on every keyboard.
I was in the ligature camp for a little while… Ultimately what is important is that we are all working in the same language if we are working together. If you google around for “Chinese keyboard” you will see the $ right there where you expect (with a great selection of additional characters. If you want to add some more symbols to your programming, might I suggest starting with a few of those before you reach for some APL bs.)
It’s just one more accident of history, like so many others.
With ฿ being the currency I use most regularly, I should invent a programming language that uses it to get it added to every keyboard. Would make my life easier.
Just get a Thai keyboard…
I modified my xkb layout. The point is that it’s arbitrary that we need to use a
$
over a฿
. Why not use generic currency¤
instead of$
?Don’t ask me, Swedish keyboards have had ¤ since forever. In fact the first language I learned after Basic used it to denote strings, lol.
Yeah I get that, my keyboard doesn’t my own country’s symbol for currency on it, but I’m willing to bet many more keyboards in the world have a dollar sign on (which I’ve always felt is a weird token to use for languages and tools but that’s another topic)
Point stands, <= is pretty accessible, some obscure symbol isn’t. And I don’t think keyboard manufacturers are going to start adding all the math symbols! We’d end up with an emoji keyboard 😂
Ah, but which arrow do you want? And how do you type it out? Do you need charmap open at all times just to edit code and hope you selected the correct glyph from the “arrow” search?
Keyboard layers, Compose key, kitty terminal’s Unicode input, Vim’s digraphs, other editor macros… That’s a lot of freedom of options.
i also don’t want a keyboard with 5000 keys on it.
(maybe OLED keys somewhat fix this. there’s still a discoverability issue, though)
If only there was a key that would allow you to compose multiple ASCII characters into one Unicode character.
hopefully they do that later on, then.
I wish there was a limit on citations of this article. Are there any others on the internet?
Have you actually experienced in-person sharing and them being confused? I’ve used ligatures for who knows how many years, and I don’t remember someone experiencing that. The common experience is “oh this is cool, how do I get this?”.
Whenever I see people on HN or Lobsters complaining about people liking ligatures, it reminds me of people saying that desire paths are wrong.
I’m happy that ligatures exist and make people happy but I get thrown off when I’m pairing with someone who uses them. In languages I’m proficient in, ligatures conflict with the familiar structures I type. In language I’m unfamiliar with they obscure what I need to type to replicate a result. I spend most of a session like that mentally translating to the byte-representation I expect.
I also find the transition to and from ligatures jarring and distracting when I’m watching someone edit code.
Every presentation/talk I’ve ever went to where the writer didn’t consider the audience always had someone ask about it. Base symbols are the lingua franca.
It’s often cited because it expresses many folks’ thoughts more consicely & from the authority of a typographer.
≤ has been the lingua franca for centuries, until a few people decided that <= is better and then everyone jumped on the bandwagon.
But I don’t see the “≤” key on my keyboard.
Getting serious now. Keyboards came from typewriters (d’uh!). If I’m using a typewriter, I can type a ‘<’, then hit backspace and type ‘_’ to get the ‘≤’ symbol. I could even hit the ‘=’ key, backspace, then ‘/’ to get ‘≠’. It’s unclear if the designers of ASCII (back in the 60s) deliberately wanted to emulate this behavior with the definition of BS (backspace, character 8). It’s definition doesn’t state that the previous character be erased, just the cursor moved back one space without erasing. I often think it would be nice if an editor (or system) could do this, and just know I realized that maybe this is what the ‘AltGr’ key (which, being an ignorant American, don’t have on my keyboard) does (even if conceptually).
I can hold
<
on my phone’s keyboard to get a≤
. The touchscreen keyboards arguably make it even easier to add symbols assuming your keyboard is open source so you can fix the issues in it.It’s Option-, on a Mac ;)
Ah. While I do use a Mac, I use an IBM model M keyboard to prevent injuries and have Option (which is Alt) mapped to the Command key.
I’ve never used any of the weirder characters that lurk beneath the Option and Shift keys on the Mac, I just know they’re there. Unfortunately every time I need to type °C I’m on another platform.
I use ± fairly often and, if I’m entering anything non-English, the accent-modifier keys (option-i, option u, and so on) are great. I tried typing Étoilé on a Windows keyboard a couple of years ago and was amazed at how hard it is (on Mac, it’s option-e E t o i l option-e e). Oh, and I type dæmon if I’m feeling particularly smug.
Agree that ligatures are awful. I have to get used to it and/or always second guess what the actual characters are that somebody has written on the screen.
To be clear, ligatures as intended make it easier to read like fi, ffi, etc. but these never obscured the letters
But with a fi ligature I can be reasonably sure that I and everybody else will read it as fi.
With a ≠, it’s obscured and becomes a guess whether the computer is getting a =/= a != or a ≠ or something else entirely that I didn’t think of.
Haskell uses
/=
and Lua uses~=
while OCaml uses<>
and!=
(for structural vs. physical equality).I have a Neovim plugin that I’m hoping to smooth over all of these by concealing all language’s differing choice under the
≠
banner.So, that’s literally what I hope would not happen.
I find reading it clearer and easier to skim with conceal on than trying to remember each of these languages specific notions of these ASCII combos (while using the expected, basic math symbols I can use in those languages that do support ≠), the proper Unicode symbol is used so no looong equals or ambiguity issue, there are no false positives, & when working on a line the true input is always displayed (which sometimes helps jog my memory on how language X represent symbol Y.
Usually I’ll disable it for any long pairing sessions.
The dedicated copilont font thing is even cooler than that: they propose leaving code produced by copilot in the different font, so you retain that information after the fact. Font family as metadata. It’s genius!
I thought they were just saying that the current copilot suggestion would have the different font.
I don’t follow how a text file could even store that metadata.
Hey azeemba! As I read it, they are saying it as “this is a cool thing that becomes possible now”, because they really go out of the way to say “after the fact”:
But it is in a section titled “What if” and you are right that it requires collaboration on the part of the code editor, so it’s not coming soon to a terminal near you. But it might be something for GitHub codespaces themselves, or the collaborative editor discussed at https://lobste.rs/s/s4mdxb/github_next_realtime_github .
Thanks!
There’s this thing called “rich text”, and file formats like RTF.
Which programming languages are you using where the tooling accepts rich text files?
It’s been about 20 years since I looked, but I seem to recall this being one of the early features of D. I can’t remember if it was RTF or HTML, but the idea was that you’d have rich text for comments and be able to embed images, cross-references, and so on directly in the source files. A lot of D has changed beyond all recognition back then, so they probably gave in to the tyranny of git diff.
It wouldn’t need to; you could easily insert a preprocessor that converts RTF (or whatever) to plain text. (Vaguely similar to Knuth’s “weave” utility for literate programming.)
I’m not necessarily arguing this is a good idea; just a thought experiment.
Lookup “colorForth”
ligatures in programming fonts i think got more popular with hasklig, then it branched out to other programming languages with unsavory effects. ones that don’t change the look of the original ascii drastically are not terrible, but they are still irritating to the eyes. In other cases they just plainly look nasty and draw attention, which is the opposite of what one wants. They are based on static rules and just guaranteed to be wrong in so many programming languages that it doesn’t make sense to ponder what ligatures are required, and where they are suitable.
Pity that using multiple fonts for different document elements in VSCode is such a kludge. Requires a third party extension that must be re-enabled after every editor update.
You should be able to style them through
settings.json
, no? I customize token styling and colors withsemanticTokenColorCustomizations
for example, I thoughtfontFamily
would be supported there, too.Ruby doesn’t have semantic syntax highlighting so I’m using the
editor.tokenColorCustomizations
version, but it seems likeforeground
andfontStyle
might be the only css attributes supported.Oh, that’s sad.
Why You Should Just Write HTML
OK, I’ll expand.
Using at least something like staticjinja is not going to hurt you. You can keep using plain HTML and only make use of template inheritance and includes to at least move the unimportant parts of the pages away from the content in a way that makes it easy to come back to them and change things without going through multiple files and repeating the edits.
I would personally probably also add a way to use Markdown, because I find writing plain HTML tedious and distracting. Good when I need it’s power, bad when I need to
&
,"
and<strong>
constantly. I suffer from ADHD, which means that any accidental complexity will make it easier to procrastinate. Also</strong>
.Using something like staticjinja looks like it’d exactly be a pain. Look at how many fricking breaking changes there’s been in 2 years https://staticjinja.readthedocs.io/en/stable/dev/changelog.html
You can setup your css so
<b>
can be synonymous with<strong>
Yea, typing
&
is annoying, I suggest typingand
instead and using regular quotes than"
- maybe there’s some other solution to this that isn’t immediately obvious to me :pLooks like zero? Especially if you just used it from the command line.
Quoting MDN:
Quotation marks as
“…”
typographically, as Godzilla intendedThe problem I have with using a form of text markup (like Markup) is properly escaping asterisks when I really want an asterisk (which isn’t often, but does happen from time to time). It’s especially bad when it happens in code I’m posing. Then I have to go back and fix the post. Yes, this happened recently, and it affected the output of the code to render it useless.
With some way to include navigation and common header, footer, breadcrumbs…
nav, header, footer.
cp template.html todays_post.html
. If you need extremely basic templating,template.html.sh > todays_post.html
.Why do you need breadcrumbs? If we’re talking beyond blogs, you probably shouldn’t write any static site generator and use what exists, because others will need to come along to maintain it…
Writing raw HTML is also a matter of your editor. If your editor supports snippets and smart expansion, you can write just plain HTML pretty quick. There’s some great vim plugins like emmet.
I just can’t quit HTML
I’ve wanted to go to an SSG for years but the simplicity of HTML for such a simple and rarely updated personal site is unmatched. I dealt with Wordpress for a decade more than a decade ago and I’m glad I got away from it because I spent more time upgrading and hardening it than I did blogging on it.
A few thoughts about this beautiful piece of writing -
My grandfather is a farmer, something I am immensely proud of. It holds tremendous dignity, providing food for others, something we all need to live, what sustains our life force. He’d grind rice in his hands to de-husk the grains. He’d make a rope bed, each strand out of the plastic fibers in fertilizer bags. The townspeople would entrust their cash to him for safe-keeping, and they’d come to him for medical emergencies. He gave generously to the town’s temple, and even land to those of other faiths, so they can build their own house of worship. You can ask people in a dozen towns around and they’d know him. He assiduously labored at our land for seven decades - and his children and grandchildren are well-taken care of. What’s all this? Care - caring for his family, for his land, for the well-being of others. It’s not saintly austerity or total alturism, but a balance between the private and the public.
At work, I am a software engineer - I work on an infrastructure service. It’s used by hundreds of millions of people. What does caring look for me? It’s gently tending to the system, improving every thing I touch, knowing my small changes will ripple through the years and the decades. It’s working assiduously, paying attention to small details - that’s where the devil lies. It’s generously sharing tools and tips and advice, making others reach their potential, saving them wasted time. It’s being dependable, someone you can trust to do the right thing. It’s being a good example through good conduct. These are all human things, social things, ways of relating to your craft and to the people around you.
I think caring is at the root of craft, of a vocation. How else can you possibly spend your life?
I always find complex joins like this hard to read.
Here’s an alternative approach using a cascade of where … in expressions:
I actually think this is easier to follow.
I’d be interested to compare query plans and see if this can be as efficient as the solution proposed in this article.
Part of this is cultural I think. Joins feel more “relational” and more “correct” than a cascade. I also don’t think you see as many examples of cascade queries as you learn SQL, which most people do in an ad-hoc way. Joins also work everywhere, and some databases might have limitations with cascades (I can’t think of one but I don’t know - is it ANSI SQL?)
Yeah, this pattern doesn’t seem very common.
I found my enjoyment of writing SQL improved substantially after I gave myself permission to lean more on tricks like this rather than try to figure out the right joins for everything.
You could pop this cascade off of a stack and turn it into a CTE.
I write a bunch of ad-ho queries for my job and I do it in this style all the time. It’s great!
I especially find it easier to exploratively build up a query from parts this way.
It’s definitely a “try it and look at the query plan” thing, but I’ve run into cases where PostgreSQL’s optimizer did a worse job on “in (subquery)” than on an equivalent join.
I think in theory the optimizer should have enough information to be able to detect when the two styles are semantically equivalent, but in practice, it has a limited CPU budget and can’t cover every possible case. (Or maybe it’s just that nobody happens to have added the detection logic to the optimizer yet.)
I do this but with cascading CTEs.
Yeah, I really like CTEs for making this kind of thing easier to follow.
My DRY instinct wonders: why factor out the subqueries as CTEs rather than views?
My understanding is that in most database engines views and CTEs are effectively the same thing under the hood - or at least they result in identical query plans.
One way of thinking about CTEs is that they are way of defining a view that exists only for the duration of the current query.
I ran a quick experiment and the view and CTE queries did both appear to produce identical query plans, at least in SQLite https://chat.openai.com/share/93aaca2f-4769-48b8-83fd-4ccf7efa14f9
I love these little tools. They present a new way of creating something, and make it easy to try things out, even if you aren’t “trained” as a visual artist or musician.
The real killer feature for these tiny apps is being able to share creations via URLs. You can encode the state as a base64 value in the URL itself.
I can’t actually find the really tiny ones, but these ones I like none-the-less:
Please share more of your favorites in this universe.
PuzzleScript is a domain-specific language for making sliding-block puzzles
I’ve also made a few things like this myself; they don’t encode programs in URLs, but either provide the ability to download a self-contained single-file html export, include a built-in pastebin service, or both:
These are fantastic - especially Octo - I just went down a Chip-8 rabbit hole. It seems feasible to make a Chip-8 emulator for the Arduboy I bought recently.
EDIT: ah, the Chip-8 requires more buttons (basically a num-pad) than the Arduboy has (more like a Gameboy).
There’s actually a chip8-based game jam going on right now- plenty of time left to participate if you’re so inclined.
tixy.land - 16x16 javascript tiny art environment
Oh yes! This one’s clever - it saves the code as plain URL-encoded text in the URL when you press enter - frictionless!
Or they simply are not real-time applications. ¯\(ツ)/¯
David Harel made the following distinction, which has been widely adopted:
(The term Reactive Programming comes from this third definition, though it has become almost completely mangled in the process).
UI Applications are interactive systems, which means that their environment can wait for them. And it can. I don’t die if I see a SPOD, and in fact it can be exactly the correct information: the program is busy with a task I just gave it, and it will be responsive again once it is done.
In many cases, this is vastly superior to alternative behaviours. For example, if I save a document and it takes a while, I would rather not be able to terminate the program while the save is in progress. Or a program remains theoretically active, but grays out all its UI elements. Technically no SPOD, but not useful either. And more difficult to get right, so you more often get issues like the program not reactivating its UI. Just block normally and let the OS figure it out! Don’t be deceptive by claiming you are active when there is little or nothing useful to do.
Can you please point to the definitions of these three systems, per Harel?
I first encountered the definitions in the paper describing Lustre.
This references the following: On the Development of Reactive Systems.
and
Real time programming: special purpose or general purpose languages
I do remember seeing a more compact definition in one of Harel’s other papers, but can’t find it now.
I love this! Excited for more work on Rust on CLR.
but eventually I guess returning some heap object back to C# will involve putting it in managed memory (or else it won’t ever be dropped). I guess you can achieve this with just a wrapper object that has a finalizer that asks Rust to drop the internal object and then the
impl Drop
can run and you get it all for freeFinalizers in .net are pretty slow, if I remember correctly, since they don’t work nicely with the generational GC. So it might not all be free, but it would still work :) But if you’re already writing a custom rust compiler, you might not even need an additional wrapper, just compile the Drop trait as the IDisposable implementation?
I also think there’s some gotchas with finalizers: they might not actually run, their run order is not predictable.
Isn’t the .NET equivalent the
IDisposable
interface? That can be used to manage the lifetime of COM objects, which should be somewhat similar (single owner, no reference counting, explicit destruction, wrap them in a .NET object if you need multiple owners).Thanks for the link. I don’t have time to watch the video now, but I am interested in this space.
We repeatedly see the tension between code and configuration. Tools like Chef and Puppet used a Ruby DSL, so a limited subset of a full language. Then everyone started stuffing logic into YAML, with tools like Ansible and Salt. Invariably, they “evolve” loops and conditions. Now we have tools like Terraform that use HCL, which is just an abstraction over JSON, to also do loops and conditions and templating and so on. Tools like Pulumi take the other approach again of using a full programming language used in a specialized way, and a lot of the newer stacks from AWS and Terraform similarly use JSII to bring-your-own-programming-language for their CDK platforms.
We keep going back and forth on this and the churn feels really stupid and a waste of lifetimes of human potential. Clearly we desire a more constrained way to write more constrained domains of code, but the more we constrain the more we need to break out of the constraints!
The language I’m most interested in as a reasonable compromise between a “full” language and a “configuration” language is https://cuelang.org/. It’s got an interesting use of types, among other things. I’m not so familiar with Dhall. Would you please give a quick comparison between the two?
I don’t think a simple config language is tenable for IAAS configuration. Modern infrastructure is replicated, so a simple language will require tons of repetition if a new block is to be copied per server or per region. It’s also common to have duplication with slight changes. For example. nonprod envs are usually the same as prod envs but with different dependencies and names, most parameters won’t need to change. (In fact, you want minimal changes so testing can happen in an env that’s very similar to prod.)
So, very quickly, you end up with ways to increase repetition with variation (loops over a list) reduce duplication (inheritance, mixins, includes).
I think what people do want is to be able to diff two versions of a simple language. The input language can be complex, and, in the limit, might as well be a regular programming language, as Pulumi does it. But it is easier to review a diff using the final, expanded, simple output language.
You can end up in the middle tar-pit, like GCL at Google. It’s a super complex language with lots of gotchas. It actually is Turing-complete in a terrible way. It’s simple to just use something like a restricted Python - and there has been a general switch to that at the company, as well.
Which leads to another sub-optimal endpoint: now every tool you use has a slightly different interpreter which has cherry picked different language features to support. Now you get to play Python feature roulette every time you edit a configuration file!
Anyone who wants a restricted Python should use Starlark https://github.com/bazelbuild/starlark/blob/master/spec.md
Starlark seems pretty nicely designed, tho there aren’t many implementations - there’s a golang one and a java one (part of bazel). But I really hope it doesn’t suffer from multiple dialects.
There’s also a Rust implementation as part of Buck 2: https://github.com/facebookexperimental/starlark-rust.
As a software dev, Terraform HCL drove me absolutely nuts. So much copy and paste. “There are patterns here, can I make a function?” “You can create an HCL module”. Ugh.
You might like CUE. Among other things, it’s built on the lessons learnt from the problems of GCL. The author of CUE was one of the original authors of GCL.
I also think Cue is very interesting! I haven’t looked at it very much, so I don’t think I can do a proper comparison with Dhall. Generally my understanding is that you use Cue together with .yaml, and cue defines the validations etc. With Dhall you just use Dhall. You can convert it to json/yaml, but you can also use it directly. Also, Dhall mostly does typing, as in you just say “this is a number” and “this is a string”, while cue does more validation like “this is a number that is larger than this other number”. You can do that in Dhall as well, but it’s more clunky. Dhall feels more like a “Json for Haskell”, and CUE I guess is more of an “TLA+ for yaml” or something.
For cloud stuffs I have used the AWS CDK, and I think it’s probably the best approach there. I should try Pulumi at some point. :)
I like Cue’s types because in practice types are not “this is an integer” but “this is an IP address” or “this is a number in the range of…” and so on. I don’t think Cue is at all dependent on YAML, my understanding is it’s both the configuration format itself, as well as the language in which you define the types/constraints on top of your data fields. So it’s got a neat consistency “all the way down”.
Yes, that’s what I was trying to say.
It’s not bound to .yaml, but it seems very cleary advertised as validation for .yaml, .json and other text. The home page of CUE shows a video of it validating .yaml on the top.
CUE is a superset of JSON and you can write all your data in CUE. YAML and JSON are possible output formats.
There is a third way - Pulumi (and I think AWS CDK) let you use a full programming language with no restrictions. With CDK it’s Typescript, and in Pulumi’s case you can use “any JVM language (Java, Scala, Kotlin, Clojure), .NET (C#, F#, PowerShell), Node.js (JavaScript, TypeScript), Go, Python”.
I’ve been using Pulumi with Typescript and it’s been great. My last exposure to DevOps had been with Chef, which I really disliked using.
I wouldn’t call myself a DevOps engineer or SRE, more just a fullstack engineer who ended up needed to deploy and manage a bunch of infrastructure on AWS.
I cover Pulumi and AWS/Terraform CDK in my comment. I’m glad to hear your experience with Pulumi has been good, It’s the product I’m most interested to try next time I need to do IaC.
This sounds like a bad idea to me. One of the main benefits of Dhall is that it is a total programming language giving you guarantees about program termination. I don’t want my infrastructure deployment blowing up because I got too cute with recursion in javascript or whatever.
I talk about this in my talk as well, sadly total programming doesn’t guarantee that. It can still use way too much memory or create a function that will take so long, it might as well be forever. This blog post describes it pretty well: https://www.haskellforall.com/2020/01/why-dhall-advertises-absence-of-turing.html
I can’t remember the last time I managed to crash a JavaScript interpreter. I’m pretty sure that in practice this is not a problem anyone has (it would be recoverable, at least with Pulumi). Anyway it’s always possible that any tool could experience eg a network or power outage so they all need to be able to recover from that kind of thing.
Puppet has its own language.
The heritage from Ruby is quite obvious though.
I’m still at a loss why anyone would knowingly use the Chrome browser. It was created with exactly one purpose: To help Google track you better. Oh wait, it wasn’t Google wanting to “give something back” or “donate something for free out of the kindness of their hearts”? Nope. It was created as a response to browsers like Firefox and Safari that were slowly improving their privacy settings, and thus reducing Google’s ability to violate your privacy for a fee.
And if you’re curious, Google didn’t create and give away fonts out of the kindness of their hearts, either. If you’re using Google fonts, you aren’t anonymous. Anywhere. Ever. Private mode via a VPN? Google knows who you are. Suckers. Seriously: How TF do you think they do perfect fingerprinting when everyone is using only a few browsers on relatively small number of hardware devices?
TLDR - Google dropped the “do no evil” slogan for a reason.
To be fair, they also wanted their web apps to run better. They went with Google Chrome rather than making Gmail and Docs into desktop apps. If the owner of the platform I make my apps on is a direct competitor (Microsoft Office vs Google Docs), I wouldn’t be happy. Especially when that competitor platform sucks. Now that Chrome holds the majority of market share, Google can rest easy knowing that their stuff runs how they want for most users. Chrome also pushed the envelope for browser features they directly wanted to use in their apps.
The tracking and privacy thing is a LOT more pronounced now than it was in 2008 when Chrome came out. That’s definitely an issue that’s relevant today, but you can’t really pretend it was the sole driving force of the original release of Google Chrome.
Note: I don’t use Chrome.
I knew that Google was building Chrome for the purpose of tracking back when it was still in development, based on private comments from friends at Google. I don’t know if that was 2008, but it was somewhere in that time period. Yes, they needed a better browser experience to support some of their product goals, but Google’s overwhelmingly-critical product is tracking users, and protecting that one cash cow is important enough to give away gmail and browsers and fonts and phone OSs (and a thousand other things) for free.
Google loses money on pretty much everything, except advertising. And despite whatever the execs say in public, they’re actually quite content with that situation, because the advertising dollars are insane.
“If you’re not paying for the product, then you are the product.”
They could have done that by funding development in Firefox.
It would have been hard to work within an existing technical framework, especially considering that Firefox in 2008 or whatever was probably saddled with more tech debt than it is today, but it’d certainly be an option.
You can’t strong-arm the web into adopting the features you want by simply funding or contributing to Firefox.
And it’s not clear to me that Google would’ve been able to get Mozilla to take the necessary steps, such as killing XUL (which Mozilla eventually did many many years later, to compete with Chrome). And sandboxing each tab into its own process is probably also the kind of major rework that’s incredibly hard to pull off when you’re just an outsider contributing code with no say in the project management.
I get why Google wanted their own browser. I think they did a lot of good work to push performance and security forwards, plus some more shady work in dictating the web standards, in ways that would’ve been really hard if they didn’t have their own browser.
I still feel a bit bitter about the retirement of XUL. Back in the mid-2000 you could get a native-looking UI running with advanced controls within days. Haven’t seen anything that would get close to that in speed of development so far, maybe except VisualBasic?
They essentially do (and did) fund the development of Firefox.
Yeah, which I’m sure very conveniently prevents them from attracting too much anti-trust attention, the same way that Intel or NVidia don’t just buy AMD. But I doubt they pay any developers directly to contribute to Firefox, the way that for example AMD contributes to Mesa, Valve contributes to WINE, Apple contributes to LLVM, etc.
There’s a difference between not crushing something because its continued existence is useful to you, and actually contributing to it.
On one hand, you’re totally right. Throwing cash at keeping other browsers alive keeps their ass away from the anti-trust party.
On the other hand, again, between 75% to 95% of [Mozilla’s] entire yearly budget comes from Google. At that volume of financial contributions, I don’t think it matters that they’re not paying Google employees to contribute to Firefox—they’re literally bankrolling the entire organization around Firefox, and by extension basically its paid developers.
That’s probably fine if they don’t have a say in technical or business decisions.
They pretty much were back then. At the time Google weren’t happy with the uptake of Firefox vs IE, despite promoting FF on their own platforms, and wanted to pursue the option of their own browser. Mozilla weren’t particularly well known for being accepting of large contributions or changes to their codebase from third parties. There was no real embedding story either which prevented Google from going with Gecko (the Firefox browser engine) as the base instead of WebKit.
And yet, Google Chrome was nicknamed “Big Browser” from the start.
Chrome was the first browser to sandbox Flash and put Java behind a ‘click to play’. This was an extreme game changer for security.
Expanding on that, Chrome was the first browser to build sandboxing into the product from day 1. This was an extreme game changer for security.
Between (1) and (2) the threat landscape changed radically. We went from PoisonIvy and BlackHole exploits absolutely running rampant with 0 or 1 click code execution to having to nothing in a few years - the browser exploit market, in that form, literally died because of Chrome.
Continuing on,
Firefox had tons of annoying bugs that Chrome didn’t. “Firefox is already running” - remember that? Chrome had bugs but ultimately crashes were far less problematic, only impacting a tab. Back then that really mattered.
Chrome integrates with GSuite extremely well. Context Aware Access and browser management are why every company is moving to enforce use of Chrome - the security wins you get from CAA are incredible, it’s like jumping 10 years into the future of security just by choosing a different browser.
Whether that’s true or not, the reality is that for most of Chrome’s lifetime, certainly at least until very recently, there were very very few meaningful privacy issues (read: none, depending on your point of view) with the browser. Almost everything people talked about online was just a red herring - people would talk about how Chrome would send out LLMNR traffic like it was some horrible thing and not just a mitigation against attacks, or they’d complain about the numerous ways Chrome might talk to Google that could just be disabled and were often even part of the prompts during installation.
I don’t see why it’s hard to believe that Google wanted more control over the development of the major browser because they are a ‘web’ company and controlling web standards is a massive competitive edge + they get to save hundreds of millions of dollars by not paying Firefox for
google.com
to be the homepage.https://www.google.com/chrome/privacy/whitepaper.html
Chrome has been publishing whitepapers around its features for a long time. I don’t keep up anymore and things may have changed in the last few years but there was really nothing nearly as serious as what people were saying.
Just to be clear, what you’re talking about is, I assume, the fact that if a website loads content (such as fonts) from a CDN then your browser makes requests to that CDN. Google discusses this here, although I’m not sure why this behavior is surprising:
https://developers.google.com/fonts/faq#what_does_using_the_google_fonts_api_mean_for_the_privacy_of_my_users
https://developers.google.com/fonts/faq/privacy
Is there some other aspect of Google Fonts that you’re referring to? Because I’ve really lost my ability to give statements like “Google Fonts tracks you” any benefit of the doubt after a decade of people misunderstanding things like “yes, a CDN can see your IP address”.
Who says they do perfect fingerprinting? Also since when are there a relatively small number of hardware devices? An IP, useragent, and basic device fingerprinting (“how big is the window”) is plenty to identify a lot of people.
Infosec people love Chrome for architectural reasons. Which just goes to show that privacy and security are separate concerns that only marginally overlap.
I agree, Privacy is totally separate from Security. That said, I do not believe Chrome has represented a privacy concern since its inception - at least until recently, which I only say because I no longer care to follow such things.
*$font,third-party
slap this bad boy in your uBlock Origin config & you won’t be downloading any fonts from third-party sites.…But do be warned that laggards are still using icon fonts (even on contemporary sites!) despite it not being the best practice for icons for over a decade.
Out of interest, what is current best practice? I have stopped following most of the frontend stuff over a decade ago.
https://css-tricks.com/svg-symbol-good-choice-icons/ (which as links, but it’s not from 2014 to show how vintage font icons are compared to using vector graphic symbols via SVG)
I use it because (among other reasons) I want protection against viruses more than against Google. The last thing I heard about Firefox security (I don’t follow it actively) was Patrick Walton commenting that they have made significant improvements but still have never caught up to Chrome on security. I want Chrome’s security for lunch, there is no free lunch, and I’m okay with paying for that lunch in ad targetting data. With JavaScript disabled by default (for security), I never even see many of the ads that they might spend that data on targetting.
Your attitude is a good one: You’re conscious about what they’re probably trying to do with data about you, and you accept the trade-off for the services provided, and you do so consciously.
If Google were above-board in what they’re doing, I’d be 100% thumbs up for their behavior. But they’re not.
A major financial reason for Chrome is to save the cost of paying browser vendors to make Google the default search engine. Google pays Apple like $10 billion a year for this purpose on Safari. This is why Microsoft aggressively promoting Edge is such a threat to Google - fewer users using Google.
How do they track using their fonts?
When I looked at this many years ago, I obviously had the same exact question, but I don’t actually have an answer. The same browser version (stock) with the same config (stock) on the same OS and OS version (stock) on the same hardware (stock) with the “same” Google fonts apparently generates a different Google fingerprint, apparently even in private browsing mode through the same VPN IP. Drop the Google fonts, and the fingerprint is apparently identical. It’s been a decade since I looked at any of this, so my memory is pretty fuzzy at this point. And of course Google doesn’t provide any hints as to how they are unveiling users’ identities; this is a super closely guarded trade secret and no one I knew at Google even gave me any hints. (My guess is that they are all completely unaware of how Google does it, since the easiest way to maintain secrets is to not tell all of your employees what the secret is.)
The Google fingerprinting does a render on a hidden canvas (including rendering text using fonts) and then sends Google a hash of that render. Somehow the use of Google fonts (note: specifically when downloaded from Google, which is what most web sites do) appears to give different users their own relatively unique hash. If I had to guess (WAG WARNING!!!), I’d suggest that at least one of the most widely distributed fonts is altered ever-so-imperceptibly per download – but nothing you can see unless you render large and compare every pixel (which is what their fingerprint algo is doing). Fonts get cached for a year, so if (!!!) this is their approach, they basically get a unique ID that lasts for the term of one year, per human being on the planet.
If you examine their legalese, you’ll see that they carefully carve out this possible exception. For example: “The Google Fonts API is designed to limit the collection, storage, and use of end-user data to what is needed to serve fonts efficiently.” Right. They don’t need to collect or store anything from the Fonts API. Because your browser would be doing the work for them. Similarly, “requests for fonts are separate from and do not contain any credentials you send to google.com while using other Google services that are authenticated, such as Gmail.” So they went out of their way to provide the appearance of privacy, yet somehow their fingerprinting is able to defeat that privacy.
The only thing that I know for certain is that Google hires tons of super smart people explicitly to figure out how to work around privacy-protecting features on other companies’ web browsers, and their answer was to give away fonts for free. 🤷♂️
I’m not normally accused of being a conspiracy theorist, but damn, writing this up I sure as hell feel like one now. You’re welcome to call me crazy, because if I read this shit from anyone else, I’d think that they were nuts.
That’s really ingenious, if true. To go along with supporting your theory, there is a bug open since 2016 for enabling Subresource Integrity for Google Fonts that still isn’t enabled.
I’m a bit sceptical about the concept, that seems like it comes with an enormous cost of downsides - fonts are not light objects, and really do benefit from caching. Whereas merely having the Referer tag of the font request in addition to timing information & what is sent with the original request (IP addr, User agent, etc) seem perfectly sufficient in granularity to track a user.
This feels too easy to detect for it not to have been noticed by now - someone would have attempted to add the SRI hash themselves and noticed it break for random users, instead of the expected failure case of “everyone, everywhere, all at once”.
The fonts are constantly updated on Google fonts at the behest of the font owners, so the SRI hash issue being marked as WONTFIX isn’t very exciting, as I wouldn’t be surprised at it being legally easier for Google to host one version of the font (as Google is often not the holder of the Reserved Font Name), as the Open Font License seems to be very particular about referring to fonts by name. Reading through the OFL FAQ (https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL-FAQ_web), if I were a font distributor I would be hesitant to host old conflicting versions of the font amongst each other. Plus, easier to cache a single file than multiple, and lower effort on the side of a font foundry, as it means they do not need to have some versioning system set up for their font families (because they’re not just one weight, type, etc).
The fonts not being versioned goes beyond the SRI hash benefits, fonts often have breaking changes[0] in them e.g. https://github.com/JulietaUla/Montserrat/issues/60 so a designer being to know future font changes wouldn’t result in any changes in the page. So in my mind, it really feels like it’s the foundry who’s wanting there to be a single authoritative version of the font.
0: I suppose a semver major version bump in the font world would be character width changes.
Even if cpurdy’s version is true, I’m sure they use every normal and not so normal trick in the book to track as well. If your singular goal is identifying users uniquely, you would be stupid to rely on only 1 method. You would want 100 different methods, and you would want to deploy every single one. So if a competing browser vendor or unique edge case happens to break a single method, you don’t really care.
I agree caching of fonts is useful, but the browser would cache the most common fonts locally anyway. It would behoove Google to set the cache lifetime of the font file as long as practically possible, even if they were not using it to track you.
I agree, fingerprinting is a breadth of signals game, but I just can’t believe this vector, it feels way too technically complicated for comparable methods available within the same context - the idea was minute changes in font to result in different canvas render hashes, but a user already has a lot of signals within JS & canvas (system fonts, available APIs, etc) that are much quicker to test.
Fonts are cached per site by the browsers as a means of avoiding fingerprinting the cross-domain timing effects - Safari & Chrome call it partitioned cache; Firefox, first party isolation. So Google can tell you’ve visited a site as the referer gets sent on first load, unless they set Referrer-Policy: no-referrer, of course
I agree it’s technically complicated, but I imagine they want a variety of hard and not very hard methods. Assuming they do it, perhaps they only run it when they can’t figure out who you are from some other, easier method.
Considering the other BS that big companies tend to do, my first thought on this is basically https://www.youtube.com/watch?v=WRWt5kIbWAc
You win the interwebs today. The tick is the greatest superhero ever. ❤️
I always have a degoogled Chrome fork installed as a backup browser, in case I have website compatibility problems with Firefox. Some of my problems might be caused by my Firefox extensions, but it’s easier to switch browsers than to start disabling extensions and debugging.
On desktop I use Ungoogled Chromium. On Android I use Bromite and Vanadium. My Android fork is GrapheneOS, which is fully degoogled by default. I am grateful that Google created Android Open Source to counteract iOS, it is an excellent basis for distros like Graphene. I use F-Droid for apps.
Also, I have the Google Noto fonts installed as a debian package (fonts-noto). It’s a great font that eliminates tofu, and I thank Google for creating it. I don’t think Google is spying on my debian installed package list. If I don’t connect to google servers, they can’t see the fonts used by my browser.
I primarily rely on Ublock Origin for blocking spyware and malware, including Google spying. It’s not perfect. I can always use Tor if I feel really paranoid. The internet isn’t anonymous for web browsers if you are connecting with your real IP address (or using the kind of VPN that you warned about). Google isn’t the only surveillance capitalist on the web; I expect the majority of sites spy on you. Even Tor is probably not anonymous if state actors are targeting you. I wouldn’t use the internet at all if I was concerned about that.
This seems ahistoric to me, when Chrome was created, most popular browsers were IE6 and IE7?
Chrome initially came out in late 2008, when Firefox and Safari were actually doing OK, and IE8 was just around the corner, its betas were already out on Chrome’s release date. Chrome wasn’t even a serious player* until about 2010 or 2011, by which time IE9 was out and IE 6 was really quite dead. This article from June 2010 has a chart: https://www.neowin.net/news/ie6-market-share-drops-6-ie8-still-in-top-spot/
You can see IE8 and Firefox 3.5 were the major players, with Safari on the rise (probably mostly thanks to the iphone’s growing popularity).
Firefox was the #2 browser (behind only IE*) when Chrome was introduced, and at the time it was still growing its market share year after year, mostly at the expense of IE.
After its release, Chrome quickly overtook Safari (then #3), and proceeded to eat almost all of IE’s and Firefox’s market share. It is now the #1 browser, by a significant margin.
Interestingly, Safari did not yield market share to Chrome, and continued to grow its market share, albeit at a much lower rate than Chrome did. I assume that this growth is based on the growth of iPhone market share, and relatively few iPhone users install Chrome. Today, Safari is now solidly the #2 browser behind Chrome.
Edge (the new IE) is #3.
Firefox has dropped to the #4 position, in a three-way tie with Opera and Samsung.
Agreed. I’m not sure if IE7 was a thing until after chrome. Also when Chrome first came out it was a breath of fresh air because at the time you either had to use Firefox or Opera, both of which had the issue of sites breaking that were made with IE in mind or the whole browser locking up because one site was hung. While I won’t speculate that tracking was a primary goal of Chrome development let’s not pretend that it wasn’t leaps and bounds ahead of what else was available at the time on the IE6 centric web.
Chrome was definitely aimed directly at IE, most likely because they couldn’t bribe MS to default to Google search and because its outdated tech made the push to web apps much harder - consider the fact that early versions didn’t run on anything other than Windows (about 6 months between 1.0 and previews for Mac and Linux), and the lengths they went to get sandboxing to work on WinXP.
I think it’s fair to say that Firefox did have an impact - but it wasn’t that Chrome was created as a response, rather that Firefox defeated the truism that nothing could dethrone IE because it was built into Windows.
I generally don’t like when technology companies use their product to push some ideological agenda, so I would probably choose Chrome over Firefox if I would have to choose between only those two. Also the new Firefox tabs waste a lot of screen space, and they didn’t give any official way to return to the previous look, so that’s another argument (last time I’ve used FF I had to hack through some CSS, which stopped working few updates later). The only thing I miss from FF are tab containers, but that’s about it.
But still, I use Vivaldi, which runs on Blink, so I’m not sure if I match your criteria, since your question is about “Chrome browser” not “Chrome engine”.
My work uses Google apps heavily and so I maintain a personal/work distinction in browsing by routing everything for work to Chrome. Privacy is a technical dead letter.
Yeah, I obviously have to use Chrome a bit, too. Because as a developer, ignoring the #1 browser seems stupid, any way you look at it. And a few sites only work on Chrome (not even on Safari or Firefox). I try to avoid Edge except for testing stuff, because the nag level is indescribable. “Are you super double extra sure that you didn’t want me to not be not your not default web browser? Choose one: [ Make Edge the default browser ] [ Use Microsoft suggested defaults for your web browser choice]” followed by “It’s been over three minutes since you signed in to your Microsoft cloud-like-thingy user account that we tied to your Windows installation despite your many protestations. Please sign in again, and this time we’ll use seven factor authentication. Also, you can’t not do this right now.” And so on.
I abhor and abjure the modern web, but we all have to live in it. On my Mac I use an app called ‘Choosy’ which lets me reroute URLs to arbitrary browsers, so I can use Safari without worry, given that I send all the garbage to either Chrome or a SSB.
My issue is that 99.99% of the time I’m mindlessly using a tiny fraction of git - clone, branch, add, commit, push. So 99.99% of the time I don’t need to understand git, think about how it works, or remember the rest of its capabilities. If I only ever use the first page of the manual, why would I have a refresher read of the remaining 300 pages every six months on the off chance I need to do something out of the ordinary? There should be two tools: everyday-git, and chaos-git.
Git was designed to for a whole most engineers don’t inhabit. One of the core goals is to allow distributed, peer-to-peer sharing of commits. This makes sense when you work on the Linux kernel. In that world, they routinely test WIP patches shared via a mailing list. But that’s not the world most of us live in. Usually, you just want to make some changes, have them reviewed, and merge them. Merging is a pain no matter what system you use since you have to choose how to do the operation. That’s why it’s common for people to hold off on making big changes if they know another colleague is working on the same files.
So Git makes possible what most of us don’t care about (distributed/peer-to-peer sharing of commits), and can’t help with what makes version control complicated (merging) because it’s just essential complexity.
It would be useful if someone made a system where merging was made as simple as possible - perhaps by tracking edits from the editor itself, chunking them logically (instead of “mine or theirs”, “keep these extra logs I added but keep their changes to add retries”).
It doesn’t help that the most popular OSS repository, GitHub, is so tied to this technology.
Gitlab is also so tied - Hg support was specifically rejected IIRC: https://gitlab.com/gitlab-org/gitlab-foss/-/issues/31600
(This quote was in the context of why adding Mercurial support would be difficult and expensive.)
In my team’s health checks, we go down the tree of classes and take all the locks in reader mode. This catches deadlocks quickly and is a good proxy for the task being productive.
I agree with the article that your health checks shouldn’t check dependencies as well. But not for the author’s stated reason of ensuring partial availability if not all of them are degraded/down. It’s simply so the health check is simpler to understand and so gives you a clear signal for what’s not working.
I’m not so versed in these matters, but can anyone guess how much power this model has? Is it Turing-complete?
Yeah, it’s a reduction of counter machines without an instruction/state pointer. 2-counter machines are Turing-complete.
FRACTRAN is a similar model.
nearly every professional programmer works in some sort of specialized domain. Most programmers think that the domain they work in is representative of programming in its entirety, and they’re usually wrong. An example of a specialized domain is “stateless http servers”. If most of your work is in stateless http servers, most of your opinions about programming are actually opinions about programming stateless http servers, which is a smaller and more specific topic. If most of your work is in game engine programming, most of your opinions about programming are actually opinions about game engine programming, which is a smaller and more specific topic.
Nearly every topic involving Casey Muratori and Jonathan Blow boils down to this:
That’s not to defend Clean Code specifically though, that book is pretty bad.
There’s a good saying by Paul Bucheit that captures this:
Limited life experience + generalization = Advice
:-)
Well said. I’m often baffled by the choices made in new versions of C++, but that’s because I have no idea how people use the language in embedded, real-time, or low-latency systems.
I do think, though, they proselytize principles that cut across domains. Primarily: actually understanding what a computer is doing, actually caring about performance, actually molding your tool set to your domain. This isn’t all bad.
How do you mean? I think the only place I routinely see C++ performance being worse than C is iostreams, which to me is more a byproduct of the era than C++ itself.
I think what GP was saying was not “these features are slow” but instead “The design of the API has decisions that I find questionable but assume makes sense in other contexts”
I think you could characterize this as a dynamic we have observed, although I think you’re selling a lot of folks in the general programmer community short by generalizing it to “nearly every” or “most” and by saying they themselves over-generalize from their limited frame. Maybe, maybe not. It’s a vast community. As a stateless http server programmer by trade but a “person who likes to understand how things work” by disposition, I always get a lot of value out of hearing from the wisdom of experts in adjacent domains. It doesn’t always have to be relevant to my job for me to get that value from it. It’s not as if I come back to my team hollering that we have to implement a HTTP handler in assembly, but it does help form mental models that from time to time break through the layers of abstraction at which my code sits, increasing opportunities to pattern-match and make improvements that otherwise would have been hard for me to conceptualize.
Relatedly, the creator of Zig recently drew on some of the same performance-oriented learning from the games community to restructure his language’s compiler and dramatically speed it up. Seems like he applied good judgment to determine these seemingly disparate areas could benefit each other.
I think perhaps the really interesting hot take here is that such a community doesn’t exist in any meaningful sense.
I should have said the set of all programmers
Sure, sure, but I think that you touched on a really interesting point, right? I think we could make the credible argument that we don’t have “general” programmers and instead have a (large) cluster of web programmers, an even larger cluster of folks who use SQL and Excel, another cluster of embedded programmers who mostly do C and assembly, another of game developers, and so on and so forth. All of those clusters experience the act of programming very differently.
Anyways, I think you were on to something or at absolute worst had kicked off a really interesting idea. :)
yeah, “the general programmer community” is about as substantive of a concept as “the general hammering community”. It puts the focus on the hammer instead of the blow. It’s a great way to get people to avoid thinking about the consequences of their work, which is really useful if what you want people to focus on is “I went from using Java to Rust” instead of “I am building systems that violate the consent and boundaries of a large number of people and cause harm to society”.
It would be a community of moving things around in memory for its own sake and nothing else. Even memtest86 would be too much. “I made a list of things and no one ever used it.” “I printed hello world to /dev/null”. An isolated unapplied spikes-only meetup.
Hell, some programs for microcontrollers use only CPU registers. ;)
What was bad about Clean Code?
Not parent, but I have read the book, and have an opinion: avoid. Much of it teaches fairly bad habits, shows the wrong heuristics, and the code examples range from “meh” to downright awful.
Strictly speaking the book is not all bad. Much of it is fairly reasonable, and some of its advice, as far as I recall, is actually good. Problem is, the only people capable of distinguishing the good from the bad are people who don’t need the book in the first place. The rest are condemned to take the whole thing at face value, and in the end we get SOLID zealots that blindly follow principles that makes their programs 3 to 5 times bigger than they could have been (not even an exaggeration).
Unless you’re a historian, I would advise you to read A Philosophy of Software Design by John Ousterhout instead. Here’s a teaser.
I like this article on the subject of Clean Code. In particular, the code examples that have been taken straight from the book just show the kind of havoc that following all the advice blindly can cause. For example, the prime generator example at the end of the article is 70 lines long and requires 7 functions with “readable” names such as
smallestOddNthMultipleNotLessThanCandidate
. By comparison, a simple sieve of Eratosthenes function takes roughly 20 lines of code and does not needlessly split the logic into unnecessary auxiliary functions.The function names you mention were put into an example of refactoring another example source code (in the book). I pick Bob’s exploded version with long names over the original source code every day. It’s not that I like the name. I prefer it to the original, because the original is obfuscated in some places.
Honestly, I really have an impression that most people criticizing the book didn’t read it. There is a lot of good advice in the book, and maybe some shitty details. But those shitty details shouldn’t invalidate the good advice and I think that most of people think that it should. I’m really happy I haven’t followed the advice that the book shouldn’t be read.
In a nutshell: it espouses premature abstraction and a dogmatic expert-beginner approach to programming.
https://en.wikipedia.org/wiki/Shuhari
Clean Code leaves the reader in the first of the three states of mastery.
Too bad the tradition taught in Clean Code is the wrong one to follow.
We should start from a better one. Such as A Philosophy of Software Design.
Games are pretty broad.
Even within a single game there are lots of modules with varied constraints. include rendering, sound, gameplay, controls, platform compatibility, tools… Some of it needs top performance, some of it needs top flexibility… from the outside I would guess expertise acquired when developing indie games as significant as Braid and The Witness is very likely to be relevant in many other domains. Perhaps even most.
The Witness took seven years to develop, was privately funded off of a prior success, uses a custom engine, has very sophisticated optics and rendering, and has no combat, no networking, and no skeletal animations. Even in games, The Witness itself is highly irregular in terms of development. Most people don’t have seven years and $800k to make a puzzle game with a fine-grained attention to rendering and no combat. It’s an extremely specific context. The other thing I find so weird is that on HN and Lobsters people constantly bring up The Witness, but working in games, it’s not a game I hear talked about often.
Two points:
This is a link involving Casey Muratori, and a comment thread mentioning one of his closest peers, Jonathan Blow. Of course The Witness was gonna come up.
Really well said. It’s hard, because on the one hand I’d like to think that there are some universal truths about software. And maybe there are. But, so much is context-dependent.
Does anyone know if sound cards still make sense today? From what I understand, a good motherboard will be good enough.
Sometimes. I’ve owned a computer with a sound chip soldered to the motherboard and also a plug in sound card with exactly the same chip on it (same drivers, etc). The one on the motherboard had faint but audible noise (like squeaking sounds when the hard drive motor was busy). The one on the card had a noise floor not noticeably higher than the quantisation noise floor.
The electrical power for a chip on a motherboard tends to be very noisy. The power the chip on the card was was being fed via the PCI pins was much cleaner. :)
A good motherboard will feed clean power to its sound chip. IME mediocre ones don’t and you’ll get better sound out of a $5 USB sound card since it gets the advantage of cleaner power.
I think this is even more noticeable with USB mics sounding nicer because mic input is even more sensitive than speaker output?
One big win from a lot of the early cards was having a big MIDI sample bank. This became pointless first when CPU speeds and RAM were fast enough to handle the MIDI synthesis and then more so when RAM got big enough that games used recorded (or even procedurally generated) music. Beyond that, they offered buffering and low-latency mixing. This was important because a CPU would often be interrupted at a time and leave a buffer empty (or, since they were rings, leave the card replaying the same sample instead of moving to the next), being able to DMA from a few ring buffers in memory and mix meant that the CPU could have a lot of jitter without causing audio artefacts. By the time CPUs were 100 MHz or so, this was less important. Then they got DSPs for dynamic effects and positional audio. By the time CPUs were a few hundred MHz, you could do most of this on a CPU.
These days, the only thing that the audio interface is doing that’s really useful is the digital to audio conversion. Higher-quality DACs make a noticeable difference (or, more accurately, low quality ones do. Modern DACs have such ridiculously high tolerances that they can be way above what a human can perceive, but that doesn’t stop people putting absolutely terrible ones in some systems). More commonly, decent electrical isolation makes a difference. After the DAC, you have analogue signals flowing to an amplifier / speaker and these will easily pick up interference. This is why a lot of setups have an optical connection between the digital source and the DAC / amplifier. Using an external USB audio device can give better quality for a similar reason: moving the DAC away from the case can make a big difference.
There’s also some complexity in synchronisation. Audio is often carried over HDMI now so that latency from HDMI encoding and decoding is the same for the audio and video signals. Doing this moves the DAC out of the computer, though not all displays have decent electrical isolation and so this can make the signal very bad.
So true! I remember installing Pidgin on any computer I could. I’d talk to friends on AIM, Google Talk, and Facebook Messenger at once. It was simple and fast. It even had a good plug-in ecosystem. I recall one that enabled “psychic mode”, which opened a chat window as soon as the person on the other end started typing. I’d send a message quicker than them and freak them out. Now my social life is on a bunch of apps that don’t talk to each other. It certainly isn’t in their interest to.
They have a custom toolchain:
which gives them:
The system also integrates with their source control. It supports portable snapshots which preserve a timeline of app state + graphical state + a source control snapshot.
The future is impossible to predict, but perhaps the next level is something like computing as in the novel Permutation City - many providers vying for business on a generic MIPS exchange, with computations paused, their state captured, then seamlessly restarted from the same state on a computer somewhere else. It’s a neat thought although this level of interoperability is anathema to cloud provider profits. Competition is expensive; monopoly/oligopoly with vendor lock-in is where the real money is. Beyond those political/economic concerns I’d say data transfer bandwidth is the main technical hurdle to this vision becoming reality.
That’s the most succinct criticism of capitalism I’ve ever read.
Interestingly I got it from a very pro-capitalist man, Peter Thiel. This is a prominent thesis in his book Zero to One: the purpose of a firm is to achieve monopoly.
This is a very interesting subject in economics. Are you familiar with the paper from Ronald coast on why firms exist? It is pretty short, readable and changed the whole field. And the whole monopoly thing appears as empire building in governance and information economics. If you like the subject, you will like the texts :)
The problem is data gravity. With a bit of leg-work, moving container load around multiple clouds is already possible. Kubernetes allows multi-cloud deployments with some effort, for example. But if you rely on DBs or data warehouses in a particular region/cloud, the compute cost savings need to be massive to justify hopping over the egress cost wall.
There’s also latency requirements for online services. If you need to be in US-central, you’re constrained by the ambient costs of that area - land prices, wages, electricity costs. You can’t just pack up and move to Taiwan.
Chances are that future infrastructure will be affected by laws and regulations more than by technical limitations. We may end up in a future where countries have sovereign segments of the network with strict rules regarding data storage and transport.
Maybe this will drive enthusiasts to find refuge in an alternative to internet - small private mesh networks that are integrated with each-other.
I find that possibility quite compelling, but your wording confuses me. The internet is already a “network of networks” - how is what you’re describing different?
Data residency requirements are already here. Every government/health usage is being constrained this way. The only thing you get is physical presence. It’s just as easy to exfiltrate data if storage is connected to the network. And it prevents you front taking advantage of the cheapest prices, wherever they might be world-wide. And yet, governments forge on ahead.
Hopefully next is some degree of ops-conservatism going mainstream. The current situation is only bearable for very large organizations and IMO we have just gotten better at “throw it over the wall”.
We are now at a point where we are really bad at anything but kilo-core/TB-ram clusters because at less than that the cost of ops eclipse the hardware. Continuity from development, small deployments to “web-scale” has been largely sacrificed.
The other main branch in the tree is “own-nothing” of specialized cloud offerings where you have to use mock implementations to even do testing.
Containerization was a significant improvement for the “works on my machine”-problem, but it has been terrible for deployment performance and artifact management. It’s proof we failed to package and distribute our services.
Similarly the overlay-network based mesh is an indication that the network layers and OS integration doesn’t match how we think about connectivity between services.
My hope is that we do more to resolve these basic issues at the OS level and then rethink k8s etc, how would they work if the OS solved networking and process isolation?
The container abstraction is so shallow that once you start trying to debug multiple containers working in concert, it only works for everyone using the same operating system. It essentially only “solved” disk snapshotting and distribution of snapshots. Engineers working on macos vs linux vs windows (even WSL) are working as diffrerently as a cloud engineer deploying on ECS vs EKS vs AKS. We’ve just shifted the character of the differences between machines.
But wouldn’t the containers be talking via some RPC mechanism? Shouldn’t that help with OS heterogeneity? Perhaps I misunderstand what you mean.
The RPC nature is a big part of the issue. The networking options around containers are very different across operating systems. The ability of containers to interact with the host is a big area of difference. The Docker Engine approach of running containers in a VM limits those containers in ways they would not be limited when deployed (in most cases). This is particularly true on MacOS where the interactions between containers and the host depends (at least at one point ~2017) on whether you were using a wired or wireless connection to your network.
So move to SOA and RPC, partially spurred on by containerization, pushes the differences to the area of maximum difference. The reaction most people have is to try to push everything into a network managed by Docker Engine. That can make debugging tests completely unrepresentative of the relationships between applications when they are deployed. The ability to mock external dependencies has been very important in my debugging work.
The MacOS wired vs wifi case is extreme but I’ve been bit by this in my work. I was debugging a call to an external API. I had the application running locally, working against a containerized version of the external API (the connections may have done in the other direction, this was a long time ago). I was making progress debugging it. I had to leave the office to catch a flight. While on the plane I could no longer reproduce the issue because the host application could no longer connect to the container. Worse than “works on my machine” because it was the same machine!
Ah! So container runtimes aren’t as uniform as the snapshot/distribution formats.
NB: Pandas is a killer library in the opposite sense: its is so painful for interactive data analysis that it justifies avoiding Python. I especially want to single out three of its design decisions. First, “the index is not a normal column” leads to no end of special cases. Second, “you can’t index by (row numbers, column names)” completely ignores how people usually indicate rows and columns in a table. Thirdly, its API is insanely large, because once you start method chaining everybody expects their function to become a method, too.
Yeah I agree – Pandas is not really a killer library for Python, because
I use Python for almost everything, but I don’t use Pandas.
It seems to me like NumPy / SciPy / machine learning frameworks attract more people to Python than Pandas.
On the other hand, I think ggplot2/tidyverse are a major reason that many people use R. (The other reason is that it’s taught in stats courses in colleges.)
Ya, and you can also add scikit-learn to that list.
If you work in statistics, especially for the life and behavioural sciences, there’s a third reason: most new models are published as R packages, as are many domain-specific models and datasets. A quick look at the last four days of CRAN’s recent[ly updated] packages turns up this interesting bunch. (The real list is 10-times as long, so I’ve picked a few raisins from the pudding).
I imagine that for the right specialist, any of these can be a killer library. Or, given that they are used by end users, you could call R a platform and these its killer applications.
A C# language feature, extension methods, solves this. “Extension methods enable you to “add” methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.”
You can have one type and import whichever set of extension methods for that type. This allows modular and fluent interfaces.