Jump to content

PaulL

Members
  • Posts

    544
  • Joined

  • Last visited

  • Days Won

    17

Everything posted by PaulL

  1. Well, I don't know how seriously this is intended, but I think it questions the point of doing software modeling at all. At the risk of derailing my own thread, here are a few thoughts on why modeling is advantageous and, I think, essential for effective programming: 1) We want to be able to propose, analyze, and modify design approaches prior to implementing them. (The underlying argument is that, apart from trivial or by-rote implementations, if we just start implementing code we will not likely achieve an optimal implementation immediately; on the other hand, careful analysis can result in better-designed applications.) a) It is much faster and easier to do this in UML than in the development environment. b) UML expresses relationships more effectively than the LabVIEW IDE can. (LabVIEW's class view, for instance, does indicate inheritance relationships but it does not indicate in any fashion relationships between methods, nor other essential types of relationships, e.g., composition.) 2) Within a UML/SysML tool we can also model behaviors (e.g., state behaviors), and link all of these to other essential elements of software engineering (e.g., requirements, tests). 3) Of course, it is even better to be able to be able to create code from the model, but that is something I don't presently do (but would very much like to be able to do--without losing the other capabilities). Paul
  2. OK. Lol. I think I understand what your configuration class does. What we do is slightly different. We store the configuration in typedef'd clusters. Each class that uses that information keeps a copy of the cluster in its private data and reads the data from file on each initialization (during a state transition defined as part of the application--not really object initialization, although one can look at it that way). Then each class that needs the data has it ready for use. This makes it easy to reuse configuration items. It does not prevent a calls that contains a copy of the cluster from modifying its copy of the cluster data, but I don't think we need to do that. Now what you are calling a configuration class is, it seems to me, actually a layer above that, that performs some action with the configuration data. This I would not call a configuration class (I'd pick something descriptive of the channels or application), but that's probably not the key point. In any case, it seems the Channel class (yet another class) is the one you are not sure should have public methods. Or do you mean the ChannelConfiguration.generateChannels() method, that in turn has access to the Channel class methods? OK, I guess I don't quite understand the class relationships and purposes you intend yet, after all. Can you clarify? (I'd love to see a diagram, of course.) Paul
  3. What you have is that you want to equip an axis instance with a particular algorithm (BasicMove or HandleBacklash) for motion (e.g., Move), and you want to specify that algorithm dynamically without overriding the Axis.move() method, for instance. The Strategy Pattern does just that, by encapsulating algorithms in a separate family. See http://lavag.org/topic/14213-strategy-pattern-example/?hl=%2Bstrategy+%2Bpattern for a LabVIEW discussion and example. Good luck!
  4. No worries! It's a great extension of the discussion! I don't model accessor methods, nor do I add the owning class terminal inputs and outputs or error cluster inputs and outputs to method references, since these are understood (and I'm not doing code generation), so the resulting UML diagrams are relatively simple but convey the information we need to know. Consequently, I haven't thought about how to label inputs as dynamic, etc., but I could see this might become an issue for code generation. Still, for the most part I think I would put that in the code generator logic and template. (Every method on a class will have class terminals--dynamic terminals if the method on this class or its parent is abstract; also error terminals, except for accessor methods.) Hence the input and output parameters in the method definition in the model are just those that are really of interest for the method.
  5. Not quite what you are asking, but when I close a block diagram my habit is to use Ctrl + (EW) to close the VI completely ([save], Switch to front panel window, Close). Nothing special, but very useful for the purpose.
  6. So, does this answer your original question? You are using JSON for serialization? Does that relate to the configuration class accessor methods scope, or is this a separate question? I'm not a fan of community scope in general (haven't had a use case where it really added anything--maybe they make sense for the XControl use case they targeted, but I don't create XControls; lack of inheriting the relationship is in practice inconvenient for other use cases; community scope was dropped in C++, after all), so I would make these methods public myself, but as a disclaimer, I don't actually store the configuration in objects, but as typedefined clusters (clusters have front panels, which helps when makes it easier to create a configuration editor; there is no nonaccessor functionality anyway, so clusters suit the needs well; also for historical performance reasons). Cluster access is public. That works in our environment, but may not be suitable for code that one distributes widely.
  7. Here is a question I am pondering: The UML specification defines ParameterDirectionKind (7.3.43 in the V2.4.1 superstructure specification, available at omg.org) for an operation defined on a class. The description there is: "ParameterDirectionKind is an enumeration of the following literal values: • in Indicates that parameter values are passed into the behavioral element by the caller. • inout Indicates that parameter values are passed into a behavioral element by the caller and then back out to the caller from the behavioral element. • out Indicates that parameter values are passed from a behavioral element out to the caller. • return Indicates that parameter values are passed as return values from a behavioral element back to the caller." So, do we model the outputs of a LabVIEW class method (VI) with the "out" or "return" direction? I decided long ago to use "out" and never "return" for a number of reasons (some theoretical, some practical: "inout" does make sense, after all; many languages support only one return value, although this is a design choice), and I delete "void" for the return type in the operation prototype since I regard that as meaningless for LabVIEW. I still think that is the best approach, but I'm not certain that I have the most rigorous explanation, and of course I could be wrong altogether. Thoughts? Paul
  8. The Enum for the states is a strict typedef inside a project library (.lvlib) within the component. Interacting components that need to know the state have access to the typedef so that they can interpret published State information (a U16 published via a network shared variable). Since we only have one system, usage is by (obvious) convention. All the typedefs in that particular .lvlib are for elements related to elements published for external availability.
  9. Again, thanks! I have a couple notes to update the presentation: 1) On slide 23, I have a note about the representation of internal and recursive transitions. I sent a feature request to Sparx Systems, and recent release notes indicate there may be a fix for that in a recent version of Enterprise Architect, but I have not confirmed that. 2) On slide 85 there is a bullet suggesting a slight change to facilitate the implementation of orthogonal regions (slide 94). Shortly after the presentation I tried that and it worked great! I should find a place to post the Powerpoint version, since then folks can read the slide notes, which I think are helpful in this case.
  10. Yes, that's it! Thanks for tracking down the link! Paul
  11. Exactly! (Well, we use the Factory Method Pattern to create State objects.) I presented the essentials of our implementation at NI Week 2012. I should put this presentation on a server somewhere. ... I think you are on a fruitful track. ... Edit: Was replying to post #10.
  12. Consider making the State classes flyweight classes and maintaining state information (big s and little s, actually) in the Context. (That is what we do; it works quite well, and I think it is the best way to implement the State Pattern. My impression is this would be difficult to do with the Actor Framework, though.)
  13. "What I meant was that I see benefits using those patterns from a maintainability point of view, but it is not clear to me that the end result is better overall. Partly because my experience with dynamic dispatch in LV is a killer of performance, and partly because the examples are too simple and too far from real world applications. ... For instance the factory pattern, if you don't use it in relation with pointers to objects (by ref), what is the benefit?" The factory method pattern lets clients create concrete objects without having any references to the concrete objects. For instance, clients create state objects without having a reference to the concrete states. This sometimes makes a huge difference in the amount of interlinking and hence can affect project load time (and on RT can make the difference between successfully deploying an application or not). (It also means that one developer can work on the client code in one project while another developer works on the state code in another project.) I haven't completed incredibly thorough studies of the performance of dynamic dispatching except in a few cases, and in the situations where we use dynamic dispatching performance is not an issue for our applications.* Certainly in absolutely performance-critical pieces it will be necessary to use static methods and in-line them. (*We did identify one complex but repeatable situation where using an object that was a collection of objects was many, many times slower than when using a cluster containing those objects, and we reported that to NI. That is the only situation we have encountered such an issue to date.) We use OO design patterns in all our applications. I think you are on the money, in that the primary benefit of using design patterns is to the programmer and thence to the customer, in that it can make the code more maintainable (and, I would add, easier to design and write in the first place), rather than in application performance; I think that it is of immense value. For instance, we find using the State Pattern results in a very clean and explicit implementation of states, with hierarchical states (so that we don't need to repeat behaviors in subclasses), and when something works in an unanticipated manner anyone on our team knows exactly where to look in the code to investigate the issue. Those are pretty huge benefits for us when we are developing robust applications that we want to remain operable for many years. We definitely have seen the benefits in the real world, where our system is functioning extremely reliably.
  14. We define an interface using an abstract (noninstantiated) class with all pure virtual (abstract) methods. For more details (and clarifications) see Appendix I in this the paper linked in this thread: http://lavag.org/topic/14213-strategy-pattern-example/page__hl__%2Bstrategy+%2Bpattern__fromsearch__1.
  15. Yes. For instance, a transformational system (a data processing algorithm not requiring user interaction) is not a reactive system (that responds to events). State machines are appropriate for designing reactive systems. Here is a link I have found helpful when contemplating the essence of state machines: http://xlinux.nist.gov/dads/HTML/statemachine.html.
  16. We have implemented asynchronously communicating, stand-alone state-based components (which meet the descriptions I have seen thus far for actors, even though we don't think of them as actors) using native by-value classes and design patterns (see especially the State Pattern and perhaps my NI Week presentation on it.). (We have since also implemented orthogonal state machines within an application.) Our components can communicate over the network, allowing flexibility in deployment, and maintain state information in the proper places. And yes, we reuse the top-level state machine, for instance, in every component controller. :-) I think that the Gang of Four Design Patterns book and Head First Design Patterns are wonderful sources on how to implement and use design patterns effectively, but those texts didn't really click for me until I began to understand interfaces, which is why I bring up the topic so often in the papers and presentations I have compiled on design patterns.
  17. I will concede that some design patterns likely require object references. On the other hand, we have successfully implemented all the GoF design patterns we have tried thus far with by-value classes, and we didn't need any special tricks to do so.
  18. On the original topic, my observation is that an actor and a UML component (which of course one often realizes with OOP) seem to be essentially the same thing.... The abstracts to these papers on actor-oriented design (http://www.google.com/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=1&cad=rja&ved=0CDwQFjAA&url=http%3A%2F%2Fciteseerx.ist.psu.edu%2Fviewdoc%2Fdownload%3Fdoi%3D10.1.1.230.1295%26rep%3Drep1%26type%3Dpdf&ei=srTQUK7fIMrjiwKI2oGgCw&usg=AFQjCNFpmCrg3Kg13RXHZjh7_rBbOlaSkQ&bvm=bv.1355534169,d.cGE, http://www.google.com/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=1&cad=rja&ved=0CDIQFjAA&url=http%3A%2F%2Fciteseerx.ist.psu.edu%2Fviewdoc%2Fdownload%3Fdoi%3D10.1.1.9.6762%26rep%3Drep1%26type%3Dpdf&ei=HLXQUJ3sE-eOiAKt3IDIDA&usg=AFQjCNFkPU5eV46p7bZYT9p01zHPSPmWIQ&bvm=bv.1355534169,d.cGE) are very interesting in this regard. (Take a look at a component in UML for comparison!) There may be a fine distinction here, but I think actors and components are pretty much the same thing (and one of the abstracts starts with, "Actor-oriented languages provide a component compositio methodology that emphasizes concurrency.") So I guess my interpretation (I'm not an expert on actor-oriented programming, by any means) is that an actor (or a component) is a way of programming that emphasizes concurrency (and as such looks somewhat like dataflow, which is, I think, why LabVIEW appears in the abstract of one of the papers). Object-oriented programming aligns well with that concept since it emphasizes encapsulation, but of course it would be possible to implement actors or components without objects. With objects it seems to me to be easier since the concepts of encapsulation and delegation already are central themes. Actors/components and OOP are complementary concepts, it seems to me.
  19. Hmmm..., can you explain further what you mean by that? In the glossary of T. Budd, An Introduction to Object-Oriented Programming, 3d. ed., we find: "object-oriented programming: A style of design that is centered around the delegation of responsibilites to independent interacting agents and a style of programming characterized by the use of message passing and classes organized into one or more inheritance hierarchies." I see similar descriptions of OOP elsewhere. Certainly one can do all those things with native by-value objects!
  20. Mark, I think this is a well-posed question! I have some suggestions, and I will try to put them in some coherent order: 1) I recommend keeping the top-level state methods abstract (thus maintaining an interface to the invoking context). (If there is a need to implement concrete methods shared by all states, consider creating a concrete class directly beneath the interface.) 2) I also recommend putting all the behaviors within the state methods (except for transition logic, which we, at least, put in the state methods directly) into another class (Context or Model, preferably via an IContext or IModel interface). Prepare IModel (I will describe this option) methods for the largest reusable units the state methods will invoke. (I don't think it is bad to reuse a particular IModel method in different state methods, but if two state methods call the exact same sequence of IModel methods, and hence do exactly the same thing, which is what you described, then I think it is worth considering refactoring.) 3) Most importantly, consider carefully the hierarchy of states. The hierarchy certainly does not need to be flat! Maybe you can end up describing (and hence grouping) states in a different way. In the example above, what is the relationship of ConcreteState_C to the other states? (From what you describe it is possible that the system actually has two orthogonal state machines, with C being a sort of combination of A and B, although there is not enough information in the description to determine that.) 4) There might be some situations where repeating implementations is appropriate, for example, if the implementations could vary independently in the future (which is likely the case if the states logically don't have any sort of inheritance relationship between them). Paul
  21. On RT, which the DSC module does not support, we have used an approach similar to what you suggest, yes (as I have previously mentioned in another thread). We use the "Read Variable with Timeout" VI in the shared variable API and then create a user event. In our case on the RT side all messages arrive via a single shared variable (since we are using the Command Pattern) so we haven't attempted to extend this to support n variables, but I would guess this is possible. We haven't explored this further since we use the logging features of DSC anyway, but from a technical standpoint it might in fact be a way to do event-driven programming with shared variables without purchasing the DSC module. (Disclaimer: From a business standpoint I'm not advocating either approach at this time. Lol)
  22. I couldn't agree more. Publish-subscribe messaging is an essential feature of many types of today's applications, and to do publish-subscribe messaging without events (or the equivalent) is pointless.
  23. We use networked shared variables and also ActiveMQ (an implementation of Java Message Service) -- via a custom LabVIEW interface -- for messaging much as John describes. Both are examples of publish-subscribe communication (although ActiveMQ actually supports several modes); see also Observer Pattern. Communication with both (in our system) is event-driven (the DSC Module supports shared variable events). (I think polling is not as desirable both because of the resource issues but even more because it is possible to miss value changes and, on the flip side, it means acquiring and at least in some sense processing the same data multiple times.) John, you might want to look at the publish-subscribe approach. Isn't publish-subscribe communication really what you are after? That seems to me to be more or less what you are describing. (For the record, RTI offers a LabVIEW interface to yet another implementation of publish-subscribe communication, this time using the DDS standard. The LabVIEW interface in the earlier versions wasn't as convenient as the native shared variable API was, but I haven't seen the latest versions.)
  24. Shane, If I understand correctly then you want directives (commands) from your main processing loop (client) to find the appropriate target (receiver) to execute them. This is exactly what the Command Pattern does. Yes, it is possible for each Receiver to maintain its state. We actually combine the Command Pattern and the State Pattern to do exactly this. Our solution differs from what you describe, since the Receivers do execute their atomic actions within the main control loop (of course in parallel to the View). If a Receiver broader action (e.g., a point-to-point axis move) requires a long time, we break up the action into smaller pieces (not segments, but, for instance, "check if we are there yet" actions each loop). In other words, we use a Run-To-Completion execution model. Does this help? Paul
×
×
  • Create New...

Important Information

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