Every developer has that moment of realization when you look at your code and barely understand what it’s suppose to do or how it got to be so many lines long. This doesn’t mean you have to completely start from scratch, but it’s important to be open to refactoring parts of your code. The point of refactoring is to make your code more understandable, testable and/or modern.
This is the first post of many where I’m going to share the refactoring process for my app, We Read Too, along with the patterns, libraries & tools I learn along the way.
When I first started learning iOS development four years ago, the design pattern I learned was MVC which stands for Model View Controller. The following diagram shows the user interaction in an MVC pattern:
If you’re learning iOS and rely on Apple’s documentation you’ll notice that they follow the MVC pattern. Over time as your app grows it’s easy to write all the logic for your app into the view controller which leads to extremely large classes that are hard to test and hard to understand (commonly known as the Massive View Controller).
A different design pattern that has grown in popularity recently is MVVM which stands for Model-View-ViewModel. The view model allows the business logic to be decoupled from the view controller. That way our view controllers stay small and focused on the UI. The view model usually doesn’t import UIKit and has no knowledge of the view or view controller. This allows the view model to be unit testable. The model is usually a struct or simple class that represents the data.
Following the MVVM pattern doesn’t mean your code will be perfect. Just as you can have massive view controllers, you can also have massive view models. You don’t have to use one design pattern throughout your whole app, it depends on what’s works best for the functionality you’re trying to implement.
In the MVVM diagram above there are terms like “data and user action binding”, “updates”, and “notifies”. How do you actually implement those relationships in MVVM?
Many developers model those relationships through reactive programming. Reactive programming is a paradigm that has existed in software development for decades that allows developers to write declarative code focused on asynchronous data streams. Check out this great documentation written by Andre Staltz that goes into more explanation. Reactive extensions (Rx) are how reactive programming became popularized especially in mobile development.
Why I am learning Rx? Users expect modern apps to be responsive. Thinking of everything as streams with inputs and outputs makes sure there is always a reaction to any change that comes in whether it’s a user action or network request. Reactive programming uses an Observer design pattern where a subscriber “listens” to a stream (the observable). For more on reactive programming and RxSwift specifically, watch this great talk by Shai Mishali or read the documentation.
Red, green, refactor method for testing
I wrote earlier about how testable view models are, but how will we test them?
I’ve decided to use the Red green refactor method created by John Shore. This ensures I’m following a TDD mindset when writing my code. The tests are written before the logic is completed and you write the logic to conform to the tests. Once the tests are passing you find ways to improve your code without breaking the tests. Kickstarter follows this method in their codebase and you can watch this video to see how it works. They use ReactiveSwift and have written their own test helpers. I’m using RxSwift and found a Cocoapods library that has been very useful called RxExpect.
Implementing the refactor
Now that we’ve laid the ground work for understanding the basics of what MVVM and reactive programming are, let’s get into beginning implementation of refactoring my app We Read Too which is written all in Swift.
We Read Too is a book directory app with the following features:
- a collection view that displays the books filtered by age category
- search by author, title or description
- a detail view that shows the specifics of a book with data pulled from Goodreads and allows the user to share the book or view it on Safari/Goodreads
- a suggestion view that allows the user to send a suggestion of a title that should be added to the directory
The database (recently moved to Firebase) contains all the books and can be updated at anytime with new data or changes on existing data.
For the refactor I started with the suggestion view because it is the least complex and will help me build my comfort level with writing code in MVVM reactively. In later posts I’m going to cover how I refactor the other parts of the app and how I improve the code over time.