The service action was introduced with ARS version 7.1. It allows the creation of sets of code to be processed at the served that can be called from anywhere, proving input and output parameters. This new action opened a new developing paradigm where the creation of shared libraries of code where allowed.
In this post I provide a little tutorial about the service action, giving some hints and providing some best practices.
Before the version 7.1 it was very difficult to create shareable pieces of code in ARS system. Some options where, to use forms as objects or to emulate the assembly function within Remedy. I explored both options on previous posts. These options continue to be useful but at many scenarios are superseded by the service action.
To use forms as objects is the simplest way to create processes where no answer is needed. That is to perform some process to the data, modifying this data. But the PUSH action that calls the code doesn’t receive any output about what was done. The only to read the output of a PUSH action, is forcing the cache release after performing the PUSH. But this must be used only when no other option is found, since releasing the cache can have collateral effects.
On the other hand, creating functions in Remedy, emulating the assembly code where the input and output parameters are shared between the caller and the function, can be also usefull for little pieces of codes, used at a lot of places. Two characteristics define this kind of code sharing: permission coherency and easier traceability. Permission coherency stands for functions developed with active links, where the code is executed at the client and the permissions inside the function remain the user permission, not admin. Also functions can do active link actions, not allowed at services.
But the service action is a better choose at most of the cases. The advantages are numerous:
- They are always executed at the server, with admin privileges, allowing complex permission rules. The result is independent of the user.
- Unitary testing is possible and easy to perform.
- The same code can be accessed from active links or filters.
- The form doesn’t need to be modified to call a service.
- Are easier to share between developers (through community).
- And a lot of other advantages.
As said before, services opened a new set of options inside Remedy.
A service action is always related to a form that hosts the service. In fact when you perform a service action you are calling a service from one form to another. Both forms can be the same, which can be useful at some cases.
A service is a set of filters that are executed according to its order to compute an output. When you call a service you provide some input parameters, the filters are executed and the result placed at some fields is returned to the caller. The service never changes the data at the host form, except is a PUSH action is found. When developing a service you must think of it like if it was in a “server dialog view”. The filters fired are the ones with the execution option “service” marked.
So the concept is easy, to create a service you only need to add filter with the service execution option to a form, and you can call a service to this form from any form. When you call it, just need to select the input mapping and output mapping.
To ease of understanding I will provide an example. Let’s create a new display-only form called AAA:Service. This form will have three numeric fields: A, B and C. We set public permissions on fields and form.
We add a filter to this form, with the service execution option. This filter will have one SET action: C = $A$+$B$.
Now the service is created. Now we will create another form to call the service. We create a display form AAA:Caller with the same fields, and with a button (btnCallService), all with public permission:
And we add an active link that fires on button pressing that calls the service.
EDIT: As commented, there is a mistake on the previous snapshot. The Form Name field at the service action should be AAA:Service, instead of AAA:Caller. Thanks for the correction.
Now we can check the result. We connect with a user to the AAA:Caller form, set values for fields A and B, and press the button. We will see the result at field C. If we check the log, we can notice that when pressing the button a service call is made. Values for fields A and B are transferred from AAA:Caller to AAA:Service.Then the filters with service execution option at AAA:Service are fired, computing the sum at C. Finally the content of field C is transferred from AAA:Service to AAA:Caller.
When calling a service you can set a request id. The service will retrieve the related request as input parameters. Then it will write the input mapping, execute the filters and export the output.
This can be useful at some situations, but normally I don’t recommend its use, as you will see on my recommendations.
Let’s review some situations where the service action can be of great help.
It’s obvious, if we have a complex part of code, we can create a service and reuse it from several forms. This will not only save us time, but also is a best practice for error reduction, since all error testing for one form is shared between all forms.
Filters are always fired with admin permission. Your user needs access to the form of the service and access to the mapped fields, but from here, the service can access any form with admin privileges. That can be of great advantage. For instance imagine that you want to obtain data from CTM:People for other tenancy that the current user hasn’t access. You don’t want to give him access, but you want that he can be able to retrieve some information from users. Then you can create a service that gathers this information and call it from an active link. Thus you are allowing the user to access this piece of information from the client.
There are some actions that can’t be performed using active links, like some $PROCESS$ actions, or call a web service or log to a server file. Using a service allows you to access those actions from the client.
All service actions are performed immediately. Even the SQL cache is sent to the database before exiting the service. So if you want to retrieve the data after a PUSH, you can put the PUSH action inside a service. Then when the service ends you can check the results.
This is the current behavior of the service action, but it is not as designed. I mean, nobody guarantees you that future versions of ARS will retain this behavior.
Sometimes you have a lot of code that perform a lot of actions. A way to reduce the complexity is to divide the code into isolated pieces, each one with one task. Thus the developing is easier, since the developer only focuses on its part. A way of isolating pieces or code is to use guides. But guides are not completely isolated, since the state of temporary fields are transferred between guides. For instance, a developer can assume that a field is null when starting its guide, because other developers have told him that they didn’t use this temporally field. But at the future one developer uses this field, resulting in a malfunctioning of the next guide. So you can’t look at the guides as completely isolated pieces of code. Services are completely isolated, and unitary testing is valid.
After designing a lot of services I arrived to set some best practices for my team. These best practices made the developers life easier and provides an ordered result.
You can use services on any kind of form. In fact an standard practice of BMC is to create services for main forms like HPD:Help Desk. In My Humble Opinion, this is not a best practice, since you arrive with a lot of code for services messed with other execution options like submits or modifications. The code is not easy to follow, and unitary testing is difficult. So, I don’t recommend it, unless a clear advantage comes from the use of the Request Id.
I recommend to create an exclusive display only form to host a service or a family of services. This form will have all input parameters at one side, all output parameters at the other side and all temporally fields below. Also I recommend to add a button to the form with an active link that calls the service itself with all the input and output mapping. Thus a user can connect to the service a test it’s functionality.
Sometimes is useful to have more than one service on the same form, since a lot of code can be shared between them. For instance you can have two services to retrieve the name of a user, one provides it as “First Last” and the other as “Last, First”. The code of getting the first and last name can be shared between both. In that case you must include an action field, that tells which action do you want to perform.
One thing developers tend to do is to group related services on the same form. Something like “Text processing services”. This is not a best practice if these services do not share code. If you want to group them you can do using some naming convention or a grouping element like packages or applications.
It’s a best practice to create services for complex functions, since you can easily do unitary testing on them. On such cases it’s of great help to create some filters with some mark at the name that only do logging on the server. Then using the developer you can enable or disable them. Thus you are activating or deactivating the debug logging for the service. If something strange starts to happen, activate the log filters and see what’s happening.
I always do it for services related with integrations, where sometimes I want to track all communications.
No comments:
Post a Comment