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
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?