Jump to content

Decoupling the UI


Recommended Posts

A great thread over here on Best Practices brings up something I have occasionally wondered about -- the concept of decoupling the UI from the code.

While I grasp the concept philosophically, I'm trying to figure out what it looks like in practice. I'm not sure if this is just a fancy term for something I already do (as "plug-in architecture" turned out to be), or if it's something I should be looking at doing.

Does anyone have some code they don't mind offering up that would be a good example of decoupling the UI?

Cat

Link to comment

The old VIE LabVIEW Advanced Architectures Course (that was subsequently purchased by NI and rebadged as the LabVIEW Advanced course) had an example in it where there was an engine that did all the interesting stuff, and there were 2 UIs that just handled events from the user (well, they weren't event-events, since the event structure didn't exist back in the ol' days :) ) as well as handing a reference to the VI back to the engine which would then update the UI using "Set Control" by-name methods. I'm not saying it's necessarily the best solution, but I recall it working well, and if you added in a true event structure then I'm sure it would be sufficient.

Link to comment

I'm trying to figure out what it looks like in practice.

What it looks like depends an awful lot on exactly what kind and how much decoupling you want. All decoupling requires inserting some sort of abstraction between the two components being decoupled. The simplest form of what *I* would call a decoupled UI is to have all the UI code in one loop and all the processing code in another loop. That means no controls, indicators, property nodes, etc in the processing code. All information is transmitted through your messaging system. If you can wrap your process loop in a sub vi and still have everything work right then you've taken a good first step.

In that scenario your UI is still dependent on your functional code. In most cases that's fine. Sometimes you might want to develop a UI that is completely independent of the functional code--maybe one team is developing the processing engine and the other is developing a complex UI. In that case you'll need a third component (the controller) to tie the two pieces together.

Does anyone have some code they don't mind offering up that would be a good example of decoupling the UI?

Hmm... some of my cld practice exams might show a decoupled UI. I'll try to take a peek in the next couple days.

Link to comment

The really old way (before events, queues etc) might be easier to visualise.

It used 2 global variables (data pools). The UI would write to one of the globals to configure and control the acquisition and all the acquisition stuff would write to the other to update the data in the UI. (Completely asynchronous. Non blocking and damned fast - not to mention built in system wide probe..lol) So the UI was completely decoupled from the acquisition spending most of its time just polling the UI global to update the screen.

But basically all it means is removing execution dependency between the UI an other parts of the code usually via an intermediary interface. The inverse I would imagine would be something like a sequence structure with the acquisition in the first frame an the indicators in the last frame.

Link to comment

I would say a truly decoupled UI would be one driven by an API that is not limited to LabVIEW. In other words, using something like Web Services, you could build your UI in LabVIEW or HTML or C++ or any other language and interface to the underlying engine via calls.

There are other options to this of course.

I think a good first start would be to separate the UI code from the engine code so your low level logic does not access any GUI elements. This could be done by using queues, events or other messages to communicate state changes and user actions between the UI code and the engine.

Next, you need to ask yourself what the physical channel will be between the two. If you will be on the same machine in the same app instance, then you can use queues and events. If you plan to be across the network, then some other method will be needed (web services, raw TCP/IP, network streams, share variables) and if your UI is not going to be LabVIEW, then you narrow yourself to web services or something like web sockets (http://www.bergmans.com/downloads.html).

Overall, decoupling now can allow you to pursue these options down the road more easily.

Lastly, you need to consider if you will build a client server model where multiple UIs can interact with a singe engine simultaneously. That is a harder nut to crack...

  • Like 1
Link to comment

A great thread over here on Best Practices brings up something I have occasionally wondered about -- the concept of decoupling the UI from the code.

While I grasp the concept philosophically, I'm trying to figure out what it looks like in practice. I'm not sure if this is just a fancy term for something I already do (as "plug-in architecture" turned out to be), or if it's something I should be looking at doing.

Does anyone have some code they don't mind offering up that would be a good example of decoupling the UI?

Cat

A Model-View-Controller architecture? An old-school solution is the examples outlined in Conway and Watts 'A Software Engineering Approach to LabVIEW'.

If you go the the InformIT page for the book, you can download the examples. The Wigetometer Test System is based on parallel loops where the execution of the test is decoupled from the UI. http://www.informit.com/store/product.aspx?isbn=0130093653

The addition of event structures, queues and OOP makes certain things much easier. Apply your knowledge of these features to this old example.

  • Like 1
Link to comment

A great thread over here on Best Practices brings up something I have occasionally wondered about -- the concept of decoupling the UI from the code.

While I grasp the concept philosophically, I'm trying to figure out what it looks like in practice. I'm not sure if this is just a fancy term for something I already do (as "plug-in architecture" turned out to be), or if it's something I should be looking at doing.

Does anyone have some code they don't mind offering up that would be a good example of decoupling the UI?

Cat

I am in a similar situation. This thread on the Dark-side

http://forums.ni.com/t5/LabVIEW/Strange-Problem-Cluster-of-References/m-p/1110076#M490461

has images showing how I seperated the GUI from the logic. Once i have refs to all of the FP object the underlying code can run under any FP that has that set of objects. Technically speaking the control refs still represnt a dgree of copling that I could work-around but then I get into text based solutions (control names to find refs) that I avoid since it would only open me up for typos and any LV implementation that leads to the potential of typos feels like an oxymoron to me.

Take care,

Ben

Link to comment

The old VIE LabVIEW Advanced Architectures Course (that was subsequently purchased by NI and rebadged as the LabVIEW Advanced course) had an example in it where there was an engine that did all the interesting stuff, and there were 2 UIs that just handled events from the user (well, they weren't event-events, since the event structure didn't exist back in the ol' days :) ) as well as handing a reference to the VI back to the engine which would then update the UI using "Set Control" by-name methods. I'm not saying it's necessarily the best solution, but I recall it working well, and if you added in a true event structure then I'm sure it would be sufficient.

Hi Cat

I used one of the examples (there were two strategies: reference and queue based) successfully after seeing it in the manual, and I agree, it does work quite well.

I normally like to update the UI using Events and receive events from the UI using the Events but I also like to get references to the FP for working with Properties e.g. setting up Graphs etc...

NI Intermediate I (now Core 3) course also shows a way to decouple the UI, like how Dave (*simple*) describes, I used to use it a lot a few years ago. It is queue based.

Cheers

-JG

Link to comment

If you are passing control refs from your UI FP to your core engine, they you have a strongly coupled UI, not a decoupled UI. The better solution would be to setup a messaging system where the core engine tells the UI what the new data is and then the UI takes that and applies it to the actual controls. That way, you could completely change the UI to display the data in any way you wish without touching the core engine.

I'm not saying I don't pass refs in some of my code, but I acknowledge this is a coupling issue I want to avoid in future designs.

Link to comment

I don't see it as that. Sure, its not the highest level of decoupling but it is still decoupling. And there are situations were this is advantageous.

You want the UI to be extremely lightweight, and if you have 'skinnable UIs' you don't want duplicate code in the UI's. And there needs to be some interaction with refs because you need to access properties etc. I usually encapsulate this functionality. If you were really concerned then yes, you would have to implement e.g. a controller component as Dave mentioned.

Most of the time I find the extra work can be overkill but it is really dependent on the project.

Link to comment

Every rule is made to be broken (when it makes sense). Typically, I would not pass control references from the UI to the "worker" VIs, but I had one application where it made perfect sense. All the application needed to do was open some number of TCP/IP connections (30 or 40 something) and then display the streams to the user. Each stream was independent. So all I had to do was create enough FP indicators, get a ref to each, launch the re-entrant TCP/IP listeners dynamically with a control ref as input, and wait for each reentrant instance to update its corresponding indicator. Any more decoupling (in this very specific case) would have just added unneeded complexity.

Mark

Link to comment

I'm not saying you should always decouple your UI from the core engine of your code. I'm just saying that if you are passing FP refs to low level code, you are not decoupled.

I do this all the time in many application. And I know full well that I am essentially tying these two parts together in a way that would not be easy to separate in the future. So, while this might be the right approach in many cases, it cannot be called 'decoupled' if you do this.

But, in my case I want to move to a system where the UI could be replaced without changing the core engine code. And I want to eventually change to a client-server architecture where the core server can manage several client UIs simultaneously. That requires a fully decoupled UI design.

Link to comment

I'm not saying you should always decouple your UI from the core engine of your code. I'm just saying that if you are passing FP refs to low level code, you are not decoupled.

I do this all the time in many application. And I know full well that I am essentially tying these two parts together in a way that would not be easy to separate in the future. So, while this might be the right approach in many cases, it cannot be called 'decoupled' if you do this.

But, in my case I want to move to a system where the UI could be replaced without changing the core engine code. And I want to eventually change to a client-server architecture where the core server can manage several client UIs simultaneously. That requires a fully decoupled UI design.

I agree - I was trying to make the point that while decoupling the UI code is generally a good practice, one size doesn't fit all and one should consider the requirements of their particular application to decide how decoupled they need to be. Sounds like you've given it a lot of thought and know what you need. I just don't want to encourage anyone to try to decouple UI code where that approach really doesn't fit and would add unneeded complexity.

Mark

Link to comment

I just don't want to encourage anyone to try to decouple UI code where that approach really doesn't fit and would add unneeded complexity.

Agreed. As I said, I don't do this normally. Just need to look into it for a particular application. I like the idea of having a channel between the UI and core that I can monitor, log and use for test injection. Also, this would make external automation very easy. All these things matter in my application.

Link to comment

Lastly, you need to consider if you will build a client server model where multiple UIs can interact with a singe engine simultaneously. That is a harder nut to crack...

Naaaah. shifty.gif

Dispatcher 1.0 does 90% of that. Dispatcher 1.2 does 100% (including to and from browsers after a very nice little thread a couple of weeks back thumbup1.gif )

Edited by ShaunR
Link to comment

I'm not saying you should always decouple your UI from the core engine of your code. I'm just saying that if you are passing FP refs to low level code, you are not decoupled.

I do this all the time in many application. And I know full well that I am essentially tying these two parts together in a way that would not be easy to separate in the future. So, while this might be the right approach in many cases, it cannot be called 'decoupled' if you do this.

Given you have stated that your requirements are absolute decoupling, I still wanted to point out that I disagree somewhat with the above - somewhere in your code you need to communicate with the UI. If you encapsulate this code e.g. in a Class, then you could override it for different methods of communicating with the UI.

This may not be the best example but I have it lying around at home.

It was a small app and I decoupled the screen as to separate the code for ease of programming rather than any other reason.

For the most part I program in LabVIEW, so the FP is usually going to be LabVIEW.

It goes something like this:

Send the references from the UI to the controller via a message on startup

post-10325-0-44015600-1297950323_thumb.p

Set the UI references in the Class (that's it - they are never exposed outside of the UI Class again)

post-10325-0-82405900-1297950325_thumb.p

Controller pokes data from the Model (in this case a Map) into the UI Class.

post-10325-0-51060700-1297950324_thumb.p

Now my screen is just a bunch of UI Elements with no code behind them. I can change this with little fear of messing up underlying code.

Link to comment

As far as i can recall, this is the first serious discusion of what Decoupling the UI really means in LV.

Question:

Is ther anyway to interact with a LV FP without using ActiveX via properties or methods?

None come to my mind.

So my gut feel for what the term "Decoupling the UI" means in LV has to assume the the use of control refs somewhere in the game.

I think I am coming down on the JG side of this discusion since differnt GUI's that provide the same set of controls and indicators (think of these as different classes that expose the same properties and methods) the underlying functions should still operate regardless of how I have re-arranged things.

But I am just and old wire jockey and these CS concept are not my area of expertise.

Take care,

Ben

Link to comment

maybe I totally misunderstood the question / discussion, but why are you all talking about using control references when decoupling the UI from the Code?

I simply use this pattern:

post-885-0-80105300-1297961045_thumb.jpg

The upper state machine handles all the FP events (button pressed, value changed, etc ...) and the statemachine below does all the work. In the user-event state also handles all the dialogs, etc. - all that stuff that blocks FP actions - and you can use the user-event case, too, do send messages back from the lower state-machine to the event handler (e.g. to disable buttons, set values to controls, etc ...)

If you have more "tasks" that need to run in parallel, you can simply expand this pattern with a 2nd or 3rd "lower state-machine" ...

gl&hf

CB

Link to comment

I guess my original point is not getting across. How about thinking about it this way: If you UI can run on one computer and your core engine can run on another computer, with nothing between them other than the network, then your UI is decoupled.

I am not saying that the UI portion has no code in it. In fact, I expect it to have a lot of code in it to interpret messages from the core engine then implement the data changes as UI control changes, utilize whatever methods are required. I also expect the UI code to convert user events into messages to tell the core engine what to do. That way, the only connection between the UI and the core is a bidirectional messaging system. Those messages can then travel over whatever link you desire. And you can monitor and log those messages for debugging. You can also inject messages from non-UI actors to automate your core engine and your can do the same to create test simulations for your UI. That is what IMHO a decoupled UI is. You are free to disagree but I hope you at least understand what I am trying to say.

Link to comment

So my gut feel for what the term "Decoupling the UI" means in LV has to assume the the use of control refs somewhere in the game.

It all depends on how much decoupling you're looking for. Injecting control references decouples *that specific* UI from the funcitonal code, but the functional code still requires *a* UI. Ultimate decoupling means you can, for example, attach multiple UIs at the same time, or run the code with no UI at all. It also means you can change the data type on the display without changing the functional code. Reference injection doesn't allow that.

"Decoupled" isn't a binary attribute--it's a gradient. If you have implemented an insufficient decoupling strategy for a given change request, you'll end up having to rewrite a lot of code, or at least do a significant overhaul. Personally I like to build my UI's more along the lines of what John (Lokanis) does with a UI component that sends/receives messages and contains UI specific logic. (Practical realities don't always allow it, but I do prefer it.)

maybe I totally misunderstood the question / discussion, but why are you all talking about using control references when decoupling the UI from the Code?

You've decoupled the process and ui threads. That is a good example of what I called 'simple' decoupling above. More advanced decoupling has it's place, as well as it's costs and benefits.

Link to comment

It all depends on how much decoupling you're looking for. Injecting control references decouples *that specific* UI from the funcitonal code, but the functional code still requires *a* UI. Ultimate decoupling means you can, for example, attach multiple UIs at the same time, or run the code with no UI at all.

"Decoupled" isn't a binary attribute--it's a gradient. If you have implemented an insufficient decoupling strategy for a given change request, you'll end up having to rewrite a lot of code, or at least do a significant overhaul. Personally I like to build my UI's more along the lines of what John does with a UI component to send and receive messages, and interpret and display data.

:beer_mug:

And since I have to code for LV basics I & II customers, I stick with the references since adding code to get that extra degree of "uncoupling" would not sit well with most of them. Hell, an Action Engine seems "overly complicated" (actual quote from customer) to some customers.

Take care,

Ben

Link to comment

Hell, an Action Engine seems "overly complicated" (actual quote from customer) to some customers.

I hope their requirements are fairly simple then.* Complicated requirements require complicated solutions. I haven't found a way around that yet. It's all a matter of how you manage the complexity.

(*What do you do when someone asks you to build an F-22 fighter jet, but make it as simple to understand as a bicycle?)

Link to comment

I hope their requirements are fairly simple then.* Complicated requirements require complicated solutions. I haven't found a way around that yet. It's all a matter of how you manage the complexity.

(*What do you do when someone asks you to build an F-22 fighter jet, but make it as simple to understand as a bicycle?)

I have done the system that tested out the new fuel pump for the JSF and the sytems that tests the GPS for cruise missles.

I document everything with the assumption my audience knows little about software. The final code get deployed with diagrams in the BD detailing the states with each state being very boring.

Ben

Link to comment

You are free to disagree but I hope you at least understand what I am trying to say.

yepp. that structure you describe is called a "distributed software". I'm writing a lot of this type of code: the "work" is done on a RT-System, the user-interface (I call it "Client") is running on a Windows system. In that case I use the TCP-Messages, I send to the "server" like an event. In fact it is an event - e.g. a pressed button. The only difference is: the "messages" that go directy into the state-machine in the example above are wrapped into a TCP-packet, sent to the server, unwrapped and put into the state-machine on the RT-server ... so the only difference is the method of transportation: writing directly into a queue vs. wrapping into a TCP-packet, sending it across the network, unwapt it and enqueue it ...

gl&hf

CB

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.