System Design Thinking in SCADA: Bridging Software Engineering and Industrial Automation

December 02, 2023  •  by Abraham Ouma

Introduction

Software engineers talk about scaling, decoupling, version control, and system resilience. Guess what? SCADA engineers should too.

Modern SCADA isn’t just tags and HMI screens, it’s a distributed system with databases, services, user roles, and external interfaces. The same system design mindset used to build large software platforms is now essential when architecting Ignition SCADA projects. Only difference? A bad deployment here can stop a factory.

In this post, I explore what it means to apply software system design principles in SCADA engineering and why you need to think like a systems architect when building with Ignition.

1. Architecture Mindset: SCADA is a System, Not a Screen

When most people hear "SCADA," they picture control panels and alarms. But if you’re the one building the system, you know it’s a lot more than that. A real-world SCADA system, especially one built with Ignition is a distributed system with its own architecture, failure domains, and dependencies.

You’re not just designing interfaces; you’re engineering data pipelines, service integrations, and real-time feedback loops between field devices and human operators. That means the architecture must be as intentional as the process it is monitoring.

Key concepts to keep in mind:

  • Gateways aren’t just runtime environments but central hubs for data processing, visualization, and communication. Treat them like servers in a web architecture.
  • Your OPC servers, databases, MQTT brokers, and client sessions are individual services. If one breaks, what happens to the system?
  • Think in data flow maps: where does data originate? Where does it go? What transforms it? What stores it? What visualizes it?

Also: every component can fail. Ask yourself:

  • What if the historian database disconnects?
  • What if the gateway crashes mid-shift?
  • What if the client network is down?

Design with redundancy, isolation, and store-and-forward where needed. In practice, this often means separating concerns across services:

  • OPC & tag logic on one gateway
  • Visualization on another (frontend-only gateway)
  • Historian and reporting database on its own server
  • MQTT and Edge gateways handling data ingestion from remote or critical areas

2. Modularity, Microservices & Reusability

As your SCADA project grows, from one tank to an entire plant, modularity isn't a luxury. It's survival.

Just like in software systems, trying to scale a monolithic SCADA project with tightly coupled components and copy-pasted screens quickly becomes a nightmare. Updates are painful, bugs are duplicated, and design consistency becomes impossible.

That’s where modularity and microservice-style thinking come in.

How It Translates to Ignition:

  • Modularity: Break projects into separate units. One handles UI, another manages shared scripts, another defines UDTs and alarming logic.
  • Microservices: Think in “bounded contexts.” For example:
    • Project A = Data acquisition and tag structuring
    • Project B = Process analytics and reporting
    • Project C = Operator interface and controls
    • Project D = Notification and alarms handling
  • These aren’t literal services, but in Ignition they can be separate projects with clearly defined roles, sharing resources via project inheritance or the Gateway Network.

What to Modularize:

  • Embedded Views and Flex Repeaters: Use these to create reusable UI components. Parameterize them to adapt across machines or units.
  • UDTs: Treat UDTs like class definitions in code. They define structure, behavior, and relationships. Updating a UDT updates the system.
  • Scripts: Centralize shared logic into project libraries and call them instead of duplicating code in views or events.
  • Named Queries: Use them as your backend endpoints. Keep UI logic clean and decoupled from the database logic.

By designing with modularity, you get:

  • Faster iterations
  • Easier testing and debugging
  • Less risk when making changes
  • Scalability with minimal code duplication

Design definition with parameters

Number of instances generated

Design instances

3. Performance, Scaling & Resilience

A smooth-running SCADA system feels invisible. A laggy one gets users frustrated, alarms missed, and sometimes, process failures. Performance isn’t an afterthought. It should be designed in.

Don’t Just Scale Up, Scale Smart

  • Vertical scaling (adding RAM/CPU to a single gateway) works, until it doesn’t.
  • Horizontal scaling (distributing load across gateways) is more robust. Use:
    • A frontend-only gateway for Perspective clients
    • A backend gateway to handle tag logic and scripts
    • An Edge gateway close to critical devices for data buffering

In Ignition, use the Gateway Network to connect these cleanly.

Horizontal vs. Vertical Cloud Scaling

