typelevel / cats-effect

The pure asynchronous runtime for Scala
https://typelevel.org/cats-effect/
Apache License 2.0
2.03k stars 521 forks source link

Proposal: Cats Effect Contrib project #301

Closed gvolpe closed 6 years ago

gvolpe commented 6 years ago

Hi all,

Pushed forward by some ideas given by @vitorsvieira in the Gitter channel I'd like to introduce a new project called cats-effect-contrib (or cats-effect-ext).

Motivations

cats-effect was born to be simple, providing low-level combinators to build high-level ones. But it has changed. Since the introduction of features such as concurrency and cancelation, the project has gained more and more features making it nowadays a really powerful library.

However, it has gained so much functionality that many good features that will be tremendously valuable to end users don't exist yet because many of them can be implemented by using low-level combinators and at the same time we avoid polluting the base library.

Now this comes with a cost: users are ultimately confused on what are the best practices for solving some common issues because these issues are not directly solved by the library. Common cases are:

Blocking

This has been probably the most painful feature users had to suffer. The most recommended solution up until now has been using linebacker that implements the standard shift-and-shift-back pattern. And there's already ideas to bring it into Cats Effect . Also libraries such as http4s and doobie will benefit from this feature.

There is now ContextShift.evalOn which is safely implemented using Bracket to guarantee shifting back even in the present of failures. However, there's no high-level combinator blocking[F[_]](fa: F[A]) yet, even though there's a example in the docs of evalOn.

We could do a bit better and give the user a blocking function in addition to suggest what kind of thread pools are good for IO, computations or event dispatchers as linebacker does.

Retry

There are many different strategies and ways retry can be implemented, but probably one of the most common retry policies is exponential backoff. Here's an issue raised by @vitorsvieira to include retry functionality in the project but arguments are quite strong not to do so. See Gitter discussion for more.

The base inspiration for a good implementation is the retry Haskell library.

I think this functionality can belong in this side project instead of having multiple solutions lying around the ecosystem that are most of the time not very visible to end users. Also having the direct competitor zio having retry mechanisms baked-in is IMO reason enough to have this for cats-effect as well.

Console I/O

Although not something you would die for not having baked into the library, it gets annoying having to re-write the same code over and over again. How many times have you written something like this?

def putStrLn(str: String): IO[Unit] = IO(println(str))
def readLn: F[String] = IO(scala.io.StdIn.readLin)

I opened a PR some time ago to provide an effect-type agnostic Console[F[_]] but there were some strong arguments for not including it in the library so after a while I closed it. And I think that's fine. That's what makes a good library.

But I still believe having this ready to use in any project will be very valuable to stop repeating ourselves. So I think this side project could be the right place for it.

Even more

There are a lot of good ideas floating around the ecosystem that might or might not make their way into the standard cats-effect library and I think this side project could also be a good place for those experiments. Some good examples I recall right now:


So... What do you guys think? I'd love to hear your opinions and suggestions of what I might missed :smiley_cat:


EDIT: I have stumbled open solutions to problems that became quite common and in the end I believe other users can benefit from them too. For example:

Java Future conversions

We do have IO.fromFuture but no interop with Java Completable Future / CompletionStage. Here's my implementation.

First successful computation

Not as common as converting Java Futures but can be handy sometimes as a high-level combinator. Here's my implementation.

And there's probably many more I'm missing right now. @SystemFw is always giving great examples of what can be done with cats-effect in the Gitter channel.

johnynek commented 6 years ago

I personally don't like contrib type projects which often can become junk drawers.

I think many of the things you propose are good, but I would suggest either modules named: cats-effect-console, cats-effect-files etc... or putting them into the core project.

Failing that, I would start another project that depends on cats-effect that includes the things you feel are missing. fs2 and iteratee are also places we can imagine putting some functionality since both are using cats-effect and are related to some of the problems.

gvolpe commented 6 years ago

Thanks for your feedback @johnynek !

Having specifics modules sounds appealing too, I'd like to hear what other contributors think about it :) I believe these modules will have to live in the cats-effect repository and be published as a different jar right? (similiar to fs2-core and fs2-io, etc).

rossabaker commented 6 years ago

I'm in agreement with @johnynek. I'd only recommend fs2 and iteratee as a home for things related to streams and iteratees. Things that are more general belong in a more general place.

I like how @ChristopherDavenport has incubated new ideas in microlibraries. Some ideas from linebacker are finding their way in, which is good because much downstream deals with blocking and it's good to have a common idiom. Other libraries like log4cats are fine on their own, without adding to the burden of maintaining core and unburdened by other ideas, like retry. These non-core ideas mature at varying speeds, and multiple repos let them at their own speed. We just need to better publicize them.

vitorsvieira commented 6 years ago

Microlibraries are a reflection of user adoption.

Most of the microlibraries orbiting cats-effect, fs2, and http4s, are created by core maintainers of the same "umbrela" libraries. When users evaluate these core libraries, to use in their personal or professional projects, they often reach its limitations too soon, having to search outside for the "missing feature".

When searching, the microlibraries found are either:

But this is not the point.

The point is that the core is getting a positive attention and feedback from the community, but when the community jumps in and expresses their willings, ie. if feature A or B could be added, they are pushed to other libraries, usually Monix and FS2, which is fine.

If the roadmap is indeed "we don't do that here", would be perfect if the community had a place to go, where they could find support close to the support given to the core.

alexandru commented 6 years ago

I think the goal of Cats-Effect has been pretty clear from its inception, that goal being interoperability between multiple libraries that deal with effects.

