I have a driver function modifyFile
that interacts with many sources in the outside world (e.g. HTTP, filesystem). Let's say the code is as such:
def downloadFile(from: String, to: String): Try[Unit]
def runUnixProcess(cmd: String): Boolean
def modifyFile = {
downloadFile(from = "http://.../some/file.dat", to = "/tmp/file.dat") //
val status = runUnixProcess("/usr/bin/somebinaries /tmp/file.dat")
if (status == Status.OK) deleteFile("/tmp/file.dat")
}
For the sake of the argument, let's consider that these functions abide to the Single Responsibility Principle rule, and that modifyFile
is only a driver that "integrates" and facilitates communication between separate entities such as OS, File system and web service.
While this function will most likely sit in the higher level of the application logic, some other application function might be built on top of it. Hence, I want to have some kind of proper abstraction (e.g. by wrapping it with a monadic construct) so that we can still compose an even higher abstraction over it.
Now my question: What is the best language construct to abstract this kind of computation? Namely a computation that:
- calls to many entities in the external world
- may fail, either partially or completely at some steps due to various conditions. To name a few, we might be dealing with filesystem permission issue, network connection issue, unix binaries missing issue, etc.
- might need to be ran asynchronously, considering that there are several blocking calls in it.
Is Scalaz's Task
up for it?
Or should I simply wrap it as a Future[Try[T]]
, which basically captures most of the characteristics it exhibits?