I’ve been reading quite a lot about ”Domain Driven Design” lately. It’s inspired me to think about how to re-design the 700 lines long ”blob” that is pytddmon.py into something more manageable and grokkable pieces. Hopefully even less lines!
The basic idea is to use asynchronous messages to communicate between the different parts of the ”system”, which would be split up into ”actors” running in their own thread:
- A ”Heartbeat” thread/actor simply publishes ”beats” to the message bus at regular intervals
- A ”FileChangeMonitor” thread/actor subscribes to the beats, and checks for file system changes. If a change is detected, it publishes a ”FileChange” message.
- A ”TestRunner” thread/actor subscribes to the ”FileChange” message, and does the actual test running (using a separate Python interpreter process as usual – we still need that to avoid the import cache). When the run is over, it publishes a ”TestResult” message.
- A ”GUI” thread/actor subscibes to the TestResult message, and updates the appropriate UI widgets.
A nice side effect of this refactoring, apart from a humble hope that it will be simpler to unit test each part in isolation, is that extending the system becomes easier.
- Exchanging the TkUI based actor with a console/text UI becomes almost trivial; just instantiate another class on pytddmon boot. The implementation of a TextUI is in itself trivial. Doing a text UI in the current architecture would mean duplication and a lot of headache!
- Creating a plugin system, e.g. to make a plugin for snapshotting the source code after each test run, is almost trivial: just allow dynamic importing/instantiating of plugin modules, that can subscribe to the events published by pytddmon.
Of course, this needs some thought. For example, I still want to keep both the ”xcopy” installation model of pytddmon, aswell as trying to separate things into more files to ease development (700+ lines of code is not my idea of well-structured code…). This in turn puts more demands on the CI system (Travis) which needs to not only test one pytddmon.py file, but also ”assemble” that pytddmon.py file, aswell as test the separate-module-version of pytddmon.
We will also need a mechanism to actually send asynchronous messages, but after having read and tested Python threading over the summer, I think Queues and threads are all that’s needed for a straight forward implementation. Going in the ”as few dependencies as possible” philosophy of pytddmon I’ll likely roll my own class ”MessageBus” (which is the likely and conventional name for such a mechanism). Read more about the architecture over at wikipedias article on the Publish-Subscribe pattern.