Most of the microlibraries orbiting cats-effect, fs2, and http4s, are created by core maintainers of the same "umbrela" libraries. When users evaluate these core libraries, to use in their personal or professional projects, they often reach its limitations too soon, having to search outside for the "missing feature".

Note that it's not fair to punish people for being productive. If you have a project and want to get it into the same "umbrella", you can always:

  1. apply for Typelevel membership
  2. or kindly ask a mention in the Cats-Effect README; if the project is well maintained, I'm sure there won't be any issues with it

Of course in such a case you can't expect Cats-Effect contributors to also contribute to your project, so the project is your responsibility. This is a problem in open-source indeed, but you can't expect otherwise.

But speaking of the "umbrela", if there's one thing in Scala that I don't like is the tendency to go for mega libraries, like for example Lift, Akka, Play Framework, Scalaz. Haskell does not suffer from this. Clojure does not suffer from this. Small, composable libraries are a feature.

There is in fact a clear trend in Scala ... frameworks are preferred over libraries, mega libraries preferred over smaller ones; so first they get popular and then they whiter away, because mega libraries are in fact discouraging other libraries from existing.

If the roadmap is indeed "we don't do that here", would be perfect if the community had a place to go

Just as a confirmation, that has always been the plan, which is why I personally joined the project. With any other roadmap, I would have never joined. For any library, what is kept out is just as important as what's allowed. N.B. I'm speaking for myself obviously, not sure about the other contributors.

As for a place for the community to go, you cannot compete with a standard library and a standard library is in fact anti-community. That Cats-Effect does not allow the kitchen sink is actually good for the community, because it means you have a chance to contribute with your own libraries.


On the proposal, just as a sample — we have had for example a proposal for a "Console" in #256.

That proposal, I'm sorry to say, was weak for the reasons I mentioned in my comment.

And the better approach needs to show a design that scales to more than providing println, because otherwise it doesn't scale and if it doesn't scale it just turns into junk that users learn to avoid should they do anything more than a simple toy.

Now if you can come up with a better design for doing I/O via Cats-Effect, I would be happy to see it, I would help with acquiring Typelevel membership, I would approve of a README/website mention, etc.

But we cannot have that in the Cats-Effect repository or tied to Cats-Effect's lifecycle. It needs to be a project of its own. We've got enough problems as it is with the set of features being already provided — on master for example I just broke compatibility for Resource, which would have never happened if we wouldn't provide a Resource. And now that we do, well, we have to live with it.

SystemFw commented 6 years ago

As I've already mentioned in #295 and #212 , I have to agree with Alex, Ross and @johnynek on this one. It's very tempting to shove everything in cats-effect, because it's a common dependency and it's trusted in terms of quality and "branding". But imho we need to break this tendency and start developing libraries that depend on cats-effect instead.

If the roadmap is indeed "we don't do that here", would be perfect if the community had a place to go, where they could find support close to the support given to the core.

I fully, fully understand this concern :) But please note that this level of support comes with a very high cost in terms of effort, and every new feature increases this cost significantly. Adding another feature to cats-effect instead of its own library won't magically multiply the core contributors time I'm afraid, and the fact that a lot of micro libraries end up having poor support actually highlights what the issue is: writing code is easy, maintenance is the real problem (as an example, I could have written 100 microlibraries out of my gitter snippets, but I know I'd hardly have any time to maintain them).

But that being said, if a retry or console library gets created, we can definitely help out in making it "official" in terms of mentioning it in the readme or whatever, as long as the lifecycle is independent and the libraries are maintained.

We could for example have a microsite for all these things, while still keeping the projects separate to avoid the junk drawer effect.

gvolpe commented 6 years ago

Thank you all for your feedback!

I also agree with @johnynek , that a contrib type of project was not probably a good idea but I do like his recommendations as having different specific modules that can possibly live in different repositories and have and independent lifecycle with cats-effect as a direct dependency.

Just to be clear @alexandru I always understood the purpose of cats-effect but we have to recognize that the original idea have diverged since you've taken the lead :)

So... I decided to create console4cats and see how it goes from there. Thank you all once again :smiley:

gvolpe commented 6 years ago

WRT the retry functionality, given that there's already a project cats-retry we can contribute to it and give it more visibility on the cats-effect microsite, WDYT @vitorsvieira ? It looks good except for the blocking sleep approach it uses but it's easily fixable :)

cb372 commented 6 years ago

Regarding the cb372/cats-retry library, I've basically put it on hold until cats-effect 1.0 comes out but I'm happy to look at PRs and other contributions.

alexandru commented 6 years ago

Just to be clear @alexandru I always understood the purpose of cats-effect but we have to recognize that the original idea have diverged since you've taken the lead :)

🙂

It’s not just my fault, I’m not the only contributor or maintainer.

Most introduced features were desperately needed. For example I fought against IOApp but the that ended up being one of the biggest complaints on forums, plus we now have a pretty cool implementation that does interruption.

We have Ref, Semaphore, Deferred and MVar, however these are essential, being used in our own laws and in the literature on concurrency.

On the other hand I promised a CircuitBreaker (that we have in Monix) but I am not convinced that it is general purpose enough.

So we’re not as minimal as at first but we still do triaging.

But we should do a better job at encouraging micro-libraries. If there’s anything I like about Typelevel Cats is how it encouraged collaboration between libraries by not providing the kitchen sink.

ChristopherDavenport commented 6 years ago

I also threw together system-effect as a baseline we can improve for system level interactions. Although currently it has what I needed it for only. However I think it could handle basic file handles as the tool for most of this work rather than the scala tools. Just as a place to collaborate on the system level tools.