Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Opinion solicitation] How should the api converting from third part object to Promise look like? #2

Closed
vipcxj opened this issue Sep 15, 2021 · 3 comments
Labels
help wanted Extra attention is needed

Comments

@vipcxj
Copy link
Owner

vipcxj commented Sep 15, 2021

The implementation module which wrap the third part library such as Reactor or JxJava should be completely isolated from the core module. In other words, the implementation module should depend on core module, but the core module should not depend on the implementation module. This cause a problem, I don't know how should the api converting from third part object to Promise look like.

  • a: Use static method <T> Promise<T> JAsync.from(Object) in the core module. Obviously this is ugly and error-prone. But the fact that apis are aggregated together is an advantage.
  • b: Use static method <T> Promise<T> Promises.from(XXX<T> from) in the implementation module, where XXX may be Mono or Single or Future. This API makes perfect use of generics and looks more reliable but it doesn't make for a unified API.
@vipcxj vipcxj added the help wanted Extra attention is needed label Sep 17, 2021
@vipcxj vipcxj pinned this issue Sep 17, 2021
@mojo2012
Copy link

mojo2012 commented Sep 17, 2021

Every implementation module could expose "java service loader" services (https://docs.oracle.com/javase/9/docs/api/java/util/ServiceLoader.html). In the JAsync.from method you fetch all implementations of the converter interface and check if any of them supports the type of the passed object.
This allows you to have a generic JAsync class in the core and n implementations in the modules. The core does not need to know about them.
The incoming object's type is not that important here anyway. If someone passes anything unsupported, you just throw an exception.

@vipcxj
Copy link
Owner Author

vipcxj commented Sep 18, 2021

@mojo2012 But an object argument is ugly and error-prone. And the error will be found until runtime.

@DidierLoiseau
Copy link

I’m just coming across this project out of curiosity, as I’m discovering WebFlux and I saw your comment on electronicarts/ea-async#54.

Just to add my 2 cents:

  1. Since this is a Maven project, you could have an actual dependency on those APIs but mark them as optional. This will allow you to declare type-safe methods in the core and properly compile it without forcing them on your users.
  2. I’d also suggest providing just a static <T> T await(Mono<T>) method like EA Async does, without the need for any annotations in the code.

This would considerably reduce the impact on the code, only needing to import that static method. Consider the first EA Async example from their homepage:

    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        if(!await(bank.decrement(cost))) {
            return completedFuture(false);
        }
        await(inventory.giveItem(itemTypeId));
        return completedFuture(true);
    }

vs your example:

    @Async()
    private JPromise<Double> _getEmployeeTotalSalaryByDepartment(String department) {
        double money = 0.0;
        Mono<List<Employee>> empsMono = employeeRepository.findEmployeeByDepartment(department);
        JPromise<List<Employee>> empsPromise = Promises.from(empsMono);
        for (Employee employee : empsPromise.await()) {
            Salary salary = Promises.from(salaryRepository.findSalaryByEmployee(employee.id)).await();
            money += salary.total;
        }
        return JAsync.just(money);
    }

with a static await() like EA Async, it could be rewritten simply as:

    private Mono<Double> _getEmployeeTotalSalaryByDepartment(String department) {
        double money = 0.0;
        List<Employee> emps = await(employeeRepository.findEmployeeByDepartment(department));
        for (Employee employee : emps ) {
            Salary salary = await(salaryRepository.findSalaryByEmployee(employee.id)));
            money += salary.total;
        }
        return Mono.just(money);
    }

which is much more readable and does not clutter the code with foreign types.

@vipcxj vipcxj closed this as completed Sep 23, 2023
@vipcxj vipcxj unpinned this issue Sep 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants