For next time
- Check that your MP3 slide includes your name!
- Reminder: Toolbox 2 due Friday
- MP3 survey
- MP4 kick-off
- Model-View-Controller pattern introduction
- Resolving git merge conflicts
We used the results of previous surveys to form MP4 partner pairs for today. We’ll use the results of this post-MP3 survey to respond to your feedback as best we can on a rolling basis and when we form Final Project Teams. When you are done with MP3, and have had a moment to sleep (we know that our assignments keep rolling, but we do expect that you know when to call it a night), please fill out the Post-MP3 survey.
MP4: Interactive Programming
See who you are partnered with on this MP4 partner and studio list. Take a moment to find the partner(s) and sit with them for the rest of this class - all in AC326 today, but in the studio listed after Spring Break.
With your partner(s), discuss the issues raised in the “Getting Started” section. Bring course staff into your conversation as desired.
After you’ve come to a shared understanding, start generating project ideas and working on your written proposal (due at 9:00 AM tomorrow as a Canvas submission).
If your partner was unable to make it to today’s class session, you will set up and host the repo from your account. The proposal that you add to the repo and submit a link for on canvas can include up to three ideas for a project. Submitting more than one idea can get you instructor feedback on more than one possible MP4 direction. You can then discuss these possible directions with your partner when they are able to meet. If possible, this meeting should happen before Friday’s class.
The Model-View-Controller (MVC) Pattern
Throughout this course, there are implementation techniques that you have learned and applied in different contexts. For example, you have created and iterated over a list to do things like find a maximum value, process a series of files, or to read and write a dictionary. Many implementation tasks often decompose into sub-problems that can often be solved by applying a pattern you have seen before.
Similarly, when thinking about the design of larger programs, there are patterns that you can learn to recognize and apply. As this description would suggest, we call these design patterns. The world of object-oriented programming uses design patterns quite often, and these patterns often provide helpful templates to structure your classes and their methods.
In interactive software and user interface design, the Model-View-Controller (MVC) pattern is common. In short, MVC separates the design of a system into three components:
- The model is a representation of the system. More specifically, the model represents the state of a system at a particular point in time, and contains all of the data of the system that can be read or written.
- The view is a representation of the model, and is particularly oriented towards the user. The view includes functionality to process and show the state of the system in a way that is suitable for the end user.
- The controller is the way by which the user can change the system, or more specifically, the model that represents the system. Any action the user wants to perform on the system goes through the controller.
Here is a graphical representation of the MVC components and their interactions with the user:
When done well, MVC makes it easy to reason about what can change the state of the system (the controller) and what can read the state of the system (the view). The relatively intuitive separation of tasks also makes the design modular: components can be easily swapped out for others that do a similar task. For example, two different views and controllers can be used to interact with the same system model, one on a desktop and one on a phone or tablet.
Because this mini-project focuses on interactive computing, we think the MVC pattern is particularly well-suited for your tasks, and we’d like you to spend some time practicing designing software that follows this pattern.
To help get you started, here’s an example of how MVC could be used for a code editor, like Atom:
- The model contains things like what directory the editor is in, what files are currently open, what line the cursor is on, which files have unsaved changes, what plugins are installed, and any configuration settings the user has.
- The view contains functions to show keywords like
import(in Python) in specific colors, to make the cursor blink at a certain rate, display the font of the editor, etc.
- The controller takes input from the user, which includes code, comments, and
key sequences (like
Ctrl-Sto save a file). It turns these keypresses into actions by calling functions that change the model state, such as moving the cursor up one line if the user presses the Up Arrow key.
It’s important to remember that design patterns are about the structure, and may leave some details unclear. For example, in the above design, should the font be part of the model or the view? It depends, and you could make a well-reasoned case for either one.
Now, you can try coming up with a similar design for an interactive graphical game.
Take a few minutes to think about how the game Pac-Man could be designed according to the MVC pattern. What would the model, view, and controller contain or do?
Once you have answered these questions, try to translate that design into classes, functions, and variables in Python. Try not to look ahead until you’ve gotten the chance to write your thoughts down.
Here are some classes that we came up with that you might use to implement a Pac-Man clone:
Model: encodes the overall game state of the Pac-Man game (including level, position of pellets, position of Pac-Man and ghosts, etc.)
- Provides an interface to the Controller to respond appropriately to user commands
- Handles collisions between Pac-Man and ghosts as well as Pac-Man and small and large pellets
PacMan: represents the player’s avatar in the game (a part of the model)
- Provides an interface to respond to player actions as communicated by the controller (e.g. Pac-Man’s next move)
Ghost: represents a ghost in the game (a part of the model)
Small pellet: represents a small pellet in the game (a part of the model)
Large pellet: represents a large pellet in the game (a part of the model)
Controller: handles commands from the user and manipulates the model appropriately
PyGameView: draws the game state encoded by the Model to a pygame window
(The last class in the above list is specific to a certain Python library that follows this framework.)
There are many ways to implement Model-View-Controller, so this is not the only way to operationalize Model-View-Controller in the context of Pac-Man. Remember, this is not the only way to structure your object-oriented design (code that uses classes), but we hope it will be helpful at least as a jumping off point.
Other possible MVCs
With your partner, revisit one of the project ideas that you discussed. Try to think about what a model of that project might contain. What would be some of the controls in a controller class? The teaching team will be available throughout the studio time to ask questions about this.
Git merge conflicts
Today is a great day to sharpen your understanding of how working on code with someone else in the same repo can bring you great joy and great pain. Below, you’ll find exercises and examples that help you prepare to avoid or resolve situations that arise when partner pushes modifications to the same file.
When this happens, you need to go through a process to decide how to blend these changes together into a single new version. Read about resolving merge conflicts.
Exercise: resolving merge conflicts
Let’s create a merge conflict so we can practice resolving it.
Follow along with these commands and try it yourself.
We’re going to do everything locally, but you can imagine that
repo2 belong to you and your partner on separate machines - everything works the same way.
# Create new Git repository and commit a file $ mkdir repo1 $ cd repo1/ $ git init $ echo -e "Knock knock\nWho's there?" > joke.txt $ git add joke.txt $ git commit -m "Add joke setup" # Clone the repo (simulating a partner) $ cd .. $ git clone repo1/ repo2 $ cd repo2 # Make a change in both repos simultaneously (merge conflict) $ cd ../repo1/ $ echo "Interrupting cow" >> joke.txt $ git commit -a -m "Cows are always funny" $ cd ../repo2/ $ echo "Banana" >> joke.txt $ git commit -a -m "Fruit-based jokes are the best"
So now we’ve got a merge conflict brewing. Two copies of the repository started from the same commit (the joke setup) but made diverging changes. Let’s see what that looks like, and how to resolve it:
# From within repo2: $ git pull origin master remote: Counting objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From /home/ben/merge_example/repo1 * branch master -> FETCH_HEAD b056309..2d02106 master -> origin/master Auto-merging joke.txt CONFLICT (content): Merge conflict in joke.txt Automatic merge failed; fix conflicts and then commit the result.
Here Git is attempting to merge the two repository contents automatically for you. Many times it can do so successfully (e.g. if you have each changed different files, it will merge by creating a commit that has both of your changes). But in this case, we’ve edited the same part of the same file, so a choice must be made by a human about what should stay and what should go.
At this point, the contents of
repo2 look like this:
Knock knock Who's there? <<<<<<< HEAD Banana ======= Interrupting cow >>>>>>> 2d0210609e38d9f38bb48d8a77fbf57c3d05d15c
Git has inserted these markers around the two choices that need to be resolved.
We fix the merge conflict by choosing one of the options, removing the other option and the marker lines (
>>...), and then committing the file.
You can use any text editor you like to do this, but Atom is particularly nice since it is aware of how git works (you can actually do everything including writing commit messages within Atom, feel free to explore on your own). If you open the conflicted file in Atom, it presents you with buttons like this:
Clicking one of them automatically performs the edits described above. With those changes made and saved, the last step is to commit the merge:
$ git add joke.txt $ git commit -m "Resolved merge conflict (cows rule)"
At this point the merge conflict is resolved in
repo2. In your actual workflow you would then want to push the merge resolution commit to a shared location, so that
repo1 can pull it and both partners can work from a common history again.
So: merge conflicts are nothing to be afraid of, but they certainly are annoying. Some concrete suggestions for avoiding merge conflicts
- Pull first before you start each work session, to make sure you have the latest version of everyone’s work to build on.
- Avoid working on same file (and especially the same section of a file) simultaneously. Organizing your code into modules as we read about in Chapter 14.9 can help with this.
- Commit/push/pull updates frequently, so there’s less opportunity for major divergence.
Going Beyond: Git branches
What is the “master” in
git push origin master? It’s the name of a branch!
Developers often use branches to work on a new feature (without halting ongoing development on the master branch). Then once the feature is complete and tested, they can merge it back into master.
To see this visually, work through the first three levels of “Learn Git Branching”