Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Actors and interfaces - am I doing it right?

Solved!
Go to solution

@cbutcher wrote:

Imagine instead that A.lvclass is a testing dummy class, and you can more easily imagine why you'd not need it in all users of A-interface.lvlib


This.  If all my messages are interfaces, I can swap out any nested actor with a stub, usually one that redirects the message to my unit test VI.

 

Even if I have no plans to ever have another working actor inherit that set of messages, I would still use an interface just for this purpose.

0 Kudos
Message 21 of 37
(1,176 Views)

@justACS wrote:

@horuable wrote:


Ok, but if A (root) is already sending some messages to B (nested) without using interfaces, just normal messages from B's "Messages for this Actor" folder doesn't that alone make it so A cannot be used without B?


It does.  The interfaces to A still do not belong in B.  You may (for example) want to send some of those messages from another actor (A's caller, perhaps, or a new nested actor).  That new actor should not have to depend on B's library in any way.

 

 


I'm not sure I understand this part. Couldn't you just create a new interface for that?

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 22 of 37
(1,174 Views)

@justACS wrote:Personally, I don't even want A coupled to B.  I put an interface on B as well, and have A call the interface.  I have almost no coupling between my actors.  Even if all it does is make it easy to isolate actors for unit testing, I count it as worth my tim

Not sure I agree with that (with the caveat that I'm not sure I understand it enough to be able to disagree with it).

 

Not coupling to your callers - absolutely. If write a low-level driver for some instrument, I absolutely want to be able to use it in other projects and have it be called by any actor. In that case, keeping the interface for what it sends to the caller as part of the driver makes sense to me. If I want to distribute it, I just distribute that one library. Any caller, just inherits from that interface and done.

 

Not coupling to the things you are calling, not entirely sure I understand the use case for that. If you are doing plugins and HALS, sure, but otherwise? Generally I know what I'm calling. And you are really only talking about middle layers here? right? because the top layer is probably application specific and not reusable anyway. So we're really only talking about reusing actors somewhere in the middle layer. How often are you actually reusing those? Wouldn't they have a lot of application specific logic in them anyway? Is there really that much to be gained by reusing them?

 

And also as far as HALS, do you really need a seperate actor for each instrument? or could you just have one actor that wraps the interface to your HAL using composition? Wouldn't that be easier? Then the only interface any other actors have to worry about is that one actor interface?


Also as to the unit testing, maybe that level of decoupling makes it easier, but is it required?

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 23 of 37
(1,171 Views)

Not trying to be argumentative. Just having a really hard time following this conversation and I'm sure I'm I must be missing some important point that you and AQ are trying to make.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 24 of 37
(1,169 Views)

If the content is different then they aren’t sending the same data. I didn’t say data type. 

0 Kudos
Message 25 of 37
(1,162 Views)

but shouldn't that imply that the interface should be a part of A (as

> in inside the same library), since A is always going to depend on it (the

> interface) anyway?

 

Whether discussing actors or not, I would suggest that it is a code smell if the same library owns both an interface and a class implementing that interface. I’m having trouble coming up with any case where packaging those together isn’t wrong other than the case of packaging for distribution in a packed project library, and I might question that one depending on circumstances. 

0 Kudos
Message 26 of 37
(1,157 Views)

@Taggart wrote:

@justACS wrote:Personally, I don't even want A coupled to B.  I put an interface on B as well, and have A call the interface.  I have almost no coupling between my actors.  Even if all it does is make it easy to isolate actors for unit testing, I count it as worth my tim

Not coupling to the things you are calling, not entirely sure I understand the use case for that. If you are doing plugins and HALS, sure, but otherwise? Generally I know what I'm calling. And you are really only talking about middle layers here? right? because the top layer is probably application specific and not reusable anyway. So we're really only talking about reusing actors somewhere in the middle layer. How often are you actually reusing those? Wouldn't they have a lot of application specific logic in them anyway? Is there really that much to be gained by reusing them?

 

...


Also as to the unit testing, maybe that level of decoupling makes it easier, but is it required?


You can have the same reason here, like ACS wrote. If I can replace the called actor at will, I can trivially replace functions I don't like ("Spin Motor At Dangerous Speed.vi") with nicer versions (same name, but just log the command to a text file, or update a global variable, or something).

 

Then I can run my application whenever I want, and don't have to connect to hardware etc.

I can do that without an interface, via shared inheritance, but it's basically the same argument - if I need a parent class, I might as well have the interface (in 2020+), and if I plan to instead have my test class inherit from the real class, I have a whole range of potential problems (really hard breaking of LSP, plus probably I didn't use template method for a real class if that was the only goal, so no injection points for test code, etc...)).

 


