In the past few episodes, you learned how the Model-View-ViewModel pattern can transform a project and its architecture. In the remainder of this series, we build an application from scratch. Through that process, you deepen your understanding of the MVVM pattern and how it affects a project's architecture, testability, and structure.
Before I show you the application we build in this series, I want to set expectations. It is important to ask yourself why you think the MVVM pattern is a good fit for you, your team, or the project you're working on. I want to avoid that you choose for MVVM because you read or heard it was a solid architecture, only to find yourself frustrated by the pattern and the limitations it imposes on your code. I cannot stress enough how important this step is. If you choose for MVVM for the wrong reasons, then you are in for a rocky, frustrating ride.
One of the key concepts of the MVVM pattern is a clear separation of concerns. A view should be dumb. It should only be concerned with the user interface and user interaction. It shouldn't know what it is presenting to the user.
As the name implies, the view model bridges the gap between the view layer and the model layer. It is the view model that ensures the view can be dumb. The view model itself isn't aware of the view layer and that makes the view model easy to unit test. That brings us to another key concept of the MVVM pattern, unit testing or testability in general.
If you skip unit testing, then the MVVM pattern isn't for you. You are free to choose whatever pattern you feel is right for your project, but if you ignore unit testing, then I don't recommend investing the time and effort in the MVVM pattern.
SwiftUI has a number of convenient constructs that we won't be taking advantage of when using MVVM in a project. For example, it is trivial to access a value from the user defaults database using the
AppStorage property wrapper, but remember that a view shouldn't be aware of the model layer. It may be fine to use the
AppStorage property wrapper for trivial settings as long as you are aware of the consequences. It reduces the testability of your project. A SwiftUI view wasn't designed to be testable and the more a view is aware of the model layer, no matter how subtle, the more challenging it is to unit test your application.
We focus heavily on testing in this series, but we won't cover user interface testing. Even though the Model-View-ViewModel pattern facilitates unit testing, it has no direct impact on user interface testing. You can still write user interface tests in addition to unit tests, but the process isn't any different than that for a SwiftUI project that doesn't adopt MVVM.
Before we start building the application for this series, I want to show you what it is that we are building. The application is named Thunderstorm because every project needs a catchy name. As the name suggests, Thunderstorm is a weather application that fetches and displays weather data from a remote API, Clear Sky.
The user can add and remove locations. The application displays the current weather conditions for each location. Tapping a location takes the user to the location view, displaying the current weather conditions at the top and a forecast at the bottom. The user can remove a location by tapping the delete button in the top right.
The user can add a location by tapping the Add a Location button at the top and entering the name of a city. The application uses Core Location's geocoding APIs for linking the city name to a set of coordinates. Tapping a result adds the location to the list of locations and fetches weather data for the newly added location.
The Clear Sky API is straightforward to use. The application performs a
GET request, passing in an API key and a set for coordinates. The Clear Sky API responds by returning the current weather conditions, a summary for the next hours, and a summary for the next days.
We build an API client that performs the request and extracts the current weather conditions and the summary for the next days. The application uses the response to populate the locations view and the location view.
What Is MVVM?
There is no strict definition of what the MVVM pattern should look like in a SwiftUI project. This is confusing, but it also makes that you can choose what MVVM looks like in your SwiftUI project. In this series, we apply MVVM as strictly as possible because it makes it easier to understand what MVVM is about and how it is applied. It is fine to apply MVVM more leniently and that really is up to you to decide. It is important that you end up with a solution, an architecture that you enjoy using. It may even evolve over time and it probably will, especially as SwiftUI continues to evolve itself.
In the next episode, we create the project for Thunderstorm and update the structure of the project to make sure it is easy to extend and maintain.