Why I told Archax to drop its desktop trading app

When I joined Archax in April 2022, the exchange’s trading app was an Electron desktop app built on Finsemble. Finsemble sits on top of Electron and manages the windows and the messages between them, much like OpenFin does. The idea was to give institutional traders something that felt like a Bloomberg terminal, with the app spread across several windows that all talk to each other.
I knew that kind of software well. Before Archax I spent three years at J.P. Morgan on the core team of a desktop trading platform that other teams built React widgets on, and by the time I left it had around a hundred of them. So I knew how much time and money a platform like that takes to keep going, even for a bank with a whole team behind it.
Around the same time, Archax was turning towards retail crypto traders. Someone buying a bit of bitcoin wants to open a website and get on with it. A multi-window terminal built for institutional desks was more than they needed, and it was a lot for a small team to keep releasing. There was a second front end as well, because sign-up and profile management lived in a separate portal that an outside team built and ran for us.
From my first months there I’d been saying we should drop the desktop app and build one web app that did both. It was about fourteen months before the company went that way, and I can’t say how much my arguing had to do with it. The harder argument was about what the product should look like. On institutional desks a Bloomberg terminal is still the standard, so a desktop app built in its image looked like the modern choice, and it took time for the company to let go of that picture.
There was talk of a mobile app too. I argued against that as well, since without a feature that needed one it would be the same screens again for a small team to keep up to date, and a web app that worked on phones would reach the same people. It’s becoming more important all the time for a business to build exactly what its users need. Putting out the same thing again, or something novel that isn’t useful to them yet, only hurts you.
Seven months, two front-end developers
Once the decision was made, the rebuild took about seven months. I was team lead by then, and the front end was me and one other developer, so I was writing a good share of it as well as leading it. We had a product manager and two QA engineers, and two or so backend engineers from other teams made the database migrations and API changes we needed alongside looking after their own services. Along with trading, the new app brought the AML/KYC checks and the financial promotions checks, which UK rules require before someone can buy crypto, into our own app.
We also got rid of a CMS. It was there so that people outside engineering could change the app’s text at a moment’s notice, and it had its own development, QA and production environments, with a sync script that ran on every deploy to copy content between them. Small text changes kept ending up different from one environment to the next. Once releases were quick, I argued we should delete the whole thing.
I’d rather nobody could change the app’s text on the fly.
With the text in the codebase, a change went through review and a deploy like any other, and the sync problems went with it. It also left a clean slate for the real need that came later, which was supporting more than one language.
Onboarding worked on phones from the day we launched. Trading came in a second phase, and until then opening it on a phone showed a message asking you to use a desktop. Fitting the trading screens onto a phone took longer, because they had to keep most of what the company’s leadership was used to seeing in the desktop app.
A weekly email to the people deciding
During the rebuild I sent a weekly email to the CEO, the CTO, the key product people and the tech team. Each one covered roughly the same ground:
- what we’d done that week, with screenshots, and what was left
- scope we’d cut or added, and the trade-offs behind it
- open questions for everyone
- my own thoughts on where things were heading, marked clearly so people could skip them
Nobody replied to it except the CEO. Anyone else could bring it to a meeting or come and talk to me, which kept the thread short.
I tried to be open in them about my guesses, including the ones that might be wrong. I’d show screenshots of ideas for upcoming features, and the CEO or CTO would say what they liked, what they didn’t and what I’d misunderstood. Sometimes the misunderstanding was mine. Sometimes the whole tech team or the product people had a different picture from the leadership, and the email was where that came out, so we could correct course that week. It also helped us agree how far to go on regulation compared with our competitors, which mattered because UK crypto rules were still new.
The CEO and CTO were driving the product and they read their email, so that’s where it went. I also pushed developers, the quieter ones especially, to write their ideas up in their own space in Jira or Notion, as practice at putting a view forward.
Why there’s no Redux in it
Trading front ends often reach for Redux and sagas, or RxJS. At J.P. Morgan and again at Archax I’d seen teams put sub-second market data into Redux, along with state that only one component ever used, and then spend their time fixing the problems that caused. I thought a good grasp of async JavaScript and React’s own hooks and context would cover what we needed, and it did.
When I arrived, the socket sent updates as fast as they came. Profiling showed that was the real cost, so we throttled both ends to two or three updates a second. At that rate, passing one plain object down through context was cheap.
The socket lived in one class, and a context created it and kept a plain JavaScript object up to date from it. Components got live data through one hook:
const book = useData({ topics: ["orderbook/3"] });
That sent a subscribe message for the buy and sell books of instrument 3, unless another component had already subscribed to it. On unmount it unsubscribed from that topic without dropping the socket, and when no topics were left the socket closed. The topics were the ones the API already understood, so the other developer on the team could build screens without ever touching the socket.
Account management and AML/KYC had a separate context of their own. If you were on the account side, the trading WebSocket wasn’t connected at all, so no market data piled up in state that nobody was looking at. On the trading side, we polled the account management API so the screens picked up any change to the customer’s AML/KYC status.
Switching over, and what it changed
We ran the old and new apps side by side for a few months, kept an eye on how much the old one was still used, and emailed customers to warn them it was going away. The numbers were small enough that nothing cleverer was needed. Onboarding was the tricky part. For a while there were two AML/KYC flows that stored their data in different shapes, so the API and the tables behind them had to be versioned and migrated, with both versions kept working until a clean-up many months after launch.
Releases used to go through several systems. Afterwards a release was an ordinary web deploy, with no desktop installers or code-signing certificates to look after.
Testing got much easier too. End-to-end tests on the old app had to drive several windows at once, which tools built for a single browser don’t do. Chrome can expose each window’s process for debugging through a launch flag, so I wrote a script that found them and attached Selenium through the Chrome DevTools Protocol, and from there the tests were ordinary Selenium. It got the QA engineers writing tests again and made their stability reports easier to produce, but it never made end-to-end tests in CI easy, and keeping it working was a time sink. With one web app we could write them in Cypress instead, which was much nicer to build on.
With onboarding in our own code, we could put PostHog on it, and for the first time we saw where people were giving up during sign-up. It was mostly the appropriateness test and proof of address. Later we replaced a lot of that onboarding code with an external AML/KYC platform, which was one more piece we no longer had to maintain ourselves.
Everything ended up in one monorepo, with roughly half the front-end code we had before, and it took less developer time to keep extending.
The retail app no longer takes new accounts. The rewrite left the company with an app that was much cheaper to change and a clear view of where sign-ups were failing. What I’d push on harder next time is the question underneath it. Against Kraken, Coinbase and Revolut, what would make someone sign up with us instead?
A rewrite can’t answer that, and it’s worth asking before you start one.
The picture is from Archax’s own website.