Humility and Better Programming, Part 5
Programs, like any other human-made objects, are designed—or should be designed—with a definite lifespan and scope of application in mind.
…a program should have neither over-designed or under-designed parts. Yet it is an occupational disease of programmers to spend more time on those program parts that present, for some reason, the most intellectual challenge rather than on those that require the most work.
…each program has an appropriate level of care and sophistication dependent on the uses to which it will be put. Working above that level is, in a way, even less professional than working below it. If we are to know whether an individual programmer is doing a good job, we shall have to know whether or not he is working on the proper level for his problem.
Nancy and I recently got into a discussion about the best programming approach for a particular application. We both had in mind that maintainability of the application was very important. As is common for the two of us, we wanted to take different approaches to get to the same place. She proposed on OO plugin approach that I thought was more complex than needed. As we talked about it, I realized we had slightly different ideas of what “maintainability” meant.
I was thinking that the need for maintainability emphasized simplicity. She was looking down the road a bit, thinking the customer was going to need more flexibility than would have been afforded with my approach. Thus, her more scalable solution was going to be more maintainable in the long run.
Who is right?
Well, I am, of course. The customer isn’t asking for scalability right now. So Nancy is speculating. I’d rather wait until the customer asks for (and convinces me she needs) the scalability before I go to the trouble of writing it.
To be fair, Nancy’s approach is just as right, and she may know what the customer wants better than I do—and maybe even better than the customer does. Nancy may also be confident that she can add the scalability without adversely affecting the initial development time or the maintainability of the code. This seems like a prime opportunity to go ask the customer for clarification on their future plans.
This example also illustrates another key point. Nancy and I both have enough LabVIEW experience and skill to design and build an OO-based plugin architecture. I made a conscious choice to exclude it. Nancy made a conscious choice to include it. If we didn’t know about OO plugin architectures, we would not have a choice to make—we would have left out the scalable solution because we knew no better.
That right there is why I want you to become a Certified LabVIEW Architect. I want you to know enough about LabVIEW that you can decide when to use—and when not to use—the many tools that are available. Don’t let a lack of knowledge of advanced LabVIEW concepts make the decision for you.
Going back to the quote at the top of this post about using an “appropriate level of sophistication”, I’m reminded of another discussion I had with an engineer at NI. First, let me show you an example which in a loop, acquires 200 samples of analog data and scales the data based on the value of a front panel control. The acquisition timing is configured in the task in MAX. A novice programmer might program it this way… (Click the images to see full-sized versions.)
The conversation with my colleague, who is a very fast LabVIEW programmer, went something like this… “Polling user interfaces are bad. You should use an event structure. Something like this example…”
There’s a good chance that the novice programmer wouldn’t have known how to build this event-driven program. But here’s my question for the expert programmer… “Why didn’t you write it the simple way?”
In this case, the novice programmer is me. I do have the skills to build an event-driven program for this application, but I didn’t think it was appropriate. What’s an example of something I give up by not using an event structure? If my read hangs waiting for a trigger, then the stop button takes up to ten seconds to stop the VI, while I wait for the timeout on the read. What if that’s not acceptable? What if I needed to respond in less than five seconds? Before diving into a rewrite using event-driven programming, I’d first ask whether I could just lower the timeout on the Read to be five seconds. Maybe I know my trigger will never take that long without it being an error.
There are ways I can make this program more robust, more responsive, more scalable, more capable. But why do that if those aren’t requirements? Mandates such as “don’t write polling user interfaces” are too stark. Fortunately, my colleague has backed off of his tough stance against polling user interface loops. He doesn’t like them for most user interfaces, but he sees that there are times when they are the most appropriate solution.
A note about frameworks… Nancy has been thinking about software frameworks recently. (I’m hoping she’ll write a blog post about it.) Lifting from the entry in Wikipedia about software frameworks…
A software framework is a universal, reusable software platform used to develop applications
It goes beyond just a reuse library or a design pattern which provide only elements of an application. A framework imposes a structure on the entire application. One such framework is the Actor Framework, which we started shipping in LabVIEW 2012. There are many other frameworks for LabVIEW applications. Some companies have developed their own for their typical applications. Some are shared for the community to use. In the theme of being “too clever”, I have seen some customers apply their favorite framework to every programming problem they have. If all you have is a hammer, everything looks like a nail. One of the traits of a good Certified LabVIEW Architect is that they have more tools in their toolbox, and know when to use each appropriately. The Actor Framework, as an example, is one way to architect an application when you have a bunch of independently running processes that need to communicate. If you have an application that doesn’t involve a bunch of independent processes, I wouldn’t try to force my application to the framework. Instead, I’d recommend finding or creating a more appropriate framework.
If you’ve made it this far, thank you for sticking with this long post. As an old programmer, I have a fair number of battle scars (also known as “experience”) which I sometimes take for granted. I make many programming decisions almost without thinking. Some are just a force of habit, and I might not stop and teach these habits explicitly, and this blog post is an attempt to capture and share a few of those thoughts.
I would love to hear your feedback on this series. Let me know what you think. I’ve put together a short bibliography if you’re interested in additional reading.
Very good series. Most of the intermediate-to-advanced programmers I’ve talked to subscribe to these ideas. Most of the managers we’ve had do not. How does this mindset get “pushed upstream”? Become a manager?
Excellent series Brian, thanks for writing it.
Something I’m looking into is whether a simple solution is inherently easier to change, scale and maintain than a very complex solution with extensibility built in and what the pinch point is. Also that flexibility and scaleability are very different things that are sometimes confused. I would suggest a simple flexible solution is pretty much always required, a scaleable system is not required that often. I think this is to do with LabVIEW being a very high level language, so for C++, scaleability is really important, LabVIEW not so much.
I’ve no evidence to support this though!
Congratulation – great series! I sent to all the team-mates…
” I want you to know enough about LabVIEW that you can decide when to use”…
I agree wholeheartedly. I recently said the following in a gchat with regards to LabVIEW: “I also like learning new things in general because the more tools I have allow me to choose which is right for certain situations.” I think this can be applied to everything, not just writing code.
Good series Brian. Two points:
1. I strongly agree with the principle of only writing what I need, with the caveat that I have a clear path to easily add new functionality when the customer requests it. I hate coding myself into a corner. I’ve run into (and even written) too much legacy code where developers implemented the “simple” solution, built more functionality on top of it, and ended up with a rigid app that was unable to adapt to changing requirements. (*cough* QSM *cough*) What sets great programmers apart is not only using simple solutions, but knowing when to abandon the simple solution and use a solution with a higher level of complexity.
(Another way of thinking about it is to write the code as simple as possible given the *project* requirements, not as simple as possible given the software’s immediate *functional* requirements.)
2. To you maintainability (I prefer “sustainability,” but either works) meant simplicity. To Nancy it meant extendability. In my opinion, maintainability encompasses a host of -ilities developers need to keep in mind, including:
– Readability (understanding the code in a single vi)
– Comprehensibility (understanding the program structure and how the components work together)
– Extendibility (adding new functionality)
– Debugability (finding previously unknown errors)
– Testability (regression testing)
These are the -ilities I focus on, in roughly that order (though they get reshuffled according the project.) Applying the word “simplicity” to source code feels too ambiguous. It could refer to either readability or comprehensibility, and emphasizing one can reduce the other.
Excellent series. Thanks.
Thank you so much for these articles, I really do love them. Already shared them with fellow programmers, also “non-graphical” ones 🙂
Really nice series! Good job Brian!
Thank you for the series, Brian. It’s been a real pleasure to read through it and be able to reflect on my own work and work of others through the lens of your post.
Excellent Brian, This series will really push the programmers to think the way to write LabVIEW program in the appropriately, recently I started working on the Actor framework and this post really made me to push myself to explore more about actor framework.