Re: Help on choosing a valid pattern: composite or not?
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Sat, 03 Dec 2005 23:13:02 GMT
Responding to CarmineM...
I've always relegated learning to weight balancing, not to linking nodes each other. There are a few literature's sections I've skimmed only, which talk about "growing" networks and "adapting" ones. Those are, if I'm not wrong, the ones in which learning involves modification in linking between nodes and sprouting of new nodes. Too complex at that time and for a toy app. :)
Either way. In the first case alone one might use Strategy where there is a different Strategy for execution and weight balancing. That is, there might be a different "walker" for back propagation. [Though I suppose one could argue that it would be easier to put both methods in a State and have the "walker" invoke the right one based on context. But then one would only need one State instance. B-)]
Having a State object containing two Strategies references, one for the execution and one for the learning, wouldn't add a little more to expansion?
Sorry I wasn't more explicit about my assumptions. What I was assuming was that the only thing being pluggable was a choice of methods between execution and back propagation. (I.e., both were generic and any differences in results would be driven parametrically by state variables.) Then one wants to substitute the behaviors based upon the direction one is "walking". So Strategy might be a reasonable choice where the [Context]/[Strategy] relationship is instantiated based on directional context.
However, separate classes for just two pretty orthogonal responsibilities might be overkill. If one just made them different methods in one object (e.g., a State pattern), the "walker" would naturally know which one to invoke. But if those were the only things that were pluggable, that would be a bit silly because there would be only one instance of [State]. So my point was that one might as well put the methods in [Node]. But...
I mean, this way I could plug the best/preferred learning strategy keeping the standard execution one.
This is different because the individual "execute" and "back propagation" methods have alternatives that can be substituted. If "execute" and "back propagation" are orthogonal, then State would not be a good choice because one <potentially> would have a combinatorial number of subclasses (N*M), one for each combination of substitutable "execute" implementation (N) and "back propagation" implementation (M). That would, indeed, put us back at Strategy where the worst case would be (N+M) subclasses.
Then it's me not understanding the MVC infrastructure.
I thought it this way:
- View: Some classes with following capabilities
- GfxNode class:
. Can paint a node on screen
. Can paint a node's links to it's children
. Can intercept UI events (double clicks pops up a window with information on a node's state...)
...
Fine. But that class would only exist in the UI subsystem in my world. That is, it would get initialized there using data from an interface method like displayNode(<data packet>) where the <data packet> content was encoded from a Node object in the neural net view. Now the GfxNode class can have all the composition or whatever needed for the MVC infrastructure to make the display code simpler.
Well this looks familiar to me :)
My old GfxNode implemented event catching for: - left button double click This was used to popup a window with node's state information.
- left button down/up - mouse move Those were used to drag and drop node's representation over the drawing area.
- right button down/up
This was used to set the start and the end of a link
between nodes.
GfxNode also implemented event dispatching in order to: - Ask a node for a Dump of its state - Set/Get properties from the node
The wrong part was that the message sent in event dispatching, was nothing more than a container for the message's ID. There was no other data passed in the message. The information were taken reading from the contained GfxNode's node properties. So was setting done. Thus, GfxNode relied on a tight coupling with it's represented node.
I don't like this.
Nor do I. However, in CRUD/USER contexts it isn't that bad because all the application is really doing is converting one view to the other and one would expect coupling in doing that conversion. In my world I don't want the problem solution to be exposed to any view but its own since that is complicated enough. Hence the subsystem partitioning and "firewall" interfaces to decouple the view contexts.
As of now I'm in the middle of a "designing/coding" crisis. I found myself spending a lot of time "thinking" and almost no-time coding (I'm speaking about personal projects. At work is quite the opposite: AKA "Rush to code")
Considering this neural network toy app, I have some ideas about the model and how to implement it. When it's up to the UI for example, I can't think of a good way to decouple it from the model.
Is it a "good thing"(tm) that a glyph representing a node has to use "node.Threshold" or "node.get_Threshold()" in order to retrieve that property's value? Or, instead, should I ask for "node.dump()" and scan trhough the results to find if there's some "Threshold" property in that node?
I argue: None of the above. B-)
In the GUI subsystem where GfxNode might live I am expressing an entirely different set of paradigms for display and I might have a handy MVC infrastructure to make the code simpler, which is where GfxNode comes into the picture.
However, I don't really need the model part of things as an object _in that subsystem_. I can go directly to the View from the subsystem interface. IOW, instead of GfxNode asking the Model's Node for data, it would ask the subsystem interface for data. Think of it this way:
1 gets data from 1 [GfxNode] ------------------------ [Node]
To make that query [GfxNode] needs to navigate a relationship to get to the right [Node]. All I have done is stuck a subsystem interface in the way to implement that relationship as a sort of middleman. Let's say I have defined a Facade pattern class for the interface called, for lack of anything better, GUIInterface. And let's assume I have a Facade for the neural net solution called SolutionInterface. Now at the OOP level we have (in C++ pseudocode):
GfxNode::doIt DataPacket* data; ... data = myGUIInterface->getGfxNodeData(this->name); // request data this->weight1 = data->getWeight1(); // decode data packet ...
GUIInterface::getGfxNodeData (String s) return mySolutionInterface->getNodeData(s);
SolutionInterface::getNodeData (String s) Node* node; DataPacket* data; node = Node::find (s); // static find function to get instance data->setWeight1 (node->getWeight1()); //encode data packet ... return data
This is functionally identical to
GfxNode::doIt this->weight1 = myNode->getWeight1(); ...
where myNode happens to be instantiated for the right Node instance. All I am doing in the first case is inserting an interface and data packet processing logic to implement the relationship. So the MVC Model is still there; its access has just been obfuscated.
One benefit is that GfxNode may not map exactly to Node. For example, it might map to a specific subclass of [Node] and the interface would make that transparent to the GUI subsystem. I can also tinker with things in other ways. The Node::Find search is something to avoid so I can cast identity across the boundary more efficiently than a string. If I map identity into consecutive integers, I can eliminate the search with a table lookup and save string manipulations.
[I have to take care to synchronize identity across the boundary, though, so that the GfxNode.name displayed will be the same as the Node.name on the solution side. Usually, though, that falls out with the way GfxNode will be instantiated. That is, the neural net overall solution will dictate when [GfxNode] instances are created and, consequently, what name (and lookup index) they will have.
In fact, back to my point about who is running the show, I would not expect GfxNode to /want/ to request data. It would be told the values when it is created or when they have changed in the neural net view. IOW, it would have attributes for the values. Either way, those interface messages would be instigated from the neural net side because it "owns" the master view of the data.]
Question time :) - Should GfxNode be aware of every possible property a node can have? What about future properties?
No. GfxNode only needs the properties that are relevant ot display. However, it needs all the properties that are relevant, regardless of whether those properties are are shared by the neural net view. That is, one abstracts the objects for the GUI to solve the display problem by implementing the GUI design. One solves that problem without regard to other objects in other subsystems that are solving different problems.
[At the risk of getting side tracked, one can abstract the entire GUI paradigm sufficiently so that the subsystem can be reused across applications. One just has to provide application-specific configuration data. Note that this is exactly how GUI and web builder tools work. They provide generic abstractions for the paradigm that are parametrically instantiated based on a "resource" configuration file. The tool essentially just constructs the configuration file from the WYSIWYG design tool.]
Since both subsystems are likely to be abstracting the same problem space entity (a node), they are likely to share knowledge properties because quite different behaviors can operate on the same data. (However, they should not share /any/ behaviors because each subsystem addresses a different subject matter and that implies that they resolve different functional requirements.)
That presents a problem because the same data values are on both sides of the subsystem boundary and that means one has a synchronization problem. There are tricks, such as having a setter always generate a message to the other subsystem, that can make this pretty mundane in most situations. However, there are exceptions, especially when there is concurrent processing, where one needs to provide additional handshaking protocols in the interface.
This again gets back to who is running the show. One reason for having the problem solution run things rather than the GUI is so that synchronization can be handled centrally in the place where it is likely to be most important. So the GUI may forward a user request that will result in something getting displayed. But the solution will tell the GUI what to display and when to do it. That may require that the solution wait before sending the displayX message until the GUI has responded that it has received all the data the solution sent for the display as part of a handshaking protocol.
[This all sounds very complicated but it is actually rather rare that one needs to worry handshaking protocols because the points where display are required are usually mapped very clearly into major processing breakpoints. Similarly, objects that persist in the display while the solution is running and changing values are fairly unusual. Perhaps most important of all, the user's view of time is a whole lot slower than the system clock's view so data updates can usually be "batched".
If you haven't done a lot of R-T/E development, you will have to take my word for another benefit. Despite the complexity, this model actually makes it much easier to deal with concurrency. That's because the interface itself provides a focal point for synchronization issues that might not be very clear in direct collaborations.]
- How could GfxNode deal with read only properties? (maybe letting node.dump() pass this kind of information)
I would argue that on the GUI side, all Node properties are read-only. B-). That is, they all have their origin in Node on the neural net side. The user can supply new values for the neural net side but the GUI really shouldn't understand that semantics. It would dutifully forward the message and the neural net model would decide if it were legal (and would provide a rude response if it weren't).
[Typically the easy way is to enforce that in the GUI design itself by making certain display fields read-only. To that extent the GUI design (as opposed to implementation) is just reflecting the same problem space rules and policies as the neural net solution. So this would only be relevant if there were different contexts where values were or were not read-only. However, the solution model should be the arbiter of that context and it could tell the GUI subsystem which context applies so it can do its thing in the display.]
- Controller: Some intermediate (Mediator, Adapter, Façade?!?) class which are responsible to fetch and set model objects states (e.g.: changing node's links, properties, weights...)
Typically the subsystem interface is in the form of a Facade pattern except it is two-way. [There is a post in the Application Partitioning category of my blog that presents the two-way subsystem interface model.] You might have an MVC Controller in the UI subsystem but it would not talk directly to the neural net objects; it would talk to the output Facade interface.
Without Facade GfxNode calls node.dump() to show its state
With Facade
GfxNode calls node_facade.dump() which, in turns, read the node state via node.dump() or accessing node's properties.
Bingo!
Am I correct? If so, then ...
...Having a Facade to do such things, and since Facade has to have a deep knowledge of the nodes it talks to, wouldn't mean to have a specialized Facade for every specialized node?
Well, maybe not quite a Bingo. B-)
The Facade just knows how to talk to the Facade that is the neural net solution's subsystem interface. Only the neural net's Facade would understand Nodes. That's why one needs the bother of encoding/decoding the data packets. Each Facade interface only knows how to encode/decode for its local subject matter.
BTW, the original impetus for this sort of two-way interface decoupling was large scale reuse. A major problem with reuse is that any complex semantics can usually be accessed by multiple syntaxes (interfaces). So when one introduces a service into a new reuse situation it is quite possible for the new client to want to use a different access syntax than the one provided with the service. The result is the client can't talk to the service even though it is not at all confused about what service is being provided.
The answers to this problem tend to be ugly and the Facade approach is a lesser-of-evils. One can provide the "glue" code for syntactic mismatches in the Facade implementation. That is, one just has to change the implementation of the output Facade to talk to the other subsystem's input Facade. However, to do that easily and cleanly the interfaces must be highly disciplined, message-based, data transfer interfaces AND the Facade needs to be two-way. Generally one can't afford that overhead at the object level but it is quite feasible at the subsystem level.
However, I don't really like that execution model because it implies that the UI is running the show. That view is fine for CRUD/USER processing but in more complex applications it is the problem solution that is running the show (i.e., deciding what data should be displayed). IOW, the UI subsystem is simply providing a communication service for the solution that allows communication with the user.
The user may initiate the communications (e.g., "Show me Subnet X") but the UI really should not know anything about the semantics of 'subnet X'; it should just relay the message to the solution and let the solution determine the appropriate response. [Note that <philosophically> this implies an asynchronous interface. The UI sends the user's message and the solution sends back a separate message with the data to display. While the response is tied to the request in the solution, the UI really shouldn't know that.]
I agree with you. This reminds me of the so known "Hollywood's principle": Don't call us, we'll call you.
The model will tell the UI when there's something "fresh" to eventually display, right?
Right. The UI initiates things by sending something like userClickedX but the UI really doesn't understand the semantics of what X means to the problem. It only understands that when the user clicks a certain control it should send this message. The solution then sends back a message with a fat data packet that will trigger creating a bunch of GfxNode objects or whatever and getting them on the screen.
Observer pattern.
Usually not that complicated. Identity is usually embedded explicitly (node name) or implicitly (position in the data packet) in the message. Mapping of identity to objects in memory is usually handled more mundanely with things like lookup tables in the Facade.
Except for very few occasions, I've always had a complex model under the UI's hood, and that could explain why each time I thought about MVC to do UI decoupling, I've had the feeling its a bit of overkill.
OTOH, MVC (more precisely, the "canned" infrastructures that support it) do provide some isolation from the grunt work of talking to the OS Window Manager and whatnot. So there can be advantages in creating a UI subsystem in using MVC. (Similarly, one has similar advantages on the persistence side for SQL, etc..) To take advantage of that convenience outside the CRUD/USER realm, one just needs to decouple UI and data views from the model somewhat.
Finally, there is the philosophical issue above about who is running the show. IMO, that is the thing that really separates the 1D layered model infrastructures of CRUD/USER processing from the 2D subsystem organization of more complex processing. For more complex applications the UI subsystem ends up being at the same level of abstraction (layer) as the persistence access subsystem and both are regarded as low level services. IOW, the partitioning is a directed acyclic graph where the overall control is in a single root node and the UI and DB access are sibling leaves at the base that have virtually no problem intelligence.
Well, about the philosophical issue, I guess it strongly depends on the kind of application.
Simulations, are a good example of model driven show.
Application wher the user asks for something (AKA queries a database) are a sample of UI driven show.
I think the above cases are extreme ones. What happen in the middle, where there's a mixture of a rich UI and a complex model?
I see the breakdown as depending on what the problem is. In CRUD/USER processing the basic problem is to present large amounts of data on an ad hoc basis. Thus the application is essentially just a pipeline between the persistence and display views. That is an inherently 1D characterization and that leads to the common layered models like MVC. As it happens, those sorts of problems are very common in IT contexts so, simplistic as the models are, they are extremely useful and they gave birth to RAD IDE automation where the UI maps 1:1 with tables and tuples. In that case, the "business" objects have no need to map to anything else.
However, once the problem requires something more than view conversion between DB and UI I think one is out of the realm where such 1D layered models are useful because the "business" objects will probably not map 1:1 to tables and tuples. Then one wants to separate the concerns of the "business" layer precisely because it /is/ complex and warrants independent treatment.
************* There is nothing wrong with me that could not be cured by a capful of Drano.
H. S. Lahman hsl@xxxxxxxxxxxxxxxxx Pathfinder Solutions -- Put MDA to Work http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman (888)OOA-PATH
.
- References:
- Re: Help on choosing a valid pattern: composite or not?
- From: H. S. Lahman
- Re: Help on choosing a valid pattern: composite or not?
- From: CarmineM
- Re: Help on choosing a valid pattern: composite or not?
- Prev by Date: Re: Decouple SQL queries from class in OOP design
- Next by Date: Re: Decouple SQL queries from class in OOP design
- Previous by thread: Re: Help on choosing a valid pattern: composite or not?
- Next by thread: Javascript String Concatenations
- Index(es):