In this post, I'll try to walk you through my journey in writing a testable, pure, effectful program in PureScript. Hopefully it will be useful in illustrating the types of problems more advanced techniques like monad transformers, free monads, and bifunctor IO try to solve.
A few months ago, Kent Dodd wrote an article highlighting a maxim about testing philosophy which is I believe is unhelpful. It goes: "Write tests. Not too many. Mostly integration." On the first point, I agree. You should be writing tests for most all the code you write. It not only helps you for regression testing, but also as a tool for iterating on the design of your code. The second point ("Not too many") is where I start to scratch my head. I have yet to work at a place where too many tests are the problem. TDD is a discipline, and like all disciplines, it more tempting to neglect it than to overindulge. So recommending you "not write too many tests" seems like harmful advice.
Extract error types (and their message templates) into a separate file for cleaner code.