I think there's some point on the spectrum between "commit your dotfiles to git" and Nix that would be useful, I don't know what it is though. Containerization is kinda like this, but they're entirely imperatively defined rather than declarative and I wouldn't really want to use a docker container as my main system environment.
I wouldn't want a docker container as my main environment, but I do like having NixOS managing my main environment for a few reasons.
First, the declarative nature of everything makes it clear and easy to know what is actually installed on my computer. I can simply look at my configuration file and see if a program is installed, and if it's not. If I want to uninstall something, I delete the program from the configuration.nix and rebuild. This might not seem insignificant, but to me it's game changing. How many times have you uninstalled things in Ubuntu or something and had a ton of lingering transitive dependencies? How many times have you been trying to debug a problem, end up installing a million things, and then painstakingly having to track down every unnecessary dependency and transitive dependency that you ended up installing, only to miss something for months? Maybe most people here are better at this than I am, but these things happened to me all the time.
Second, the declarative nature of NixOS makes snapshotting trivial. Again, this is game-changing for me, and it makes fixing stuff on my computer more fun and less scary. If I break something, all I have to do is reboot and choose the last generation, then fix it.
This might not seem like a big deal, and again maybe for people smarter than me it's not, but for me it completely changed the way I deal with computers. When I first started using Ubuntu, when I would do something like break the video driver or the WiFi driver, I would end up having to nuke the system and start again, because I would get into a state where I didn't know how to fix it. I probably could fix these things now, I've been doing this stuff for awhile, but even still, it's nice to be able to not ever have to worry about getting into a state like that.
That and when things do error, the error messages may as well be generated from /dev/random
It seems like flakes are another way to do that, but they seem way too over-complicated for my taste.
This is not a small difference.
I work at a place that uses Nix for almost everything. Despite that, most developers do not like it (and usually create tickets asking the "experts" to fix things). The above quote is basically exactly what the experts are always telling the developers. That, along with "you just need to try harder." As if it's not valid that someone can think Nix isn't ergnomic and often sucks to use.
I personally don't mind it all that much, although nowadays I just use it for home-manager. But I've seen people go from disliking it to hating it because of the way some experienced Nix people have treated them.
It’s inherently hard to learn new things, especially if they’re contrary to things that you’ve been doing for N years, so I understand frustration, but that doesn’t imply that Nix itself is more difficult than anything else.
There are plenty of things that aren’t inherently difficult for most humans, but are hard to learn simply because they’re different. I don’t know that Spanish is a more difficult language than English, but I would have trouble learning it just because I have spent my entire life speaking English and approximately none of it speaking Spanish. This doesn’t mean Spanish is more difficult than English.
I will agree that the Nix language itself is kind of a pain in the ass with wonky syntax, though I have grown to kind of like it begrudgingly.
The conceptual problem with Docker isn't imperative vs declarative. It's that Docker doesn't even try to be reproducible. Executing the same Dockerfile twice doesn't necessarily build you the same container.
(Imperative vs declarative is still an interesting problem to think about, it's just independent of reproducibility in the abstract.)
Nix's strength and weakness is that it wants to take over everything, and if you want to do something without it, you might be in a world of pain. And after doing more or less standard unixy things for 20+ years, it's difficult to hand over control to a new thing like that.
git also has a clear model (the Merkle tree of file and directory nodes) but a famously unfriendly UI (git checkout does 5 or more unrelated things)
Some people do not like git, but I get the feeling that most people just use it, and get on with their day.
Why the difference with Nix? Maybe because building packages is inherently slower. Whereas you can quickly get yourself intro trouble with git, but you can also quickly get out of trouble (rm -rf, git clone)
Maybe Nix is more stateful? Although the git index/staging area I find to be a fabulously odd piece of state, and honestly breaks all the rules when I think about CLIs
Also Nix does rely on a very big global repo, whereas git doesn't
It also seems that Nix's model is less clean, and perhaps doesn't match the problem domain as well ... there are disagreements on whether it is "reproducible", etc.
Or maybe it's just a harder problem
Just today I was working on some integrations with a runtime dependency resolver for shell programs that uses OSH for parsing on the job. We use Nix to manage our development environments, and we use it to make some small wrappers and tools written in Bash into something portable and reproducible that we can include in development environments that run both on Linux and macOS.
Historically we've just included them inline in our Nix files, but thanks to resholve, we're switching to a nicer system so that they live in separate files that are more pleasant to edit. The "source code" of the scripts lives in the repo as normal bash scripts, but when they get built into the development environment, all command invocations get automatically replaced with hard-coded references to the paths of the relevant executables in the Nix store, the shebang gets pinned to a specific bash version in the same way, and they also get run through ShellCheck. Now we have not only a really nice and quick way to define portable wrappers in our Nix code, but a sane way to manage longer scripts without any portability issues.
So thanks for your cool shell and associated tools and libs!
> Or maybe it's just a harder problem
Fwiw, I think this is true.
> Some people do not like git, but I get the feeling that most people just use it, and get on with their day.
I think one of the other devs on my team probably feels this way. He thinks it's conceptually cool but is somewhat horrified by the complexity and UI. He makes simple uses of it in ways that have precedent on our team, but never really dives in.
> Why the difference with Nix?
Nix didn't have a celebrity author to spur adoption early on, in some ways it can be slow, and I think maybe it isn't as much better than entrenched alternative stacks than Git was as opposed to SVN. The pain of SVN was very acute for the average developer. I'm not sure that any of the pains of dependency hell, stateful configuration management, distribution of portable executables, etc., are quite as acute for the average operator or developer as that. People who feel Nix makes their professional lives easier tend to have come to it after their career has inflicted more specialized pain upon them.
Using Git also doesn't generally (ever?) involve writing code in a Turing-complete language, but to make the best use of Nix, you do have to do that. The paradigm of that language is not very mainstream, either, and although it's generally suited to its domain imo, it certainly has some warts.
Now that Oils has been completely translated to native code (as of last year), we should probably find a way to officially support that functionality.
It is basically built on 'osh --tool syntax-tree foo.sh' ( https://oils.pub/release/0.28.0/doc/ref/chap-front-end.html )
I've also gotten a request for "tree-shaking", which is very related
Thanks for letting me know it's useful!
---
And on reflection I do think Nix has a harder problem, in part because it has to deal with the "outside messy world", where as git just stores files. For example, I noticed that on Debian the set of root packages is actually pretty coupled to apt-get. So any package manager has to have some hacks. Also OS X and libc make that even harder, etc. Some decisions are at the mercy of the OS itself
In a way, I suppose resholve also directly shares a goal of Oils itself— namely, to make shell scripts "more like 'real programs'". YSH pursues this goal through more powerful and flexible language constructs, greater facility with data structures, more ergonomic error messages and other feedback for the user, things like that. Resholve pursues this goal by trying to make it possible for shell programs— even shell programs that rely on a mixture of third-party programs from God-knows-where— can be more portable, less sensitive to changes in the environment, and more amenable to a kind of static analysis of their behavior and dependencies. And both try to achieve their missions in a "conservative" way, letting users retain (or continue to write) code written in the shell language they're most familiar with.
Certainly here on HN, "disruptive" innovation gets a lot more consideration (and praise). But I think that "conservative" innovation of the kind I've just outlined is sometimes even more ambitious and challenging. It's a great thing to see such projects manage to produce interesting and useful results.
So long live Nix, resholve, and Oils!
Nix is:
1. difficult & different, where similar-ish tools are straightforward & familiar, (e.g. cloud-init, ansible, vs NixOS; or devcontainers using Dockerfiles, vs nix shells).
2. demands a significant amount of understanding, even for tasks which you'd expect to be easy.
e.g.: git is difficult, but you can get by with rote memorizing 5 commands (& copy-pasting the repo if you mess up). Emacs is difficult, but you're not required to use it. Haskell can be difficult to work with, etc.
I'd say that running `direnv allow` & using nix that someone else has written is unlikely to be difficult. But, having to write your own Nix code can be quite high friction.
> It also seems that Nix's model is less clean
I think nixpkgs is cluttered with organic mess of inconsistent designs.. but I think there's also friction where Nix's ideal package is built with `./configure && make && make install`, and many packages aren't quite that clean.
That would be configuration management tools such as Salt/Puppet/Ansible/Chef.
They were popular ten years ago, and gained a lot of exposure as the devops movement gained ground, but they never stopped being useful.
Having your non-running state defined declarative is powerful, and if you can define a single source of truth for entire distributed systems, that suddenly makes you able to reason about state on whole systems.
I want to reach into a big tree of derivations and force library and compiler versions to a single common one so we don't, for example, have 6 rust compilers being used.
The https://codeberg.org/amjoseph/infuse.nix project looks nice as a way to simplify annoying chains of overrides; though I haven't used it personally.
For me (even though I use NixOS the desktop) there is a difference between desktops and servers. I can set up a desktop pretty quickly - install a bunch of flatpaks, checkout a bunch of dotfiles and I don't do it often.
Also, popular desktops like Fedora tend to be far more polished than the NixOS desktop, which has all kinds of glitches. Just to name two current ones: (1) gdm login will fail if you are too fast and log in before WiFi is up (usually you are thrown back in gdm, sometimes the session freezes up completly); (2) fwupd firmware updates usually fail.
On the other hand, on servers and remote development VMs, the setup work is annoying because I spin up/down machines far more frequently and managing them as pets gets old pretty quickly. So NixOS is much nicer, because you can have a system up and identical in 5 minutes. You could of course approximate it with something like Ansible on non-NixOS.
Though, I think the differences will become smaller since Fedora-based immutable systems will switch from OSTree to bootable containers soon [1].
Of course, you can use Nix on another immutable distro than NixOS.
[1] https://docs.fedoraproject.org/en-US/bootc/getting-started/