Reduce Load Early

  • Use tag groups wisely.
  • Use deadbands to prevent flooding the system with data that hasn’t changed meaningfully.
  • Consolidate tag change scripts. 100 small scripts are worse than 1 well-structured handler.

Don’t Query Like You’re in Excel

  • Avoid heavy database queries directly in bindings or views - cache what you can.
  • Use named queries + memory tags for lightweight, fast lookups.
  • For large reports, do the processing in the background (e.g., a Gateway Timer Script) and serve from a temporary table.

Plan for Failure

  • Assume something will go wrong:
    • Network drops
    • Database timeout
    • Gateway crash
  • Use Store-and-Forward to buffer data on the gateway when the DB is unreachable.
  • Implement health monitoring: build a simple tag status dashboard to track gateway load, database connection status, MQTT state, etc.

4. Data Design: From Tags to Tables

Tags are your variables; tables are your logs. If you get this relationship right early, you’ll avoid painful rewrites later.

Tags as Data Objects

  • Use UDTs (User Defined Types) like class definitions: encapsulate related tags (e.g., for a motor: status, fault, run time, etc.).
  • Parameterize UDTs to auto-generate tags per device or unit.
  • Structure your tag tree like a namespace, not a dumping ground.

Normalize Your Database

  • You’ll want to analyze this data later, see trends, get reports, and integrate with KPI dashboards.
  • Avoid storing data as blobs or dumping everything in one table.
  • Normalize by:
    • Separating events e.g. start/stop, logs e.g. run time, and metrics e.g. temperatures, flows
    • Using foreign keys like unit ID, cycle ID
  • Easier to join with external systems such as ERP, MES, and analytics tools later 

Normalized vs. Denormalized DBs

Partition and Shard as You Scale

  • Huge logs? Break them into monthly or yearly tables. Use views to stitch them back together.
  • Multi-line plant? Shard by machine or area.
  • Use indexes on timestamps and IDs otherwise queries may crawl to a halt.

Caching and Temporary Storage (Ignition Named Queries have a cache feature)

  • Store frequent reads (e.g., “last 10 records”) in memory tags or intermediate tables
  • Don’t recalculate stats or summaries on every page load
  • In batch processing, use a “working” table and move results to long-term tables after validation

Plan for Retention and Cleanup

  • Set expiry policies. Don’t wait until the DB fills up and crashes your gateway.
  • Use scheduled scripts or DB jobs to offload old data to archive tables or S3 buckets if you have cloud integrations.

5. Versioning, Lifecycle, and Backups

Not all SCADA solutions support version control with platforms like GitHub and GitLab, with Ignition, this is possible. With tools like GitLab integration, project exports, and project inheritance, you can bring versioning discipline into your SCADA workflow just like in software development.

Versioning is important because in SCADA, versioning isn’t about convenience but about operational survival. If something breaks mid-shift, you need to know what changed, roll it back fast, and get the plant back online.

Git Integration in Ignition

  • Use GitLab or GitHub with Ignition's project export system.
  • Sync project directories to a Git repo for:
    • Change history
    • Collaboration between engineers
    • Branching for dev/test environments
  • Additionally, you can trigger CI jobs for packaging, backups, or automated tests.

Project Structure with Inheritance

Even without Git, Ignition has built-in project inheritance:

  • Base_Project: shared views, styles, scripts, templates
  • Site_A_Prod: inherits base and is used in production
  • Site_A_Dev: inherits base and is used for testing new features
    This gives you environment separation and allows changes to flow upward from development to production in a controlled way.

Versioning Tags and Database Schema

  • Export tag provider trees regularly as JSON or XML, especially after structural updates.
  • Store CREATE TABLE scripts and schema differences in a shared versioned folder.
  • Maintain a central documentation file (even Markdown in Ignition or a complete documentation/support section) explaining:
    • Tag naming conventions
    • Data retention policy
    • UDT structure updates

Backup Strategy (Non-Negotiable)

Schedule automatic backups for:

  • Ignition Gateway which includes projects, tags, users, certs etc
  • Databases via cron jobs, AWS RDS snapshots, etc.

Backups should be versioned and archived by date and environment.

Document Everything

Avoid “tribal knowledge” failures. Your SCADA should be understandable by someone new, not just the original developer.

  • Use naming standards: an example like Plant1/Motor_01/RunStatus is better than Tag_1834
  • Label everything - views, UDTs, scripts like someone else will take over next week (because one day, they will).

