Simplicity: working with Clojure at Nubank

A quick view on why we chose this technology and how we use it to fight complexity and empower people

(In collaboration with Wilker Lúcio.)

Nubank has helped change the landscape of financial services in Brazil. In 2014, we launched our first product, a no-fee credit card. Since then, we grew to be the most innovative company in Latin America and the biggest independent digital bank in the world, with more than 22 million customers.

Our product portfolio includes, other than the credit card, Nubank’s account, a digital savings account; Nubank Rewards, a loyalty rewards program; Lending for personal loans; and Conta PJ, a digital account for small and medium-sized business. Both Lending and Conta PJ are the most recent additions to our portfolio, introduced in 2019, the same year we announced the launch of our operations in Mexico and a tech hub in Argentina.

A big part of our success comes from the fact that we are not a financial company per se: we are a technology company focused on developing financial solutions.

In other words: technology is at the heart of everything we do — which is why software engineering is a core competence for Nubank.

We strive for state-of-the-art software development practices; Nubank has enjoyed significant benefits from embracing practical, functional programming concepts to build our business. These concepts play an essential role in the clarity and consistency of our codebase, and we put a lot of effort into making sure engineers understand them when they join the company.

These are a few examples of practices and techniques we adopt:

  • Horizontally scalable microservices written mostly in Clojure, using Finagle and leveraging functional programming techniques and hexagonal architecture (more on that in this video);
  • High throughput jobs and inter-service communication using Kafka;
  • Continuous Integration and Deployment into AWS;
  • Storing data in Datomic and DynamoDB;
  • Monitoring and observability with Prometheus;
  • Running as much as possible in Kubernetes.

It’s interesting to note that most of our engineers had never worked with this particular set of technologies (that are either abstracted in a tool, so you don’t have to know much about it, or easy enough to onboard on). Nor had they been in contact with financial services, which are a little bit harder to onboard. Still, we’d have to do it anyway, no matter what technology we choose.

Why Clojure and Functional Programming?

The world we live in has machines on the cloud, with multiple cores that allow us to run several things in parallel. Besides, Nubank provides services in the finance domain, which is very close to mathematical functions — and functional programming is an excellent fit for both scenarios.

The previous systems we had built before joining Nubank used languages and frameworks that force you to add too much boilerplate to solve a problem, which makes evolving the system harder and harder over time. Clojure, on the other hand, has simple constructs that allow us to focus on the problem we are solving, making evolving the system a small incremental challenge, which doesn’t get that much harder over time.

Most of our codebase can be understood locally, looking at any given pure function, understanding its outputs for any given set of inputs. There’s rarely any need to reason about or recreate the internal state of objects. Data moves through the system in a composable, inspectable, consistent, and immutable way (without hiding it inside of objects).

We’ve built a number of enablers in Clojure over the past six years — useful tools that help us be faster and scale up at an accelerated pace. With Clojure, we can effortlessly create new products. When it comes to infrastructure, for example, we have a continuous delivery pipeline that enables any given change to master on GitHub to be running in production within 30 minutes. That is done with the aid of declarative EDN configuration files that define how the deployment and the pipeline look like. Functional code is much easier to test, and that gives us the confidence to deploy an average of over 50 changes per day in a mission-critical domain.

Speed is crucial at Nubank, as we grow our customer base and expand to new segments and geographies. We are continually evolving our product and structure — which is why we are constantly looking for people to join our team.

Engineering at Nubank

We currently have over 400 engineers working from our HQ in São Paulo, our engineering hub in Berlin, and our offices in Mexico City and Buenos Aires. And we also nurture a global environment regardless of the location, since we host more than 30 nationalities, and English is our first language.

We’re looking for individuals who are passionate about what they do and eager to solve complex problems at scale – all this while working in a safe, welcoming surrounding. We seek people who want their work to have a positive impact on the lives of millions of people who, otherwise, would be stuck in a bureaucratic and inefficient relationship with their money.

Enter your name

Receive the newsletter