Stack at Front Row Education
by @gregwebs on June 26, 2015
Stack is a Haskell development tool for package management and project building. To build your Haskell project with stack, first install stack, and then just run stack build
.
Stack is an alternative to using cabal-install. Unlike cabal-install, stack features:
- first class projects (a project has multiple cabal files)
- first class package curation
- package management that just works
- simple workflows
Support for projects
My first commit at Front Row Education was to add a stack.yaml
file. A commercial project always ends up with many .cabal
files. I have written build scripts for such projects at least 4 times at 3 different companies. This is in addition to authoring build scripts for open-source projects, including a package called cabal-meta
designed to make dealing with a multi-cabal file project easier.
Every build system I have created has been problematic. Usually it consists of bash scripts because that always seems like an easy way to get started.
I have found cabal sandbox add-source
to be buggy for some of my use cases. But even if that was not the case, the project workflow never ends up being 1st class. You have to write a wrapper for the build that initializes a sandbox and adds the other project.
With stack, you list where the .cabal
files are for your project and everything just works. Bad build systems end up being a net huge distraction, so I am relieved that FPComplete has put in the effort needed to help the Haskell community make a great project build tool.
I also contribute to several open source projects (wai, yesod, and persistent, among others) that contain multiple .cabal
files. Stack makes development there much nicer also.
At Front Row Education we merged multiple haskell git repositories into a single git repository that is now built with stack for development, continuous integration, and deployment. We spent less than a man-week (this includes staying involved with the stack project by reporting bugs and features and writing this post). At a previous company I worked at, more than a man-month was spent producing a worse build system. With stack, there was no build system to create, we just had to switch over from cabal. The only real build task was to make sure caching worked in Circle CI, our continuous integration provider. CircleCI made this easy: here are the main things we needed to add:
dependencies:
cache_directories:
- "~/.stack"
override:
- stack test --only-snapshot:
timeout: 1800
Support for package curation
Stacakge is a curated set of packages known to build well together. stack has first class support for building against stackage and helping you figure out when your need dependencies out of your current package set.
Package management that works
cabal sandboxes together with freezing made it possible to have a consistent build of a Haskell project that would not break another project. But there were still major problems.
- waiting for minutes for a sandbox to compile from scratch
- The sandbox layer introduced obscure bugs (one I experienced was an interaction with a custom Setup.hs)
- remembering to delete the sandbox when done to free up disk space
Note that stack does not garbage collect unused packages for you. However, 95% of the packages you use will probably come from stackage so you will end up with a high degree of package re-use across projects. You can always delete stackage snapshots (as you move on to newer ones) with the knowledge that it will never change a build plan of an existing stack project.
Simple workflows
In addition to better package management, With stack you don’t have to do
- type
cabal sandbox init
- type
cabal install --only-dependencies
- type
cabal freeze
- reconfigure tests (
cabal configure --enable-tests
) - type
cabal install --only-dependencies --enable-tests
- figure out how to invoke ghci to work across multiple cabal files
Stack is not perfect for everyone
Don’t use stack
- If you are perfectly happy using cabal
- If you will lose tooling support that you need
- If you don’t want to freeze your builds or test against stackage (for now)
Application authors that produce binaries should always build with exact (frozen) dependencies, and they will benefit a lot from stack. Libraries rarely freeze any of their dependencies and instead seek to support wide version ranges. Many library authors find it convenient to test against the latest stackage build: stack makes this workflow simple. However, others wants to continually test against the latest packages from hackage. Since cabal defaults to this behavior, cabal may always be better at this use case even as stack’s support for this use case improves.
Additionally, stack is young software.
- It has bugs (although probably no more than cabal)
- It doesn’t handle every use case that cabal does.
- Haskell’s tooling eco-system does not fully support using stack yet
The good news is that you can build a project with both cabal and stack and the two tools will not conflict.
Stack works well at Front Row Education
We worked around the lack of support in yesod devel
(a yesod project re-compiler) by writing an inotify script that isn’t quite as good. Stack support should be landing in yesod devel
in the future and there are already efforts to add stack support to many other tools.
Other than the above, everyone at Front Row was able to switch to using stack without difficulty and we are enjoying the ability to run stack build
or stack test
and have it work across all our project’s packages.