Chippin’ away at the Monolith

An overview of how the iOS team at Chip is moving to a modular codebase!

Jack Tudor
Nov 14, 2019 · 5 min read
Breaking big things into small things, one Chip at a time.

This isn’t a “how-to” guide, but really documenting what challenges we have faced and what solutions we came up with, I hope it sparks some ideas you can use in your own project.

To provide a bit of context, I’ve only been at Chip for around four months, but the codebase is around 18–24 months old. We are using RxSwift with the Model-View-ViewModel (MVVM) design pattern.

When I first joined, the app did have Cocoa Touch Frameworks for common/shared modules but not at all for feature modules, which if introduced would help the codebase scale, make it a lot easier to navigate and ultimately pleasant to work with. This is very similar to what Backend Engineers call Micro-services.

The distinction between them is; feature modules know nothing about each other, so must never import each other. Any code that needs to be shared between feature modules should be moved into a common module.

What we set out to achieve.

Where did we start?

This was the Tab with the smallest amount of logic, so it was fairly easy to decouple and we were able to immediately reap rewards, as we not long after had to build some new features within it.

After getting a taste of modularisation, I tried to move another Tab (Account) into its own module.

This turned into a nightmare as I tried to move one object, it was relied upon by multiple others, so rather than wasting anymore time I stopped. We had to take a bit of a step back to work out what was causing us the biggest pain when trying to move anything, when creating the Accounts module, the biggest issue was anything relating to our models / API resources.

Solving our first problem

This was not ideal but was necessary to achieve what we wanted to do. The reasoning behind this was to allow us to freely move all of our UI code out and into feature modules.

After moving Chip X into its own module.

We agreed that this was temporary solution, and that when a new feature module was created we should move the models and API functions so they aren’t shared with the whole codebase. This allowed us to start moving code into feature modules.

It wasn’t our only problem…

For example, we have a UserService which is responsible for fetching any resources relating to the user and populating model objects. This is used throughout the codebase as we need to know details about the users state across the app.

But we didn’t want to share any of that implementation detail with the “Activity” framework, because it doesn’t need to know about the inner-workings of the class. We created a ActivityAdapter that has our UserService injected and conforms to our ActivityAdapterType which declares what is needed from our UserService:

Our ActivityAdapter which is responsible for transforming our models
ActivityFramework doesn’t need to be exposed to UserService

With an adapter we’re able to pass this into our ActivityCoordinator, to enable it access to these shared models whilst still being able to test the adapters by providing a mock type in our unit tests. Our Coordinator is the entry point into our framework and manages the relationship between the controllers in the framework.

What were the biggest benefits of doing this?

As the team begins to scale, we want to be able to work on features and areas of the codebase in isolation of one another. We don’t want to deal with huge conflicts when there’s many developers committing code.

It allows us to set a solid foundation for which we can build upon over the next few years, whilst the job isn’t complete it’s important to bear in mind that this will really set us up for the future.

Improved build times with a modular approach because we don’t need to rebuild the whole project, but rather that module so it’s much quicker developing features.

We’re able to see tangible evidence of this, we’re releasing at such a frequent rate (around every 1–2 weeks on average). The number of bugs we’re finding in the app is much lower than a few months ago, and our App Store rating has increased by nearly one whole star!

This is how the Chip iOS codebase highlevel structure looks now

What’s next?

We’re constantly looking to make improvements in our ways of working, whether that’s architecture, testing or code styling.

If you’re interested in learning how to create a Cocoa Touch Framework, Sam Dods has an excellent blog series outlining how you can make a start.

Chip

We’re the team behind Chip, the AI savings app.

Chip

We’re the team behind Chip, the AI savings app. We’re automating your money stuff, so you can make the things you want in life happen. getchip.uk

Jack Tudor

Written by

iOS Engineer @Chip, previously @theappbusiness

Chip

We’re the team behind Chip, the AI savings app. We’re automating your money stuff, so you can make the things you want in life happen. getchip.uk

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Start a blog

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store