240 comments

[ 0.19 ms ] story [ 293 ms ] thread
Once in a white, we discover a piece of software that transcends mere utility. These tools capture our imagination, open new possibilities, and affect how we design our own systems. I call such software enlightenmentware.

In this article, I praise the software that contributed the most to my enlightenment.

What’s your enlightenmentware?

Speaking of Bazel, I wanted to try it out for a Java project, but it felt a bit more complex than expected.

Would you recommend using it even for mono languages projects?

If you haven't already committed, consider Nix instead.
I'm still trying to understand why people recommend Nix in place of a build system. Nixpkgs stdlib by default expects an autotools project. It will happily integrate with other build systems, as long as you've spelled out your dependencies in both. I've yet to see it generate a Makefile or make any decisions about compilition that weren't spelled out in a "traditional" build system. Could you shed some light on what I've missed?
I'm not sure why you'd want to generate a Makefile if you're using nix. Unlike make, nix understands the inputs to a build step and won't bother rerunning it unless their inputs have changed. You would lose that you generated a Makefile instead of having nix build whatever it is that the Makefile builds.

Otherwise it does the same things as make: this bunch of commands depends on this other bunch of commands... It just makes you express that as a function so it can be smarter about memoization.

I've not used it for large complex builds, so maybe there's some itch it fails to scratch at finer granularity which I'm overlooking. I liked this artical about where it shines and where it fails to be a build system: https://www.tweag.io/blog/2018-03-15-bazel-nix/. I've been waiting for the problem to arise that encourages me to learn Bazel so I can use it alongside nix, and it just hasn't yet.

(comment deleted)
So.. it's sort of a battle over territory between build system and package manager.

Bazel is there becoming ever more complex and unwieldy in an attempt to provide supposed reproducibility - taking control of the provision of ever more of a project's dependencies (in often very janky ways). But to Nix people it's clear that what people are actually doing here is slowly building a linux/software distribution around their project, but in a very ad-hoc and unmaintainable way. And bazel projects will continue to grow in that direction because until you have control of the whole dependency stack (down to the kernel), you're going to struggle to get robust reproducibility.

I don't think many Nix people would suggest actually using Nix as the build system, but probably to use a comparatively simple cmake/meson/whatever build-system and use Nix to provide dependencies for it in a reproducible and manageable way.

Thanks for the summary. I've been using Meson + Nix, so the comments about using Nix as a build system have been confusing. I think what I've been seeing though are "use Nix instead of Bazel", not "use Nix as your build system".
What I mean is use a relatively simple build system instead of Bazel, and deal with dependencies and reproducibility through a Nix development environment.
You lose out on some of the incremental compilation speed that Bazel offers doing this. I think many in the Bazel space suggest using Bazel inside of a Nix environment.
You call blaze side janky and ad-hoc but to me (as complete outsider) using monorepo+build tool seems more principled and working more with fundamentals, while nix feels more ad-hoc and trying to fix stuff post-facto.

> And bazel projects will continue to grow in that direction because until you have control of the whole dependency stack (down to the kernel), you're going to struggle to get robust reproducibility.

This is bit weird statement, considering that it's not where bazel is growing to, but where bazel is growing from. The whole starting point for bazel is having full control (via monorepo) of the dependency stack

> You call blaze side janky and ad-hoc but to me (as complete outsider) using monorepo+build tool seems more principled and working more with fundamentals, while nix feels more ad-hoc and trying to fix stuff post-facto.

The Nix side is a maintained software distribution, which is a lot more than a bunch of random versions of tarballs pulled down from random urls, wrapped in minimal build scripts and forgotten about for years on end. It's also work that is shared across packages in the distribution and it produces consistent results that don't have dependency conflicts - if you have two bazel projects that each build against their own cpython, I can guarantee that they will have chosen different versions of cpython. Which one wins when they're used together? Who knows...

Every project building-out their own separate pseudo-linux-distribution cannot produce good results.

> The whole starting point for bazel is having full control (via monorepo) of the dependency stack

I'm not aware of a bazel project that builds its own glibc (I imagine there are some which people could point out...). But then.. do they ship that glibc with the end result? Or just shrug and hope it works fine on whatever glibc the target system happens to have?

I haven't worked at google, but my understanding is that their monorepo does contain everything, including kernel and libc etc. So it's not bunch of random tarballs, its complete in-house maintained source tree.

> But then.. do they ship that glibc with the end result? Or just shrug and hope it works fine on whatever glibc the target system happens to have?

That's the whole point of monorepo, you don't have some random target systems, it's all included in the same repository.

> I'm still trying to understand why people recommend Nix in place of a build system.

