reactive programming for java developers – rossen stoyanchev – qcon

For more QCon posts, see my live blog table of contents.

General notes

  • Spring 5 has reactive features.
  • Maybe a third of the audience is doing something with reactive, a little more have read about it (that’s me) and a lot haven’t heard of it. Which is good given the title of this talk!
  • Moore’s law slowing down. No more free lunch from the hardware
  • Now apps more distributed/independent/cloudbased compared to 10 years ago
  • Now we expect latency
  • Thread now has to do more async things. Hit limits of scale. imperative logic more complicated.

Other approach

  • Async/non-blocking
  • Use very few threads. node.js has a single thread. Must be careful because blocking those few threads blocks the whole app
  • Reactive programming – think async. Not everything is a callback

Comparing styles

  • Imperative
    • call a method, get a result, do something with that result
  • Async
    • return a Future instead of a value. Don’t throw a checked exception because my happen in a different thread. They are asynchronous in that you can get a result later. But when you eventually call feature.get(), it throws different checked exceptions.
    • In Java 8, can return a CompletableFuture and call future.whenComplete((user, throwable) -> {})
    • If doing a findAll(), the future/completable future approach doesn’t give you a callback/return anything until all of them are ready. You can’t stream or could run out of memory.
    • Async results as stream – get one notification per data item and another for completion or error
  • Declarative
    • Focus on what, not how
    • Declare what should happen rather than focusing on callbacks
    • Java 8 stream API uses this style. It is meant for collections and pull based/usable once
    • Hot streams – latency sensitive streams, data need to be pushed for you
    • Cold streams – pull based

Reactive libraries

  • Stream like API
  • Can be used for hot/cold streams
  • Project Reactor – Similar to ReactiveX, easy to bridge to Java 8 streams. (ReactiveX is like XUnit – commonality for different languages)

Abstractions

  • Flux – sequence of 0 to n – equivalent of Java 8 stream – can convert to/from Java 8
  • Mono – sequence of 0 or 1 – can convert to/from CompletableFuture

Reactive streams spec

  • Back pressure – producers must not overwhelm consumers. Communicates if downstream isn’t ready for more items. Ex: a slow client like a mobile device isnt able to handle more data and server isn’t blocking
  • Small API – only 4 interfaces
  • Rules
  • Interoperability across reactive components so can compose chain

Java 9

  • Reactive streams included (the four interfaces)
    • Publisher
    • Subscriber
    • Subscription
    • Processor
  • Use a reactive library. Don’t implement the four interfaces yourself
  • subscribe() triggers the flow of data
  • “push” was missing until now. Want in JDK to have foundation
  • Classes
    • java.util.concurrent.Flow – the four interfaces
    • SubmissionPublisher – bridge to reactie streams
    • Tie-ins to CompletableFuture and Stream

Reactor

  • GA release scheduled for July
  • Currently called 2.5. Might changed to 3.0

Reactive Spring MVC

  • Apps annotate controllers even now.
  • Return a Flux type.
  • Spring MVC itself needs to change a lot – called Spring Web Reactive
  • The servlet API assumes blocking. There are async workarounds. Servlet 4.0 might support reactive spring integration, but probably just the basics. Using own bridge to Servlet 3.1 in meantime.
  • Can still use Jetty/Tomcat. They are non-blocking behind the scenes.
  • Don’t need servlet container. Can use Netty.
  • HandlerMapping – change to return a Mono so can be non-blocking
  • Focusing on REST/microservices scenarios

Other reactive efforts

  • MongoDB – reactive driver
  • Couchbase – reactive driver
  • Thymeleaf – split templates into chunks and throttle to respect backpressure

unprivileged containers – jessie frazelle – qcon

For more QCon posts, see my live blog table of contents.

Today

  • Docker typically runs as a privileged user.
  • Containers are meant to limit the damage from a compromise. The world an attacker can see inside the container is a limited one)
  • Want unprivileged containers so don’t need sudo/privileged access to launch container in the first place.

Chrome sandbox on Linux

  • uses Seccomp, Namspaces, Apparmor.
  • doesn’t need to be run as root.
  • each tab is in its own namespace – process only knows about itself
  • if Chrome can do this, why not Docker

