Hi,
A question about design … I have some code here: https://github.com/sageserpent-open/kineticMerge/blob/issue-1-clean-merging/src/main/scala/com/sageserpent/kineticmerge/Main.scala . It’s a command line tool.
The intent is to run a workflow of commands that change state in a Git repository, but abort immediately on a serious error, provide a custom error message that provides some context instead of an exception, and to rollback any changes made so far in the workflow prior to the error taking place.
When operations in the workflow succeed, logging entries are made and are shown on completion as a summary of what happened.
It works nicely enough, but has a bit of a hash of use of imperative Try
expressions that are converted into a Workflow
- that’s Cat’s EitherT
layered on top of Writer
. I’m bit uncomfortable with the mixing of Try
with its immediate execution semantics with things like Writer
that defer the logging in a nice clean functional way. If immediate execution is OK, why not simply print the logging entries directly in the imperative blocks?
Anyway, I thought I’d scratch an itch and refactor to using something like IO
. My first thought was of a transformer version of IO
, but I haven’t yet seen such a thing. What I’m left thinking of is an explicit …
private type Workflow[Payload] =
IO[EitherT[WorkflowLogWriter, String @@ Tags.ErrorMessage, Payload]]
So the job is to cutover Try
to IO
, handle the exceptions with IO.handleError
and spit out IO[EitherT[WorkflowLogWriter, String @@ Tags.ErrorMessage, Payload]]
.
I looked briefly at LiftIO
but this would seem to do much the same as Try.toEither
- my instincts tell me to stay in IO
for as long as possible.
Rollback could be done with IO.bracketCase
, I imagine.
Any suggestions from the floor?
Should I just stick with what I’ve got?