Storystreaming by Example: Event Storming a Bike Sharing App
Early-morning cold rain darkness misery. Walk to the coffee shop or … look, is that a bike share? SIGN UP, download the app RIGHT HERE RIGHT NOW and GO. Push the UX, indulge that geek, REALLY push it, nothing like cold-fingered drizzle, street lights on puddles, fiddling phone and credit card, User Experience my !@!@$$…
And reverse-engineer the bike sharing app by event storming it with StoryStream at the same time.
StoryStream is our event storming tool, based on something we’ve used in-house for a while. It’s definitely in alpha. Very much in alpha. It’s what I was going to work on when I get to that coffee shop. So why not start now …
Event storming is great for understanding the behaviour of both existing and new systems. It avoids crossed wires and gets everybody on the same page.
So let’s reverse-engineer a bike sharing app.
Shout-out to the folks at uBicycle. It’s great to see more riding happening in the Vancouver area and bike sharing is a big part of that!
Let’s establish the initial version of the “happy path” (= the path usually taken by most types of users in the ordinary run of business) from the bike share company configuring locations and stocking them with bikes, to users registering, riding, eventually un-registering, and full circle to admins removing bike locations.
We find that covering the deletion/removal/unregister workflows early on as part of building a minimum viable product has many benefits because being able to go all the way from an “empty database” to a fully working system and back to an “empty database” uncovers many potentially bug-prone edge cases and encourages better testing.
From beginning to end, our “happy path” for the bike sharing system consists of the following workflows:
- Set up Bike Sharing Locations
- Register User
- User Deletes Account
- Remove Bike Sharing Location
Let’s walk through them one by one:
Set up Bike Sharing Locations
The initial setup to get started in a new city where the bike share service is offered: We need to identify the places where bikes are kept and stock them with bicycles.
/// Locations Set Up Bike Sharing Location-> : locationId, lat, long, name Location Added Locations* locationId, lat, long, name Add Bike To Location-> bikeId, locationId Bike Added : bikeId, locationId // "Bike Added" could happen many times, depending on how many bikes are kept at this location. Location* : list of bikes at location
We are live! Users can register. We take a deposit. They are good to ride!
/// Register User Register-> email Registration Started : userId, email Pending Registrations* Confirm Registration-> confirmationCode Registration Confirmed : userId Confirmed Registrations* Set Password-> userId, password Password Updated : passwordHash Add Payment Method-> Payment Method Added : creditCardToken, last4Digits My Profile* : userId, email, creditCardToken, last4Digits Charge Deposit-> Payment Processed Deposit Received // Deposit received only occurs if payment processing succeeded.The "Charge Deposit" command may be (e.g.) issued by a process controller "microservice" which issues it as a result of having received "Registration Confirmed" and "Payment Method Added" events.
Cyclists can now unlock bikes and ride.
/// Ride Unlock Bike-> locationId, bikeId Bike Unlocked : bikeId Ride Started : rideId, bikeId Rides In Progress* : Bike Removed : locationId, bikeId Lock Bike-> bikeId, bikeLocationLat, bikeLocationLong Bike Locked Bike Returned // Only mark bike as "returned" if it's within 10 meters of a location. Bike Added: bikeId, locationId
User Deletes Account
/// User deletes account Rides in Progress* : userId, bikeId, startLocationId, startTime // Registration cannot be deleted if a user is currently on a ride Delete Registration-> userId Deposit Refunded : userId, amount, date Registration Deleted
Remove Bike Sharing Location
/// Remove bike sharing location Remove Location-> locationId=123423 Bike Removed : locationId=123423, bikeId Bike Added : locationId=123456, bikeId Location Removed : locationId // "Bike Removed" for each bike at the location which is being removed (123423), followed by "Bike Added" for to another location, e.g. 123456. Maybe one location (e.g. 123456) could be the depot or maintenance location?
You have seen an example of the ESL event storming language in action. In reality we’d explore workflows other than the “happy path” to understand edge cases and user experiences better, for example:
- What happens if a rider does not return the bike to one of the designated locations?
- What if payment processing of either deposit or rental time charges fails?
- How about riders deleting their account immediately after unlocking a bike but before they return it?
We have used ESL as a requirements modeling language in a number of different client projects in the last year or so, all of them CQRS/event sourcing based, with good results. It has evolved a bit during that time and will no doubt continue to do so, but the current version was sufficiently expressive for the Real Life systems we have used it for at this point. The advantage over Post-Its is that we get a nice digital, versionable, shareable and editable artifact suitable for use with assorted tooling.