What Unreadable PLC Code Costs You at 2 A.M.
A contact named M0.0 tells a technician nothing when the line is down. What maintainable PLC code actually means — structure, naming, traceable constants — and a ten-minute drill that measures it better than any audit.
There is a test for control code that no style guide fully captures, and every plant passes or fails it the same way: at 2 a.m., with a line down, when the person reading your logic has never seen it before.
Call it the night-shift test.
A technician gets paged. Conveyor 3 won’t start. They open the program and meet a rung guarded by a contact named M0.0.
M0.0 tells that technician nothing. Not what it represents, not who sets it, not why it’s holding the conveyor. Every minute spent reverse-engineering the author’s intent is downtime — and it is downtime that was designed in, years earlier, by somebody who knew exactly what M0.0 meant on the day they wrote it.
What the delay actually costs
The shape of it is familiar enough that most maintenance engineers can fill in their own numbers.
A fault trips at 02:10. The technician is in the program by 02:20. If the logic is legible, they find the holding condition, confirm it against the field device, and the line is turning by 02:35 — twenty-five minutes, most of it walking.
If the logic is not legible, the same technician spends the next forty minutes cross-referencing unlabeled bits against a drawing set that may or may not match the installed program. They call someone. That person is asleep. By the time the line moves, the shift has lost the best part of two hours, and the shift after it inherits a backlog.
Same fault. Same technician. Same equipment. The entire difference sits in choices made at the keyboard years earlier, by someone who was never going to be in the building at 2 a.m.
That is the argument in full. Everything below is mechanism.
Maintainability is a design property, not a virtue
It is tempting to treat readable code as a matter of professional pride — nice to have, polished, first thing dropped under schedule pressure. The plant experiences it differently.
Correct execution is only one dimension of software quality. Structure, naming, interfaces, diagnostics, documentation, testability, versioning, and change evidence determine whether another competent person can review, diagnose, and modify the application — and how long that takes while production is stopped.
Three structural decisions carry most of the weight.
1. Separate coordination from behavior from equipment
One architecture that transfers across vendors, top to bottom:
- Task coordination — what runs, in what order, under which task and period.
- Modes and sequences — what the plant is allowed to do, and how it steps through it.
- Equipment objects — each motor, valve, and drive with its own command, state, interlock, and diagnostic interface.
- I/O mapping — the field boundary, and nothing else.
- Across all four — alarms, diagnostics, communications, configuration, and testing.
The point is not elegance. When a fault surfaces, that layering tells the reader where to look before they read a single rung. A maintainer should be able to find “the alarm code” or “the motor code” in one place, not scattered across the program by whoever touched it last.
2. Name for the reader, not the writer
M0.0 is a fact about memory. MOT_FEED_Running is a fact about the plant.
A documented convention should make purpose, scope, type, unit, state, and ownership legible in the tools the site actually uses. Group related signals into user-defined types, so a single Motor type carries Start, Stop, Running, Fault, and Speed together rather than scattering them.
The convention extends past tags. Give every element type a consistent form — modules, modes, states, alarms, interlocks, presets — and the code starts to read like the plant instead of like memory.
Prefix patterns are examples, not requirements. The requirement is that the convention is written down, and that everyone uses the same one.
3. Make constants traceable
Every consequential number in the program should have a name, units, a source, and change control.
A hardcoded 4500 in a comparison block is a question nobody can answer at 2 a.m. PRESET_FillTime, with a documented basis, is a number somebody can reason about — and, when the product changes, safely alter.
The honest limits
Two cautions keep this from becoming a slogan.
First, no structure survives contact with a runtime it wasn’t verified on. IEC 61131-3 gives the industry shared language concepts, but vendor task models, addressing, libraries, and file formats differ. Neither code nor skills port automatically between brands. Choose structure for the control intent and the people who maintain it — then verify it on the target platform, not on the standard.
Second, maintainability is not proven by a document. A naming standard in a folder is not evidence that anyone can read the program. The only evidence is a person reading the program.
Make it measurable
Which is the part most sites skip, and the cheapest thing on this page.
Give a colleague ten minutes and one fault scenario in your own code. Don’t help. Watch where they stop, backtrack, or reach for a drawing.
That location — not the style guide, not the audit — is where structure or naming needs work. Run it twice a year on the code that matters and you have a maintainability metric that costs nothing and cannot be gamed by documentation.
Two exercises, one afternoon
Open one controller’s task configuration and write down what is actually there: tasks, periods, priorities, watchdogs. If you can’t explain why each period was chosen, you have found your first documentation gap — before it finds you during a fault.
Then run the ten-minute drill above. Two findings, one afternoon, no capital request.
The plants that pass the night-shift test did not get there by hiring better firefighters. They got there by writing for the reader they will never meet.
What’s the M0.0 in your plant — the tag everyone has quietly learned to work around?
Drawn from Industrial Automation: Real-World Frameworks & Implementation Guide (Part 4: the control layer — program structure, naming standards, and code reuse).
Questions industrial leaders ask about this
What makes PLC code maintainable?
Structure, naming, interfaces, diagnostics, documentation, testability and change evidence — not just correct execution. The practical test is whether another competent person can locate a fault, understand the holding condition, and modify the application safely while production is stopped.
How do you measure PLC code maintainability?
Give a colleague ten minutes and one fault scenario in your own code, and watch where they stop, backtrack, or reach for a drawing. That location is where structure or naming needs work. It is a maintainability metric that costs nothing and cannot be gamed by documentation.
Does IEC 61131-3 make PLC code portable between vendors?
No. IEC 61131-3 gives the industry shared language concepts, but vendor task models, addressing, libraries and file formats differ. Neither code nor skills port automatically between brands. Choose structure for the control intent and the people who maintain it, then verify it on the target platform.
Why are hardcoded constants a problem in PLC programs?
A bare number in a comparison block has no name, no units, no documented source and no change control. Nobody can answer what it means or safely alter it during a fault or a product change. Every consequential number should carry a name, units, a basis and change control.
Industrial Automation — Real-World Frameworks & Implementation Guide
The ten-part guide this series draws on: project framing, system architecture, the field, control and supervisory layers, OT networks and cybersecurity, functional safety, integration, delivery and operations — with 28 technical figures and a 38-asset working pack.