Leave a rating/review
We’ve made some great progress with Bull’s Eye - we’ve created the basic user interface, and we’ve added some code to print out the value of the slider when the user taps the button.
At this point, we have all of the pieces in place in order to write the core gameplay logic.
But the question is, where should that code go?
Our first thought might be, “well, let’s just stick it in ContentView. After all, that’s where all the rest of the code has gone so far.”
And for a small, simple app like Bullseye, that might actually work out just fine. But what if your app grows, and you start adding tons of more features, like you do for most apps you work on?
You’ll find that in practice, if you put all your code inside a single View, soon your View will become a massive mess of what we programmers like to call ‘sphagetti code’.
It becomes a massive file, and it’s hard to find what you’re looking for or to fully understand what it’s doing. This makes it hard to make changes or to fix things without introducing bugs. It also becomes hard or impossible to test.
This leads me to a concept called App Architecture, which is a fancy way of saying the strategy you use for how to organize your code. Putting all of your code into one file is one strategy; it’s just not a very good one!
One of the best practices of App Architecture is called the “single responsibility principle”. That means that you should think about how to organize your app into multiple classes and structs, where each class or struct has one, and only one job.
For example, you might have an struct whose job is to parse a file, another whose job is to authenticate the user, and a final one whose job is to perform a difficult calculation.
Each class or struct takes care of a specific part of the program. In a full-blown app you will have many different classes or structs (tens or even hundreds).
We already have one struct in our app: ContentView. Its job is to display the user interface for the app. Asking it to worry about the gameplay logic in addition to that would be violating the single responsibility principle, because now ContentView would have more than one job. We want our classes and structs to be lazy!
So instead, it would be better to create a new struct that handles all of the Gameplay - we could call it Game for example.
The Game struct could have data, like the current random target the user is aiming for, the current round and the total score.
The Game struct could also have methods, like one to calculate the points based on the user’s guess, or a method to start a new round.
As you’ve learned earlier in this course, ContentView is an example of a “View” class. On the other hand, objects like Game that are responsible for your app’s data are commonly called “Model” classes.
When you’re thinking about app architecture, you also need to think about how these objects are connected, and how they communicate.
In this case, we want our view classes to have an instance of the game model - as a property. The “View” classes can then interact with their “Model” classes whenever they need to interact with the app’s data. For example, the View could ask the Model for the current random target, or to calculate the points for the current round.
Notice that the arrow only goes one way - we don’t want the View to call methods on, or even know about, the Views. This makes the model classes more independent, and hence more reusable and testable.
By following the single responsibility principle, our Bull’s Eye code will become a lot cleaner. It will be easier for someone looking at our code ot understand it, it will be easier to add new features and make changes, and as you’ll learn in the next part of this course, will be easier to test.
The strategy we sketched out here is an example of an extremely simple App Architecture; we have a View that handles the user interface, that has a Model that handles the gameplay logic.
You should consider this level of separation into Views and Models as the bare minimum for you should go far in an app architecture. But this is only the beginning: you can go a lot further with more advanced app architectures, such as the popular Model-View-ViewModel app architecture.
The subject of app architecture goes quite deep; we have entire books and video courses just on app architecture. But for now for your first app, the important thing to remember is the #1 rule we covered today: give each class or struct you create a single responsibility.