Hybrid Client-Server actions
507
Views
6
Comments
New
Service Studio

I see this feature as a must-have on the concept of Build It Fast, Right, and For the Future!

So I would like to start with an example:

Imagine you need to create an action/function that given certain parameters it will return you a text, this action/function can be done in a client-side action/function (does not require server logic), but you need to use the same action in an asynchronous logic which will require a server-side action/function.

With this, at the moment, you need to decide on two approaches, both with pros and cons:

1 - You go for the code reusability approach, which is you implement a server-side action/function, and on the client-side, when needed you make a request to the server using this server-side action/function. So the benefit of this approach is that you have a centralized place to manage this action/function, however, you will perform server requests when they could be avoided.

2 - You go for the more performant approach, which is, you implement a client-side action/function and you implement the same logic on a server-side action/function. The benefit of this one is that you will spare the requests towards the server when you are using the action/function in the client-side logic, but you will always have to maintain the logic in two places.

The idea would be to create a folder in between Client Actions and Server Actions that could be called Hybrid Actions, and these actions could be used both as Client and Server actions, when it was used on the Client side it would behave as a client-side action and in server-side it would run as a server-action.

I know that the code generated under the hoods is different, but it is there where OutSystems brings its maximum value by abstracting the developers of the high code layer :)

Just borrowing from your idea, I would like to see some user-defined functions being used inside aggregates as well.

For example, to define an SLA rule that says that a task is overdue after 30 days of being created, one could create a function Boolean IsOverdue(DateTime CreateDateTime) that returns True if DiffDays(CreateDateTime, CurrDateTime()) > 30. Then we should be able to use this same function in server actions, client actions, and aggregates, because the function itself relies only on DiffDays() and CurrDateTime(), and both are well-defined in server/client/aggregate contexts.

For example, we could add a filter IsOverdue(Task.CreateDateTime) into an aggregate, and the platform would inline the function definition to achieve the same result as having the filter DiffDays(Task.CreateDateTime, CurrDateTime()) > 30.

Merged this idea with 'Universal Action - Client Server Action' (created on 14 Mar 2022 14:59:48 by Adam Husník)

Sometimes there is a need to create same logic which needs to run both on client and server. Under the hood the logic is fundamentally different (JS vs C#, frontend vs backend) but on a first glance both of those use similar bubbles (assign, if, foreach...)

I would higly appreciate an opportunity to design an universal action, which would be both available on server and on client with only a single source code (at least from OS Service Studio perspective). Under the hood once such univesal action compiles, it would create separate JS and C# code and it would work just as if the action was defined separately as server and client.

The universal action would have an unsignificant amount of limitations, no server nor client specific logic would be available (f.e. popups, SQL queries). Calling client actions would be prohibited, but other universal actions or server actions would be allowed. Many system actions as they exist now would be universal instead of being separate (list operations f.e.). The universal acton would be useful for in place data operations, validations, creations, filtrations...

This would be only a Service Studio UI, usability improvement, as mentioned before, the code would be compiled separately for frontend and backend as it is now

An universal action example:

ConvertSquareToTriangle()
- in: Square(decimal sideLength, enum color)
- out: Triangle(decimal sideA, decimal sideB, decimal sideC, enum color)
- assign: triangle.sideA = sqrt(5)/2 * square.sideLength
- assign: triangle.sideB = sqrt(5)/2 * square.sideLength
- assign: triangle.sideC = square.sideLength
- assign: triangle.color = square.color

Another example:

AddAllPurpleShapesWithOddNumberOfCorners()
- in: list of Shapes - toAdd
- in: list of Shapes - targetList
- out: list of Shapes - resultList

...

Also make these actions publishable in libraries as well.

I couldn't agree more with this idea—it would be a game-changer for developers using OutSystems! I've personally encountered the need for Hybrid Actions multiple times, most recently while building a browser-based application for financial submissions involving complex calculations.

In our case, we needed to calculate values client-side for a better user experience with quick response times. However, for security and validation purposes, we also had to replicate the same calculations server-side during submission. This forced us to maintain duplicate logic, resulting in an inefficient architecture that undermines the core principles of low-code: maintainability, flexibility, and speed of development.

A Hybrid Action feature would allow developers to centralize logic while optimizing for performance where needed. It aligns perfectly with OutSystems' promise to enable us to build applications fast, right, and for the future. This abstraction would also reduce redundancy and eliminate the complexity of deciding between performance and reusability.

By addressing this gap, OutSystems would further solidify its position as a leading low-code platform, streamlining the development process while empowering developers to create scalable and maintainable solutions. I truly hope this idea gets the attention it deserves—it's not just a convenience; it's a necessity for modern application development.

This would be fantastic!

If this won't be implemented for some technical reason, OutSystems should consider adding "clone as server action"/"clone as client action" options in Service Studio.  This would still be a major timesaver.  Those could include a comment "This client action was auto generated by cloning ServerAction1.  Changes to this action should also be implemented on that action".  This gives developers working on similar methods a prompt which will hopefully help avoiding divergence between two methods which are expected to match.