Probably because Nix is a build system. After using it for a decade, I dislike that it describes itself as a "purely functional package manager"; that causes all sorts of confusion, since it has far more in common with something like Make (e.g. see my "Nix from the bottom up" page http://www.chriswarbo.net/projects/nixos/bottom_up.html )

> Nixpkgs stdlib by default expects an autotools project

Ah, I see the confusion. Nixpkgs is not Nix; they are different things!

Nix is a build tool, similar to Make. It has some differences, like caching results using their hash instead of timestamp, but the main advantage is that its build receipes are composable (thanks to the FP nature of their definitions).

For example, say I run `make` in some project repo, like Firefox. Make will read that project's Makefile, which contains elaborate rules for how the various build products depend on each other. Yet despite all that care and attention, I get an error: `cc: command not found`. Oops, I don't have a C compiler! So I grab a copy of the GCC source, and what do I find inside? Another Makefile! The `cc` command required by the Firefox Make rules is itself defined with Make rules; but the Firefox Makefile can't refer to them, since Make is not composable.

In contrast, Nix is composable: Nix definitions can `import` other files, including from build outputs! For example, we can write a build receipe which imports its definition from a build output; where that build fetches a git commit; and the definitions inside import things from some other builds; and those download and extract a bunch of .tar.gz files; and so on.

Nixpkgs is the most obvious example of this composability, with mountains of build receipes, built up from a relatively small "bootstrap" (pre-built binaries for a few basic tools, like parts of GNU). It's also a testament to backwards-compatibility, since it features build receipes (and helper functions) which act as wrappers around all sorts of legacy tools like Make, PIP, NPM, Cargo, Cabal, etc. (if you're working on a project that's stuck on such things).

Whilst Nixpkgs provides support for all of these things; Nix itself is only capable of invoking a single `exec` syscall (see "Nix from the bottom up"). Everything else is built up on that foundation, and isn't tied to any particular tool, language, framework, etc.

Hence it's not so much that Nix is a "package manager", or "orchestration" tool, or "configuration manager", etc. It's more like: those categories of tools are workarounds for crappy, non-composable build tools like Make. Nix is a composable build tool, so all of those other things turn out to be unnecessary.

Bazel is probably at its simplest in a monolingual codebase. Toolchains have a lot of complexity.

It's like that Churchill quote about democracy: Bazel is the worst build system except for all those others.

Used bazel for years, now using pants[0] and really enjoying it as a tool that is good in the same ways, but better in some smaller ways.

0: https://www.pantsbuild.org/

While maven and gradle may lack the architectural purity of bazel, they work much in the same way.

Plan and execute steps, building a graph of the required build tasks, only executing the tasks that have changed inputs.

With that said, it's quite common to see maven/gradle builds that are misconfigured and execute tasks unnecessarily.

I would use choose it for a C++ only project, but that’s because the alternatives are so horrible.
Doubt anyone will be surprised by this from me, but, Nix, 1000x. The amount of crazy stuff you can make work with Nix and Nixpkgs is nuts. This weekend someone pinged me wanting a static build of a Rust binary that had some gnarly bindings to C++ libraries. In under 100 lines of Nix, we have everything: static musl-based build, dynamic glibc build. Want an AppImage? `nix bundle` with an AppImage bundler. Want an OCI image? dockerTools.buildImage on top of your derivation. Throw it in GitHub actions using the Determinate Nix Installer action and you get automatic caching of the Nix store using GitHub actions cache; pretty useful since neither musl Rust nor static LLVM are cached in Hydra. Want to share your cache? Pipe a list of Nix store paths to Cachix, then they can pull it down, or add the Cachix GitHub action to automatically pull from and/or push to it for the CI build. So if anyone wanted to re-use your cache from GitHub Actions CI runs, they could, provided they trust you. You can even cross-compile with MinGW, or run it on macOS.

It's a hugely complex time sink, but my God, it's great. Whereas I don't generally recommend people go down the NixOS rabbit hole unless they're convinced it's right for them, I definitely think Nix is worth having in your toolbelt, it's ridiculously versatile.

This 100%. It's the gift that keeps on giving.
You need to give the first gift, however. Time. And lot of it.
Wait, this is a pretty good sell. I'm going to give this Nix thing a shot. All the other times it's posted people talk about things I don't care like replicable builds and stuff.
My guess is that if you use it long enough for it to start being useful, you'll find that "replicable builds" solves a wider variety of problems than you initially thought it did.

At that point, the hard part becomes getting your co-workers to recognize that all of these little problems that they perceive as separate are actually just facets of the the same huge nondeterminism problem.

I'm sure. It's just not a selling point for me right now.
Perhaps that's exactly the problem: 'reproducibility', 'determinism', 'functional'-- these are unfortunately too much 'insider language' to be great sells to most people who aren't already FP or Nix people... even when they're closely related to benefits those prospective newcomers might enjoy!

I'm glad you've identified a use case that appeals to you. Have fun!

I see tons of people very happily using Nix, but also from what I've seen Nix is one of the most opaque hard to understand inscrutable systems on the planet. The language is impossible to learn, and my limited experience has been that there are extremely few good guides to peering under the covers.

Nix is one of the most powerful & well-used bits of modern computing, hugely adopted and loved, but my limited understanding (and what's kept me broadly uninterested) is that it is on the wrong side of the Age of Reason trying to overthrow the Age of Magic war.

Honestly, I suspect a lot of what makes it opaque is the fact that it hinges a lot on functional paradigms, this definitely made it a lot harder for me to understand. The trouble is that now that I understand it, I'm not sure how they could architect this in a more scrutable way. This is the problem.

I think most of us who use and love Nix understand that it is too complicated, but it's too complicated because none of us can figure out how to make it simpler.

I'm also nix-curious and intimidated by the wall. I feel like things would be a lot easier to grok if Nix actually had a static type system or even something opt-in instead of "the object has whatever fields I happen to put in it, good luck lol"-typed.
The language is not the hard thing, it's actually straightforward once you get it. It's the crazy amount of convention and the number of layers in the stack that make up the Nix ecosystem that takes so long to grok.
> The language is impossible to learn, and my limited experience has been that there are extremely few good guides to peering under the covers.

Maybe my "Nix from the bottom up" page would help? It peers so far "under the covers" that I only introduce the Nix language very briefly near the end (as a saner alternative to everything else on that page!) http://www.chriswarbo.net/projects/nixos/bottom_up.html

What's the right way to learn how to use NixOS?

There are a few different approaches to doing everyday development (oh use Flakes or just make it a default installed package) that it's tedious to do lots of things I've found.

I don't think there's a right way to do it, you are correct in that learning NixOS is pretty tedious.

Re: flakes, my personal opinion is to use flakes. While Flakes are imperfect, they still provide a lot of functionality that Nix doesn't otherwise have. In my mind, it's like Nix's equivalent of "Go modules" or something like that. I do feel like people who do not like flakes make many valid points (the boilerplate, the fact that the top-level flake expression is a subset of Nix for some reason, etc.) but the argument isn't that those problems shouldn't be solved, it's that flakes are a sub-optimal design. Since they're so proliferated throughout the ecosystem though, it is quite unlikely that Nix or any prominent fork will outright drop flakes support any time in the near future. For better or worse, Flakes are part of the Nix ecosystem for the foreseeable future. In my opinion, one may as well take advantage of that.

If you haven't already, I'd get your feet wet with installing Nix on a non-NixOS machine first, and please feel free to ask questions about Nix in the NixOS Discourse "Help" section.

I have some recommendations:

1. https://github.com/nix-community/nix-direnv - Since Nix derivations usually wrap around other build systems, the entire derivation is recomputed when any file in it changes; using direnv, you can just get your normal dev tools upon cd'ing into your project directories. This gives you a lot of the benefits of Nix during local development, but with your normal stack, and without needing to globally install anything. Importantly, this works around the problem of needing to rebuild your project every time a file changes; Nix caching isn't granular enough (at least when wrapping around other build systems as it normally does.)

2. If you are trying to build something, chances are you can find inspiration in Nixpkgs. Are you curious how you might package a Bevy game? No problem: literally search "bevy" on the Nixpkgs GitHub repo and see what comes up. I found a derivation that does: https://github.com/NixOS/nixpkgs/blob/master/pkgs/games/jump...

3. If you use flakes, you should keep the flake "schema" handy. There are a lot of different kinds of flake outputs and there are different ways to specify the same thing, which is somewhat needlessly confusing; keeping the flake schema handy will make it easier to understand what Nix is looking for in a flake, which might make it easier to see what's going on (especially if it's obfuscated.) The most important takeaway here: A command like `nix run flake#attr` will try multiple different attributes. https://nixos.wiki/wiki/flakes#Flake_schema

4. Likewise, I really recommend reading up on what NixOS modules are. NixOS modules are the basis for configurations on NixOS, and having a clear understanding of what is even going on with them is a good idea. For example, you should understand the difference between the Nix language's `import` directive, and using the NixOS modules `imports` attribute to import other NixOS modules. Understanding how the configuration merge works saves a lot of headache, makes it easier to understand how people's configurations works, and also makes it easier to modularize your own NixOS configurations, too. https://nixos.wiki/wiki/NixOS_modules

Unfortunately though, there's just no way to make it "click", and I can't guarantee that it's worth all of the effor...

Thanks for the inspiration. I actually already have nixOS installed on another laptop, but lapsed back to my Ubuntu machine out of a bit of frustration. I'll try it again and see how far I get with these tips.
Point 4 is incredibly under-marketed. Almost all of Nix/NixOS documentation focus on the language-y and build-system-y parts of Nix, and the NixOS modules are usually not talked about. Terrible state of docs doesn't help.
Knowing what are the 3 official manuals for the 3 most important projects in the core Nix ecosystem (the manuals for Nix, Nixpkgs, and NixOS, respectively) that together make up the core of the official docs will save newbies a lot of trouble.

> the language-y and build-system-y parts of Nix Language-y manual: https://nixos.org/manual/nix/stable/language/index.html

Build system-y stuff manual: https://nixos.org/manual/nixpkgs/stable/

> the NixOS modules

Using the NixOS module system in the sense of leveraging existing modules is the main topic of the NixOS manual: https://nixos.org/manual/nixos/stable/

Details about the module system mostly live in this section of it: https://nixos.org/manual/nixos/stable/#sec-writing-modules

The piece they don't tell you is that as a NixOS user, you generally want to look for a NixOS module that supports your application first. Only if you don't see one should you then directly/manually install a package into, e.g., environment.systemPackages.

In other words, search here first: https://search.nixos.org/options

And search here second: https://search.nixos.org/packages

The landing page that ties these reference docs together and also contains a lot more example-centric and tutorial content is nix dot dev, here: https://nix.dev/

Imo nix.dev is a great entrypoint and quickly getting better. In addition to providing a bit of a map to help you navigate the official docs, it includes the best official starting docs on flakes, and links to the highest-quality external tutorial and expository material about Nix.

Make a mental note about the 3 big reference manuals, and bookmark nix.dev, and you have everything you need to learn your way around the official docs.

The No Boilerplate video is what got me started: https://youtu.be/CwfKlX3rA6E?si=hJZ_mm9vaeKI0w8V

It's just super nice having everything in a git backed config, for multiple systems. Working with NixOS seems like I'm simultaneously working 10 years in the future and 10 years in the past.

> What's the right way to learn how to use NixOS?

Just commit. Make it your daily driver, engage the community for help, and learn whatever you need to learn to do things the idiomatic way. Then settle in and get comfy.

That said, I hear you about the paralyzing number of choices. Here are some okay choices you can fall back on when you get dizzy:

  - use flakes with direnv for all your projects
  - when in doubt, just write the damn package
    - need to use some Python library that depends on another Python library that's not in Nixpkgs? Package 'em. Package all the recursive dependencies, then package the library you wanted to use.
    - want some program that's not in Nixpkgs? package it
    - want to reuse a binary built for a traditional distro? package it. Look at examples in Nixpkgs of similar things (e.g., Discord, Steam)
  - seek community engagement on Discourse and Matrix, not elsewhere (not Reddit, not Discord, not Slack, not IRC)
This is the best way to learn NixOS, imo. But if it seems like too much, it's not the only way.
I found using Nix package manager on my current daily-driver OS was a great way to break the ice. After translating my dotfiles to Nix and figuring out my project-specific development workflow I had given myself a strong foundation for NixOS.

Jumping into the deep end and going straight to daily-driving NixOS, is certainly also a good option.

Nix is one of the reasons open source wins in the long run. I would have never imagined that package dependencies could be installed and managed across programming language boundaries, kernel boundaries, shell boundaries, dotfile boundaries etc.

Given that computer complexity grows exponentially all the time, then at some point everyone will be forced to use something like Nix.

I agree with the article with Emacs and Unix/Linux.

Functional Programming approaches usually win in the long run. This is a common thread in the article too, although not explicit.
I think you mean declarative. Whether something is FP or OP usually doesn't matter too much (unless you go to the extremes of each end of the sprectrum a la AbstractBeanFactory/IO Functor State). Declarative solutions last longer by virtue of their declarativeness; the underlying implementation can evolve as long as the declarative layer is untouched.
Isn’t a class a declaration (of a class type)? Isn’t a function a declaration (of an algorithm)?

I’d assert that every programming language is declarative. Especially once you get enough written to constitute a DSL.

I think they mean declarative in the sense that you write down want you _want_ in a solution (prolog/datalog/terraform/etc) without specifying exactly how to compute it (day to day programming languages).
The definition of computation depends on the abstraction level. Languages span multiple abstraction levels. The point is that there’s no meaningful definition of “declarative language” as proven by the examples I’ve already given.

For example you can “compute” a roguelike in TypeScript types, but a type system is declarative!

If you are willing to go to extraordinary lengths, then yes any programming language can be written in a declarative style, at least some part of the program. Some parts of a Java or PHP program can be written declaratively.

In the Nix language context however, they mean declarative and functional like Prolog.

There is also Guix which uses Scheme to declare dependencies, and Scheme is not a declarative language. Scheme is a functional language, but it can be easily written in a declarative style.

Everyone knows this, friend. It's still a useful distinction.
I'd say the distinction is more at the semantic level, i.e. denotational vs operational.
I had only a dim awareness that Nix was even a thing before a few weeks ago. Then somehow I decided that I needed to commit to it 100% and make NixOS my daily driver and make myself learn this. It's been a lot of fun. Like, Dwarf Fortress kinds of fun. The kind of fun where when I first looked at it I thought it was insane inscrutable nonsense, and now I kind of wonder what happened to me that it's kind of making sense now. The kind of fun where I keep telling myself I just want to make some tiny little thing work, but actually I find excuses to rabbit hole down a bunch of different pathways and find amazingness under every stone. The kind of fun where I know better than to try to count how many hours I've spent on this now.

Except unlike Dwarf Fortress, I feel like things are actually improving over time instead of shambling ever-onwards towards an inevitable downfall. So I guess maybe it's more like the kind of fun the very first time I installed Linux and didn't know my way around anything.

I'm surprised how much I enjoy customizing things now. I always thought of my desktops sort of like betta fish before -- like, I've taken care of them, but also known better than to get too attached. Eventually the reformat is gonna come, and I'm never gonna set things up QUITE like I had it before. That's definitely not true now. I could start from scratch and be up and running with my entire suite of applications, themes, add-ons and configurations in no time, because it's all just a git repo of nixfiles.

> I had only a dim awareness that Nix was even a thing before a few weeks ago. Then somehow I decided that I needed to commit to it 100% and make NixOS my daily driver and make myself learn this. It's been a lot of fun. Like, Dwarf Fortress kinds of fun. The kind of fun where when I first looked at it I thought it was insane inscrutable nonsense, and now I kind of wonder what happened to me that it's kind of making sense now. The kind of fun where I keep telling myself I just want to make some tiny little thing work, but actually I find excuses to rabbit hole down a bunch of different pathways and find amazingness under every stone. The kind of fun where I know better than to try to count how many hours I've spent on this now.

That's absolutely what diving in with NixOS was like for me. Wonderful description. :)

> I'm surprised how much I enjoy customizing things now. I always thought of my desktops sort of like betta fish before -- like, I've taken care of them, but also known better than to get too attached. Eventually the reformat is gonna come, and I'm never gonna set things up QUITE like I had it before. That's definitely not true now.

Yes. NixOS makes customization feel more worth it than other operating systems can! I first heard it expressed best in this video: https://www.youtube.com/watch?v=17-TRCpDizA

You have a typo. "earn to" when you probably meant "yearn to".
I would say the compiler explorer[0] fits the definition perfectly. It may seem like a straightforward piece of software, but it has immensely changed the way people discuss and share knowledge around compilers and performance optimization.

I regularly feel the impact on the quality of forum discussions. There's a lot less speculation about if "call X gets inlined", or "Y gets vectorized". Bold claims can be supported or disproven quickly by sharing a link. And then you have tools like llvm-mca[1] or uiCA[2], if you don't mind going into the weeds.

[0] https://godbolt.org/

[1] https://llvm.org/docs/CommandGuide/llvm-mca.html

[2] https://uica.uops.info/

along those lines, the entire notion of a web playground (a sandbox where users can just write and execute or otherwise process code) has vastly reduced the barrier for checking out a project or experimenting with its behaviour
> web playground

This _so_ much. Where in the past I've used Jupyter Notebooks for short, one off stuff or to test something, I now do that online for almost any language.

Notebooks are still useful to write documentation though.

Well, Notebooks main use case is a different purpose, not for trying one-off stuff or checking if some syntax is valid. It's for doing stuff step by step, annotating the steps and/or explaining each result.

Web playgrounds are ok for testing some syntax (if you don't have a local REPL/easy way to test), but not for one-off stuff that involves file input or that you want to check against real environment assets.

> Well, Notebooks main use case is a different purpose, not for trying one-off stuff or checking if some syntax is valid.

I know, but that's what I had used it for too. Like posting some code, for example in a HN post ;) As I've said, I still use it mainly for documentation.

I was thinking about including Mathematica as enlightenmentware. Mathematica 6 (https://www.wolfram.com/mathematica/newin6/) was the first truly interactive system I used (we happen to have a box with a license at the university). It impressed me so much that I still have a lot of warm fuzzy feelings toward Stephen Wolfram and his work.

Unfortunately, my relationship with Mathematica didn’t go anywhere: It was too expensive back then, and I never found a good use for it except for double-checking my homework.

I tried other computer algebra systems, but they didn’t impress me as much.

If you own a Mathematica license and found a good application for it, please let me know!

I have a network that work for numerical in Lagos Nigeria headquarters address Ojuelegba Stadium Bus Stop Premier lotto numbers work for CSI if you can decor ideas for what information you need help with .I use a NECO ECOWAS textbook to jackpot liquid cash from the organization Reach out me directly to help you post on the machine number agl2329762557@gmail.com
I would dare say for me the https://pythontutor.com/ even more so than compiler Explorer. (hint: it's not just for python)
> (hint: it's not just for python)

I would definitely have overlooked it, and it really needs a better domain name.

Pahole is a related utility for high performance programmers. I've been able to attain orders-of-magnitude performance improvements in trading applications using it.
Docker is one of these tools for me.

The unspeakable amount of my time and headache it saved during my consulting career puts a smile on my face.

Docker allows me to quickly iterate over the steps required to run ancient projects.

Not having to install 5 different relational database servers on my host OS alone is worth the learning curve.

Also crucial for running concurrent, reproducible, Python environments in my laptop.

While it takes heavily from the UI, podman with user namespaces enabled is the completion of this idea for me.

No more sudo requirements, greatly reduced attack surface, isolation as a "user" concern. It sits happily in my UI doing exactly what I need it to do for all these use cases.

Imo, making a Dockerfile for an ancient project isn't always easy
But usually easier than making it build locally.
And more easily repeatable. Plus, it avoids polluting the full environment.
In comparison to what? Making a chroot env for such a project is way harder than dockerizing it. VirtualBox and Vagrant might not be much harder, but are slower to the point of being irritating. I might be missing some alternatives, but among the approaches I tested, Docker is still the easiest way to build and run unfamiliar projects.
Not to mention, Vagrant projects just... seem to stop working, eventually?

I've had this happen to me a few times, always for different reasons, always a huge time sink to debug.

Did anybody else have the same experience?

Maybe one day the buck2 ecosystem will evolve to be that bazel replacement. It has a much smaller core. Right now it’s lacking in ecosystem support, tooling, examples, and a local build sandboxing (which could be fine if there was an easy to use local implementation of remote build that felt natural). Also no go support is sort of painful, and it’s a bunch of work as i understand it to get something like rules_go to work for buck2.
Buck2 is really enticing. If I had too much time on my hands, I'd love to try to make a full bootable Linux distro as monorepo and built with buck2. I do see some sort of convergence between package managers and build tools, nix and buck2 do seem to approach similar problem from different angles.
> examples

As it may be that people don't find them, the official ones are in `examples` https://github.com/facebook/buck2/tree/main/examples language examples in `examples/with_prelude` https://github.com/facebook/buck2/tree/main/examples/with_pr...

There is a minmal Go example too: https://github.com/facebook/buck2/tree/main/examples/with_pr...

More "real world" examples are dtolnay's CXX for Rust and C++ interop: https://github.com/dtolnay/cxx

and my own ones (sorry to link these again, but I do not know of any others):

C++ with Vcpkg: https://github.com/Release-Candidate/Cxx-Buck2-vcpkg-Example...

C++ with Conan: https://github.com/Release-Candidate/Cxx-Buck2-Conan-Example...

OCaml: https://github.com/Release-Candidate/OCaml-Buck-2-Examples

And a remark: the "real" problem when using Buck 2 is the interface to the LSP, as most LSPs only work with the "native" project configuration. For C++ generating a `compile_commands.json` is quite easy (see my C++ examples in the other post), not the least because there is no single standard for a project's configuration.
> I couldn’t fathom why anyone would use Windows²

I saw this sentence, was about to type something in response, and then I expanded the footnote (side note: is it really a 'foot'note if it's not in the footer of the page?):

> I became significantly more tolerant since my early university years. Windows (specifically the NT family) is a great operating system. I even have it installed on my gaming pc so that I can buy games I never play.

It's pretty rare to see such a balanced perspective with respect to Windows when someone starts off with 'UNIX'.

> From that moment on, unix followed me through all stages of my life: the toddler phase of keeping up with the cutting-edge Ubuntu releases, the rebellious teens of compiling custom kernels for my Thinkpad T61p and emerging the @world on Gentoo, the maturity of returning to Ubuntu lts and delaying upgrades until the first dot one release, and to the overwhelmed parent stage of becoming a happy macOS user.

I started off as a Linux zealot and followed a very similar trajectory. I think it’s a sign of maturity to realize there is no absolute “best” in engineering, just a best solution in a particular problem space, and Windows is the best for a large number of users for a reason.

I started as a Linux enthusiast a long time ago, these days in my own time I use macos and I don't miss Linux that much, as long as I'm in the terminal I don't feel a difference.

At daily job I'm forced to use Windows, the only thing that's keeping me from changing jobs is WSL2. I'm just not productive with mouse based tools, I need a terminal and powershell doesn't do it for me. Everything feels alien and less usable to me even after years, fonts, window decorations, file manager, UI inconsistencies between different tools. Everything seems slightly hostile and out of place.

Pedantry: it feels like false balance.

Windows is fine, that's it. I use it every day, but it's got so many weird quirks that (that I can't do anything about, being the difference with Linux) it seems ridiculous to call it "great".

I'm in the other room from my windows laptop. It's late, there's almost nothing running in it, the lid is closed, surprise surprise I can still hear the fans.

> I can still hear the fans.

I could not deal with that I’m sorry. I’d have to turn it off.

The only way I could make Windows usable day after day in a previous job was to shut it down every night, and then I had the BIOS configured to start it up again and iterate through my extensive startup list before I got into work. Was quite effective like that.

My Ubuntu machine is also noisy. I’m fairly certain it has nothing to do with system activity.
Fans are probably either a rogue service you can find in the task manager or hardware problem (maybe it needs some new thermal paste or a good air blow to remove dust).

That has usually nothing to do with the OS itself.

Recent Windows releases are notable for not running software without the consent or wishes of the user :)
And what about rogue services that come with the OS itself? Things like Windows Update, Windows Defender, the Phone app thingy, diagnostics policy service, the Xbox game bar or whatever it's called, the .NET optimization thingy and a dozen other things that like to wake up randomly and start consuming resources whenever they feel like it. Most of these things you can only disable temporarily, if at all, without resorting to dubious 3rd party tools.
Counterpoint: I bought a System76 laptop last year. As it came, the CPU fan was never off for longer than a few seconds, even when there was no load at all. The fans are not very loud, but the coil whine just before re-enabling the fan was disturbing.

The motherboard's firmware is open, however, so I rebuilt it with a slightly adjusted "CPU fan curve." After flashing it, the fans now go online when there's an actual need, which is to say - rarely. The coil whine still happens, but hearing it once or twice a day is much less irritating than hearing it every 10 seconds.

So it's possible the problem is on the OS side (I think we can agree the firmware is part of the OS) and it's sometimes possible to fix the problem in software... as long as you have control over it.

> That has usually nothing to do with the OS itself.

More often than not this mystical rogue service ends up being something internal to windows.

Windows 2000 was great IMO, and peak Windows!

XP was peak if hardware compatibility is important.

Then it went downhill slowly. UI decisions and telemetry and now needing an internet connection and a MS account to install and now Win11 refuses to install on perfectly good but older hardware.

Microsoft cloudifying Office ironically makes going to Linux as a normie fairly easy as Office is the only thing I would miss. And mainly due to it’s dominance rather than it being great.

Windows dark side is a shame as MS as a developer’s company is really good. VS, VSCode, Typescript and C# and F# are awesome. And also some changed to Windows are good.

Occasionally I have to help my father with his windows computer and each time it actually gets worse. Edge. Suggestions.

Like I am sure the actual fundamentals of the OS are fairly high quality but holy shit it sucks to use.

I had a similar, frustrating experience last weekend trying to copy data from a phone to a windows machine.

Windows is trying to hide all "technical" stuff so hard that it becomes impossible to do anything.

I put the peak at Windows 7.

Windows 7 UI is like Windows XP but prettier thanks to GPU acceleration. Compared to the XP generation, it had better security, 64 bit support out of the box, it was an "internet age" version of Windows, but it could still run offline and wasn't too obnoxious with ads, telemetry, etc...

It definitely got downhill after that.

> Windows 7 UI is like Windows XP but prettier

Isn't 7 UI basically Vista?

Sorta, but Vista was slow and stuttery, so they don’t feel the same.
Is Windows 7 fast on Vista-era hardware?
Windows 7 effectively cleaned up some details, and by the time of windows 7 the vendors shipping broken drivers already had to correct for NT6 changes or deal with their hardware not working.
> Windows 2000 was great IMO, and peak Windows!

> XP was peak if hardware compatibility is important.

It all started with Windows NT 4. It had its own kernel and was enterprise (and network) focused, compared to Windows 98 (which was Windows 95 (which was Windows 3.11 minus the DOS host dependency)) with bolted on network capabilities.

Windows 2000 is literally "Windows NT 5.0", and Windows XP is "Windows NT 5.1". The win95 lineage was decisively killed by Windows Me, after which the NT kernel took over the entire product line.

On the contrary, footnotes on a webpage belong in the margins. Putting them at the foot of the article in current year is like banging rocks together.
The main thing keeping me on Windows is touch screen support. I know I'm a freak for wanting it, but we all have our ergonomic preferences.

Beyond that, I treat the OS as an appliance. Most of the software that I use is platform independent.

After 20 years of using Linux on the desktop (and FreeBSD, and NetBsd) in parallel with Windows, I gave up. I don't like to always configure things, I don't need 20 different ways to accomplish a task and some of the software I use is not available on Linux. So I went Windows only for the desktop since 4 years. Of course, when I had to do something server side, it was Linux only.

Recently I bought a MacBook Pro and the experience is very Windows like. I don't have to mess with the OS and it just works.

Stick to one Linux distribution and you can have the "one size fits all" experience you want. Who's forcing you to unixhop and constantly fiddle with your stuff? I'm on Debian and never have to change anything and my setup just works.
For me at least, it's personal discipline. If I can fiddle and change stuff, I will.
> (side note: is it really a 'foot'note if it's not in the footer of the page?)

These are rather sidenotes (or margin notes).

> It's pretty rare to see such a balanced perspective with respect to Windows when someone starts off with 'UNIX'.

I dunno. I've posted some pretty balanced opinions on OSes: I've frequently criticised Windows, Macs, Gnome, Plasma and more.

They all each suck in their own specific ways. Most people acknowledge this.[1] Many people are just like me: we put up with the crap on each system in order to get work done.

[1] The exceptions are almost always Mac and Gnome users: trying pointing out that UI can be objectively bad, and the default Mac/Gnome experience fails on more than a few of the objective UI metrics, and you almost always get multiple Mac/Gnome users saying that UI is all subjective.

To some extend it is? After all, those users like that objectively bad UI that you are talking about. The fact that they’re idiots doesn’t make it any less subjective.
I'm not the Linux zealot I was as a kid, but I can never see myself going back to Windows. The particular niceties of a Unix environment are ones that I've come to rely on, and I could never go back to managing all my files and data through rat wrestling, the way Windows seems to want you to do.

That said, I can see the merits of Windows, especially for normies or video game players. It's just absolute friction town for me to use it.

I think the peak of windows was when they introduced WSL, making windows the ultimate crossplatform dev OS.
I hope the author would consider trying Doom Emacs, he mentioned knowing Vim and using Vscode, so with Evil and lsp support he will feel at home, the configuration has great defaults!
Evil offends my simple sensibilities. I prefer boon for modal editing due to its simplicity and how it fits with emacs so well.
I tried God Mode and Evil several times, but it never ended well. Mostly because of the muscle memory I accumulated over a decade.

Evil is fantastic, but it doesn’t play well with all the packages in the ecosystem. There are adapters for Magit, Compile, etc., but most packages define key bindings that require Ctrl-Meta cords, which causes cognitive dissonance.

God mode is a neat idea, but I never committed to it, and I found it confusing at times.

Overall, I decided to accept Emacs as it is, with all its quirks, and embrace its way of doing things. I’m not married to it, so I can occasionally cheat by switching to Vim or VS Code without feeling guilty.

I never was able to use evil per se but it works really well in doom emacs (and before that in spacemacs). Oh and use Caps Lock as Ctrl to minify pinky usage!
Great article. For me it's creative use of tools by others - sometimes myself - in a non-standard way (sometimes that becomes standard!) that brings enlightenment. Be it language, source control, networking, you name it.

Aside: assuming the author is reading, minor typo in the first para: But once in a w̶h̶i̶t̶e̶ while

> But once in a w̶h̶i̶t̶e̶ while

Thanks, fixed! It's “occasionally” now. Even Grammarly didn’t find it :(

Happy to see emacs on the list, changed my life.

Enlightenment hardware: kinesis advantage 2, many non obvious, non ergonomic benefits, like adapting the hardware to _my way_ of working/thinking.

Certain games also feel like enlightenmentware.

What games would you classify as enlightenmentware?
dwarf fortress

ultima-likes

minecraft

I’m not much of a gamer, but those definitely made a pretty big impact on me as far as what one or a small group of people can accomplish

Smalltalk and as a particular case Pharo is an example of this for me. (https://pharo.org/). When I was in uni a paper that I always came back to was Licklider's 1960s paper on human-computer symbiosis.

"[...] to enable men and computers to cooperate in making decisions and controlling complex situations without inflexible dependence on predetermined programs."

Experimenting with Smalltalk (and also with Clojure and Emacs) was one of the things to me that genuinely felt like that vision of programs as living, interactive, organic things rather than the formulaic, static and low level programming that I was used to learning. I think it's still such a shame that in daily jobs it's so difficult to convince people of trying these technologies out because it requires such a big shift in how people think about software.

https://worrydream.com/refs/Licklider_1960_-_Man-Computer_Sy...

NixOS fits the mold. The confidence it instills feels similar to when I moved from Windows to (Ubuntu) Linux.
I want to thank wmii for being a vanguard force in illuminating the path before me, by being both a fine tiling window manager, while also showing it's guts, exposed as a 9p file-system.

Being able to craft together super crappy shell scripts to monitor and manage my windows was amazing. It was a huge turn on to feeling like someone who was really communing with the computer at it's deeper level, rather than just surfing above the application's crust. This feels like the real enlightenment goal: bringing forward the (ab-)natural philosophy that underlies each bit of software, rather than crafting facades of interface atop the core.

I have high hopes that general systems research can one day again spark an age of revelation & understanding, that we can form better more earnest symbiosis with machines. wmii was a good example of one way to let bonds grow close & strong.

> They are "round": they pack the most volume in the smallest surface area. unix surface area is tiny, but it unlocks much power. Emacs and Git are all over the place, but their core is small, sweet, and easy to appreciate.

I really like this 'round' concept, seems very precise. Maximum interface area / use cases (surface area) with minimum core volume.

Unfortunately, a sphere of characterized by exactly the opposite property. The article switches the intended meaning of surface and volume to get away with the metaphor, but I’m less than thrilled about the metaphor.
"encapsulate the most complexity with the smallest API" seems to fit the metaphor better.
I am not defending this specific metaphor as I am not sure it is really good in this case. But they are right about this specific property of spheres: they have the highest volume/surface ratio (i.e. that’s the way of minimising the surface area of the enveloppe for a given volume).
In Ousterhout's "A philosophy of software design", this aspect is described similarly via "deep classes", as opposed to "shallow classes".
Docker would be on the list for me - for reproducible environments. Probably JUnit as it was my first real testing framework - for being able to use test driven development for hard problems.

With programming, I had so many "aha"-moments, it's hard to remember them. It's not all about software, but more about understanding the concepts and being able to transfer this knowledge. Being able to pass functions or function pointers. Streaming / piping data instead of a fixed data structure. Interpreted vs compiled languages. How everything we do here only happens through a long list of 0s and 1s and how this clever setup makes us even see graphics on the screen. Or hear audio through a screen reader....

blaze is one of mine too, specifically for the realisation that your build setup really feels rock solid when your entire dependency list is spelt out as an explicit DAG in a build file. inferring or otherwise auto discovering dependencies on the fly is seductive, but it always ends up letting me down when things get complex.
LaTeX.

I LaTeX, Git, and emacs every day.

Honestly TeX/LaTeX the engine is a marvel of technology,

But everytime i see a \makeatletter or get a runaway argument it reinforces my belief LaTeX the language was a mistake

(La)TeX is an example of a very enlightened _idea_ that offed itself \footnotemark{} with a spectacularly cursed user interface. It is simply gross to write, and it's difficult for frontends, converters and GUIs to make it much better.

Yes yes, I can already hear the cultists chant "YoU dOn'T wRiTe In LaTeX" but this mentality is precisely the problem. If I can't write directly in your typesetting system nowadays, then I'm sorry, your system probably sucks.

You could unfortunately write an article or thesis quite comfortably in Word or even InDesign, while formatting as you go. (I say "unfortunately" because from a business-model and hacker's perspective, these tools suck.)

\footnotetext{not implying that LaTeX is dead, but referring to how it sentenced itself to the academic niche, in which case it might as well be dead…}

From what I’ve seen from Latex GUI applications, there’s no way we can avoid complexity. Most users will do OK with a basic word processor. We do not need a silver bullet for every use case. You select the best one and move on.
> I also must confess to a strong bias against the fashion for reusable code. To me, "re-editable code" is much, much better than an untouchable black box or toolkit.

I had never come across this particular thought by Knuth, but this hits home so hard.

It feels that most of our productivity is a function of how re-editable the code is in the codebase we operate.

It’s intriguing to think about what makes code re-editable vs simply reusable.

Reusable = interface (UX or API) that is intuitive, simple, and powerful; implementation that is fast and reliable.

Re-editable = Implementation building blocks are also intuitive, simple, and powerful; and coupling is minimal (implies intuitive/simple/powerful) and not error-prone (i.e. missing links raise compile errors or fast, descriptive runtime errors).

You can have software that is useful but the implementation is an obfuscated spaghetti mess. This is common for old but popular software e.g. C++ compilers, Microsoft Word, and Firefox, which has gone through maintainers and bitrot but is continually improved and bugs continually fixed. And you can have an application with great code quality but terrible CLI or GUI, such as Git and ffmpeg (for those who disagree on Git, read https://jvns.ca/blog/2024/04/10/notes-on-git-error-messages/... my argument is that you’ve adapted to some design choices, such as the error messages, which could objectively be made more intuitive without sacrificing usability). Although I bet it’s more common that surface and implementation are similar quality.

You can’t really have a bad library with a good implementation, because if the structures/functions/… in your implementation are reusable, that extends to the outermost ones that make up your API. But the larger the implementation, the harder it is to make a good API, so it might just be the case that the low-level design is good and it (gradually or not gradually) gets worse at the higher level.

JAGS - allows you to specify a probabilistic model and sample from the posterior distribution
I’m barely a programmer, but I have been using computers for nearly four decades. Among the various tools that have, over the years, captured my imagination, opened new possibilities, and affected how I create things with computers, the current leading enlightenmentware by far is LLMs. Nearly every day I discover something surprising and useful that they can do for me.
I would add

Haskell - the rabbit hole to category theory and all the mad stuff Haskell people get into (compilers, proofs etc.)

Bitcoin - love or loath it, technically it is a marvel. At the time Bitcoin came out I was musing on the same problem but never could figure out how to avoid double spends and would never have come up with blockchain!

Now that the blockchain itself is actually not novel, it was already a part of Git at the time of the Bitcoin white paper. The novel part, I believe, was the proof-of-work concept.
Even proof of work was not novel, there were proposals for fighting email spam with similar techniques. Bitcoin's fortune is combining the right pieces at the right time and getting sufficient buy-in to become relevant and more difficult to ignore.
Yes I take blockchain to mean proof of work (or proof in general) validating blocks such that you can track time to some extent in a system that cannot be sure of time because of being distributed and nodes not being trusted.
Haskell was one of my most important discoveries; it affected my thinking and approach to software engineering the most.

However, as I mentioned in the opening section, I deliberately removed programming languages from candidates for several reasons: 1. They received enough praise already. 2. My presentation would be very biased. 3. The article would be way too long.

> Git was nothing like Subversion. It had a steep learning curve and confused everyone to no end

I've actually found git much easier to teach to people who don't know subversion than to people who do. It's still a confusing mess, though. Why do you create a branch with `git checkout -b` rather than something like `git branch -c` (`-c` to checkout new branch)?

It looks like the `git switch` command helps a lot, but I never remember to try to use it as I'm used to the old ways, so I never teach it to new people either. I wish I could alias `git branch` and `git checkout` to remind me to use `git switch` but you can't alias over a built in command.

I started on mercurial, then git, and I think that was the happy path / easy on-ramp. Actually I still mostly prefer hg, but it has some downsides and the overall ecosystem really prefers git.
For teaching to newbies, please use the new commands! Much better to distinguish `git switch` from `git restore` than to use `git checkout` for all possible tasks.
One day, I'm working on a Linux machine with my Emacs open, I'm using a Bazel to clean my today's to-do list project. And I open the browser to find a person who wrote a blog about Boost.graph which I never heard about, but I'm really interested to look at. I finish this writing, save the buffer and =C-c g= to lunch magit to write a commit message "good day", then pushed to my git repo.