Some parts could be smoother.
Here's a rough sketch: the Nix expression language is really configuration oriented; it's a "JSON + functions" kind of language. You write Nix to describe how a package is built; the ideal case being "./configure && make && make install" as such. The resulting packages are put in a Nix store. (Almost) every dependency is put in the Nix store; so your program links against libraries in the Nix store, or runs other sources from the Nix store.
- Nix is "just" declarations of those instructions which output into directories and everything gets symlinked. But, it can take time to build an intuition for how to do things.
- There's some fundamental friction where most Linux systems assume shared libraries are available globally in a typical place on Linux. -- e.g. Python's "wheels" come with precompiled dependencies which assume shared libraries are available in a global place. Nix doesn't provide that.
- "Why not just provide globals?" For one, by having everything not be global, you can have multiple versions available at the same time.
- Since Nix is quite 'strict' by default about everything coming from the Nix store, it practically means 'paying' for all the difficulties up front. (There's a trade-off where you could write packages in a less strict manner; this is great for iterating, but bad for maintainability).
- Since Nix is strict about symlinking all dependencies, often if upstream software does things in a "quick and dirty manner" (e.g. hardcodes "/bin/bash", hardcodes paths for binaries to run, etc.) then it can be difficult to describe how to package that software with Nix. -- Fundamentally, you're taking something which works loosely, and bringing it into a stricter system.
- Upthread the comment mentions "flakes". Flakes provide both dependency management (i.e. being able to declare other Nix codebases you'll use), as well as a standard entrypoint into a Nix codebase. -- Without flakes, the UX is a bit cumbersome..
- The majority of packages which people use come from "Nixpkgs" package repository. This has a lot of organic complexity to it, coming from multiple contributors, with competing ideas for achieving results.
- With Nix being a "json + functions" language.. not sure I'm articulating this right, but it means that practically a large codebase is built as a single 'expression' (i.e. soft boundaries between bits of code).. and the tooling for troubleshooting problems is ... not very good.
- The Nix expression language is functional and lazy. This can be rough for people who don't have this background.
- Since Nix adds a layer of abstraction, it means you might need to have both a broad and a deep understanding to get something working (e.g. understanding how to drive Python or Linux in non-conventional ways). -- A kind of "do everything properly" which more conventional systems don't require.
So ... some aspects could be easier. But I think there's a fundamental friction to it.
Here's a rough sketch: the Nix expression language is really configuration oriented; it's a "JSON + functions" kind of language. You write Nix to describe how a package is built; the ideal case being "./configure && make && make install" as such. The resulting packages are put in a Nix store. (Almost) every dependency is put in the Nix store; so your program links against libraries in the Nix store, or runs other sources from the Nix store.
- Nix is "just" declarations of those instructions which output into directories and everything gets symlinked. But, it can take time to build an intuition for how to do things.
- There's some fundamental friction where most Linux systems assume shared libraries are available globally in a typical place on Linux. -- e.g. Python's "wheels" come with precompiled dependencies which assume shared libraries are available in a global place. Nix doesn't provide that.
- "Why not just provide globals?" For one, by having everything not be global, you can have multiple versions available at the same time.
- Since Nix is quite 'strict' by default about everything coming from the Nix store, it practically means 'paying' for all the difficulties up front. (There's a trade-off where you could write packages in a less strict manner; this is great for iterating, but bad for maintainability).
- Since Nix is strict about symlinking all dependencies, often if upstream software does things in a "quick and dirty manner" (e.g. hardcodes "/bin/bash", hardcodes paths for binaries to run, etc.) then it can be difficult to describe how to package that software with Nix. -- Fundamentally, you're taking something which works loosely, and bringing it into a stricter system.
- Upthread the comment mentions "flakes". Flakes provide both dependency management (i.e. being able to declare other Nix codebases you'll use), as well as a standard entrypoint into a Nix codebase. -- Without flakes, the UX is a bit cumbersome..
- The majority of packages which people use come from "Nixpkgs" package repository. This has a lot of organic complexity to it, coming from multiple contributors, with competing ideas for achieving results.
- With Nix being a "json + functions" language.. not sure I'm articulating this right, but it means that practically a large codebase is built as a single 'expression' (i.e. soft boundaries between bits of code).. and the tooling for troubleshooting problems is ... not very good.
- The Nix expression language is functional and lazy. This can be rough for people who don't have this background.
- Since Nix adds a layer of abstraction, it means you might need to have both a broad and a deep understanding to get something working (e.g. understanding how to drive Python or Linux in non-conventional ways). -- A kind of "do everything properly" which more conventional systems don't require.
So ... some aspects could be easier. But I think there's a fundamental friction to it.