I am just starting to watch but at the beginning of the video they both agree that TTD sucks because no one wants the tests to direct the architecture design. I strongly disagree because one does not just start by writing tests. There is a thinking phase before, were architecture decisions are made. And then you can let the tests drive the implementation of the different modules interfaces/API.
I think in Elixir there are two styles of modules : big modules and small modules. The big module kind is where you have one module that manipulates multiple types (records, structs, tuples, and lists of such types), and where structs module contain only the defstruct, and maybe a new
function and a couple helpers. The small module kind is where each module, notably struct ones, contains all the logic related to the type. I find myself fighting for that pattern, because it is heavily influenced by OOP, while I find that big modules are better to write complicated logic involving multiple types, all in one place (though the struct or data-structures modules are still useful to handle everything opaque – like how a username is stored in memory for instance, but not how we use that username).
And I feel TDD is perfect to find the good design of such functional code.
Now when I think architecture in Elixir, I think processes. Pure functional code is easy to write, and easy to change, it is about algorithms. TDD does not focus on algorithms, rather on APIs and interfaces. Complex algorithms are in defp
land and TDD does not force you about how to write that. It helps you make your code more testable, more modular.
For process architecture, the thinking phase is crucial, the sup tree design is very important, and you should come up with a full design that works before starting to write code. TDD is not very helpful here, but neither does it enforce any architecture. And that TDD is not helpful there is only partially true. If you use TDD to design a modular functional core that has usable APIs, it will be easier to use in higher layers (gen servers, tasks, subscribers), and that higher layer will be easier to design once the core is ready, because you will have choices.
Two remarks though:
First, I often find myself writing small prototypes without any tests in .exs files, just to verify that some design could work. Thas is code to throw away when the concept is proven to work, and the TDD phase can start. It is not forbidden to write code, throwaway code, during the “thinking” phase.
Second, I know “architecture” is not only processes. We could call that “system” architecture, but there is also “architecture” in the choice of how some complicated data pipeline is designed. But that generally boils down to the same old patterns we always use : repositories for persistence, a transform layer that converts data structures to other data structures, queues to manage the load, etc. Sprinkle a couple adapters on top of that when you have to deal with different shapes for the same “thing” and you are good to go. TDD is perfectly compatible with that. On the opposite, I find mylself bringing a lot of useless abstractions when I think too much about that kind of architecture without writing code and tests.
Edit: regarding their criticism of Elixir, it is “I would never recommend anybody ship it but we got a lot done with it”.