The bottom line is SCADA without version control is like coding without undo. Ignition gives you the tools and Git can help make them bulletproof.

6. Security and Access Control

A lot of SCADA systems live behind a firewall and call it a day, which is not enough. Security isn’t just about firewalls rather about controlling what users can do, auditing what they’ve done, and making sure a misstep doesn’t become a disaster.

Use Identity Providers

  • Don’t use default users. Configure an IDP (e.g., Active Directory, OAuth) or at least a secured user source.
  • Map users to roles and use roles to gate actions.

Role-Based Access Control (RBAC)

  • Define roles like Operator, Supervisor, Engineer, Admin.
  • Use Security Levels in Perspective to control access to buttons, views, and tag writes.
  • Example: only Engineer can write to setpoints, only Supervisor can acknowledge alarms.

Audit Everything

  • Enable audit logging to track who changed what and when.
  • Store audit logs in a dedicated DB table because you’ll need this when troubleshooting or proving compliance.

Secure External Access

  • Use SSL on all remote access; you can terminate at an Nginx reverse proxy or use Ignition’s SSL setup.
  • Never expose ports like 8088 directly to the public.
  • For remote access, use VPN tunnels or cloud bastions with multi-factor authentication.

Separate Frontend from Backend Logic

  • Clients don’t need access to everything. Use project separation or security levels to isolate critical logic from casual user interfaces.
  • Use named queries with role validation instead of allowing open DB bindings.

Security in SCADA isn’t just about hackers; it’s about preventing accidental misuse from inside as well.

7. Observability: Monitor Your Own System

Most SCADA systems are great at monitoring machines but completely blind to their own health which is a huge risk. If your Ignition gateway slows down, if the DB connection fails, or if MQTT stops pushing, you need to know before the operator does.

Build a System Health Dashboard

Create a dedicated view that shows real-time status of your SCADA infrastructure:

  • Gateway CPU and memory
  • DB connection health (e.g., periodic test query + timestamp)
  • Store-and-forward queue size
  • MQTT connection status (via tag or API)
  • Any alarm pipeline or notification backlog

This feature will cat as your early warning system. Thanks to Ignition gateway, the status and log section is very robust for system troubleshooting.

Tag Your Own SCADA

  • Use internal memory tags to track custom system metrics.
  • Example: last DB write time, script error count, queue sizes.
  • Bind them to alarms if thresholds are exceeded.

 Use Logging to Your Advantage

  • Use system.util.getLogger() for custom logs in tag or gateway scripts.
  • Structure logs clearly: "FAILED to write temperature to DB – value: 82.3, reason: timeout"
  • Set up log rotation and filters in Gateway settings.

🔹 Alerts for Your Alerts

  • Alerting systems should have watchdogs. If no alarms fire for 24 hours on a live system, raise a flag.
  • Missed data from MQTT or sudden drops in tag updates = potential disconnects.

Ignition Status Dashboard

Conclusion: Don’t Just Build SCADA. Architect It.

Modern SCADA design has grown beyond tag bindings and pretty screens. Today’s systems are complex, distributed, and business critical. If you approach them with a a control, automation, software engineering mindset focused on modularity, scalability, observability, and security, you build something that lasts.

With Ignition, you have the tools. What matters is the architecture behind the tools: the planning, the naming, the boundaries, and the mindset.

Because it’s not just about running the plant.
It’s about running it well, safely, and for years to come.

TL; DR:

SCADA systems aren’t just about HMI screens and tag bindings but full-fledged distributed systems. This post breaks down how to apply software system design principles to Ignition SCADA projects: think modularity, scaling (both vertical and horizontal), decoupling, backups, security, version control (yes, with Git), and observability. Architect your SCADA like you would a backend system: resilient, maintainable, and built to grow.

Credits & Inspiration

For a deep dive into the system design mindset applied in this post, especially around data flow, modularity, and distributed reliability, I highly recommend Designing Data-Intensive Applications by Martin Kleppmann.

Some of the system design mindset was inspired by the excellent content from Gaurav Sen’s YouTube channel. Highly recommended for anyone diving deeper into distributed systems and architecture thinking.