Vaadin 25.1 and the signals journey

It’s very special for me to see Vaadin 25.1 released with signals as a production-ready feature. This has been my main focus for the last 2.5 years. During these past few months of intensive finalization work, I’ve been ever more convinced that Vaadin feels like a new framework now when reactive UI state management is a first-class framework feature.

Building all of this has been a very interesting journey. I might have been the front figure and a driving force, but I couldn’t have done it alone. There’s also product management seeing the potential and prioritizing development, the development teams making sense out of my vision and incoherent prototypes, and last but least you in the community. You believed in the concept, gave encouraging feedback, and also told us when things were amiss. I don’t know if we’ve ever had this much community involvement for a large-scale development project. Thank you for that!

The initial idea: reconnecting websockets

Like so many other features, this one started with a sudden flash of insight when connecting the dots between several recent discussions and problems. The core of the idea was to make it easier to deal with websocket reconnects in Hilla by sharing state instead of passing messages, and to manifest that shared state in the same way as regular UI state in Hilla, i.e. based on React’s useState mechanism.

It didn’t take long to realize that the “signals” concept that we had been looking at for other reasons would be an even better abstraction than the function-based useState mechanism. I quickly put together a design document, titled “Signaling the state of Vaadin”, where I explored the concept. The document also had a “Java-only component” example as an additional idea of how the concept could be expanded in the future.

The document helped me clarify my thoughts and I did actually never ever show it to anyone else…

First appearance in the wild

Based on encouraging feedback when discussing the idea with colleagues, I started building an initial prototype. The actual implementation was really ugly but I could quickly validate that the concept worked end-to-end and also iterate on both the internal architecture and important aspects of the API exposed to application developers.

We were soon introducing “regular” signals as the recommended state management mechanism in Hilla while the Hilla development team started working on a the real implementation for synchronizing signal values through the server. Almost exactly one year after the initial idea, I presented “Using Full-Stack Signals for Real-Time Reactive UIs” at Devoxx Belgium based on the preview feature that the team had built.

The server awakens

The implementation in Hilla had so far been centered around client-side functionality and APIs while the Java part was quite basic. We knew that we would need a more sophisticated architecture on the server in the future for cluster synchronization and a richer API for Flow applications. While the main focus was on finalizing the initial Hilla feature set, I started designing a new Java architecture and API. The intent was mainly to find out any constraints in advance so that we could reduce the risk of breaking changes for Hilla users in future versions.

I built a new prototype from scratch with a pure-Java implementation of all the core signal concepts such as effects and computed signals, along with things like thread safety and cluster synchronization that were never a concern in existing frontend-focused signal libraries. As one test case for the prototype, I built a really crude Flow integration; basically just a few lines of code in the demo application. It hooked up signal effects with UI.access and attach/detach events and included subclasses of a few core components to add shorthand methods for creating effects to bind a signal value to a component setter. No changes to the Flow framework or the actual components but just building on top of what’s already there.

I showed a demo to the team with a simple reactive UI state management example in Flow. And then changing one line of code to share the state between multiple users, and then another small change to share state between two servers in a local Hazelcast cluster. :exploding_head:

The rest is history

This 5-minute demo made us clearly see the potential with signals for reactive UI state management in Flow. Many had looked at the “Improve support for reactive programming” ticket and discarded it as something complicated that would require a massive effort to redesign the entire framework. Maybe later.

But now there was suddenly a working prototype right there in front of us. With just some hundred lines of code that belonged in the framework rather than in the demo application. In the end, we added much more than those hundred lines of code. We also ended up redesigning much of the initial prototype.

But the shift on the conceptual level was even larger. It’s like a new framework, but fully backwards compatible.

We have morphed from fixing websocket reconnect issues in Hilla to re-imagining the structure of typical application code with Flow. Just one small incremental trajectory adjustment after the other. That’s the magic of software engineering!

6 Likes