Our technology stack, and how we got here

Mike Webb profile image Mike Webb 2023-03-01

We’ve come a long way in terms of our technology stack since launching the first version of bellroy.com on Shopify, way back in 2010. In this blog post, we delve into Bellroy’s technical history, and the company’s journey through various platforms and languages. We also reveal some of the challenges we faced, and innovative solutions we employed to overcome them.

Bellroy’s initial foray into e-commerce was through the popular Shopify platform. Although the platform was easy to set up and use, we soon ran into limitations customising it to meet Bellroy’s unique needs. As our reputation grew internationally, we needed a solution with multi-currency and multi-language support without having to maintain separate configurations for each combination. Thus, the company decided to migrate to Magento, a platform that - at the time - seemed a better fit for our needs.

We soon discovered that Magento presented its own set of challenges. Particularly: finding skilled developers who could work with the platform, and smoothly migrating product configurations between staging and production environments once we’d tweaked them. These challenges led the company to explore other options, ultimately resulting in a full website build using Ruby on Rails and React in 2014. This decision happened to have a positive effect on hiring; because those were niche technologies at the time, they attracted a certain type of developer - the type who naturally fitted well with Bellroy’s culture and values. These were passionate hobbyists who loved to get better at their craft.

The new website initially served Bellroy well, but as the company continued to grow, the codebase became increasingly difficult to maintain, and - despite having a more capable team - prone to costly mistakes. It became clear that we needed an even more robust and reliable technology stack.

Bellroy’s first experience with functional programming came in 2018 through the development of a new version of our checkout using Elm, a statically typed functional programming language for front-end web development. Errors all but evaporated, and we could refactor and add new features with confidence. The positive experience with Elm inspired us to explore other statically typed functional programming languages. We began to experiment with the Sorbet type-system and dry-monads library for Ruby. We eventually committed to migrating significant parts of our codebase to Haskell in 2019. With Elm and Haskell we found again - as we had with Ruby and React - that the majority of developers who gravitated towards those languages were focused on continuous improvement and the craft of programming, which proved to be a good fit for Bellroy.

Haskell and Elm are not without their challenges. Haskell has a steep learning curve and - compared to Ruby - low penetration. A few of our Ruby developers decided to move elsewhere rather than learn it, and it took months for those who stayed to get to grips with it. Elm is a solid language but suffers from being perceived as abandoned by its creator, despite having an active community. However, these languages have positive characteristics that are unignorable. We regularly have the experience of releasing new tools and services that just work - first time - and we don’t have to touch for months or years at a time beyond package updates. The very first service we deployed is responsible for all of the product images on bellroy.com, and has remained functionally unchanged since 2019.

In Ruby, we would write and test code defensively, trying to cater for every likely possibility. In Haskell and Elm, we rely on type design, the compiler and property tests to give us rock-solid guarantees that the code does only what we want it to do. As we’ve deprecated parts of our Ruby codebase, the Haskell equivalent is a fraction of the size.

A graph of Haskell vs Ruby lines of code since January 2022

We decided to explore statically typed functional programming languages - like Elm and Haskell - for their reliability, scalability, and maintainability. By reducing the complexity of code and the potential for human error, programming languages like these can save companies time and resources, allowing them to focus on the growth and development of their business rather than fighting fires. This has certainly been our experience, and we hope that this post will encourage others to consider these languages for their next projects.