Caching for incremental changes (including `ghc-nix`)

I’m not sure what sort of project size we’re talking about, but IME, HLS was doing fine in projects that had >50k LoC. I’m not sure what exactly it does under the hood, but I’m pretty sure it doesn’t just call cabal to build the project, it probably calls it to get the compiler flags and the dependency tree.

IME, HLS struggles the most when you open two files simultaneously with too may modules in between on the dependency tree. I.e. you’re working on the Utils module that almost every other module depends on, and you have the Main module open at the side, so that means HLS has to reload your entire project every time you make any change in Utils. I always try to avoid doing that. You can easily put yourself into this situation if you have a TestUtils module that all of your tests use and that TestUtils depends on a large chunk of your app/library modules. Then whenever you’re working on tests together with the module you’re testing, you’ll be waiting for the entire project to reload. Employing a little mechanical sympathy for HLS and being mindful of the shape of your module dependency graph goes a very long way.

My default choice for a Haskell project setup is to go with a cabal.project + haskell.nix. Specify your GHC version and the hackage snapshot in the cabal.project and that will make sure you get the same Haskell packages across your cabal build/repl and nix build. If your project depends on tricky system dependencies that you get from nixpkgs, you can always prepare a nix develop/shell environment that brings in just those packages and then run cabal build in that shell.

IMO, the ultimate Haskell development experience is when you set up a way to test the code you’re working on in a very fast ghciwatch loop. In your editor you have the app module on one panel and the test module in the other, with very few dependencies in between and in a terminal you run ghciwatch to run the tests whenever you save, so you get feedback within seconds of saving. Set this up from day one, make sure it stays smooth and neutralize with a taser anyone that tries to take that away from you.