posts: take Standard out of draft
This commit is contained in:
157
src/pages/blog/std.md
Normal file
157
src/pages/blog/std.md
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
---
|
||||||
|
layout: $/layouts/post.astro
|
||||||
|
title: From DevOS to Standard
|
||||||
|
description: Why we made Standard, and what it has done for us.
|
||||||
|
tags:
|
||||||
|
- std
|
||||||
|
- nix
|
||||||
|
- devops
|
||||||
|
author: Tim D
|
||||||
|
authorGithub: nrdxp
|
||||||
|
date: 2022-10-31
|
||||||
|
---
|
||||||
|
|
||||||
|
## Two years later...
|
||||||
|
|
||||||
|
DevOS started as a fun project to try and get better with Nix and understand this weird new thing
|
||||||
|
called flakes. Since then and despite their warts, Nix flakes have experienced widespread use, and
|
||||||
|
rightfully so, as a mechanism for hermetically evaluating your system & packages that fully locks
|
||||||
|
your inputs and guarantees you some meaningful level of sanity over your artifacts.
|
||||||
|
|
||||||
|
Yet when I first released it, I never even imagined so many people would find DevOS useful, and I
|
||||||
|
have been truly humbled by all the support and contributions that came entirely spontaneously to the
|
||||||
|
project and ultmately culminated in the current version of [digga][digga], and the divnix org that
|
||||||
|
maintains it.
|
||||||
|
|
||||||
|
## Back to Basics
|
||||||
|
|
||||||
|
For whatever reason, it really feels like time to give a brief update of what has come of this
|
||||||
|
little community experiment, and I'm excited to hopefully clear up some apparent confusion, and
|
||||||
|
hopefully properly introduce to the world [Standard](https://github.com/divnix/std).
|
||||||
|
|
||||||
|
DevOS was never meant to be an end all be all, but rather a heavily experimental sketch while
|
||||||
|
I stumbled along to try and organize my Nix code more effectively. With Standard, we are able to
|
||||||
|
distill the wider experience of some of its contributors, as well as some new friends, and design
|
||||||
|
something a little more focused and hopefully less magical, while still eliminating a ton of
|
||||||
|
boilerplate. Offering both a lightly opinionated way to organize your code into logically typed
|
||||||
|
units, and a mechanism for defining "standard" actions over units of the same type.
|
||||||
|
|
||||||
|
Other languages make this simple by defining a module mechanism into the language where users are
|
||||||
|
freed from the shackles of decision overload by force, but Nix has no such advantage. Many people
|
||||||
|
hoped and even expected flakes to alleviate this burden, but other than the schema Nix expects
|
||||||
|
over its outputs, it does nothing to enforce how you can generate those outputs, or how to organize
|
||||||
|
the logical units of code & configuration that generate them.
|
||||||
|
|
||||||
|
## A Departure from Tradition
|
||||||
|
|
||||||
|
It is fair to say that nixpkgs module system as become the sort of "goto" means of managing
|
||||||
|
configuration in the Nix community, and while this may be good at the top-level where a global
|
||||||
|
namespace is sometimes desirable, it doesn't really give us a generic means of sectioning off our
|
||||||
|
code to generate both configuration _and_ derivation outputs quickly.
|
||||||
|
|
||||||
|
In addition to that, the module system is fairly complex and is a bit difficult to anticate the
|
||||||
|
cost of ahead of time due to the fixed-point. The infamous "infinite traces" that can occur during
|
||||||
|
a Nix module evaluation almost never point to the actual place in your code where the error
|
||||||
|
originates, and often does even contain a single bit of code from the local repository in the trace.
|
||||||
|
|
||||||
|
Yet as the only real game in town, the module system has largely "de facto" dictated the nature
|
||||||
|
of how we organize our Nix code up til now. It lends itself to more of a "depth first" approach
|
||||||
|
where modules can recurse into other modules ad infinitum.
|
||||||
|
|
||||||
|
## A Simpler Structure
|
||||||
|
|
||||||
|
Standard, in contrast, tries to take an alternative "breadth first" approach, ecouraging code
|
||||||
|
organization closer to the project root. If true depth is called for, flakes using Standard can
|
||||||
|
compose gracefully with other flakes, whether they use Standard or not.
|
||||||
|
|
||||||
|
It is also entirely unopionated on what you output, there is nothing stopping you simply exporting
|
||||||
|
NixOS modules themselves, for example, giving you a nice language level compartmentalization
|
||||||
|
strategy to help manager your NixOS, Home Manager or Nix Darwin configurations.
|
||||||
|
|
||||||
|
In simple terms, why should we bother writing the same script logic over and over when we can be
|
||||||
|
guaranteed to recieve an output of a specific type, which guarantees any actions we define for the
|
||||||
|
type at large will work for us: be it deploying container images, publishing sites, running
|
||||||
|
deployments, or invoking tests & builds.
|
||||||
|
|
||||||
|
We can ensure that each image, site, or deployment is tested, built, deployed and published in
|
||||||
|
a sane and well-defined way, universally. In this way, Standard is meant to not only be convenient,
|
||||||
|
but comprehensive, which is an important property to maintain when codebases grow to non-trivial
|
||||||
|
size.
|
||||||
|
|
||||||
|
There is also no fixed-point so, anecdotably, I have yet to hit an eval error in Standard based
|
||||||
|
projects that I couldn't quickly track down, try saying that about the module system.
|
||||||
|
|
||||||
|
## A CLI for productivity
|
||||||
|
|
||||||
|
The Nix cli can sometimes feel a little opaque and low-level. It isn't always the best interface
|
||||||
|
to explain and explore what we can actually _do_ with a given project. To address this issue in
|
||||||
|
a minimal and clean way, we package a small go based cli/tui combo to quickly answer exactly this
|
||||||
|
question, "What can I do with this project?".
|
||||||
|
|
||||||
|
This interface is entirely optional, but also highly useful and really rather trivial thanks to a
|
||||||
|
predicatable structure and well typed outputs given to us in the Nix code. The schema for anything
|
||||||
|
you can do follows the same pattern: "std //$cell/$block/$target:$action". Here the "cell" is the
|
||||||
|
highest level "unit", or collection of "blocks", which are well-typed attribute sets of "targets"
|
||||||
|
sharing a colleciton of common "actions" which can be performed over them.
|
||||||
|
|
||||||
|
## A New Challenger Approaches
|
||||||
|
|
||||||
|
For a small project with a single package and maybe one Nix shell to develop it, "Standard" may
|
||||||
|
not be entirely necessary, though hopefully not overly encumbering either. But for projects like
|
||||||
|
even nixpkgs itself, that have branched off into hundreds or even thousands of project specifc
|
||||||
|
derivations, Standard can be invaluable in keeping the complexitly of those interelated pieces
|
||||||
|
maintainable over the long term.
|
||||||
|
|
||||||
|
We have gotten plenty of feedback from the early adopters of Standard, and one main comment was its
|
||||||
|
percieved monolithic takeover of the Nix code. This is largely more percention than reality, as
|
||||||
|
Standard actually encourages you to generate additional outputs.
|
||||||
|
|
||||||
|
In fact, you can write as many output sets as you like; the [growOn][grow] function which is
|
||||||
|
typically your entrypoint into a Standardized codebase is a varaidic function taking any number of
|
||||||
|
attribute sets as arguments, where only the first set is specific to Standard. The rest are merged
|
||||||
|
together, taking the same schema as a regular flake; giving you another mechanism for organizing
|
||||||
|
your flake outputs cleanly. Use one set to ["harvest"][harvest] Standard outputs to their
|
||||||
|
corresponding expected flake paths for compatibility, use another to use other flake frameworks
|
||||||
|
independantly (flake-parts, dream2nix, etc).
|
||||||
|
|
||||||
|
Despite this, there are pieces that work well on their own, and defining them into their own
|
||||||
|
independantly useful libraries is helpful for everyone, not just Standard users. One good example is
|
||||||
|
[nosys][nosys] which was recently derived from Standard. It can be used independantly to make flake
|
||||||
|
system handling dead simple, or it can be paired up for use on these additional attribututes passed
|
||||||
|
to growOn to get the same simplified system management that Standard supplies for all your flakes
|
||||||
|
outputs!
|
||||||
|
|
||||||
|
## Encouraging Cooperation
|
||||||
|
|
||||||
|
Standard has also given us a useful mechanism for contributing back to upstream where it makes
|
||||||
|
sense. We are all about maintaining well-defined boundaries, and we don't want to reimplement the
|
||||||
|
world if the problem would be better solved elsewhere. Work on Standard has already led to several
|
||||||
|
useful contributions to both nixpkgs and even a few in nix proper, as well as some in tangentially
|
||||||
|
related codebases, such as github actions and go libraries.
|
||||||
|
|
||||||
|
One very exciting example of this cooperation is the effort we've expended integrating
|
||||||
|
[nix2container][n2c] with Standard. The work has given us insights and position to begin defining an
|
||||||
|
officially supported specification for [OCI images][oci] built and run from Nix store paths, which
|
||||||
|
is something that would be a huge win for developers everywhere!
|
||||||
|
|
||||||
|
We believe interoperability with existing standards is how Nix can ultimately cement itself into
|
||||||
|
the mainstream, and in a way that is unoffensive and purely additive.
|
||||||
|
|
||||||
|
## CI simplified
|
||||||
|
|
||||||
|
Instead of making this a mega post, I'll just leave this as a bit of a teaser for a follow-up post
|
||||||
|
which will explore our recent efforts to bring the benefits Standard to GitHub Actions _a la_
|
||||||
|
[std-action][action]. The target is a Nix CI system that avoids ever doing the same work more than
|
||||||
|
once, whether its evaluating or building, and versatile enough to work from a single user project
|
||||||
|
all the way up to a large organization's monorepo.
|
||||||
|
|
||||||
|
All in parallel and with automatic coverage for any Standard blocks specified to run in CI in the
|
||||||
|
flake.nix. Stay tuned...
|
||||||
|
|
||||||
|
[digga]: https://github.com/divnix/digga
|
||||||
|
[nosys]: https://github.com/divnix/nosys
|
||||||
|
[action]: https://github.com/divnix/std-action
|
||||||
|
[grow]: https://std.divnix.com/guides/growing-cells.html
|
||||||
|
[harvest]: https://github.com/divnix/std/blob/main/src/harvest.nix
|
||||||
|
[n2c]: https://github.com/nlewo/nix2container
|
||||||
|
[oci]: https://github.com/opencontainers/image-spec/issues/922
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
---
|
|
||||||
layout: $/layouts/post.astro
|
|
||||||
title: From DevOS to Standard
|
|
||||||
description: Why we made Standard, and what it has done for us.
|
|
||||||
tags:
|
|
||||||
- std
|
|
||||||
- nix
|
|
||||||
- devops
|
|
||||||
author: Tim D
|
|
||||||
authorGithub: nrdxp
|
|
||||||
date: 2022-10-31
|
|
||||||
---
|
|
||||||
|
|
||||||
## Two years later...
|
|
||||||
DevOS started as a fun project to try and get better with Nix and understand this weird new thing
|
|
||||||
called flakes. Since then and despite their warts, Nix flakes have experienced widespread use, and
|
|
||||||
rightfully so, as a mechanism for hermetically evaluating your system & packages that fully locks
|
|
||||||
your inputs.
|
|
||||||
|
|
||||||
Yet when I first release it, I never even imagined so many people would find DevOS useful, and I
|
|
||||||
have been truly humbled by all the support and contributions that came entirely spontaneously to the
|
|
||||||
project and ultmately culminated in the current version of digga, and the divnix org that maintains
|
|
||||||
it.
|
|
||||||
|
|
||||||
|
|
||||||
## Back to Basics
|
|
||||||
For whatever reason, it really feels like time to give a brief update of what has come of this
|
|
||||||
little community experiment, and I'm excited to hopefully clear up some apparent confusion, and
|
|
||||||
hopefully properly introduce to the world [Standard](https://github.com/divnix/std).
|
|
||||||
|
|
||||||
DevOS was never meant to be an end all be all, but rather a heavily experimental sketch while
|
|
||||||
I stumbled along to try an organize my Nix code more effectively. With Standard, we are able to
|
|
||||||
distill the wider experience of some of the largest contributors and design something a little more
|
|
||||||
focused and hopefully less magical, while still eliminating a ton of boilerplate. Offering both a
|
|
||||||
lightly opinionated way to organize your code into logically typed units, and a mechanism for
|
|
||||||
defining "standard" actions over units of the same type.
|
|
||||||
|
|
||||||
Other languages make this simple by defining a module mechanism into the language where users are
|
|
||||||
freed from the shackles of decision overload by force, but Nix has no such advantage. Many people
|
|
||||||
hoped and even expected flakes to alleviate this burden, but other than the schema Nix expects
|
|
||||||
over its outputs, it does nothing to enforce how you can generate those outputs, or how to organize
|
|
||||||
the logical units of code & configuration that generate them.
|
|
||||||
|
|
||||||
Many people point to the nixpkgs module system as the sort of "goto" means of managing
|
|
||||||
configuration, and while this may be true at the top-level where a global namespace is sometimes
|
|
||||||
desirable, it doesn't really give us a generic means of sectioning off our code to generate both
|
|
||||||
configuration _and_ derivation outputs quickly.
|
|
||||||
|
|
||||||
In addition to that, the module system is fairly complex and is a bit difficult to anticate the
|
|
||||||
cost of ahead of time due to the fixed-point. The infamous "infinite traces" that can occur during
|
|
||||||
a Nix module evaluation almost never point to the actual place in your code where the error
|
|
||||||
originates, and often does even contain a single bit of code from the local repository in the trace.
|
|
||||||
|
|
||||||
## A Departure from Tradition
|
|
||||||
As the only real game in town, the module system has largely "de facto" dictated the nature
|
|
||||||
of how we organize our Nix code up til now. It lends itself to more of a "depth first" approach
|
|
||||||
where modules can recurse into other modules ad infinitum. Standard, in contrast, tries to take an
|
|
||||||
alternative "breadth first" approach, ecouraging code organization closer to the project root. If
|
|
||||||
true depth is called for, flakes using Standard can compose gracefully with other flakes using it
|
|
||||||
_and_ those that don't.
|
|
||||||
|
|
||||||
For a small project with a single package and maybe one Nix shell to develop it, "Standard" may
|
|
||||||
not be entirely necessary, though hopefully not overly encumbering either. But for projects like
|
|
||||||
even nixpkgs itself, that have branched off into hundreds or even thousands of project specifc
|
|
||||||
derivations, Standard can be invaluable in keeping the complexitly of those interelated pieces
|
|
||||||
maintainable over the long term.
|
|
||||||
|
|
||||||
## A New Challenger Approaches
|
|
||||||
|
|
||||||
TODO
|
|
||||||
Reference in New Issue
Block a user