The challenges of software development at a rapidly growing fintech — Part I of II
I present to you an in-depth description of some of the daily technical challenges faced at Creditas, as well as our application of SOLID from an architectural viewpoint in the context of our Servicing Tribe Calculator.
Here, I wish to share our experiences and illustrate abstract concepts with facts and data.
I’ve divided this series of posts into two parts. You can find part two here.
- Historic context
- Servicing Map context
- Challenges and opportunities of a new context
- The development process
- Other sailors on the horizon
- Integration with the Pricing team
- Extraction strategy (Branch by Abstraction)
- Success factors for extraction
- SOLID applied at the architectural level
Creditas is a Fintech whose purpose is well-defined: to enable what fulfills people by unleashing the potential of their assets. We currently offer loans of the best kind to people — and we’re always looking for ways to provide people with solutions.
Servicing is the area responsible for the client’s life cycle after the origination of a loan. After receiving a loan, a client needs personalized service to pay off their loan, renegotiate contracts, expand their line of credit, and have their evolution assisted.
Our tribe was born as just two developers, a few analysts, and a legacy project module named loan origination core.
Six months after the area’s emergence in March of 2017, we built the first closed beta version of Creditas’ Mobile Application, which only consumed the Core. At this juncture, we extracted our domain to a new Ruby application which was separate from the origination system.
In 2018, we created the Calculator and in 2019, we extracted it to a microservice, passing the baton to another team.
We presently have a Tribe with a technology team of 20 crewmembers (what we call our colleagues) here at Creditas. Among them are Developers, Product Analysts, Leaders, Agilists, Data Analysts, Business Developers, and we’re still growing; after all, we have openings. Just saying :)
Servicing Map Context
At Creditas we apply a range of tactical and strategic DDD (Domain-Driven Design) patterns to handle the modeling of complex domains in an ever-changing business. This approach allows us to sustainably scale the business long-term, with a high level of decoupling and strong ties between the system and the business through a common language between areas (Ubiquitous Language).
Reading materials, such as Implementing Domain-Driven Design by Vaughn Vernon and Domain Driven Design by Eric Evans, detail the concepts cited here. If you’d like an overview of these strategic patterns, I recommend InfoQ’s ebook, Domain Driven Design Quickly. The Design Patterns (tactics) can be found in classic literature, such as those written by GoF.
- Onboarding: Entry of new loans in transit from Origination to Servicing.
- Billing: Rules for billing
Both of these contexts enabled the collection of loans to be managed by Servicing for the first time at the end of 2017.
Our challenge in mid-2018 was to create a Calculator that would ensure data reliability and enable automated bill creation. Additionally, we would need to update the value of delayed installments, insurance, and inflation on a daily basis.
Challenges and opportunities of a new context
This Bounded Context presented a set of unique characteristics compared to its predecessors. We were excited by the idea of creating a detached stateless service, with a functional approach and a new language (Scala or Kotlin).
In addition to this, the whole company was experimenting with and studying various initiatives across the other tribes, rethinking the main stack at the time, Ruby.
But everything’s not as easy as talking. After two proofs of concept and many debates, we decided, as a team, that it wouldn’t be practical to build a new project from the ground up. We considered the pros and cons of maintaining new infrastructure, the learning curve of a new stack, and the paradigm shift. Considering all the cons, and the fact that we would soon need a new post-fixed Servicing operation demanding these scaled calculations on a daily base, we figured this project wouldn’t be ready in time.
We decided to move forward with a new context inside of the existing Ruby application. This pragmatism was greatly rewarded, which I’ll discuss in the second part of this post.
Furthermore, we quickly noticed that this project’s complexity would increase rapidly. As our Rafael Manzoni, our mentor, said “Every hole we dig gets filled with water” — new needs would arise every week.
Specific exemptions would apply to specified dates and funds, the calculation of the grace period would influence the value of all the installments (depending on the product and partner), personalized negotiations would set certain rates, and so on.
In summary, we had less than two months to produce the first version in these circumstances. You can imagine how relaxed we were.
The development process
When the Calculator project was starting up, it relied on a minuscule squad: a senior developer who soon became our Tech Leader I and two back-end developers. Subsequently, a front-end developer, who was just starting to learn about back-end, joined the team (aka me).
We kept on developing, creating each calculating component in an isolated manner, each of which made up an installment. Each node and leaf created were grouped into a tree (data structure) of complex calculations, which could be configured according to specific policies. We used composition concepts, referential transparency, and inversion of control to allow for agility and confidence in the development of the parameterizable calculations.
The calculator’s evolution was discussed on a daily basis, at the cost of many ballpoint pens and white notepads. The synergy and growth mindset generated by the team was essential when we were making difficult decisions in such short periods of time. This way, we were able to quickly disseminate information
The calculator’s evolution was discussed on a daily basis, at the cost of many ballpoint pens and white notepads. The synergy and growth mindset generated by the team was essential when we were making difficult decisions in such short periods of time. This way, we were able to quickly disseminate information between each other, eventually achieving a high level of productivity in (about) three months.
This is the way that our calculator was developed, which presently updates hundreds of thousands of installments on a daily basis, ensuring that the automatic billing flow is reliable.
Everything worked pretty well without any major problems.
Other sailors on the horizon
At the same time as our project, other calculators started popping up at the company, in other tribes. Eventually, each stage in our workflow was performing calculations based on similar rules; from capturing leads, to lead conversion, to formalization, to contract assignments, to billing. It was no longer a simple case of coincidental duplication.
During this time the Pricing Team emerged from Servicing, whose mission was to unify all these calculations into a single place, supporting all the stakeholding areas of the company. However, this team had its own demands that didn’t necessarily meet all of Servicing’s needs within a feasible timeframe. Thus, it was decided that all these projects would coexist for a while, with the objective of being integrated and absorbed into Pricing in the future.
One year after the Calculator’s creation, the time had come!
After plenty of learning about the business and maturation of the teams, it was time to extract.
How was the process of migrating team B into a context A, for the sake of a context C in team D?
Although there appeared to be many risks, given that our operation depended on these calculations, that our teams went through constant change, and that our codebase has multiple contexts; it made sense for the Calculator to be extracted to a Rails API microservice, in an incredible 12 day period which had no adverse effects to the operation. With just two developers!
In the next post, I will discuss the strategies taken in this process and some of the factors we consider to have driven our successful extraction.
At its end, I will also provide some examples regarding how we applied the principles of SOLID at the architectural level.
Share your cases in the comments so we can learn together.
Thanks for your time and until next time!
Want to use technology to bring innovation to the loan market? We’re always looking for people to join our Crew!
Check out our openings here.