Consolidating Experiences & Complexity
We just deleted around 75% of the project’s code.
Before we jump in, here’s a bit of a PSA to other engineers looking to take on a new project: do less.
Alright, with that out of the way, let’s chat.
Tower makes heavy use of web socket patterns and when you’re building features in isolation it can sometimes feel like each feature should maintain its own socket. Between alerts, conversations, conversation statuses, presence, message updates, etc., it got to a point where we had created systems who’s whole purpose was to create and vend other systems that only one thing would ever need.
At the same time we had also been working with a design that included a “Home” tab as well as a “Conversations” tab, and the Home tab often just felt empty and sterile. Work was done to make it look pretty, and it did look good, but the content was entirely redundant. The focus then shifted to making a way to surface content that wasn’t redundant instead of just asking ourselves if we really needed a Home tab at this point. Two other features were built that really had no business being built without having user data to support those decisions.
So last week the decision was made: simplify.
Web sockets
The web socket issue was arguably the harder one to solve because it meant introducing even more “client”s to handle the payloads. We migrated everything to use one single web socket per user that is connected immediately at login, rather than maintain 5+ at random times. This also simplifies issues like authentication token expiration when the app has been backgrounded since reconnecting many sockets that are all fighting to refresh tokens is problematic.
The general pattern we’ve gone with is to have the one web socket wrapped in a SocketClient
type. This socket lives in our dependency container and can be resolved by anything that needs it. Then we have concepts like ConversationClient
, UserClient
, and PresenceClient
that all take the SocketClient
as a dependency. Our business logic layers (in our case we have Reducer
s since we use the “Composable Architecture” from the folks at PointFree) then depend on the various clients.
Nothing ground breaking, but it’s a bit shift from where we were with narrow-scoped sockets.
Home tab & other features
Gone. Deleted. Removed. 404.
When we really peeled back what the app does and what our primary screen should surface to users, it was clear that screen that handles our Conversations was already doing the job, just not as effectively as it could have. We went back to the drawing board to try and figure out what changes were needed to make it work better.
A day later (yes, literally the next day) we had a design that brought together all of the information that we needed. No more tab bar. No more Home Screen. No more unneeded features.
So yeah…
The key take away here for anyone building things: do less. As much as possible, work with your team(s) to really nail down what it is exactly that you’re trying to do, and never be afraid to iterate. What you ship today does not have to be the end of the road. Ship early. Get feedback. Iterate.
Happy coding!