The SOLID Principles
The acronym SOLID stands for the following five principles:Single Responsibility Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
Open-Closed Principle and TDD
Out of all the SOLID design rules, the “O” rule (Open-Closed Principle) seems to me the most important for TDD, as well as the iterative and incremental development in general. If the system we design is “open for extension but closed for modification”, we can keep extending it without much re-work and re-testing of the previously developed and tested code. On the other hand, if the design requires constant re-visiting of what’s already been done and tested, we have to re-do both the code and the tests and essentially the whole iterative, TDD-based approach collapses. Please note that I don’t even mean here extensibility for the future versions of the system. I mean small, incremental extensions that we keep piling up every day to build the system in the first place.
and Blocking in an RTOS
So, here is my problem: RTOS-based designs are generally incompatible when it comes to the Open-Closed Principle. The fundamental reason is that RTOS threads use blocking for everything, from waiting on a semaphore to timed delays.
Blocked threads are unresponsive for the duration of the blocking and the whole intervening code is designed to handle this one event on which the thread was waiting.
For example, if a thread blocks and waits for a button press, the code that follows the blocking call handles the button. So now, it is hard to add a new event to this thread, such as reception of a byte from a UART, because of the timing (waiting on user input is too long and unpredictable) and because of the whole intervening code structure.
In practice, people keep adding new thread that can wait and block on new events, but this often violates the “S” rule (Single Responsibility Principle). Often, the added threads have the same responsibility as the old threads and have high degree of coupling (cohesion) with them. This cohesion requires sharing resources (a nightmare in TDD) and even more blocking with mutexes, etc.
and Event-Driven Approach
Compare this with the event-driven approach, in which the system processes events quickly without ever blocking. Extending such systems with new events is trivial and typically does not require re-doing existing event handlers. Therefore such designs realize the Open-Closed Principle very naturally. You can also much more easily achieve the Single Responsibility Principle, because you can easily group related events in one cohesive design unit. This design unit (an active object) becomes also natural unit for TDD.
So, it seems to me that TDD should naturally favor event-driven approaches, such as active objects (actors), over traditional blocking RTOS.
I’m really curious about your thoughts about this, as it seems to me quite fundamental to the success of TDD. I’m looking forward to an interesting discussion.