mirror of
https://github.com/youwen5/blog.git
synced 2024-11-28 11:23:49 -08:00
Compare commits
1 commit
540cfd1310
...
68c5b1a9e3
Author | SHA1 | Date | |
---|---|---|---|
|
68c5b1a9e3 |
11 changed files with 243 additions and 55 deletions
10
README.md
10
README.md
|
@ -1,4 +1,4 @@
|
|||
# conditional finality - yet another developer blog
|
||||
# gradient ascent - yet another developer blog
|
||||
|
||||
This repository hosts the source code for my blog, written in Haskell and
|
||||
powered by [hakyll](https://jaspervdj.be/hakyll/) and
|
||||
|
@ -14,7 +14,7 @@ you know what you are doing.
|
|||
|
||||
Allow the `.envrc`:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
direnv allow
|
||||
```
|
||||
|
||||
|
@ -28,7 +28,7 @@ Here's how to do it locally.
|
|||
|
||||
First, we need to build the site. Run
|
||||
|
||||
```bash
|
||||
```sh
|
||||
hakyll-site build
|
||||
|
||||
# sometimes, we need to ignore the cache if things aren't working
|
||||
|
@ -51,7 +51,7 @@ In the directory, there is a `node_modules` symlink to
|
|||
`result/lib/node_modules`. If we build the `nodeDeps` package, the
|
||||
`node_modules` will be made available at this path. So, run the following:
|
||||
|
||||
```bash
|
||||
```sh
|
||||
nix build .#nodeDeps
|
||||
```
|
||||
|
||||
|
@ -61,7 +61,7 @@ need to re-run the above command or else node_modules will not be accessible.
|
|||
|
||||
Finally, run the following to generate the bundled CSS and JS files.
|
||||
|
||||
```bash
|
||||
```
|
||||
rollup -c
|
||||
```
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
description = "conditional finality";
|
||||
description = "gradient ascent";
|
||||
|
||||
nixConfig = {
|
||||
allow-import-from-derivation = "true";
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
|
||||
@layer utilities {
|
||||
.external-link {
|
||||
@apply underline decoration-solid decoration-2 underline-offset-2 hover:text-love-light dark:hover:text-love-dark decoration-love-light decoration-love-dark;
|
||||
@apply dark:text-violet-500 text-indigo-600 hover:bg-indigo-200 pr-3 rounded-sm dark:hover:bg-violet-950 transition-colors duration-300 relative;
|
||||
}
|
||||
.external-link-muted {
|
||||
@apply underline decoration-solid decoration-2 underline-offset-2 hover:text-love-light dark:hover:text-love-dark decoration-accent-light decoration-accent-dark;
|
||||
.external-link::after {
|
||||
@apply absolute top-1 right-[6px] w-2 h-2 border-2 border-indigo-600 dark:border-violet-600 rounded-full translate-x-1/2 -translate-y-1/2;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.small-caps {
|
||||
font-variant: all-small-caps;
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 43 KiB |
BIN
src/images/gradient-ascent.jpg
Normal file
BIN
src/images/gradient-ascent.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -18,7 +18,7 @@ title: "youwen wu"
|
|||
<div class="rounded-md p-2">
|
||||
<a
|
||||
href=".$url$"
|
||||
class="w-fit dark:group-hover:text-iris-dark group-hover:text-iris-light transition-colors"
|
||||
class="w-fit dark:group-hover:text-muted-dark group-hover:text-muted-light transition-colors"
|
||||
>
|
||||
<h3 class="text-2xl">$title$</h3>
|
||||
<p
|
||||
|
@ -30,7 +30,7 @@ title: "youwen wu"
|
|||
</a>
|
||||
</div>
|
||||
<hr
|
||||
class="max-w-[200px] border-0 h-1 dark:bg-accent-dark bg-accent-light rounded-lg px-2 group-hover:max-w-[250px] dark:group-hover:bg-iris-dark group-hover:bg-iris-light transition-all duration-400"
|
||||
class="max-w-[200px] border-0 h-1 dark:bg-accent-dark bg-accent-light rounded-lg px-2 group-hover:max-w-[250px] dark:group-hover:bg-secondary-dark group-hover:bg-secondary-light transition-all duration-400"
|
||||
/>
|
||||
</li>
|
||||
$endfor$
|
||||
|
|
|
@ -2,21 +2,25 @@
|
|||
author: "Youwen Wu"
|
||||
authorTwitter: "@youwen"
|
||||
desc: "a purely functional...blog?"
|
||||
image: "./images/conditional-finality.png"
|
||||
image: "./images/gradient-ascent.jpg"
|
||||
keywords: "haskell, blog, functional programming"
|
||||
lang: "en"
|
||||
title: "a haskellian blog"
|
||||
title: "why I made my blog in haskell"
|
||||
updated: "2024-05-25T12:00:00Z"
|
||||
---
|
||||
|
||||
Welcome! This is the first post on _conditional finality_ and also one that tests all
|
||||
Welcome! This is the first post on _gradient ascent_ and also one that tests all
|
||||
of the features.
|
||||
|
||||
<img
|
||||
alt="conditional finality"
|
||||
src="./images/conditional-finality.png"
|
||||
alt="gradient ascent"
|
||||
src="./images/gradient-ascent.jpg"
|
||||
style="height: 200px; width: 100%; object-fit: cover"
|
||||
/>
|
||||
|
||||
I'll be writing about computers, code, math, video games, and whatever else
|
||||
here.
|
||||
|
||||
> A monad is just a monoid in the category of endofunctors, what's the problem?
|
||||
|
||||
## haskell?
|
||||
|
@ -55,6 +59,11 @@ The code highlighting is also generated by hakyll.
|
|||
Haskell is a purely functional language with no mutable state. Its syntax
|
||||
actually makes it pretty elegant for declaring routes and "rendering" pipelines.
|
||||
|
||||
I originally wanted to build this entire blog myself. I had a working version
|
||||
with the Svelte framework, complete with GFM rendering, table of contents, KaTeX
|
||||
math, code highlighting, static generation, and other goodies. However, it
|
||||
seemed like a little too much work to maintain. I switched to hakyll because
|
||||
|
||||
1. Haskell is cool.
|
||||
2. It comes with enough features that I don't feel like I have to build
|
||||
everything from scratch.
|
||||
|
@ -68,7 +77,7 @@ actually makes it pretty elegant for declaring routes and "rendering" pipelines.
|
|||
### speaking of math
|
||||
|
||||
We can have math inline, like so:
|
||||
$\int_{-\infty}^\infty \, e^{-x^2}\,dx = \sqrt{\pi}$. This site ships semantic
|
||||
$\int_\infty^\infty \, e^{-x^2}\,dx = \sqrt{\pi}$. This site ships semantic
|
||||
MathML math with its HTML, and the MathJax script to the client.
|
||||
|
||||
It'd be nice if MathML could just be used and supported across all browsers, but
|
||||
|
|
197
src/posts/2024-10-31-a-retrospective-on-nixos.md
Normal file
197
src/posts/2024-10-31-a-retrospective-on-nixos.md
Normal file
|
@ -0,0 +1,197 @@
|
|||
---
|
||||
author: "Youwen Wu"
|
||||
authorTwitter: "@youwen"
|
||||
desc: "and the future of operating systems"
|
||||
image: "./images/gradient-ascent.jpg"
|
||||
keywords: "nix, nixos, functional programming, linux, unix"
|
||||
lang: "en"
|
||||
title: "a retrospective on NixOS"
|
||||
updated: "2024-05-25T12:00:00Z"
|
||||
---
|
||||
|
||||
Many people more knowledgeable than me have already written at length about the
|
||||
virtues of NixOS and _declarative configuration_ and _immutability_ and such. I
|
||||
doubt what I have to say is particularly novel to those already familiar with
|
||||
Nix, but I'd like to discuss precisely what brings people to NixOS in the first
|
||||
place.
|
||||
|
||||
Many people will introduce NixOS by first introducing the Nix package manager,
|
||||
and immediately jumping into terms like _derivation_ and _immutability_ and
|
||||
_reproducibility_ and whatnot. And while these are important concepts for
|
||||
understanding the system at large, it's not very convincing for people looking
|
||||
to try out the system. After all, most people don't (or at least shouldn't!)
|
||||
choose their tools based on hype or purported benefits, but based the problems
|
||||
that they help them solve.
|
||||
|
||||
Instead of immediately evangelizing about the virtues of Nix and NixOS, I'll
|
||||
first motivate the reasons for why I chose a tool with exactly its properties
|
||||
(but not to worry, the evangelizing will come later).
|
||||
|
||||
Essentially: allow me to introduce you to the
|
||||
origins of the [NixOS God
|
||||
Complex](https://www.reddit.com/r/NixOS/comments/kauf1m/dealing_with_post_nixflake_god_complex/).
|
||||
|
||||
---
|
||||
|
||||
My goals for my system are as follows:
|
||||
|
||||
- Allow my computing environment to exist on different computers at the same
|
||||
time (essentially, sync up configurations between machines)
|
||||
- Precisely control the software and services on my machine. I should be able
|
||||
to obtain binaries of most things to save time, but be able to step into the
|
||||
source and apply patches or configuration as desired
|
||||
- For the OS to be absolutely unbreakable
|
||||
- Never configure the system twice; once I solve a problem, I should have a
|
||||
reproducible solution that solves it permanently
|
||||
- Be able to backup my system configuration and quickly redeploy it whenever
|
||||
needed
|
||||
- Avoid janky solutions to these problems that introduce tech debt. I don't
|
||||
want to have to rely on disk images or backups, I want to be able to create
|
||||
fresh installations quickly
|
||||
|
||||
Essentially, I want to synchronize the configuration of my entire system across
|
||||
multiple machines while maintaining a stable and usable system I'm not worried
|
||||
will inadvertently fall apart with a routine system update. When I tweak and
|
||||
mess with some settings on my desktop, I should be able to push to a `git`
|
||||
repository and pull it down on my laptop and have the tweaks carried over. This
|
||||
even includes system-level configuration like the applications installed,
|
||||
system daemons, and other core system services.
|
||||
|
||||
I want a source and binary based distribution simultaneously. And I want a
|
||||
self-documenting reproducible system where every tiny tweak is
|
||||
deterministically applied. And I want to be able to install my configurations
|
||||
onto a new computer, from scratch, in an installer, effectively creating my own
|
||||
custom Linux distribution.
|
||||
|
||||
Oh, and I also want to solve the "works on my machine" problem, and never have
|
||||
trouble using software someone else packaged and claims works on their end, but
|
||||
fails on my computer.
|
||||
|
||||
All or even just a few of these goals seem unattainable to the typical Linux
|
||||
user (not to mention those still on Windows and macOS $\dots$ _oh, the
|
||||
horror!_). But I was in fact able to achieve all of them.
|
||||
|
||||
---
|
||||
|
||||
To begin, let's examine how one might try to approach these problems with the
|
||||
common solutions.
|
||||
|
||||
Let's talk about sharing configuration among multiple computers first, which
|
||||
can be thought of as some form of "settings sync".
|
||||
|
||||
Most people have encountered solutions to sychronizing configuration in two
|
||||
ways: either the entire service is ran in the cloud, so it's really the _same_
|
||||
environment accessed from multiple places (eg. Google Docs), or it's some often
|
||||
half baked opaque solution involving you making an account and sending all your
|
||||
settings to a sync server (eg. Mozilla Firefox).
|
||||
|
||||
The more technically minded may instead opt to create a "dotfiles" repository,
|
||||
holding their vast collection of meticulously crafted configuration files.
|
||||
These repos often come with a janky `install.sh` script that does its best to
|
||||
install all the files into the correct place. This usually works the first
|
||||
time, but trying to keep the installed dotfiles in sync with a central
|
||||
repository is a whole other problem.
|
||||
|
||||
There are also dotfile manager like `chezmoi` or GNU Stow. I have not tried
|
||||
these so I make no judgements on their utility for their intended purpose.
|
||||
These dotfile management solutions may work well for managing configuration
|
||||
files, but they both have the same issue: you also need to install the software
|
||||
you're configuring!
|
||||
|
||||
The software and the configuration are fundamentally tied together; these are
|
||||
not concerns to be separated. If the software is installed, it almost always
|
||||
needs to be configured anyways. If the configuration exists, the software
|
||||
should be installed. So a sane solution needs to both put the configuration in
|
||||
the right place, _and_ set up the system's programs along with all their
|
||||
dependencies!
|
||||
|
||||
So, the most obsessive *nix hackers reach for tools like
|
||||
[Ansible](https://www.ansible.com/), that promise automatic configuration of
|
||||
entire systems. Though Ansible was initially designed to deploy cloud servers
|
||||
quickly through the Infrastructure-as-Code approach, some people opt to use it
|
||||
for deploying and managing their systems quickly as well. I have not personally
|
||||
tried it beyond playing with a few examples The consensus seems to be that it
|
||||
seems to work fine for simple use cases but gets quite unwieldy for more
|
||||
complex purposes (especially for personal systems, which aren't expected to be
|
||||
as ephemeral as servers).
|
||||
|
||||
A system like Ansible combined with a system to manage configuration files
|
||||
might be able to achieve a few of our goals. We can keep configuration in sync
|
||||
between computers and we can quickly redeploy our system. But anyone who has
|
||||
tried this will tell you that it's incredibly uncomfortable to use; our
|
||||
existing operating systems are simply not designed to be managed in this
|
||||
manner. Inevitably you will experience desynchronization between the
|
||||
configuration and the actual state of the machine.
|
||||
|
||||
Also, this does not solve some of our other problems. We'll still need tools
|
||||
like Docker to reproducibly build software and figure out a way to keep our
|
||||
system stable.
|
||||
|
||||
If you agree with the premises I've laid out up to this point, that none of
|
||||
these solutions provide a satisfying solution to our computing woes, you might
|
||||
come to the conclusion that I've made. We need a solution that does _all of
|
||||
it_. A unified tool for reliably deploying software and managing your system
|
||||
configuration. And it must necessarily be declarative and reproducible, because
|
||||
that is the only sane way to manage a system. Imagine working on a programming
|
||||
project where recompiling with the same source code would non-deterministically
|
||||
produce different results based on the environment! We should be able to write
|
||||
files that declaratively and precisely specify the state of whole system, and
|
||||
then be able to revert these files or tweak them with deterministic results
|
||||
that don't leave behind any broken programs or files.
|
||||
|
||||
Well, [Nix](https://nixos.org/) is the _purely functional_ package manager
|
||||
(i.e. declarative, reproducible), and NixOS is a Linux distribution that is
|
||||
managed entirely by Nix. Essentially, Nix provides a solution to the problem of
|
||||
_software deployment_, and in fact was purpose built to do so in Eelco
|
||||
Dolstra's seminal [PhD
|
||||
thesis](https://edolstra.github.io/pubs/phd-thesis.pdf). It effectively solves
|
||||
the problem of "works on my machine" by _forcing_ the user to actually specify
|
||||
all required dependencies. This makes it a little harder to write the initial
|
||||
build configurations due to the strictness imposed. But the reward is that if a
|
||||
piece of software builds on one machine, it's guaranteed to build on another.
|
||||
|
||||
NixOS is a system that takes the power of Nix and applies it to declaratively
|
||||
configure an _entire Linux system_. All of the installed software and activated
|
||||
services can be specified precisely using the Nix expression language, a purely
|
||||
functional DSL used by Nix. And alongside the software, it also configures it,
|
||||
effectively acting as a dotfile manager. Indeed, many core NixOS services and a
|
||||
wide range of programs can be set up through _NixOS modules_, where the program
|
||||
is installed and configured in the same place. (and many programs like `fzf`,
|
||||
`btop`, etc have similar corresponding `home-manager` modules).
|
||||
|
||||
NixOS is also _immutable_, which means that the system cannot be modified after
|
||||
it is built from the Nix files that declare it. How do you make changes to the
|
||||
system then? Obviously, we just create a new system where the changed programs
|
||||
and files are included, and the old ones are removed. But they are not deleted
|
||||
from the hard drive, they still exist in the _Nix store_. So, the system can
|
||||
provide precise atomic rollbacks between each "generation" of itself. Broke
|
||||
your GRUB configuration so your system won't boot? Messed up your kernel
|
||||
settings? Just select an older working generation from the boot menu and you
|
||||
instantly have a working system again. You never worry about breaking things
|
||||
during either routine or massive system updates.
|
||||
|
||||
And because the system is fully declarative, and modifying the system is done
|
||||
only through modifying its Nix configuration files, you can version and sync
|
||||
them up with Git. This solves the problem of keeping system environments in
|
||||
sync; now, you truly only have to keep one repository of all your configuration
|
||||
in sync, and all the software installation and deployment is handled for you by
|
||||
a system designed precisely for that purpose.
|
||||
|
||||
This makes it possible for me to share common configuration between a multitude
|
||||
of entirely distinct machines, including an `x86_64` desktop, an `x86_64`
|
||||
laptop, an Apple Silicon Macbook running NixOS `aarch64` using [Asahi
|
||||
Linux](https://asahilinux.org/), and the same Macbook running macOS with
|
||||
`nix-darwin`, sharing `home-manager` configuration with NixOS. Specific
|
||||
configuration necessary to adjust hardware-specific details between each
|
||||
machines are isolated to the [hosts](./hosts) directory.
|
||||
|
||||
This works exceptionally well, evidenced by the fact that I have (almost) the
|
||||
exact same environment across three separate machines, spanning two entirely
|
||||
distinct CPU architectures.
|
||||
|
||||
In essence, the primary failure of deployment scripts, Ansible and the like is
|
||||
that they are _imperative_ - they must specify precisely _how_ to set up the
|
||||
system, down to minute details, whereas in a _declarative_ approach, the user
|
||||
can simply specify what the system _should look like_, and abstractions take
|
||||
care of the _how_. This is what NixOS does, and it gives you remote syncing,
|
||||
versioning (via `git`), and rollbacks _for free_.
|
|
@ -1,7 +1,7 @@
|
|||
<!doctype html>
|
||||
<html lang="$lang$">
|
||||
<head>
|
||||
<title>$title$ | conditional finality</title>
|
||||
<title>$title$ | gradient ascent</title>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
@ -116,7 +116,7 @@
|
|||
<a
|
||||
href="/"
|
||||
class="dark:hover:text-muted-dark hover:text-muted-light transition-all duration-500 text-nowrap tracking-wide"
|
||||
><em>Conditional Finality.</em></a
|
||||
><em>Gradient Ascent.</em></a
|
||||
>
|
||||
</h1>
|
||||
<div
|
||||
|
@ -126,18 +126,18 @@
|
|||
<p class="mt-8 mb-3 px-1 italic font-light">
|
||||
a web-log about computers, math, hacks, and all the rest.
|
||||
</p>
|
||||
<a class="text-sm text-iris-light dark:text-iris-dark hover:text-love-light dark:hover:text-love-dark" href="https://youwen.dev"
|
||||
<a class="text-sm external-link" href="https://youwen.dev"
|
||||
><em>by </em>Youwen Wu</a
|
||||
>
|
||||
<span class="ml-2 font-serif">|</span>
|
||||
<button
|
||||
id="theme-toggle"
|
||||
class="ml-2 text-sm hover:text-accent-light dark:hover:text-muted-dark"
|
||||
class="ml-2 text-sm hover:bg-indigo-200 dark:hover:bg-violet-950 rounded-sm transition-colors p-1 duration-500"
|
||||
></button>
|
||||
<span class="ml-2 font-serif">|</span>
|
||||
<button
|
||||
id="font-toggle"
|
||||
class="ml-2 text-sm hover:text-accent-light dark:hover:text-muted-dark"
|
||||
class="ml-2 text-sm hover:bg-indigo-200 dark:hover:bg-violet-950 rounded-sm transition-colors p-1 duration-500"
|
||||
></button>
|
||||
</header>
|
||||
$body$
|
||||
|
@ -149,14 +149,14 @@
|
|||
© 2024 Youwen Wu. Generated by
|
||||
<a
|
||||
href="https://jaspervdj.be/hakyll/"
|
||||
class="external-link-muted"
|
||||
class="external-link"
|
||||
target="__blank"
|
||||
>Hakyll.</a
|
||||
>
|
||||
View the source
|
||||
<a
|
||||
href="https://github.com/couscousdude/blog"
|
||||
class="external-link-muted"
|
||||
class="external-link"
|
||||
target="__blank"
|
||||
>on GitHub.</a
|
||||
>
|
||||
|
@ -164,7 +164,7 @@
|
|||
<p class="text-sm leading-relaxed mt-2">
|
||||
Content freely available under
|
||||
<a
|
||||
class="external-link-muted"
|
||||
class="external-link"
|
||||
target="__blank"
|
||||
href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en"
|
||||
><span class="smallcaps">CC BY-NC-SA</span> 4.0</a
|
||||
|
|
|
@ -28,13 +28,13 @@ import Text.Pandoc.Options (
|
|||
-- PERSONALIZATION
|
||||
|
||||
mySiteName :: String
|
||||
mySiteName = "conditional finality"
|
||||
mySiteName = "gradient ascent"
|
||||
|
||||
mySiteRoot :: String
|
||||
mySiteRoot = "https://blog.youwen.dev"
|
||||
|
||||
myFeedTitle :: String
|
||||
myFeedTitle = "conditional finality"
|
||||
myFeedTitle = "gradient ascent"
|
||||
|
||||
myFeedDescription :: String
|
||||
myFeedDescription = "on computers, hacks, math, and life"
|
||||
|
|
|
@ -10,42 +10,24 @@ module.exports = {
|
|||
},
|
||||
colors: {
|
||||
primary: {
|
||||
//dark: "#e7e5e4",
|
||||
dark: "#e7e5e4",
|
||||
light: "#44403c",
|
||||
dark: "#e0def4",
|
||||
//light: "#575279",
|
||||
},
|
||||
secondary: {
|
||||
//dark: "#4c1d95",
|
||||
//light: "#4338ca",
|
||||
dark: "#1f1d2e",
|
||||
light: "#fffaf3",
|
||||
dark: "#4c1d95",
|
||||
light: "#4338ca",
|
||||
},
|
||||
accent: {
|
||||
//dark: "#9ca3af",
|
||||
//light: "#78716c",
|
||||
dark: "#908caa",
|
||||
light: "#797593",
|
||||
dark: "#9ca3af",
|
||||
light: "#78716c",
|
||||
},
|
||||
muted: {
|
||||
//dark: "#6b7280",
|
||||
//light: "#a8a29e",
|
||||
dark: "#6e6a86",
|
||||
light: "#9893a5",
|
||||
dark: "#6b7280",
|
||||
light: "#a8a29e",
|
||||
},
|
||||
background: {
|
||||
//light: "#d6d3d1",
|
||||
//dark: "#101017",
|
||||
dark: "#191724",
|
||||
light: "#faf4ed",
|
||||
},
|
||||
iris: {
|
||||
dark: "#c4a7e7",
|
||||
light: "#907aa9",
|
||||
},
|
||||
love: {
|
||||
dark: "#eb6f92",
|
||||
light: "#b4637a",
|
||||
light: "#d6d3d1",
|
||||
dark: "#101017",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue