How we used Event Sourcing to build seven of Creately’s key features.
Picking the right software architecture/design is just like picking the right tool for a job. You use the wrong tool and then everything may seem a little bit more difficult or little bit more messier. When it comes to software architecture/design though, there is no such thing as the “correct” tool for the job. Most solutions would work and the difference would be relative. It really boils down to how optimal a solution is, for the problem(s) at hand.
When we started rebuilding Creately from scratch, we revised a lot of our design and architectural decisions. One of them was to use Event Sourcing as one of the key patterns in the overall solution. Lets jump right into it.
In Creately when a user starts drawing a diagram, each change that a user makes (commits) is a state. The change is stored locally and also sent across to the server where it is stored as well. The change is atomic and immutable. The diagram forms, when all changes are merged together in order. That is pretty much it.
Using this as the fundamental way of managing the diagram state/data we were able to build powerful features effortlessly. Here are some of the large features that were just possible due to this pattern.
1. Always Saved Diagrams
There was no more a need to “save” the diagram when changes are done. In its original form of the feature, the diagram is always stored either locally and/or on the cloud.
2. Offline and Cloud Syncing
When the client is not connected, the changes are stored the same way locally. This enables us to send across the changes to the server as soon as the client is online. A syncing process ensures to merge changes from the local and the changes on the server into a single list of changes. Then sends it back to the client to ensure all are in sync.
3. Realtime Collaboration
Collaboration is an important part of Creately’s experience. When two or more users edit the same diagram, making sure that changes made by each user is visible to the other in real-time, was easily possible with this pattern in place. Changes a user makes are already sent to the server. The server makes sure to broadcast those changes to whoever is listening on a subscription system. The client that receives the change stores it the same way it stores the local changes. This way all clients manage to be in sync, in real-time.
4. Reactive UI
There are plenty of frontend frameworks out there that make it possible to reactively update the UI based on state. With the implementation I’ve outlined so far, a diagram’s state is always up-to-date on the client as changes happen. The Angular/RxJX based client app simply listens to the locally stored changes to update the UI as they happen. With this we have a UI/Diagram that is reactive to changes that happen anywhere within the Creately ecosystem.
Each change contains within its data a “reverse state” which can revert the original change in place. When a user does a Undo action, the system creates a new change using the “reverse state”. When the new change is applied the original change gets cancelled out. Similarly a change can be replayed when a Redo action is performed. Each change created by and Undo or Redo are treated by the system same as any other change.
6. Granular History
A diagram in its original form is a list of changes. By simply reversing the changes a user will be able to go back in time to any point of a diagram’s history. This will be a lot more granular than browsing different versions of a document. As granular as every change :)
7. Previewing Features
One of the coolest things a user can do on Creately is to look at every feature in preview without actually applying it. For example, try out a style on a selected set of shapes before choosing the final one. With the outlined implementation we were able to add this capability to all features. During a user interaction we simply simulate a change into the change list which get’s picked up by the Reactive UI to show the feature at play. The simulated change is cleared as the interaction completes.
There is lot more to it.
I’ve barely scratched the surface of the nuances of using the Event Sourcing pattern to achieve these features. While Event Sourcing has played a key role in making these features come to life, it just is part of a complex system of multiple powerful patterns working together. Hopefully we will try to cover more technical details of these patterns in future posts.
We are excited!
All of what we have been talking on this blog is about a brand new version of Creately thats been in stealth for the past months. We are ecstatic about the Public Beta that will be coming out very soon. Stay tuned on Creately.com.