I completely agree that TDD originally meant that, and still does. The problem is too many developers don't bother to learn what TDD really means and immediately think of it as a testing methodology because the first word is "test". Maybe changing the language can change the focus to where it was supposed to be from the beginning.
HN user
jarhart
I'm often frustrated with developers looking at the term "test-driven development", focusing on the word "test", and thinking of TDD as a testing process instead of a development process. The BDD movement made some progress on this front, but it still seems to be a problem. Maybe calling it "specification-driven development" is the next step.
Actually it's not. Only the primitive readers have similar "overhead" as with the implicits approach. Most of the readers are defined by mapping or flatMapping over the primitives (either explicitly or with comprehensions). With the implicits approach all of the "injected" methods need to declare the dependency via the implicit parameter. With the reader approach, only the primitives have to declare it. Compare the implicits version of UserInfo to the reader version. UserRepository doesn't appear anywhere in the signatures of the reader version.
It does actually solve the problem that DI solves in general, because you create readers that expect the dependency to be injected into them. You still have to decide how to do the injection and that's true for all of the non-framework approaches AFAICT. With the cake pattern you still have to create an object somewhere that mixes in all of the concrete implementations. What you gain from the reader pattern is being able to limit the biolerplate to edge where the injection actually occurs.
As far as having to create a whole dummy Config for testing, that's a fair point, although the reader approach makes it easy to inject it since every reader is a function of the Config. I usually only have a small number of dependencies so it hasn't really been an issue for me. If you're mocking the dependencies each one is only one line of code, and for dependencies you don't need in the you can just use ???.
I look forward to that blog post. In order to use Scalaz's monad transformers with scala.concurrent.Future, would I have to write my own monad instance for it, or is there a way to re-use the one from scalaz.concurrent?
Technically, Scala's for comprehensions don't let you mix monads either, but implicit conversions make it work in some cases. For example, there's an implicit conversion from Option to Iterable so the Option (Maybe) and List monads can be mixed. It's really more a matter of Scala's type system allowing it. The Scala compiler just re-writes comprehensions into equivalent higher-order function application.
I actually like using comprehensions in Scala so I don't find it annoying at all. Also I think having a clear distinction between the "normal" and "injected" functions is a good thing.
I do find having to add implicit parameters to every function slightly annoying, especially because when I forget, it's not always clear from the compiler error what I did wrong.