schananas/practical-reactor

Your feedback

schananas opened this issue ยท 8 comments

This is the place where you can post your feedback about exercises.

Are exercises too hard?
Are requirements clear enough?
How much time took you to finish all exercises?
Do you feel that your knowledge about Reactor improved after doing this workshop?
Any proposals for improvements or new exercises?

Hey,

Thanks for this course. Prior to this course I already had some experience with reactive programming in JavaScript, I have used Angular with RxJs before. Angular plays well with reactive programming and I have consumed/transformed a lot of streams and also created some custom even emitters. So at first I thought that these exercises might be too easy for me, but actually those were quite challenging and I learned something new in each chapter (not just about Reactor API, but also on conceptual level on how reactive stream work in general.

I think that the level of exercise are just right and instructions are clear enough. I took my time and looked at documentation and help texts, before checking the solutions. Usually I solved the tasks on my own, but then looked at solutions branch just to make sure that I have followed the best practices. Finishing all exercises took me about 1.5 days of effort.

I especially liked the exercises on sinks, as those are vital to know when trying to combine legacy systems and reactive programming.

I noticed that some tests were not strict enough and accepted non-optimal solutions:

  • c9_ExecutionControl#blocking, this test passed without any changes to code. I don't know if Blockhound is not properly working with java17 (added the flag it required -XX:+AllowRedefinitionToAddDeleteMethods) or if default reactor scheduler is already well suited for such task?
  • c11_Batching#command_gateway, this test passed if I used .concatMap(g -> g.concatMap(this::sendCommand)) instead of .flatMap(g -> g.concatMap(this::sendCommand)), although it took more than 25 seconds to finish.
    Maybe there should be an assertion on the duration just to nudge user to select appropriate operator? Something like this:
     //do not change the code below
     Duration duration = StepVerifier.create(processCommands).verifyComplete();
     Assertions.assertTrue(duration.getSeconds() <= 3, "Expected to complete in less than 3 seconds");
  • c13_Context#pagination, template for this task starts pagination with page 1 Flux<Integer> results = getPage(1), but solution requires to start from page 0 and repeat until page is 10 (or actually any number greater than 9, since pages after 9 are all empty). I suggest to either change the template to be Flux<Integer> results = getPage(0) or to change the ContextBase class so that it emits results for first 10 pages and throws IllegalArgumentException also with page 0.

I can make PR for c11 and c13, if you want ๐Ÿ™‚, but I'm not sure what to change in c9.

Thanks again for these exercises, they were really well done and I learned a lot ๐Ÿ™‚

Hi,

I did not have much experience with Reactive Programming. Started learning as this is a requirement for my work right now - think I found Your repo somewhere on WebFlux/Reactor documentation (I can't pinpoint the source).

The exercises are very broad and due to my lack of experience, I had to use the solutions branch to better understand some concepts. Going to again read the whole Reactor reference with some own scribbles to better understand it. I spent 9 days finishing them as I was taking them occasionally (today I speed it up, as there was a risk that I will not be able to finish it at all).

Except for the things found by @Eskumu I can add a few nitpicks:

  • c11_Batching#sum_over_time - sometimes passes, sometimes not, despite that, I used the code from Your solution.
  • c8_Sinks#emit_failure - passed without changes.

I will definitely share your repository with my teammates, as maybe some of them will find it as useful as I.

PS. Sorry for that PR - forgot to change the remote :)

Thanks for the feedback @Eskumu, and @danpeczek! I will definitely revisit the exercises you have pinpointed and probably add a few new ones. @Eskumu feel free to open PRs for c11 & c13 if you have time. Contributions are always welcome, not just the bug fixes but also for suggesting new exercises. ๐Ÿ˜‰

Howdy!

I am a traditional Spring MVC developer and have been working on that model for years now.
Couple days ago I had a job offer for FedEx and they asked me to write up a little sample project for them (more on it later).
Suddenly it struck me, I can do this in reactive programming. What a great opportunity to learn it!

It was quite hard finding good sources to learn it. What I needed is exactly what you provided. A lot of exercises to practice the concepts of Reactive Programming with Reactor. There's really a lot of exercises and they cover a lot of operations. Thank you so much for your effort!

As a suggestion you could do something similar but this time with WebFlux. Basically a repo where the student can practice the concepts of Reactive Programming applied to the Server Side. I am struggling a bit with that now, understanding how to best test the Controller with Flux and Mono. And how the whole thing works in general.

I am not sure what I want to achieve is even possible, but a gut feeling tells me that I can do it. I would really appreciate your opinion if this is possible to build using Reactor + Web Flux.

Basically I need to write a web application that calls three other API's and aggregates the results. But, there's a catch. I need to call those API's once I reach a certain amount of query parameters in a cache and then fire the request to the third party API's. I definitely see Flux.buffer being used to achieve that. But how do I return what is expected by each request? Because if I cache the requests and then fire them all at once each request will return the whole list of the results from other requests.

Anyway, I know this is not the place to discuss that but your opinion would be greatly appreciated.

Once again, big thank you for this content. Just incredible!

Hi @lassounski, thanks for the feedback!

Regarding the interview task requirements that are not clear in this text.
If you need something to act as a barrier when there are 3 Url calls required before calling an external service, you might use .publish().refCount(3) for that.
If this is not what you are asking for you may ask on https://gitter.im/reactor/reactor and Il try to give you an answer there.

Hi schananas,

Thank you so much for the wonderful exercises!

I'm a Java beginner and can't pass the cleanup exercise in c6_CombiningPublishers, even after copying and pasting from the solution branch and adding the -XX:+AllowRedefinitionToAddDeleteMethods flag which was suggested by IDEA.

The cleanup test just hangs with these BlockingOperationErrors:

OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
Streaming started!

Exception: reactor.blockhound.BlockingOperationError thrown from the UncaughtExceptionHandler in thread "parallel-2"
Sending message: Message #1

Exception: reactor.blockhound.BlockingOperationError thrown from the UncaughtExceptionHandler in thread "parallel-3"
Sending message: Message #2

Exception: reactor.blockhound.BlockingOperationError thrown from the UncaughtExceptionHandler in thread "parallel-4"
Sending message: Message #3

Exception: reactor.blockhound.BlockingOperationError thrown from the UncaughtExceptionHandler in thread "parallel-1"
Sending message: Message #4

BTW, I'm using Java 17, if this is useful info.

I have the same issue with cleanup test but on JDK 11.
It works when I run it alone but it fails when I run all tests on c6_CombiningPublishers and almost all tests fail afterwards as BlockHound is installed.

I am new to Reactor. The exercises are good, but I am going to have to study them a lot. I get errors with the BlockHound.install() calls and had to comment that line out to get the test to pass - lots of these lines:

[Byte Buddy] ERROR java.util.IdentityHashMap$KeyIterator [null, module java.base, loaded=false]
java.lang.IllegalArgumentException: Unsupported class file major version 65

However, there is one thing that I still can't figure out.
I need to make a service call and use the results of that to make another service call, use those results to modify the object received from the first call and return a Mono containing the updated object.

Mono monoProperty = myWebClient.getObject(accessToken, propertyResourceId);
Property property = monoProperty.block();
String anotherResourceId = property.getAnotherResourceId()
Mono monoOther = myWebClient.getObject(accessToken, anotherResourceId);
AnotherType anotherType = monoOther.block();
// put stuff from anotherType into property
return Mono.of(property);

I want to do this without the block calls