General notes

  • cgroups (Controlgroups) limit what resources a process can use and how much.
  • Each time you docker build something it spawns a new container. Just blocking things wholesale would cause issues here.
  • I had trouble following what was current/future in the examples.

Future

  • Won’t need to run as root
  • Can customize sandboxes from defaults, better UX for dealing with security policies.
  • “postgres should maintain a postgres profile”

Impression: A lot of this was recorded demos (show typing commands as graphic/video that plays out.) For the namespaces, it was helpful seeing the examples. For the Docker part, some of it went over my head. I only know a little Docker. And my system admin Linux isn’t strong enough to understand the implications of everything she brought up either. I still go something out of it though. And learned things that would be interesting to read more about.

applying java 8 idioms to existing code – trisha gee – qcon

For more QCon posts, see my live blog table of contents. Last year, she talked about creating new apps in Java 8. This year is about migrating to Java 8 for “legacy” code. She showed specific JetBrains IDEA features. I just took notes on the concepts that are IDE agnostic. Presentation will be at bit.ly/refJ8

Usage from audience poll

  • About half compile with Java 7
  • About half compile with Java 8
  • About a quarter (half of Java 8 people)  compile with Java 8, but apps still looks like Java 7

Why use Java 8

  • Performance improvements in common data structure
  • Fork/Join speed improvements
  • Changes to support concurrency
  • Fewer lines of code – less boilerplate
  • New solutions to problems – more elegant/easier to write code
  • Minimize errors – ex: Optional avoids NullPointerException

Before refactoring

  • Make sure have high test coverage
  • Focus on method level changes – tests should still work
  • Have performance tests too to ensure not negatively impacting system
  • Decide on goals – performance? clearer code? easier to write new code? easier to read new code? use lambdas because team used to it? developer morale?
  • Limit the scope – small incremental commits. Don’t make change that will affect whole code base.

Straightforward refactoring of lambda expressions

  • Predicate, Comparator and Runnable are common places where might have used anonymous inner classes and can switch to lambdas
  • IDEs suggest where can replace code with lambdas (SonarLint does as well)
  • Quick win – reduce old boilerplate
  • [She didn’t talk about this, but it will make your code coverage go down. Make sure your management doesn’t worry about that!]
  • Lose explicit type information when use lambda. Might want to extra to method to make it clearer and call the method from the lambda.

Abstract classes – candidates for lambdas

  • See if can use an interface (if single abstract method) so can start using lambdas
  • Tag with @FunctionalInterface to make clearer
  • Then look at implementers (especially anonymous inner classes) and see if can convert to lambda expressions

Conditional logging

  • if (debug) { log.debug() } pattern is a good candidate for logging
  • Often people forget to add that conditional so opportunity to defer evaluation for those too via search/replace. Also, protects against conditional not matching log level. if (debug)  { log.severe() }. Uh oh!
  • Use a default method on the existing logging interface that takes a supplier instead of a String and has the if check

Collections and Streams API

  • Turn for loops into collect() or forEach()
  • Remember you can call list.forEach() directly without going through a stream
  • If do something like get rid of initial list size, test performance before and after to make sure not a needed optimization
  • The automatic streams refactoring might not result in shorter code. Think about whether the surrounding code wants to be refactored as well. A more dramatic refactoring. Go back to later. Also, avoid refactoring if and else code since not  a simple filter.
  • Remember to include method references when converting code too
  • Watch for surrounding code. For example, if sorting a list, move into the the stream. Or if iterating over new list, add as a forEach instead of turning into a list.

Optional

  • Be careful. Refactor locally.
  • Easy to accidentally change something that requires changing a ton of code.

Performance

  • Lambdas expressions don’t necessarily perform better than anonymous inner classes. Similarly for streams.
  • Using lambdas to add conditional logging is a big quick win performance improvement.
  • Streams didn’t need the “initial size of list” optimization
  • Adding parallel() to stream operations sometimes performs better and sometimes worse. Simple operation often performs worse in parallel because of overhead of parallelizing.
  • Introducing Optionals increases cost.

Java 7 refactorings

  • Use static imports
  • Reudndant type in diamond operator for generics