> Which goes back to the article's point of having to write code that is unit test friendly.
> Now architecture decisions have to integrate interfaces that wouldn't be needed otherwise.
You're not wrong.
But in the context of functions, that doesn't seem to me to be particularly onerous. If the worst I'm forced to do is change the type of my parameters to an interface instead of a concrete type, that seems like a pretty small price to pay for easy testability. Certainly a much smaller price than the examples in the article.
That's how a lot of great C code is written anyway. A C library should abstract out logging, allocation, and IO so that the client code can change them out if need be.
The fact that it makes unit testing easier is just icing on the cake.
Agreed, and this goes back to the initial thread that just because a language is more focused on functions it doesn't make testing automatically better, unless it was written with testing friendliness as part of the requirements.
For C, I've found it's not a test friendliness thing though; the great C libraries were doing this before unit testing made it's way into their codebases. They dependency inject IO, memory allocation, and logging because they have no idea what you as the end user are going to be using for those. So you pass all that in on an env struct when you initialize the library.
You probably want it rigged up to your own logger instead of just blindly writing to stdout. You probably want the library's allocations tagged somehow on the heap so you can track down memory leaks. You probably don't want it doing IO directly, because of how many different way there are to do IO.
It's all more a function of how incredibly varied c envs are, than design for testability. It just happens to be very testable as an aside.
Which goes back to the article's point of having to write code that is unit test friendly.
Now architecture decisions have to integrate interfaces that wouldn't be needed otherwise.
> Maybe you could elaborate. I really don't understand what you mean here.
Modules keep state via global variables, module private functions and the surface control that they might expose via public API for the module.
Additionally on languages that support them, they can be made available as binary only libraries.