snoyman.com-content/posts/breaking-changes-dependency-trees.md
2018-01-09 06:59:56 -08:00

128 lines
6.1 KiB
Markdown

My
[previous blog post](https://www.snoyman.com/blog/2018/01/drop-conduits-finalizers)
discussed a possible upcoming breaking change to the conduit library:
dropping finalizers. This is one of a number of other breaking changes
I have planned. Another one is switching over from `MonadBaseControl`
to `MonadUnliftIO`, for reasons I've
[discussed](https://www.fpcomplete.com/blog/2017/06/tale-of-two-brackets)
[at](https://www.fpcomplete.com/blog/2017/06/readert-design-pattern)
[length](https://www.fpcomplete.com/blog/2017/07/announcing-new-unliftio-library)
[before](https://www.fpcomplete.com/blog/2017/07/the-rio-monad) and
[spoken](https://www.snoyman.com/reveal/monad-transformer-state)
[about](https://www.youtube.com/watch?v=KZIN9f9rI34) too.
Beyond this change, I have a number of others planned out as well,
some more solidly than others. I've started a document
[describing some of these](https://github.com/snoyberg/codename-karka/#refactor-michaels-existing-libraries-to-match),
and I wanted to bring up one point in this design space for some user
feedback: conduit dependency trees.
## Today
The situation today is that we have a dependency graph that looks
something like the following:
* `resourcet` is at the base of the hierarchy, and defines some
non-conduit-specific types and functions used throughout the conduit
ecosystem. It currently depends on a number of packages, like
`monad-control`, but that number will naturally drop as we move over
to `MonadUnliftIO` exclusively.
* `conduit` is designed to provide basic conduit functionality with
fewer dependencies. It _does_ depend on `resourcet`, and packages
like `monad-control`. But it does not depend on `bytestring`,
`text`, or `vector`, even though these are almost always wanted with
conduit. It provides the `Data.Conduit.List` set of combinators,
which are not the best ones out there.
* `conduit-extra` adds _lots_ of dependencies, including things like
`attoparsec`, and provides a nicer set of helpers around
`bytestring` and `text`.
* And finally, at the top of the tree (or our tree for today), we've
got `conduit-combinators`, which provides the combinators I actually
recommend people use in the `Data.Conduit.Combinator` module. This
has lots of dependencies, since it inherits from `conduit-extra` and
also adds in some extra things like `mwc-random`.
Benefits:
* You can use `resourcet` without touching the conduit ecosystem at all
* You can use `conduit` without pulling in lots of resources
* `Data.Conduit.Combinators` is fully loaded
Downsides:
* The current dependency footprint even at the base is higher than I'd
like, though that's getting fixed soon regardless.
* The `conduit` package is not super useful on its own due to lack of
`bytestring`, `text`, and `vector` support.
* To get the functionality you want in either `conduit-extra` or
`conduit-combinators`, you end up with a _much_ larger dependency
footprint.
## Plans for the next version
I have a number of different ideas in mind. I'll start off with the
most conservative plan, and mention some variants below.
* As already mentioned, `resourcet` drops a bunch of
dependencies. Nothing too interesting there.
* `conduit` adds a dependency on `bytestring`, `text`, and `vector` as
basic libraries everyone should be using anyway. We move over
`Data.Conduit.Combinators` and provide most of its functionality in
`conduit` itself, and start recommending against
`Data.Conduit.List`, `Data.Conduit.Binary`, and `Data.Conduit.Text`.
* `conduit-extra` basically remains as-is
* `conduit-combinators` retains the extra functionality not present in
the new `conduit`
Benefits:
* The `conduit` package now provides most of the functionality you'll
want on a day-to-day basis
* The dependency footprint for the `Data.Conduit.Combinators` module
is much reduced
* We can finally get away from the not-well-named functions in
`Data.Conduit.List`
There aren't necessarily _downsides_ to this approach, as I think it's
simply better than what we have today already. But I want to list out
the alternatives, which will make clear some things that could be
possibly better still.
* What do we do with the `mono-traversable` package? It's currently a
dependency of `conduit-combinators`, and the simplest path forward
for the above is to make `conduit` depend on
`mono-traversable`. However, this is a slightly heavier dependency
footprint, requiring adding in `unordered-containers` and
`vector-algorithms`. Alternatives:
* Strip down `mono-traversable` to have less deps
* Redefine parts of `mono-traversable` needed for `conduit` in
`conduit` itself
* Going crazy: _really_ move `mono-traversable` into `conduit` and
swap the dependency tree around
* My inclination: minimize `mono-traversable`'s dependencies a bit
more (like dropping the `split` package, and _maybe_
`vector-algorithms`) and make it a dependency of `conduit`.
* Do we really need `conduit-combinators` as well as `conduit-extra`?
It's just adding a few extra pieces of functionality over
`conduit-extra`, and perhaps those should be folded into
`conduit-extra` itself.
* Some people may not like the heavier dep footprint of `conduit`
now. Should we split off a `conduit-core` package providing the core
data types, functions, and operators, and have `conduit` depend on
that?
* It feels almost silly to have the `ResourceT` data type live in a
separate package.
* If we have `conduit-core`, that could be a logical place to put
it, since it won't have any extra dependencies versus the
`resourcet` package itself, and then we can turn `resourcet`
into a backwards compatibility layer.
* Or it may be logical to place `ResourceT` in the `unliftio-core`
package, since both concepts help with resource cleanup in monad
transformers. The former is necessary for continuation-based
monads, while the latter (`MonadUnliftIO`) works for simpler
monads.
If people have feedback, I'm happy to hear about it. I've spent an
unfortunate amount of time bouncing around between these different
options, so hopefully writing it all down and hearing some outside
opinions can help move this forward.