Skip to content

Commit bdc53d3

Browse files
committed
Apply @angerman suggestions
1 parent 2c98b80 commit bdc53d3

File tree

1 file changed

+18
-18
lines changed

1 file changed

+18
-18
lines changed

blog/2023-11-13-devx.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,32 @@ tags: [devx, haskell.nix, hix, iogx, nix]
77

88
# The IOG Developer's Experience Shell
99

10-
The IOG's Developer Experience Shell, or `DevX` for short, is an opinionated development environment tailored for Haskell. Built on top of Nix expressions, it provides a reproducible and seamless, full-featured developer shell with tools such as `cabal-install`, `ghc`, `hls`, and `hlint`. `DevX` is built upon the battle-tested `haskell.nix`, a framework for building Haskell packages with Nix, but that knowing Nix isn't a prerequisite to read the post unless the last `hix` section. In short, `haskell.nix` turns your Cabal or Stack project and its dependencies into a Nix expression. We will explain how to use `haskell.nix` on its own using `hix` in the last section.
10+
The IOG's Developer Experience Shell, or `DevX` for short, is an opinionated development environment tailored for Haskell. Built on top of Nix expressions, it provides a reproducible and seamless, full-featured developer shell with tools such as `cabal-install`, `ghc`, `hls`, and `hlint`. `DevX` is built upon the battle-tested `haskell.nix`, a framework for building Haskell packages with Nix. Knowing Nix isn't a prerequisite to read the post except for the last `hix` section. In short, `haskell.nix` turns your Cabal or Stack project and its dependencies into a Nix expression. We will explain how to use `haskell.nix` on its own using `hix` in the last section.
1111

