Kotlin Multiplatform Money Formatter
Most features within Cash App revolve around money. We must display money accurately and understandably so our customers can make informed financial decisions. But what it means to be accurate and understandable varies based on the context! Let’s take 1,000 US Dollars as an example:
- For the payment entry pad, we use
$1,000. It’s a whole dollar amount, so we don’t need to include cents.
- For the account balance, we use
$1,000.00. Precision is vital in this context, so we have cents.
- For the Money tab label, we use
$1K. Space is at a premium, so we abbreviate.
- For investing portfolio performance, we use
+$1,000.00. The directionality is essential, so we include the plus sign.
That’s just a single currency in a single locale! Users can select a preferred denomination for Bitcoin, so one might see 0.0001 BTC while another sees 10,000 sats. A Spanish speaker in Spain might expect to see their balance formatted as 1.000,00 US$.
So we set off to design a solution that would accomplish multiple goals:
- Consolidate the money formatting logic so that new features have to be implemented only once and are guaranteed consistent across the entire product.
- Create clear ownership to reduce the number of money formatting experts required across teams and platforms.
- Define a set of common configurations so that designers and engineers can speak the same language when choosing the appropriate format for a particular feature.
- Support ISO-standard currencies and Bitcoin (which may not be natively supported by the standard formatters available on each platform).
- Make it extensible so that it’s easy to support new locales and new currencies in the future.
That’s a tall order, but Kotlin Multiplatform gave us a viable path forward. With Kotlin Multiplatform, we could choose the best pieces of the ten existing formatters and provide a single, well-documented interface to everyone at Cash App!
Of course, there were some challenges along the way. One such challenge was localization. Our existing money formatters worked in only English, and localized number formatting is a challenging problem. Luckily, the platforms that we target have already solved it! Kotlin Multiplatform allowed us to split our formatting into two phases. First, we call platform-specific code for localized number formatting (e.g.,
NSNumberFormatter on iOS, the ICU library built into Android). Then we apply some Cash App specific adjustments in common Kotlin code. Leaning on native platform logic means we don’t have to become experts in each locale and keep the library lightweight.
Another challenge was handling scale and precision. 32-bit integers might not be large enough to display amounts in some currencies while floating point numbers can introduce subtle rounding errors for fractional amounts. It’s essential to get these things right when customers trust you with their money! We’re cautious about how we represent money across the rest of the Cash App ecosystem, and we needed to ensure we didn’t lose precision in the formatter. Kotlin Multiplatform allowed us to delegate to platform types like
BigDecimal for Java or
We’re currently working with Cash App developers to migrate to the new multiplatform money formatter and deprecate the legacy platform-specific implementations. We’ve been careful to test those migrations thoroughly, asserting that the output from the new library matches the old implementation and gating rollouts with feature flags. If you use Cash App for Android, you’ve already seen it in action!
If we want to add support for new currencies in the future, the process is as easy as adding another entry in the library, and it should work on all platforms.
We’ve thoroughly enjoyed developing with Kotlin Multiplatform and find immense value in its benefits! We highly recommend developers take a look if ensuring consistency across platforms is essential to them.
This post is part of Cash App’s Summer of Kotlin Multiplatform series.