Saturday, October 18, 2008 

Some Small Design Issues (part 2)

So far, so good. The only important choice we had to make was the placement of the display logic (stage 1). That choice was easy, so to speak: a little speculative thinking, along the lines of "do we want to reuse the same display logic with another process control system" would have been enough to choose. The "do the simplest thing" approach would have lead us in the wrong direction, but even in that case, refactoring the display logic outside process control would have been easy. Now, unfortunately, things are going to get messy.

Stage 4 - different data in different states
The system can be in different internal states. For instance, some physical components may undergo maintenance, so the corresponding software component would go into an offline state. The process itself may go into an idle state between different shifts, and so on.

Sometimes, the internal state is irrelevant. Sometimes, however, we may want to display different variables in different states. For instance, if the process is idle, we might want to see the time of day and a the seconds of idle time. It would make little sense to display any data about the product, as there is no product in the idle state.

Of course, the set of internal states can change between one system and another. In many cases, the state is stored internally and not published into the database. Even the internal model of "state" can be different: in some cases, the state manifests itself implicitly, through a set of internal variables; in some cases, a single variable holds the explicit system state.

Now, we basically have two main choices, with several sub-choices and consequences. We may keep the state inside the system, or we may require the system to publish its own state.

Keeping the state inside the system seems like a good choice: after all, it's what good ol' information hiding would like us to do. However, that doesn't really fit with the idea of an external display logic. How do we know which variables to show in each state, if we don't even know the state? Of course, we may come up with some kludge, like publishing "artificial" or "synthetic" variables. These variables are published only for the display module, and they change meaning as the internal state changes. That's ugly and would get worse in the next stages. Note, however, how information hiding is now going against the clean separation of concern we aimed for in stage 1.

We may therefore decide to publish the internal state. That's not completely correct either. If the state is implicitly stored inside several internal variables, we do not want to publish those variables. In general, we don't want to publish the actual state: we want to publish a business-relevant abstraction of the internal state.

At this point, however, configuration becomes harder. We have to decide which variables we want to show, in which display, in which state. The state has to be made explicit, and visible to the user (at least, as far as configuration goes). The display subsystem has to know about state too - not the internal state, but the published state. That's an undesirable form of coupling, and it's the first sign that our solution is not going to be great.

Stage 5 - different display types
Back in stage 2, we just wanted to handle different protocols. The display type, however, was "fixed": a few rows, each with a label and a floating-point value. Now we have to handle different display types too.

In some simplified systems, or in some areas of a plant, a a standard green-yellow-red semaphore can be used as a cheaper (and more intuitive :-) display, based on 2 thresholds.

In other cases, an LCD or plasma screen is adopted, and here we have a wide choice: show more data, show more text, show trends (graphically), and so on.

Again, here we face a relatively difficult coupling/cohesion choice. Consider the semaphore: where do we configure the thresholds, and were do we place the logic? We could do both inside the control system, and publish a new variable to control the lights. That's easy, but in a sense, we are moving some display concerns inside the system. The new variable is there only because we want a semaphore. We could put that logic inside the display subsystem (actually, inside the semaphore class). But a threshold is a process concept, and we also need some logic to prevent flickering, which is more akin process control logic, not display logic.

The trend is even worse. So far, each variable had one single slot inside the [real-time] database. There was no history. A trend requires history. Where do we put that? It's easier to store history inside the display logic (the trend class) because no changes are required to the control system and (more importantly) to the database. However, that's kinda clumsy. If the display subsystem is shut down for any reason, we won't be able to show a trend when it's started up again (not for a while, at least).

Also, we may have a performance issue here. When we want to show a few numeric values, we don't need to be fast (quite the opposite :-). So the process control system can publish once in a while, or the display can sample the database once in a while (if we can't push from the database). A trend, however, may require a much faster publishing/sampling than we were prepared to handle.

Again, it's hard to find a clear-cut winning solution. The two domains are entangled, and we seem to lack the right abstractions, something that would make the control and display more independent on each other.

Stage 6 - different data sources
This just adds to the mess. Now, different control systems are implemented by different teams, working on different kind of industrial processes. We have slow processes, where data could be stored in a plain, cheap relational database. We also have moderately fast processes, where we need a real-time database. We also have hard real-time systems, where data are published periodically through a proprietary, TCP-based messaging protocol (and not stored anywhere), and so on.

Now, unfortunately, we can't store the configuration inside the real-time database anymore, because there might not be a real-time database. Overall, is no big deal, but we have to reference a variable while we configure the display, and that reference can easily break if we change the process control system. What's worse,we may not have a way to know, besides running the system, which ain't nice.

So, here it is. The problem itself is relatively easy. We also have several simple solutions. However, most of them lack elegance and quality. The natural temptation is to go after higher levels of abstractions, along the "enterprise data bus" concept on one side and the OPC initiative on the other. I've seen that, and what you get is usually a slow behemoth that nobody really likes. Another natural temptation is to go after the MVC idea and to create several "controllers" to mediate between processes and displays. In practice, we just give up and declare that mixing display concerns and process concerns is not that bad, and we name that [gordian] knot "controller". Not really elegant.

Curiously enough, I have seen similar (although superficially quite different) problems in different domains, like cab dispatching. There is probably a meta-problem pattern at play, but I haven't got the time to investigate the issue (I do have a few ideas though).

Still, it's damn hard to find a simple, elegant, flexible solution where the processes and the displays are nicely separated. Part of the problem, I think, is that we lack a way to model the force field.
More on this another time: meanwhile, if you've got any brilliant idea, just let me know :-).


this is definitely the post i've been waiting for a long time: A great sw architect in action on a real, but not trivial, problem!

i look forward to read the next parts!
Well, my hope was to get, not to give, a few [good] ideas!

Guess I'll write a "part 3" in the next few weeks :-).
Carlo, non ti credevo così "interessato"... :-))

Però il tuo livello è tale che difficilmente otterrai qualcosa, se non da te stesso.

Grazie per la tua condivisione.

Spesso non si possiede veramente se non ciò che si da.
Carlo, non ti credevo così "interessato"... :-))

:-)) ogni tanto ci provo :-))

in realta', mi serviva comunque un esempio concreto su cui ancorare alcune considerazioni future, altrimenti si rimane ad un livello troppo astratto, ed e' difficile condividere realmente i propri pensieri...
Post a Comment

<< Home