12-
But why Nix? Haskell developers often encounter the need for distinct environments per project. While solutions like stack resolvers and cabal project files address some concerns, they often fall short in terms of environment isolation. E.g., a Cabal project file could not be enough, because external (non-Haskell / system) dependencies need to be tracked too (that's exactly what Nix does), and could lead to inconsistent (non-reproducibles) builds. For instance, working on the Cardano performance regression while migrating from GHC 8.10 to 9.2, this required different toolchains. And, addressing this without `nix`would have been an absolute mess... With the `DevX` shell and `direnv`, you can achieve seamless transitions between projects. To illustrate, consider:
12+
But why Nix? Haskell developers often encounter the need for distinct environments per project. While solutions like stack resolvers and cabal project files address some concerns, they often fall short in terms of environment isolation. E.g., a Cabal project file could not be enough, because external (non-Haskell / system) dependencies need to be tracked too (that's exactly what Nix does), and could lead to inconsistent (non-reproducibles) builds. For instance, working on the Cardano performance regression while migrating from GHC 8.10 to 9.2, this required different toolchains. And, addressing this without `nix` would have been an absolute mess... With the `DevX` shell and `direnv`, you can achieve seamless transitions between projects. To illustrate, consider:
1313
```shell
1414
cd project1 # loading project1/.envrc
1515
ghc --version # 8.10
1616
cd ../project2 # unloading project1/.envrc and loading project2/.envrc
1717
ghc --version # 9.2
1818
```
19-
Nix achieve reproducibility by managing the complete dependencies graph (the _closure_) of a project, this also make it a great candidate as a cross-compilation framework! While this will not be discussed in this article, it worth noticing this is one of the main reason of why we love it at IOG. Other challenges solved by Nix are: How do we sync workspaces to make sure we're all dealing with the same technical stack? How do we make sure that Developer A can reuse the work of Developer B? One last way of introducing Nix is to say that it ensure that your developer environment respect a _semantic contract_. Like you can write a program that precisely and accurately states a meaning of some thing (e.g., the meaning of `2 + 2` _is_ the symbol `4`), with Nix you get a semantic contract for, e.g. in our case, a _shell closure_, which means a developer environment.
19+
Nix achieves reproducibility by managing the complete dependencies graph (the _closure_) of a project, this also make it a great candidate as a cross-compilation framework! While this will not be discussed in this article, it worth noticing this is one of the main reason of why we love it at IOG. Other challenges solved by Nix are: How do we sync workspaces to make sure we're all dealing with the same technical stack? How do we make sure that Developer A can reuse the work of Developer B? One last way of introducing Nix is to say that it ensure that your developer environment respect a _semantic contract_. Like you can write a program that precisely and accurately states a meaning of some thing (e.g., the meaning of `2 + 2` _is_ the symbol `4`), with Nix you get a semantic contract for, e.g. in our case, a _shell closure_, which means a developer environment.
2020

2121
So, to sum up, Nix is the tool that let you write reproducible, seamless and correct developer enviroments, and `DevX` shell is our opiniated definition on how to pack it with tools such as it is full-featured for Haskell development. This article aims to give you a technical deep dive on how to use the `DevX` shell (and other IOG Nix-related projects such as IOGx flakes' framework and `hix` CLI tool) in your own Haskell project. By the end of the following section you should be able setup it in few steps, even in your Github Action CI or GitHub CodeSpace developer environment!
2222

2323
## Getting started with `DevX` Shell
2424

25-
The `DevX` GitHub repository provides a comprehensive [README](https://github.com/input-output-hk/devx#readme) that documents the different outputs that its `flake.nix` provides. But, as this article assumes you might have not so much knowledge of how to deal with Nix, we will quickly discuss three ergonomic ways of using this tool with no Nix knowledge required.
25+
The `DevX` GitHub repository provides a comprehensive [README](https://github.com/input-output-hk/devx#readme) that documents the different outputs that its `flake.nix` provides. As this article assumes no prior knowledge of Nix, we will quickly discuss three ergonomic ways of using this tool with no Nix knowledge required.
2626

27-
You still need to ensure that [Nix is installed](https://nixos.org/download) on your machine. Then, You need Nix configured with `experimental-features = [ "nix-command" "flakes" ];` (details can be found at the [NixOS Wiki](https://nixos.wiki/wiki/Flakes)).
27+
We need to ensure [Nix is installed](https://nixos.org/download) and configured with `experimental-features = [ "nix-command" "flakes" ];` (details can be found at the [NixOS Wiki](https://nixos.wiki/wiki/Flakes)).
2828

29-
> **Side note:** In this article I will try to keep my use of the [Nix jargon](https://nixionary.org/) to the bare minimum required, but some concepts might still be needed to fully appreciate the last part of this article (about `hix`), here's a [little refresher in case of need](https://www.youtube.com/watch?v=gUjvnZ9ZwMs).
29+
> **Side note:** In this article we will try to keep our use of the [Nix jargon](https://nixionary.org/) to the bare minimum required, but some concepts might still be needed to fully appreciate the last part of this article (about `hix`), here's a [little refresher in case of need](https://www.youtube.com/watch?v=gUjvnZ9ZwMs).
3030
3131
### Philosophy and Usage
3232

33-
The `DevX` shell approach is a "one shell fits all" solution, IOG's project needs. This means it isn't the most minimalistic method for building a Haskell project with Nix, but it aims to be the most robust and generic approach. The `DevX` shell, built on top of `haskell.nix`, heavily utilizes IFD (Import From Derivation). Consequently, it couldn't be use as a build framework for distributing projects on `nixpkgs`. In such cases, you might prefer using [`haskellPackages.mkDerivation`](https://nixos.org/manual/nixpkgs/stable/#haskell-mkderivation).
33+
The `DevX` shell approach is a one shell fits most. This means it isn't the most minimalistic method for building a Haskell project with Nix, but it aims to be the most robust and generic approach. The `DevX` shell, built on top of `haskell.nix`, heavily utilizes IFD (Import From Derivation). Consequently, it can't be used as a build framework for distributing projects on `nixpkgs`. In such cases, you might prefer using [`haskellPackages.mkDerivation`](https://nixos.org/manual/nixpkgs/stable/#haskell-mkderivation).
3434

35-
To start using the IOG DevX shell in your Haskell project, simply run `nix develop github:input-output-hk/devx#ghc96` within your Haskell project's folder! This will spawn a developer shell, within you can proceed with your usual Haskell tools and development workflow; for instance, use `cabal build` to build your project. For instance:
35+
To start using the IOG DevX shell in your Haskell project, simply run `nix develop github:input-output-hk/devx#ghc96` within your Haskell project's folder! This will spawn a developer shell, within which you can proceed with your usual Haskell tools and development workflow; for instance, use `cabal build` to build your project. For instance:
3636
```
3737
yvan@X230 ~ % cabal unpack hello
3838
@@ -75,7 +75,7 @@ However, before discussing various use cases of `DevX` shell (with `direnv`, Git
7575

7676
We developed a strategy to speed up the overall download and evaluation time of our big Nix closure, we store it as an archive on GitHub package index, and then import all the derivations at once rather than letting `nix-daemon` evaluating and dowloading each store path separetly.
7777

78-
To showcase the efficiency and speed that our download closure hack brings compared to a call to `nix develop`, we'll present a short benchmarking comparison that highlight a roughtly x2 speed up improvement!
78+
To showcase the efficiency and speed that our download closure approach brings compared to a call to `nix develop`, we'll present a short benchmarking comparison that highlight a roughtly x2 speed up improvement!
7979

8080
What isn't measured is the time for evaluating the closure, compressing it, and uploading it to `ghcr.io`, as it's done by our CI and represents the caching part of the process. We measure the speed of downloading, decompressing, and performing a `nix import` on the closure against the speed of `nix develop`, so we essentially save the time of the evaluation of the Nix expression:
8181

@@ -86,7 +86,7 @@ What isn't measured is the time for evaluating the closure, compressing it, and
8686
| `#ghc962-iog` | `11m9s` | `7m26s` |
8787
| `#ghc962-static-minimal` | `4m48s` | `1m35s` |
8888

89-
> **Side note:** I ran these benchmarks on my legacy ThinkPad X230 on a French countryside internet connection, to display how it changes loading times in contexts where internet connection and computing power are precious resources, like in a heavy CI setting. You can learn more about the methodology used [here](https://github.com/input-output-hk/devx/issues/22#issuecomment-1661841652).
89+
> **Side note:** those benchmarks were run on @yvan-sraka's legacy ThinkPad X230 on a French countryside internet connection, to display how it changes loading times in contexts where internet connection and computing power are precious resources, like in a heavy CI setting. You can learn more about the methodology used [here](https://github.com/input-output-hk/devx/issues/22#issuecomment-1661841652).
9090
9191
### Direnv
9292

@@ -111,10 +111,7 @@ The `nix-direnv` prefix is not necessary, but it's a good way to prevent Nix fro
111111

112112
### GitHub Action
113113

114-
We also provide a `DevX` GitHub Action, leveraging a unique technique of pre-evaluating the closure of the development environment, compressing it, and uploading it to `ghcr.io`.
115-
This approach drastically reduces the instantiation time of the developer shell, and will talk about it a bit more in details later in this article.
116-
117-
Here's how you might utilize the DevX GitHub Action in your workflow:
114+
We also provide a `DevX` GitHub Action, that use the `fetch-closure.sh` method presented in Benchmark section. Here's how you might utilize the it in your workflow:
118115
```yaml
119116
- name: Build
120117
uses: input-output-hk/actions/devx@latest
@@ -123,17 +120,20 @@ Here's how you might utilize the DevX GitHub Action in your workflow:
123120
target-platform: '-windows'
124121
compiler-nix-name: 'ghc8107'
125122
minimal: false
126-
iog: true
123+
iog: false
127124
- name: Build
128125
shell: devx {0}
129126
run: |
130127
cabal update
131128
cabal build
132129
```
133130
131+
Here we picked GHC version 8.10.7 and a Windows cross-compiler on Linux. This means that the 2 commands (`cabal update && cabal build`) runned in this GitHub Action will produce a windows binary.
132+
134133
### VSCode DevContainer and GitHub CodeSpace
135134

136-
Finally, we also offer support for VSCode DevContainers and GitHub CodeSpaces.
135+
Finally, we also offer support for VSCode DevContainers and GitHub CodeSpaces. This is a nice feature that let you, in one-click, load within your IDE or web browser a fully-featured developer environment (e.g., with Haskell Language Server setup). Which is particularly nice for onboarding new users and let them quickly start to contribute to a project.
136+
137137
To make the DevX developer shell available in a VSCode DevContainer or GitHub CodeSpace, simply add a file named `.devcontainer/devcontainer.json` with the following content:
138138
```json
139139
{
@@ -180,7 +180,7 @@ To delve deeper into IOGx and its API, refer to the comprehensive [API Reference
180180

181181
## Hix
182182

183-
Hix is a command-line tool designed to facilitate the addition of `haskell.nix` support to existing Haskell projects.
183+
Hix is a command-line tool designed to facilitate the addition of `haskell.nix` support to existing Haskell projects. Maintaining a large Nix expression, that uses `haskell.nix`, require quite a lot of Nix knowledge within a project team. Hix helps to reduce this expression to the bare minimum.
184184

185185
### Quickstart with Hix
186186

@@ -272,4 +272,4 @@ hix-build -A hsPkgs.hello.components.exes.hello
272272

273273
## Final Thoughts
274274

275-
...
275+
As we've seen the suite of tools we've developed around `nix`, and `haskell.nix` at IOG provide a fully featured set of tools from running reproducible adhoc (DevX) build environments locally, to running them in CI either via GHA or `nix`-based CI systems (via `haskell.nix` and IOGx) as appropriate, and extending this to in-browser development environment with VSCode DevContainers / GitHub CodeSpaces.

0 commit comments

Comments
 (0)