Trying to learn functional programming on my own has been a bit challenging. Most of the resources available are either too basic (“This is an Option!” “this is an Either!”) or so complex that I can't tell if they're serious or just joking.
Let's consider a practical hypothetical scenario:
The goal of the function is to create an endpoint that takes a file name and a string, then writes it to a static store. The process involves:
- Checking if the user already has more than 10 files stored, and if so, returning false
- Recording the file name in the database
- Writing the file to the file system
- Logging the transaction
- Returning true
There are three external systems involved: the database, the file system, and the logger. An initial simplistic implementation could look like this:
const USER_FILE_MAX = 10;
const saveFile = async (user: User, filename: string, contents: string): boolean => {
if (await db.fetchFileCount(user) >= USER_FILE_MAX) {
return false;
}
const success = await db.transaction(async () => {
await db.writeFilename(user, filename);
await fs.writeFile(filename, contents);
});
logger.log(`${user}.name wrote ${filename} ${success? "un" : ""}successfully`);
return success;
};
However, from a functional programming perspective, this approach is not ideal. I'm struggling with how to refactor the function and services to achieve a more functional, readable, and testable solution.
I've come across suggestions to use IO monads, Effects monads, or Tagless-final monads, but I'm having difficulty implementing any of these options effectively.
If you have any suggestions, please feel free to share them.