@Taggart wrote:

And also as far as HALS, do you really need a seperate actor for each instrument? or could you just have one actor that wraps the interface to your HAL using composition? Wouldn't that be easier? Then the only interface any other actors have to worry about is that one actor interface?


What's the purpose of the Actor here? I think you're saying this from the point of view of already having non-Actor drivers (class, library, bunch of VIs in a folder somewhere) to operate each piece of hardware (you mention HAL, but I'm not sure if you're talking about multiple implementations of a single tool, or multiple different types?).

Can you elaborate what you're (mentally, or really) doing?

 

After a few mental shufflings, I'm sort of imagining an Actor being used to make hardware operations asynchronous from the point of view of a calling Actor, so in the simplest (?) case, some ControllerActor.lvclass calling a WrapperActor.lvclass, which uses a MyAwesomeHardware.lvclass (not an Actor) to interact with some specific hardware.

You can replace with a HAL if you want more complexity, but I don't think it matters in the case you might be imagining, with a HAL for a single specific tool/behaviour, e.g. "Temperature Measuring At a Single Point Device"? - in that case maybe just a way to init the Actor with the appropriate concrete Temperature class, and then it's the same anyway.

You don't want ControllerActor to directly interact with Temperature, because it might take time, and it's supposed to be interacting with other messages etc, so you create WrapperActor.

 

In this mental model, it seems like WrapperActor has to be a "Temperature Measuring At a Single Point Device Wrapper Actor", and not a generic (Do Some Measurement) wrapper, but it doesn't need to be specific to the concrete Temperature class.

 

The level of wrapper here seems to depend entirely on the HAL/Interface - looks to me like one different Wrapper Actor per Interface / HAL that you intend to use.
If you really wanted to cut that down, you could use a message handling type arrangement (Do X.vi, X is a string/enum, case structure) to have an Actor depend on multiple interfaces/HALs and handle all of their behaviours, but mentally debugging that sounds like a pita... plus you're losing the asynchronous behaviour you wanted unless you program that lower down (out-of-band communication methods like non-Actor-Msg queues, notifiers, etc), in which case you might as well drop the wrapper and put it back in the ControllerActor anyway...


GCentral
0 Kudos
Message 27 of 37
(1,128 Views)

My train of thought is just leaving the station... I am now understanding that this discussion is more about interface packaging rather than interface segregation.

 

Regarding the argument of packaging an interface along with a class (actor or otherwise), I agree that is not advisable. If an interface is independent of classes (as it should be) it should be packaged in its own library along with its actor messages. Otherwise, what would the rationale be for selecting one class over another to package said interface?

 

If the interface is associated with only one or more related classes, then why even use an interface - just directly use the base class of these related classes and build the actor messages for this base class. One can still create stubs sub-classed from the base class for testing.

0 Kudos
Message 28 of 37
(1,119 Views)

Sam wrote:

Not coupling to the things you are calling, not entirely sure I understand the use case for that.

 

Dhakkan wrote:
If the interface is associated with only one or more related classes, then why even use an interface

 

Testing. You can replace the concrete dependency with a mock dependency during testing to simulate a wide range of responses from the dependency. For me, this is a case-by-case call of how testable I need each segment to be: if I can test lower levels and trust them when testing higher levels (and they aren’t particularly stateful), then I don’t tend to segregate… I can refactor later if I made the wrong call. JustACS, on the other hand, segregates always because ne finds having the interface segregation is cheap compared to the expense of refactoring if ne made the wrong call. It’s a reasonable position. But both of us agree that testing is the key value proposition for interfacing even a single-inheritor class. 

0 Kudos
Message 29 of 37
(1,105 Views)

@AristosQueue(NI) wrote:

but shouldn't that imply that the interface should be a part of A (as

> in inside the same library), since A is always going to depend on it (the

> interface) anyway?

 

Whether discussing actors or not, I would suggest that it is a code smell if the same library owns both an interface and a class implementing that interface. I’m having trouble coming up with any case where packaging those together isn’t wrong other than the case of packaging for distribution in a packed project library, and I might question that one depending on circumstanc


 I think you misunderstood what I was saying. If A is the caller and depends on the interface (which some other nested actor implements in order to send it messages) then it would make sense to package them (A and the interface) together. A is the consumer, not the implementation.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 30 of 37
(1,096 Views)