The Secret to Clean Code for Industrial Automation
5 min read
“I like my code to be elegant and efficient. The logic should be straightforward to make it hard for bugs to hide, the dependencies minimal to ease maintenance, error handling complete according to an articulated strategy, and performance close to optimal so as not to tempt people to make the code messy with unprincipled optimizations. Clean code does one thing well.”
-Bjarne Stroustrup, inventor of the C++ programming language
Manufacturing is a results-oriented industry. That’s why, as automation systems integrators, our mandate comes down to improving productivity, minimizing downtime and risk, and, to put it simply, getting the machinery to behave itself. This line of thinking, however, too often leads to an unfortunate fallacy: if the programmable logic controller (PLC) code works, then it must be good enough.
While it may work in the short-term, messy coding practices always come back to bite us. It’s more difficult to understand and maintain. It’s harder to upgrade or add new functionality. On-boarding new engineers is more difficult than it needs to be. All of this amounts to spending more time and money in the long run.
That’s why we advocate for clean PLC code. In this article, we’re going to go over our top 4 best practices for industrial automation clean code, but we should keep in mind that these strategies come down to one key feature: readability.
Readability is King
In Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin explains that “the ratio of time spent reading vs. writing is well over 10:1. We are constantly reading old code as part of the effort to write new code. Because this ratio is so high, we want the reading of code to be easy, even if it makes the writing harder.”
Clean code is made to be read, whether it’s by our colleagues, our customers, or even just our future selves. The most crucial step towards clean coding is making this shift in our mindset.
Industrial automation code should tell a story. Anyone familiar with PLC programming should be able to go in, follow the logic, and recognize the flow of inputs and outputs that lead to the finished product.
As Donald Knuth, author of The Art of Computer Programming, puts it: “Programming is the art of telling another human what one wants the computer to do.”
#1: Structured Code in Reusable Blocks
We can think about PLC code as a recipe for a manufactured product in much the same way as a recipe for the kitchen. We expect a well-written recipe to follow an expected structure—such as cut up the ingredients, mix them together, and then cook them—and we expect them to appear sequentially.
We approach clean industrial code with a similar mindset. Siemens's programming manual urges us to structure our automation task, explaining “Divide the entire function of your plant into individual areas and form sub-function units. Divide these function units again into smaller units and functions. Divide until you get functions that you can use several times with different parameters.”
There’s a few key takeaways here. First, we should hierarchically structure our program, ranging from a macroscopic plant-wide view to discrete steps in an automated process. Second, we also need to look for opportunities to reuse functions in multiple areas. We can employ a function that starts a motor, for example, across many instances without having to reprogram the function from scratch each time.
The Siemens manual continues to specify numerous advantages of how “the block concept offers you a number of options to program in a structured and effective way.
Blocks can be used universally in any location of the user program.
Blocks can be used universally in different projects.
When every block receives an independent task, a clear and well-structured user program is automatically created.
There are clearly fewer sources of errors.
Simple error diagnostics are possible.”
Reusable code leads to less code, which really means cleaner code. By organizing these code blocks according to a logical, hierarchical structure, our code is more readable because it more closely tells the story of what’s happening on the plant floor.
#2: Descriptive Tag Names
“You should name a variable using the same care with which you name a first-born child,” continues Martin in Clean Code.
Choosing better tag names is one the easiest steps we can take in pursuit of clean code because they enable us to match our code more closely to the physical machinery and phenomena. Instead of using m1 and m2 as tags for motors, for instance, we should spell them out as motor1 and motor2. We never want to use tag names like x, y, or z.
The same is true for magic numbers, which often represent a constant that we hardcode into the program. If we want to set a motor to run at 1200 RPM, we shouldn’t just put that number into the code with no explanation. Instead, set RPM=1200 and then use the tag constant RPM as needed. Not only does this make our code easier to read, but it also lets us easily change the RPM count down the line if needed.
Tags should be clear, repeatable, and consistent. In addition to symbolically naming tags, we should also strive to make them as predictable as possible throughout the code. This lets a new programmer (or even our future selves!) come in, pick out a pattern, and read the code.
#3: TODO bits
One of our clean coding practices for industrial automation platforms is to use consistent, predictable, and searchable placeholder tags. Commonly referred to in the industry as “TODO” bits, placeholder tags remind us to come back to a certain section of code while we work on another part. Using “TODO” bits is ubiquitous in the industry, but things can quickly get messy, especially when multiple developers are working on a single project.
Instead of “_DONT_FORGET” in one spot, “DO_THIS_LATER” in a second, and “REMEMBER_ME” in a third, we can make them more consistent by standardizing our TODO bits .
When developing in Rockwell’s Logix Designer, we recommend the following workflow:
Create a DINT in the Controller Tags named "TODO".
Give this tag any comment (we'll see why this is important later).
When you want to add a TODO bit, add a contact with an unused bit in the "TODO" DINT (you can quickly check which bits are in use by using the dropdown tag selector after typing "TODO" into the contact).
After adding the TODO bit, add a descriptive comment to the bit by double-clicking the top-level comment shown above the TODO bit (if we hadn't added the top-level comment in step 2, we'd have to return to the Controller Tag table to do this).
Now, you can cross-reference the top-level "TODO" DINT and see every TODO bit in use in the program.
When developing in Siemens’s TIA Portal, we recommend a different workflow (due to the differences in data types):
Create a global DB named dbTODO.
When you want to add a TODO bit, return to the TODO DB and add a bool.
Give the bool a descriptive name (if you use a descriptive name here, it shouldn't be necessary to use a comment, but if you have additional notes you can enter them as a comment).
Return to the ladder logic and add a contact with the newly added bool.
Now, you can cross-reference dbTODO to see every TODO bit in use in the program.
#4: Helpful Comments
Effectively commenting on code requires a careful balance. We want to convey as much information as possible through the code itself, so we shouldn’t rely on comments to make sense of messy code that’s full of nonsensical tags and magic numbers. On the other side of the spectrum, however, not writing enough comments creates confusion when it’s impossible for the code to fully explain itself.
This is especially true at the beginnings of major sections or if our code has to do something unconventional or inconsistent. For instance, if we’re programming scripts in a human machine interface (HMI) setting, there’s often some delay in communication between the PLC and the HMI, forcing us to change the way the script executes to have it correctly update. This break in consistency is an ideal place for a comment.
Comments should be concise. They should aid readability. As Automated Electronics puts it, “The comments might explain why that piece of code is there, or why the code is performing the function that it is. Code comments help anyone else who navigates your program to understand your thought process.”
Conclusion
Writing clean automation code is an investment with a clear ROI. First, clean code drastically reduces rework time and maintenance costs. Second, if we ever need to change developers, then the ramp-up time is shorter and they’ll bill less time.
Third, code reviews are easier and faster because clean code is simpler to explain and the tech lead will comprehend it faster. Finally, clean code is easier to share with stakeholders and customers who aren’t programmers. Reasonable tag names and comments in particular can help non-technical audiences map the code’s functionality onto their plant’s processes.
Here at Outlier Automation, we take immense pride in our work. We understand that deadlines have to be met, but that doesn’t stop us from taking the time to pay attention to the minute details and writing clean code.
“Quality is the result of a million selfless acts of care—not just of any great method that descends from the heavens,” concludes James Coplien in the forward to Clean Code. “That these acts are simple doesn’t mean that they are simplistic, and it hardly means that they are easy. They are nonetheless the fabric of greatness.”
You wouldn’t compromise on your machinery’s craftsmanship, and you shouldn’t settle for less with the code that controls it either. Whether you need help cleaning up an existing code base or you’re ready to start from scratch, contact us to get in touch with our team of clean coders.