I am looking for some best practices for scoping the pipeline when calling a child service.
Assume the following:
- a child service should not be able to address any variables in its parent’s pipeline, except those declared as input variables
- a child should not be allowed to change the values of its input variables
- when returning, a child should return values in its output variables.
Then, as a best practice
- when starting, a child should clear all variables from the pipeline except its formal inputs.
- when returning, a child should clear all variables from the pipeline except its formal outputs.
Is there any problems with these guidelines?
I’m fairly against using clearPipeline (except when used for cachine, when there’s no other solution). Reason being that it has an impact on the pipeline that is not apparent at design time (i.e. clears values that still “appear” to be there in the developer).
If you want to prevent mucking around with other variables: you could try the local variable holder pattern (http://www.customware.net/repository/display/WMPATTERNS/Local+Variable+Holder)
Then your rules become:
* Only inputs, outputs and the temporary document are to be in the pipeline.
* cleanup inputs/outputs for a service invoke immediately
* map FROM:
o one of the service inputs or outputs
o from inside the temporary document
o NOT from any other pipeline variable
* map TO:
o an output of the service
o a variable underneath the temporary document holder (if the variable is needed later in the service)
* drop:
o any variables just used for the inputs to an invoke of another service
o any outputs of a service invoke
And at the end of the service you should blow away the temporary document…
regards,
Nathan
There is an easy way to achieve this: call your services as transformers in a Map step. It automatically does all that’s necessary to protect the data in your pipeline.
There are two disadvantages:
-
If the service has no outputs, the runtime will not execute the service. This can lead to some subtle bugs. Therefore always make sure your services have an output mapped back to a variable in your pipeline.
-
It makes the code less readable, as you can’t see what service is being called just by looking at the flow code. You will have to put the service name into the comment for the map step. Like all comments, it can easily get out of date, so discipline is required to keep the comments current.
Hope that helps.
Edwin.
You could also achieve this by placing everything inside a sequence that has scope set to a document…
So:
MAP (create the pipeline doc and map inputs)
SEQUENCE (all code under here, scope set to the doc)
MAP (outputs back, cleanup the pipeline doc)
If you’re dead keen on the concept…
regards,
Nathan
Hello,
How would you want to deal with the “alter a value not a reference” situation? If you pass in a string, you can easily make a new copy. If you pass in a list or table, you will have to loop all the elements and copy then to a new list or table and then do your work. Sometimes operations work well either way. Like if you are agumenting a table that will not need references to its old values, why make a copy? But some objects may need (or can only be) used as a reference. A file or a socket connection may be passed but should not under some circumstances be copied.
I like to make a specific copy service for any complex type I need and leave my other services and reference augmenting, this way I can have explicit use when and if needed. Good day.
Yemi Bedu
Looking back, I don’t really see the need to be that concerned about mutation of inputs…
Unless you’re dealing with an (idiot) team that is in the habit of doing things like looking at the Purchase Order document and then deciding to drop values in the structure, or treat some document structure in that purchase order as a dumping ground for some insane reason.
The real issue is having stuff placed (and left) in the pipeline with the same name as something that was there before and thus losing the original value.
A deep clone of the entire pipeline prior to EVERY invocation of a service is going to play havoc with memory usage, mean terrible performance (unnecessary memory allocation for all the pipeline objects), result in ugly code and will simply not work for some things (like the file stream or socket reference Yemi mentioned above).
Java with its effective pass by reference nature can suffer from this mutation problem too if, as I say, you have people coding who do crazy things… E.g. let’s say you’re writing a GUI app and you have someone writing an on click event handler who then goes and retrieves the button it came from and turns it red and changes the text to “blah”, just for the hell of it… Sure, maybe it’s worth making some magic event handler that ensures the custom developed event handlers only ever get a clone of the original button, but who’s really going to do it…
Nath