Simplicity of Design
I recently read XP Explained. It had a section on page 109 where it talked about simplicity. I often talk about the importance of simplicity. In fact, it’s on my list of fundamental assumptions about coding. In XP Explained, Kent Beck lists 4 criteria to evaluate how simple a design is. It might be helpful to think about these in terms of my previous presentation on How to Choose a FrameWork. I think these would be good things to add to the list of criteria I outline there. So let’s look at the 4 criteria and I’ll give some thoughts as to how they apply to both the Actor Framework (AF) and DQMH.
Appropriate For The Intended Audience
It doesn’t matter how brilliant and elegant a piece of design is; if the people who need to work with it don’t understand it, it isn’t simple for them.XP Explained, page 109
Right away you see an immediate difference between Actor Framework and DQMH in terms of the intended audience. Allen and Stephen designed AF for CLAs who are comfortable with OOP. Fab designed DQMH specifically to be approachable by CLDs without needing to understand OOP. As far as being appropriate for their audience, they both do a great job at that. So the question when choosing between them is who is your audience? Who is going to be maintaining the code you are writing and what is their competency level?
I used to think that the correct answer was to simply choose the framework based solely on the project requirements without taking into account the people working on it. My initial thought process was that if your people aren’t at the level they need to be at (or you wish they were at), you should invest in educating them and raising them up. I’ve come to the conclusion that yes, you should still invest in your people and raise them up, but that you also need to meet them where they are. Teaching a CLAD Actor Framework is a task that takes a lot of time and energy. They are not going to be able to contribute to an AF project any time soon. We have to be realistic about that. Creating code that is readable and understandable to the people working with it is a project requirement and it should factor into your analysis.
Every idea that needs to be communicated is represented in the system. Like words in a vocabulary, the elements of the system communicate to future readers.XP Eplained page 109
Both AF and DQMH are very specific in the language that they use. DQMH is very careful to denote broadcasts versus requests and the Message Handling Loop versus the Event Handling Loop. Actor Framework uses terms like Enqueuer, Caller vs Self Enqueuer, Pre-Launch Init, Actor Core. They both do a good job of using vocabulary to communicate intent.
AF and DQMH do differ in their communication styles though. In DQMH, everything is very condensed and easy to find. Everything you need to know about a module is all in one library in the project. It’s clear what messages it can send and receive due to the virtual folders. Outside the project, since almost everything happens in the case structure in the MHL inside the main VI, it’s very easy to find things and see what is going on. Each DQMH module also contains an API tester, which acts as an example of how to use the module.
AF is more difficult in that regard. Yes, each Actor is in its own library with its own messages and they are nicely organized. However AF’s strength of using inheritance to layer on functionality, means that you can’t just look at one Actor, you have to look at each of its parents. In LabVIEW, this requires a little extra effort. Also because of dynamic dispatch, you don’t have a case structure you can flip through, so it’s a little harder to trace things down. I just find AF in general much harder to visualize, because you have to pull together all these disparate things.
When choosing between the two, a lot comes down to how you prefer to have things communicated. Do you prefer seeing things condensed into a single library in the project and the case structure of the main VI? or Are you ok with navigating through the project window and jumping around a bit.
Duplication of logic or structure makes code hard to understand and modify.XP Explained page 110
In this category, I think AF has a slight edge. The class-based nature of AF and the ability to have inheritance layers does mean that you end up with less duplication. AF promotes this type of reuse. DQMH takes advantage of templating, which inherently means you end up with some duplicated boilerplate code. Most of the core framework code is stored off in vi.lib and shared among modules, but you still have some duplication. There is a definite downside if you start modifying that duplicated boilerplate code in some of your modules, so they are now not all doing the same thing. AF allows you to change some of that boilerplate behavior but its use of the Template pattern gives you some very clear boundaries.
At the risk of disagreeing with Kent Beck, I’m not so sure this category is all that important. At least not when comparing AF and DQMH. Yes in DQMH there is some duplication, but it’s all boilerplate code. I don’t feel like it makes it harder to understand the code. While AF does avoid duplication, I often find it harder to understand. In AF hierarchies that have a lot of parent actors, I find it very hard to keep track of the different functionality and which parent it resides in. I’d almost rather have things duplicated and be more explicit. That may just be my personal taste.
Within the above three constraints, the system should have the fewest elements possible. Fewer elements means less to test, document, and communicate.XP Explained page 110
This one is hard to judge and differentiate the 2 frameworks on. The frameworks are for the most part paired down, so it really comes down to how you implement your modules. In AF, if you have deep hierarchies of actors, I view that as an anti-pattern. I definitely prefer much shallower hierarchies. Also in AF adding messages, starts adding tons of classes and your class hierarchy just explodes. Doesn’t seem very minimal to me. The introduction of interfaces has made that situation much better. Now if you have an individual actor with just a handful of methods and messages, that seems pretty minimal. The same thing with DQMH, a module with too many messages seems like a code smell to me. Seems like a violation of the Single Responsibility Principle.
Why is this important?
This topic of simplicity along with the choice between AF and DQMH has been on my mind lately. Mostly I had been doing a lot of DQMH work lately and hadn’t touched Actor Framework in a while. Then last year I inherited a project written in AF. It seemed like AF was a little bit overkill for that project and that a simpler solution would have been better. Also in this case the developer not only used AF, but had used his own framework built on top of AF. So it got me thinking a little about the tradeoffs.
I also listened to Dan Press on the DQMH Podcast recently. He was talking about AF. He mentioned he had done a bunch of really cool stuff with it, but that when he went to hand it over to his customers he realized that it wasn’t the right audience. Right after listening to that, I read the passage in XP Explained. When I saw the first bullet point about being appropriate for the audience, I immediately connected the 2 ideas.
Something Joerg mentioned recently has also been rattling around in my head. He mentioned how DQMH has become his hammer of choice and he uses it for every new project. This AF project that I inherited probably suffered from the same fate. The original developer was an AF user and had his own framework built on top of AF, so he just automatically reached for that. He had a bunch of extra features built-in that weren’t being used. My initial thought was: “Why add all this complexity if it wasn’t being used?” I just viewed the extra features as roadblocks in my grokking the code.
Is it really well-designed?
I’ll leave you with a question that Steve Watts asked me. I was talking with Steve about the AF project that I had inherited. I mentioned how I had trimmed out a bunch of functions provided by the existing framework (built on top of AF) that didn’t appear to be used. I removed several 100 VIs and everything still worked. I was trying to be generous to the previous developer and mentioned that I thought the features were well-designed, but they just weren’t needed on this project. Steve responded with “Was it really that well-designed then?” His point was that design is about crafting a solution that meets the demands of the problem at hand. The code may have been well-designed as a general-purpose framework but was not well-suited to solving this particular problem. These extra features weren’t used and had the added negative effect that they made it harder for me to understand the code. The signal to noise ratio was off. I had to acknowledge that Steve had a point.