Ten control system programming best practices
Best practices for programmers include defining their structure, knowing the system resources and tools, consistency, and keeping track of changes during a project.
Control system programming is an art and a science. Utilizing multiple tools, languages, and functions allow engineers to produce a creative solution. However, due to the multiple methods and tools available, the road to success can vary greatly depending path chosen. Programming standards are methods of coding that have been declared acceptable and are typically defined and supported by control system vendors.
Closely tied to programming standards are "best practices," which outline recommended methods and strategies to follow when applying and deploying programming standards. Best practices may also involve the addition of extra code segments and/or removal of redundant or dead code that are not used. Best practices are recommended ways of writing a segment of code, whereas programming standards are a specific set of rules to apply to coding style and techniques. These 10 best practices can help provide a baseline to help ensure consistent success for the programmer.
1. Define the structure
When developing a program from scratch or augmenting an existing program, the programmer must step back from the details and define a structure. This provides a clear plan of how to divide up the functions, variables, and provide a logical arrangement. Segmentation of functions allows for a design that can easily be expanded and followed by other programmers.
Start by developing a visual diagram of how the code will be structured. In some cases, the programmer can clearly outline this structure within the actual code. This is comparable to building a legend table within a drawing and it should provide a map of how the program will be structured and/or any segmentation and development notes to clearly outline so the next programmer will be able to follow the same methods. This structure should include both the controller code as well as the HMI programming.
2. Supporting documentation for developing functions
Supporting documentation of functional requirements and/or specifications is essential to allow developing functions.
Just as important are supporting documentation of the programming standards that will be used to achieve the objectives defined in the specifications. Most distributed control systems (DCSs) have a standard library that outlines how each functional element will be configured, such as a valve, motor, PID, etc. that has supporting documentation. However, in other applications like PLCs, the structure does not exist and must be documented and developed.
The supporting documentation does not require a lengthy formal document but it must clearly outline the structure and programming standards that will be followed. A simple spreadsheet can be used to relay this information. However, the ideal location for this information is the actual program itself to ensure the standards are always coupled with the code and not misplaced.
3. Plan for change
When developing a system, it is important to plan for future expansion, changes, and reductions. When the programmer is defining the structure, they should always be aware of potential changes and ensure that they do not paint themselves into a corner. Do not outline limited strategies that could potentially cause a change in strategy. For example, if the programmer segments the memory locations for each data type, be sure to have plenty of room for changes and/or expansions of the system in the years to come.
In addition, it is always a good idea to outline the structure on paper to visually identify how the code will be segmented and introduce some potential changes to test the organizational structure of the design. Planning for change is difficult because you don’t know what you don’t know. It is always recommended to review the concept with other more experienced engineers to ensure the obvious is not being overlooked. There is a balance here between planning for extra-scope future expansions and meeting the requirements. Allow for future expansion, but do not devote significant resources to out-of-scope development.
4. Know the system resources
System resources are a vital part of what makes software run efficiently and the last thing the programmer wants to do is overburden the system’s capabilities, which could cause latency or even crash the system. This issue was more prevalent in years past due to memory and processing speed limitations. Technology has advanced and the programmer now has much greater capabilities within a system to provide a more structured and organized code. However, the resources are not unlimited and it is always good practice to understand where the limitations are and how the structure is impacting those resources.
This is accomplished by performing a loading test, which will help the programmer get a feel for where the limitations are. To do this, create an application with extensive loading using additional structure and routines that are far outside of the existing scope that is trying to be achieved. Not doing this is irresponsible. The programmer would be blindly adding structure and overhead processing requirements without knowing how much room you have to grow the application. A resource test may require multiple application expansions, but finding the limit is crucial for success.
5. Reuse code
The easy part of control systems is that we continually reuse of the same functions to achieve the logic task at hand. The programmer does not want to hard-code the same functions over and over, which would incur additional costs such as increased memory, processing speed, and extra time to make changes to an application that is programmed not utilizing function calls.
By separately coding common code, the programmer also introduces an opportunity for error down the road because changes to one instance must be accurately copied to all other instances by hand—an invitation for human error. All functions that are used should be referenced from a single sources library and called when needed. This will require the programmer to code the functions on a general level and, in some cases, they may want to include additional parameters or variable to help the function account for different or additional attributes. This will allow the management of these functions to be common instead of isolated by system requirements. Meaning, you do not want to create a library of existing functions and end up managing an unmanageable library.
6. Be consistent
Consistency is a common element to success on many different levels. Programming is no different and nothing is more frustrating than reverse engineering a control system to follow a design concept and find inconsistent practices. This shows immaturity in a design and can cause multiple issues over the life-cycle of a control system.
In some cases, alternative methods may be discovered after the initial development and the decision to change course should be solely dependent upon system performance and additional functionality. If the programmer has identified a more clever method that may have a "cool" factor to it, but it does not result in improved performance or save enough development time to cover all of the time previously spent in the application, then stick with the original method. Moving forward, the programmer may decide to utilize it in the future, but to achieve good practices stay the course.
7. Know your tools
A good programmer should have a good understanding of all the tools that are accessible. If the programmer doesn’t stay abreast of what’s currently available, then they are cheating themselves and potentially losing some work efficiency. Take the time to test the programming tools to ensure the programming and deploying utilize the most efficient methods available.
As an example, instead of embedding multiple "IF THEN" statements the programmer should use "CASE" statements to provide more efficiency, as well provide a more readable structure. Reach out to other more experienced engineers and discuss alternative tools they may not be familiar with and set up a quick test to gain the necessary experience.
This is not a suggestion that the programmer should experiment with multiple methods to achieve a singular goal within the application. This could interfere with and sacrifice the previous concept of being consistent. It means the programmer should know the tools prior to designing the application to ensure that an adequate solution can be provided.
Good housekeeping within a program is always good practice. In some cases, the programmer have to build functions or things to help manage the data and keep the work area clean. If the programmer allows alternative work areas to pile up trash, this can cause confusion and cause a hindrance or force unforeseen consequences in the application. All shelving or play areas should be compartmentalized. Meaning, every application needs a defined area to take care of alternative functions or shelve items for later use, but when those items are complete they should be cleaned up. Good housekeeping practices are part of being organized, which promotes efficiency and professionalism.
9. Commenting on code
Nothing is more frustrating than tracing code that is poorly commented or even worse inconsistently commented. Meaning, the terminology, tag naming, and description used within a program should be just as consistent as the code itself. The code itself explains how something is happening and the comment should reflect why this is happening.
Commenting should be performed at each level. Meaning, each function itself should have a brief comment, but each section of code should include a header comment to explain the breakdown. Then, the application as a whole should be commented on to help the person coming behind you to follow a consistent train of thought. Comments should be concise, consistent, to the point, and written while you are programming and not as an afterthought.
One particularly valuable kind of comment is descriptions of why the programmer did not code something in a particular way. If there is a standard way of coding something, and the programmer chose to do it a different way, they should explain why they chose to do it differently in a comment. This is as much for the programmer as anyone else—when they ask, "why did I do this?" a year later, the answer will be right there.
10. Keep track of changes
Keeping track of changes within an application is essential to maintaining it over the life-cycle. Change logs should be incorporated within the application and preferably in the header section for overall changes. However, if changes are needed at the function layer, they should be reflected in the overall header as well as at the comment layer in the function itself.
A good change log includes a log entry or revision number. As well as the date and person making the changes. The description should outline the need for the change and explicitly define all aspects of the application that are affected. Lastly, the change log should be consistently listed in a reserved area of the application.
Programming methods and strategies are subjective to an extent, and the flexibility of using multiple techniques allows engineers a creative avenue to produce solutions. Being creative is a form of self-expression that must be balanced with good practices to ensure the solution fits the overall objectives of the end user.
The end user obviously has common goals shared with the developer but also has additional objectives such as usability, expansion capability, and the ability to troubleshoot and interject functions to support production on an as needed basis. Following best practices should be a main consideration when providing a final solution for the end-user to ensure that the programming deliverable follows acceptable industry practices.
These methods listed above provide the overall usability, flexibility, and maintainability to ensure both developer and end-user are provided with an efficient quality driven solution that can withstand the product lifecycle. Engineers should strive to deliver a higher standard of programming to allow our clients to be successful at manufacturing. Every project should consist of solid solutions that enables our businesses to thrive in the manufacturing environment.
Robbie Peoples is an integration manager at Cross Company Integrated Systems Group. This article originally appeared on Cross Company’s Innovative Controls blog. Edited by Chris Vavra, production editor, Control Engineering, CFE Media, firstname.lastname@example.org.
Cross Company is a CSIA member as of 9/14/2017.