Program development: How to simplify a complex system

Control systems engineers work on processes that can be incredibly complex. The interactions of process, operator, environment, and control systems can produce at time a dizzying and bewildering array of outcomes.

By Bradley Ems August 12, 2014

"If you can’t explain it simply, you don’t understand it well enough." – Albert Einstein

We, as control systems engineers, work on processes that can be incredibly complex.  The interactions of process, operator, environment, and control systems can produce at times a dizzying and bewildering array of outcomes.  We make every effort to anticipate and manage those outcomes, but as systems grow more complex, the ability of even the most thorough engineer can fall short.  Add to that the growing tool sets available to us, such as the IEC 61131-3 programming languages, utilities that permit the use of pre-programmed code blocks, and the ability to manipulate our control processors down to the operating system level, and the internal complexity of our controls only adds to the overall system complexity.  Modern control processors have given us a Swiss army knife with a thousand blades to help us, and a thousand blades we can cut ourselves with, too.  Though not specifically about controls, a recent piece by Quinn Norton, “Everything is Broken,” touched on this phenomenon.

It is incumbent upon controls professionals, in my view, to find the simplicity hidden in the complexity of the systems we design and program.  Updating Einstein’s maxim:  If you can’t program it simply, you don’t understand it will enough.  Failing to do so does a disservice to our clients, users and, ultimately, to our profession.

An automotive company had a paint booth whose color-changing logic was so complex and convoluted that no one could add, remove, or edit a color.  In this case, the complexity was deliberate, the programmer doing so in the expectation that he would be needed to make any color table changes, thus making himself indispensable to the facility.  The facility engineer spent days unraveling the code and rewriting it to something understandable.  The original programmer was  then sent away for good.

A biotech firm had a machine with a simple sequence.  However, the company insisted that it be programmed using a number of pre-programmed code blocks ill-suited to the task rather than simple ladder logic.  The programming effort required many times what would have been otherwise needed to remove the vast majority of the functionality of the blocks, and the result was a “black box” program that was unable to be monitored or maintained by site personnel.

So, how does one distill simplicity down from a complex system?  Here are a few rules I’ve developed to make programs easier to understand and maintain:

1. Know your audience.  This is the prime directive of programming.  Will your system be maintained by engineers, technicians, or electricians?  What is the level of familiarity with the platform being implemented?  What languages are plant personnel comfortable with?  Handing over something that is coded at a level far above the ability to maintain it is no different from delivering system documentation written in Klingon. 

2. Keep tag names descriptive but short.  Long tag names can be as cryptic as ones that are too short, and tend to limit the amount of code viewable when troubleshooting.  Save the prose for the element descriptor.

3. Break the problem into small pieces.  Even the most complex system can be subdivided into smaller problems that are easily comprehensible.  Take the time to plan your work by chopping a Godzilla-sized task into dozens of gecko-sized ones.

4. Use fall-through programming.  Logic for the beginning of the process should be close to the top of one’s application, programming for the tail end near the bottom. Conditions that are used at a particular point in the program should be defined above that point.

5. Avoid indexing.  Using arrays or tables with pointers is a good way to reduce code size, but it’s also a good way to make a program difficult to monitor.  Unless absolutely necessary, do not use arrays.

6. Keep the use of pre-programmed code blocks limited.  These code blocks can be great shortcuts for simple devices, like motor starters or valves, and can actually improve program clarity.  But if they become too large, their functionality can become uncertain and even dependent on configuration.  Blocks can cause large portions of a program to become a black box to a troubleshooter or editor.

7. Limit the use of unfamiliar languages.  If the plant is only versed in ladder logic, using large swaths of structured text can be vexing.  If such programming is called for, do all that can be done to keep it limited and document the call to the code well, explaining what it does, what the inputs to the code are and what can be expected for the output.

8. Document, document, document.  Aside from the usual element, rung and section comments, take the time, in the very first section of the program, to tell a future user about anything you may have done that differs from the machine default.  This may include I/O scan settings, fault condition setup, program execution interrupts, etc.  You found it important to modify these things and he may find it important to know about them.

We know our business well.  Let’s prove it by making what we do look easy.

This post was written by Bradley Ems. Bradley is a project manager at MAVERICK Technologies, a leading automation solutions provider offering industrial automation, strategic manufacturing, and enterprise integration services for the process industries. MAVERICK delivers expertise and consulting in a wide variety of areas including industrial automation controls, distributed control systems, manufacturing execution systems, operational strategy, business process optimization and more.