Is GNU Guix a minimal distribution, and what might that even mean?
Presented by Christopher Baines
**Hello**, my name is Chris.
I'm going to set out some thoughts here about software,
choices about how to use software, and how those relate to
values like minimalism.
In doing so, hopefully you'll be able to answer for
yourself, the question "Is GNU Guix a minimal
distribution?", and you'll have an idea of why that might
matter to you.
A little bit about me, I've been doing stuff in and around
Guix for the last few years now, I first got involved
around FOSDEM back in 2016.
First though, if you haven't heard of Guix, here's a small
introduction.
Package manager
System
Software deployment toolkit
I often find Guix a little tricky to explain as a project,
mainly because I feel you can do so much with it.
The first thing to say though, is that Guix is a package
manager.
(Next)
Packages in this case are software packages, and
Guix can manage them, so Guix can help with things like
installing software.
Guix includes a large number of package definitions, over
15,000 at the time I'm recording this talk, There's a
whole range of software, written in many different
languages, doing many different things.
While Guix works on distributions using either Linux, or
the GNU Hurd, Guix also provides the tooling and
configuration to form a working operating system. This is
normally referred to as a Guix system.
(Next)
So, Guix is a package manager, with lots of package
definitions, and is also a distribution of GNU. That's
quite a lot already. But, there's more.
One not particularly specific, but apt description of Guix
is a software deployment toolkit.
(Next)
The guix pack command is a clear example of this. This
command allows you to take Guix packages, and wrap them up
in to tarballs, Docker images, and squashfs images. In
general, with the guix pack command can you use Guix to
deploy software to systems which don't have the Guix tools
available.
Returning to the "Is GNU Guix a minimal distribution?"
question. Surely with the description I've just given,
Guix can't be considered minimal, there's so much going
on!
Well, I've described Guix, but what does minimalism mean,
especially in the context of software.
Minimal software
Smaller systems that take less resources and consume less energy
Secure systems that are easy to understand
I think the properties set out in the call for papers for
the Declarative and Minimalistic Computing devroom are
pretty good, so that's what I'm going to paraphrase here.
(Next)
Firstly, smaller systems generally take less resources and
consume less energy. So resources in this context are
things like storage space and RAM.
(Next)
The second is: secure systems that are easy to understand.
Building on this, there's another perspective on
minimalism I want to consider.
Unix philosophy, point 1
Make each program do one thing well. To do a new job,
build afresh rather than complicate old programs by adding
new "features".
The Unix philosophy is a few ideas about building software
and systems, it's from a while back, but still pretty
relevant today. I'm just going to mention the first of the
4 points.
That point is: make each program do one thing well. To do
a new job, build afresh rather than complicate old
programs by adding new "features".
Focusing on the "make each program do one thing well", I
think that's really relevant, especially in the context of
minimalism, but how do you determine if a program is doing
one thing?
Fundamentally, all tasks can be broken down, and you can
see this in the way that software is often
written. Programs can be broken down in to small reusable
parts, often called procedures or functions that do "one
thing", and the code within those functions can be further
broken down with each line doing "one thing".
If you're familiar with writing software, you'll probably
know that how you break down a problem in to code to
tackle it is very important, not just for solving the
problem, but also doing so in a maintainable manor.
Does Guix do one thing?
Going back to the question of whether Guix is a minimal
distribution, I think it's relevant to ask if Guix does
one thing, and if so, what that is?
The first way of answering this, is no, I listed some
things that Guix is earlier, a package manager, a
distribution, plus some tools like guix pack.
But, I think there's a better perspective. I think the one
problem Guix tackles is software deployment.
Guix tackles the problem of software deployment
Now I mean deployment here in a very general sense, often
you deploy to some computer you're not sitting next to,
but I think getting some software running on your local
machine is deployment as well, you're still taking some
software and making it work.
Because Guix can be used to manage software, manage
service configuration, configure whole systems and
generate things like system images or software bundles in
various forms, Guix can capably handle a broad range of
software deployment tasks.
These are tasks that in the past, would have probably been
handled by separate tools. I think the consolidation that
Guix provides is a step forward, and is something that
just happens naturally over time.
In computer hardware for example, features
that you once would have had separate hardware for like
sound cards or network cards have been consolidated in to
motherboards. Aspects of motherboards have been
consolidated in to processors, and this generally happens
because the advantages outweigh the costs.
To show this, rather than just state it, and highlight
what's different about using Guix or an approach like it,
I'm going to try and articulate what the opposite approach
looks like.
What happens if you don't treat software deployment as one
problem, but as multiple smaller interrelated problems,
and use multiple tools.
For the last few years, I've been working with the Ruby on
Rails web development framework, I also worked on
packaging it for Guix, so I'm using this as my
example.
This isn't something you should follow, I'm just trying to
set the scene for what tackling a problem with minimal use
of Guix might mean.
I'm roughly following the "Installing Rails" section of
the Getting started guide.
First there are 4 prerequsites: Ruby, SQLite3, Node.js and
Yarn. I'm going to use Guix to provide Ruby, Sqlite and
Node. Guix doesn't yet have a package for Yarn, I'm going
to install it with NPM. To try and limit the impact on the
rest of my system, I'm using direnv to manage the
environment.
With Rubygems, I'm installing Rails. This gets me the
rails command.
Rubygems is the language specific package manager for Ruby.
That's now finished, this recording is running at 1.2
times speed so it doesn't take so long.
I'm then running the command: rails new blog, which
creates a new Rails app.
This does a few interesting things, a second tool related
to trying to manage Ruby gems appears, bundler. While
Rubygems is a package management framework for Ruby,
bundler is a tool to try and make sure Ruby applications
run the same code on every machine.
That's not the end of the package management going on
though, the rails new command invokes yarn to install some
packages, something called webpacker I believe, which
pulls in roughly 600 packages through yarn.
So, with the problem being installing Rails, there are a
number of tools involved here, and it is possible to
describe each as doing just one thing.
Guix was used to install prerequsites, apart from
yarn. npm was used to install yarn. Rubygems was used to
install Rails, at least parts of it. Bundler came in to
the mix, which provides a more strict way of using
gems. Then finally yarn was used to install webpacker.
So, what are the disadvantages of this fragmented
approach?
The fragmented approach
Time spent using multiple tools
More state to manage
Limited functionality due to lack of interoperation
Raises the cost for diverse tooling
Dependent on many tools
(Next)
Firstly, you as the user are spending time dealing with
several tools, 4 or 5 in this example, depending on how
you count.
They don't really interoperate, Rails runs bundler and
yarn, but that's not really interoperation at the package
manager level.
(Next)
You've also got lots of state to manage.
To illustrate, here are I think some of the files that
were created tracking state about what software I'm
deploying for this Rails app.
Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '3.0.0'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.1.1'
# Use sqlite3 as the database for Active Record
gem 'sqlite3', '~> 1.4'
# Use Puma as the app server
gem 'puma', '~> 5.0'
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 5.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use Active Storage variant
# gem 'image_processing', '~> 1.2'
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.4', require: false
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end
group :development do
# Access an interactive console on exception pages or by calling 'console' anywhere in the code.
gem 'web-console', '>= 4.1.0'
# Display performance information such as SQL time and flame graphs for each request in your browser.
# Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md
gem 'rack-mini-profiler', '~> 2.0'
gem 'listen', '~> 3.3'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
end
group :test do
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '>= 3.26'
gem 'selenium-webdriver'
# Easy installation and use of web drivers to run system tests with browsers
gem 'webdrivers'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
The is a Gemfile, this is used by Bundler, which works on
top of Rubygems.
This file says something about the Ruby version, this is
just a check. There's also a .ruby-version file that's
been created, I'm unsure what the reason behind that is.
This file lists the gems that are wanted, along with
constraints for the dependency resolver.
Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
actioncable (6.1.1)
actionpack (= 6.1.1)
activesupport (= 6.1.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.1.1)
actionpack (= 6.1.1)
activejob (= 6.1.1)
activerecord (= 6.1.1)
activestorage (= 6.1.1)
activesupport (= 6.1.1)
mail (>= 2.7.1)
actionmailer (6.1.1)
actionpack (= 6.1.1)
actionview (= 6.1.1)
activejob (= 6.1.1)
activesupport (= 6.1.1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.1.1)
actionview (= 6.1.1)
activesupport (= 6.1.1)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.1.1)
actionpack (= 6.1.1)
activerecord (= 6.1.1)
activestorage (= 6.1.1)
activesupport (= 6.1.1)
nokogiri (>= 1.8.5)
actionview (6.1.1)
activesupport (= 6.1.1)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (6.1.1)
activesupport (= 6.1.1)
globalid (>= 0.3.6)
activemodel (6.1.1)
activesupport (= 6.1.1)
activerecord (6.1.1)
activemodel (= 6.1.1)
activesupport (= 6.1.1)
activestorage (6.1.1)
actionpack (= 6.1.1)
activejob (= 6.1.1)
activerecord (= 6.1.1)
activesupport (= 6.1.1)
marcel (~> 0.3.1)
mimemagic (~> 0.3.2)
activesupport (6.1.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
bindex (0.8.1)
bootsnap (1.5.1)
msgpack (~> 1.0)
builder (3.2.4)
byebug (11.1.3)
capybara (3.34.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (~> 1.5)
xpath (~> 3.2)
childprocess (3.0.0)
concurrent-ruby (1.1.7)
crass (1.0.6)
erubi (1.10.0)
ffi (1.14.2)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.8.7)
concurrent-ruby (~> 1.0)
jbuilder (2.10.1)
activesupport (>= 5.0.0)
listen (3.4.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.8.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (1.0.0)
mimemagic (0.3.5)
mini_mime (1.0.2)
minitest (5.14.3)
msgpack (1.3.3)
nio4r (2.5.4)
nokogiri (1.11.1-x86_64-linux)
racc (~> 1.4)
public_suffix (4.0.6)
puma (5.1.1)
nio4r (~> 2.0)
racc (1.5.2)
rack (2.2.3)
rack-mini-profiler (2.3.0)
rack (>= 1.2.0)
rack-proxy (0.6.5)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (6.1.1)
actioncable (= 6.1.1)
actionmailbox (= 6.1.1)
actionmailer (= 6.1.1)
actionpack (= 6.1.1)
actiontext (= 6.1.1)
actionview (= 6.1.1)
activejob (= 6.1.1)
activemodel (= 6.1.1)
activerecord (= 6.1.1)
activestorage (= 6.1.1)
activesupport (= 6.1.1)
bundler (>= 1.15.0)
railties (= 6.1.1)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
railties (6.1.1)
actionpack (= 6.1.1)
activesupport (= 6.1.1)
method_source
rake (>= 0.8.7)
thor (~> 1.0)
rake (13.0.3)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
regexp_parser (1.8.2)
rubyzip (2.3.0)
sass-rails (6.0.0)
sassc-rails (~> 2.1, >= 2.1.1)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
selenium-webdriver (3.142.7)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
semantic_range (2.3.1)
spring (2.1.1)
sprockets (4.0.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.2)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.4.2)
thor (1.0.1)
tilt (2.0.10)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
web-console (4.1.0)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webdrivers (4.4.2)
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
selenium-webdriver (>= 3.0, < 4.0)
webpacker (5.2.1)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
websocket-driver (0.7.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.4.2)
PLATFORMS
x86_64-linux
DEPENDENCIES
bootsnap (>= 1.4.4)
byebug
capybara (>= 3.26)
jbuilder (~> 2.7)
listen (~> 3.3)
puma (~> 5.0)
rack-mini-profiler (~> 2.0)
rails (~> 6.1.1)
sass-rails (>= 6)
selenium-webdriver
spring
sqlite3 (~> 1.4)
turbolinks (~> 5)
tzinfo-data
web-console (>= 4.1.0)
webdrivers
webpacker (~> 5.0)
RUBY VERSION
ruby 3.0.0p0
BUNDLED WITH
2.2.3
Next is the Gemfile.lock, this goes along with the
Gemfile.
The Gemfile is what you edit, and the Gemfile.lock is
updated when the dependency resolver is run. It's a bit
longer than can fit on this slide.
package.json
{
"name": "blog",
"private": true,
"dependencies": {
"@rails/actioncable": "^6.0.0",
"@rails/activestorage": "^6.0.0",
"@rails/ujs": "^6.0.0",
"@rails/webpacker": "5.2.1",
"turbolinks": "^5.2.0"
},
"version": "0.1.0",
"devDependencies": {
"webpack-dev-server": "^3.11.1"
}
}
Switching tools, this is the package.json file which is
used by NPM the Node package manager, and in this case,
yarn, which was invoked as part of the rails new command.
Like the Gemfile, this includes lists of packages, with
constraints for a dependency resolver, just a different
one from the one I mentioned previously for the gem
dependencies.
yarn.lock
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.11":
version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
dependencies:
"@babel/highlight" "^7.10.4"
"@babel/compat-data@^7.12.5", "@babel/compat-data@^7.12.7":
version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.7.tgz#9329b4782a7d6bbd7eef57e11addf91ee3ef1e41"
integrity sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==
"@babel/core@^7.11.1":
version "7.12.10"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd"
integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/generator" "^7.12.10"
"@babel/helper-module-transforms" "^7.12.1"
"@babel/helpers" "^7.12.5"
"@babel/parser" "^7.12.10"
"@babel/template" "^7.12.7"
"@babel/traverse" "^7.12.10"
"@babel/types" "^7.12.10"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.1"
json5 "^2.1.2"
lodash "^4.17.19"
semver "^5.4.1"
source-map "^0.5.0"
"@babel/generator@^7.12.10", "@babel/generator@^7.12.11":
version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af"
integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==
dependencies:
"@babel/types" "^7.12.11"
jsesc "^2.5.1"
source-map "^0.5.0"
"@babel/helper-annotate-as-pure@^7.10.4":
version "7.12.10"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz#54ab9b000e60a93644ce17b3f37d313aaf1d115d"
integrity sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==
dependencies:
"@babel/types" "^7.12.10"
"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3"
integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==
dependencies:
"@babel/helper-explode-assignable-expression" "^7.10.4"
"@babel/types" "^7.10.4"
"@babel/helper-compilation-targets@^7.12.5":
version "7.12.5"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz#cb470c76198db6a24e9dbc8987275631e5d29831"
integrity sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==
dependencies:
"@babel/compat-data" "^7.12.5"
"@babel/helper-validator-option" "^7.12.1"
browserslist "^4.14.5"
semver "^5.5.0"
"@babel/helper-create-class-features-plugin@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz#3c45998f431edd4a9214c5f1d3ad1448a6137f6e"
integrity sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==
dependencies:
"@babel/helper-function-name" "^7.10.4"
"@babel/helper-member-expression-to-functions" "^7.12.1"
"@babel/helper-optimise-call-expression" "^7.10.4"
"@babel/helper-replace-supers" "^7.12.1"
"@babel/helper-split-export-declaration" "^7.10.4"
"@babel/helper-create-regexp-features-plugin@^7.12.1":
version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz#2084172e95443fa0a09214ba1bb328f9aea1278f"
integrity sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==
dependencies:
"@babel/helper-annotate-as-pure" "^7.10.4"
regexpu-core "^4.7.1"
"@babel/helper-define-map@^7.10.4":
version "7.10.5"
resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30"
integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==
dependencies:
"@babel/helper-function-name" "^7.10.4"
"@babel/types" "^7.10.5"
lodash "^4.17.19"
"@babel/helper-explode-assignable-expression@^7.10.4":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz#8006a466695c4ad86a2a5f2fb15b5f2c31ad5633"
integrity sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==
dependencies:
"@babel/types" "^7.12.1"
"@babel/helper-function-name@^7.10.4", "@babel/helper-function-name@^7.12.11":
version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz#1fd7738aee5dcf53c3ecff24f1da9c511ec47b42"
integrity sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==
dependencies:
"@babel/helper-get-function-arity" "^7.12.10"
"@babel/template" "^7.12.7"
"@babel/types" "^7.12.11"
"@babel/helper-get-function-arity@^7.12.10":
version "7.12.10"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz#b158817a3165b5faa2047825dfa61970ddcc16cf"
integrity sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==
dependencies:
"@babel/types" "^7.12.10"
"@babel/helper-hoist-variables@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e"
integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==
dependencies:
"@babel/types" "^7.10.4"
"@babel/helper-member-expression-to-functions@^7.12.1", "@babel/helper-member-expression-to-functions@^7.12.7":
version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855"
integrity sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==
dependencies:
"@babel/types" "^7.12.7"
"@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.5":
version "7.12.5"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb"
integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==
dependencies:
"@babel/types" "^7.12.5"
"@babel/helper-module-transforms@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c"
integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==
dependencies:
"@babel/helper-module-imports" "^7.12.1"
"@babel/helper-replace-supers" "^7.12.1"
"@babel/helper-simple-access" "^7.12.1"
"@babel/helper-split-export-declaration" "^7.11.0"
"@babel/helper-validator-identifier" "^7.10.4"
"@babel/template" "^7.10.4"
"@babel/traverse" "^7.12.1"
"@babel/types" "^7.12.1"
lodash "^4.17.19"
"@babel/helper-optimise-call-expression@^7.10.4", "@babel/helper-optimise-call-expression@^7.12.10":
version "7.12.10"
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz#94ca4e306ee11a7dd6e9f42823e2ac6b49881e2d"
integrity sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==
dependencies:
"@babel/types" "^7.12.10"
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375"
integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==
"@babel/helper-remap-async-to-generator@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz#8c4dbbf916314f6047dc05e6a2217074238347fd"
integrity sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==
dependencies:
"@babel/helper-annotate-as-pure" "^7.10.4"
"@babel/helper-wrap-function" "^7.10.4"
"@babel/types" "^7.12.1"
"@babel/helper-replace-supers@^7.12.1":
version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz#ea511658fc66c7908f923106dd88e08d1997d60d"
integrity sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==
dependencies:
"@babel/helper-member-expression-to-functions" "^7.12.7"
"@babel/helper-optimise-call-expression" "^7.12.10"
"@babel/traverse" "^7.12.10"
"@babel/types" "^7.12.11"
"@babel/helper-simple-access@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136"
integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==
dependencies:
"@babel/types" "^7.12.1"
Like the Gemfile and Gemfile.lock, there's a corresponding
yarn.lock file for the output of the dependency resolver.
Interestingly, this is a lot larger than the Gemfile.lock,
mostly as it tracks around 600 packages I think, and
includes hashes to check integrity, which is a good
feature.
The fragmented approach
Time spent using multiple tools
More state to manage
Limited functionality due to lack of interoperation
Raises the cost for diverse tooling
Dependent on many tools
That's 4 files, the Gemfile, Gemfile.lock, package.json
and yarn.lock. There's also Guix providing plenty of
dependencies which I haven't described tracking.
What I'm getting at here is that each of these tools has
it's complexities, and by using multiple package managers
at once, this complexity is shifted on to you, the user.
(Next)
Next I want to talk about the limitations this fragmented
approach imposes.
You've got the cost of two dependency resolvers involved
here, and all the resulting state so you can attempt to
reproduce the setup in the future and on different
machines.
You can't look at dependencies across these fragmented
ecosystems though, the Rubygems resolver isn't going to
pick gem versions that work with the libraries Guix is
providing. Similarly, yarn isn't going to help you pick
JavaScript libraries that will work with the Ruby code
you've got.
This is just one example of how this breakdown of the
problem roughly along the lines of programming language
makes it harder to provide a good user experience.
(Next)
All of this means you'll be discouraged from picking
software that isn't available through the limited package
managers you're already using. Ignoring Guix, and the wide
range of software it provides, Rubygems and NPM aren't
going to provide you with tools written in Python, or
Rust, or Java for example.
With this fractured approach to package management, you'll
be discouraged from picking the best available tool if
that's not available through the package managers you're
using.
(Next)
Finally, there are risks being dependent on multiple
tools. Bugs or security issues in these tools might impact
you, and both Rubygems and NPM are dependent on remote
package repositories. With these services, comes the
potential for downtime that prevents deployments.
So, with all of that said, is there an alternative?
A minimal approach
Just one approach
Declaritive and reproducible
Powerful tooling
Pick and choose from software regardless of language
Reliable, with less risk
What would be a minimal approach to software deployment?
(Next)
Firstly, take a singular approach that works for all the
software you're using. Then you're not spending time
trying to manage the use and interaction of multiple
tools.
(Next)
Then, the same principles that apply to state in a program
apply to deploying software. Rather than running a
dependency resolver, or even multiple dependency
resolvers, and storing the results so that you can use
that state later. Instead, declare what dependencies
you're going to use in a concise and reproducible manor.
Before starting to use Guix, I thought that dependency
resolvers were the core part of package managers. Now I
think in many cases, you're better off without trying to
resolve dependencies in this manor, especially right when
you're trying to install packages.
(Next)
I think it follows from taking one consolidated approach
to software deployment, that tooling can be built around
this that isn't limited by splitting down the problem
along the lines of programming language.
guix graph --type=references ruby-railties | fdp -Goverlap=2:prism -Gsplines=true -Tsvg
As a small example of this, this is visualised output from
the guix graph command for the ruby-railties package.
You probably won't be able to read the text, but each box
represents a built package output, and the lines represent
references, so the dependencies between those package
outputs.
Because Guix has all the information about the
relationships between the different packages, the Ruby
packages on the left are joined on to things like Ruby
itself which is implemented in C, and other non-Ruby
packages to the top right.
A minimal approach
Just one approach
Declaritive and reproducible
Powerful tooling
Pick and choose from software regardless of language
Reliable, with less risk
I don't think being able to generate comprehensive graphs
is a particularly enticing example of how this minimal
approach is beneficial, but it is one of the more visual.
I think the guix pack command is more generally relevant,
being able to generate tarballs, Docker images and other
software bundles makes it possible to get some of the
benefits of using Guix, while not depending on Guix being
available where you're deploying software to.
The complete view of package dependencies is important for
making Guix pack work, and work well, as that means that
Guix knows what to put in the pack, and what it doesn't
need to.
For a more futuristic perspective, I'm really excited by
the insights that Guix can provide about what software
you're using, which is really important for keeping track
of vulnerabilities that you might be impacted by. This is
simplified by having one comprehensive source of
information about what versions of what software you're
using.
(Next)
Moving on, using a general purpose package manager that
isn't specific to one language or one domain, means that
you're no longer discouraged from using tools written in
other languages, or with dependencies in different
languages.
(Next)
Finally, with one approach to software deployment,
hopefully it'll be easier to understand, and more
reliable.
Particularly with Guix, there's the Git repository to
fetch updates to Guix itself and the package definitions,
but that's not required when performing operations, and
there's the option of using a mirror of the Git repository
instead.
Considering using Guix
Check the availability of packages
Check architecture and platform support
Prior to saying even more positive stuff about Guix, I
want to do some management of expectations.
Guix has many high qualify package definitions, there's
only a few cases where Guix doesn't build things from
source out of necessity.
Unfortunately, the trade off with this approach is that
there is still much work remaining to package a lot more
software.
JavaScript in a particular area of deficiency, I'd expect
most if not all of the 600 packages I mentioned earlier
that yarn installed for the demo Rails app, are not
packaged for Guix.
Guix also only supports a number of architectures, so
that's something to check as well.
I don't want this to discourage you from considering Guix,
but do keep this in mind when considering if you'll be
able to use it immediately.
Packaging software for Guix is a community effort, so you
can help out if there are things you're missing.
What sets Guix apart
Quality package definitions
Work with source packages, or prebuilt substitutes
Dependable
Feature rich
Back now to what makes Guix so good for deploying
software.
(Next)
As I mentioned before, the package definitions that Guix
has are rigorous, build the software from source with only
a few exceptions, and in most cases run tests against the
built software.
(Next)
Guix is great at orchestrating building software from
source, but this isn't something you necessarily want to
be doing. This is where substitutes come in, they're
litrally substitutes for building something locally.
Guix provides a build farm that builds Guix packages for
multiple architectures, and you can download these build
substitutes. You can also build and distribute substitutes
yourself with tools like guix publish.
This point is also a notable difference from package
managers mentioned previously. Rubygems doesn't have such
a general approach for providing built software, and while
that's not relevant for the vast majority of Ruby
packages, there are some that require compiling native
code upon installation, which can get fustrating when it
happens again and again.
Having just one package manager allows you to solve
problems once, and solve them well.
(Next)
Guix is dependable.
It has good security properties, commits are signed, and
these signatures are checked when you pull in
updates. Rollbacks are detected, which helps to prevent
rollback attacks. Substitutes are signed, which provides
some security when fetching substitutes.
There's some security in building the software from source
as well, you're at least then not trusting the source,
Guix and whoever compiled the software, but instead just
the source and Guix.
Guix also goes without many of the features that make
other package managers less secure. Arbitrary code within
packages isn't executed when you install packages which is
something that's possible with other package managers.
Guix is also less dependent on network services compared
with lots of other package managers, which removes that as
a point of failure.
(Next)
Finally, the rich set of features that Guix has means that
it can comprehensivly tackle software deployment
problems. If you can avoid using a distro, a config
management tool, several language specific package
managers and tools for providing isolation, and replace
all of that complexity with Guix, you can spend more time
on doing whatever you're trying to do, rather than
spending it trying to deploy software.
Is GNU Guix a minimal distribution
Yes
Use it to consolidate your approach to software deployment
So, is GNU Guix a minimal distribution.
Yes.
You can use it to consolidate your approach to deploying
software.
If Guix has the packages and features you need, and you're
not already using it, adopting it might save you time in
the long run.
Even if Guix doesn't yet have the packages or features you
need, you might still be able to get some value by using
it, and that'll maybe give you the encouragement to start
contributing.
Get involved!
Talk to others on #guix on freenode
For the manual, mailing lists, papers, blog posts and
talks, go to
https://guix.gnu.org/
If you're interested in learning more, the Guix website is
probably a good place for information.
There are active mailing lists and an IRC channel.
I'm really excited by the potential I see in Guix, and I
hope you are now too.