ICS 32 Winter 2022
Exercise Set 2

Due date and time: Friday, January 21, 11:59pm


Getting started

First of all, be sure that you've read the Reinforcement Exercises page, which explains everything you'll need to know, generally, about how the reinforcement exercises will work this quarter. Make sure you read that page before you continue with this one.


Problem 1 (3 points)

One of the ICS 32 servers has the job of generating Shakespearean-style insults, based on a technique described by Chris Seidel, among others. Your job is to write a client program that generates random Shakespearean insults and displays them to a user. It should not be necessary for the user to know any of the details of how the Shakespeare server works; all of the network-handling should be done behind the scenes.

Of course, given that the Shakespeare server is a program running on another machine, we'll first need to understand the protocol for communicating with it, which is slightly more complicated than the echo server described in the Networks and Sockets notes, but not much moreso.

(Before you try writing code to solve this problem, I'd suggest experimenting with the server a bit, using PuTTY on Windows, or using telnet or nc on macOS.)

What your program should do is hide all of these details, which means it would do the following:

It's fine if details like the server's host and port are hard-coded into the program, but do use named, global constants, placing them at the top of your script (making them easy to find and update, should they need to change). While we don't allow the use of global variables in this course, global constants that give a clear name to an unchanging value are fine; the problem with global variables isn't that they're global, but that they vary.

There are no requirements around error-handling, so you can do whatever you'd like in situations where your program is unable to connect to the server, receives data from the server that doesn't conform to the protocol above, or encounters other issues along the way, but you will want it to close the connection if it was ever successfully opened.

What to submit

Submit one Python script named problem1.py, which implements your Shakespeare insult client. Executing your script should cause the client to run (i.e., we shouldn't need to call a function to start it up), but importing your script should not (i.e., use the if __name__ == '__main__': technique described in the Modules notes).


Problem 2 (1 point)

(This week, we made use of a Python feature called namedtuples, of which, in my experience, incoming ICS 32 students have a varied depth of understanding. Since we're going to need them this week — as well as going forward — it's worth taking some time to make sure you're familiar with them. You'll find a discussion of these in the Python background notes and I've also shared a video on this topic amongst the Python background videos, if this feels like new territory to you, which isn't entirely uncommon.)

Python offers two seemingly similar features: namedtuples and dictionaries. Both offer the ability to associate values with corresponding names, so that those values can be looked up again by those same names. So, it stands to reason that anything you could store in a namedtuple could also be stored in a dictionary instead.

If that's true, then it's worth considering why Python offers both. Think about that and then answer these two questions about them.

  1. What is an advantage of namedtuples over dictionaries?
  2. What is an advantage of dictionaries over namedtuples?

You won't need to write a page to answer this question, but you will want to briefly explain why, in a sentence or two, your proposed advantage is actually an advantage.

What to submit

Submit one PDF file named problem2.pdf, which contains your answer to these two questions.


Problem 3 (3 points)

Write a function pretty_print, which takes one parameter that can be any type of namedtuple. It returns no value, but "pretty prints" the contents of the namedtuple to the Python shell, including both the names of its fields and their values. This is subject to a few rules.

A couple of examples follow.

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y', 'z'])
>>> pt = Point(z = 5, x = 9, y = 13)
>>> pretty_print(pt)
x: 9
y: 13
z: 5
>>> Person = namedtuple('Person', ['name', 'age', 'favorite'])
>>> instructor = Person(name = 'Alex', age = 45, favorite = 'Boo')
>>> pretty_print(instructor)
    name: Alex
     age: 45
favorite: Boo

Testing your work

You are required to test as much of this work as you can, which means you would want to write assert-statement-based tests, as described in the Testing notes. However, your tests should not generate any output or other effects, which means you won't be able to test precisely what gets printed by the print function — we haven't learned techniques that would allow us to test that, anyway! — so your best bet is to write helper functions that are "pure" (i.e., whose outputs are determined solely by their inputs), with as much of the functionality appearing in those helper functions as possible. Everything but the printing should be tested.

Your tests should not generate any output or other effects, however. We'll be running automated tests of our own separately; if we can't run our automated tests, you may not receive full credit here.

What to submit

Submit one Python module named problem3.py, which contains your pretty_print function, along with your helper functions and any assert-statement-based tests.

Docstrings and type annotations are required on your helper functions, because we haven't agreed ahead of time on what your design should look like; by documenting that design, you'll also have thought carefully about what problem each function solves, whether they'll fit together properly, and so on. That's the funny thing about a documentation requirement: It's not entirely about documentation, though that's an ancillary benefit; it's also about slowing down enough to think about one's own design before fully committing to it. Testing, as we'll see in more detail later this quarter (but you'll start to see it here, if you approach this in the way we're asking you to) has similar benefits.


Problem 4 (2 points)

While there are many protocols in use on the Internet, and while they certainly differ in their details, there are some aspects of those protocols that recur. It's those recurring details that make us wonder whether there's a deeper principle at work; when lots of smart, experienced people solve a problem the same way, it's often because they've internalized a key insight that makes that solution the obvious one.

We've seen a number of protocols already this quarter: the "echo" protocols from the Networks and Sockets lecture, the Polling protocol from the Protocols lecture, the Shakespeare protocol from Problem 1, and the I32CFSP protocol you'll be implementing in Project #2. While they, too, differ in their details, they do have one common detail that they share: The client speaks first. And, other than the "echo" protocols, they share one other common detail: When the client speaks first, what's sent is a message that identifies, in some way, what protocol the client intends to use. These turn out to be commonalities not only amongst the protocols in ICS 32, but also amongst Internet protocols more generally, so one might wonder why that is. Rather than wonder about it, let's think about it and answer a couple of questions about it.

  1. Why is it so common in Internet protocols that clients speak before servers do? (In other words, what would be an important advantage of having a client speak first, or, thought differently, an important disadvantage of having a server speak first instead?)
  2. Why is it so common for clients to begin with a "hello" message that, in some way, identifies what protocol it wants to use? Why not just get down to business and start by asking the server, more directly, for the first thing the client wants?

What to submit

Submit one PDF file named problem4.pdf, which contains your answers to these two questions.


Problem 5 (1 point)

In the Protocols lecture, we mainly wrote a medium-sized program that implemented a Polling client (i.e., a program that can interact with the Polling server, so that a user can see the questions, vote on them, and see the results without knowing the details of how the Polling protocol works).

In polling.py, three of the functions — _read_line, _expect_line, and _write_line — were marked private, while the others were not. In a sentence or two, what would be a good rationale for making these private? In other words, why would I have written them that way, instead of making them public instead? (Note that I'm asking specifically about these functions, not for a general definition of what public or private functions are. This isn't about the concept; it's about the application of the concept.)

What to submit

Submit one PDF file named problem5.pdf, which contains your answer to this question.


Deliverables

In Canvas, you'll find a separate submission area for each problem. Submit your solution to each problem into the appropriate submission area. Be sure that you're submitting the correct file into the correct area (i.e., submitting your Problem 1 solution to the area for Problem 1, and so on). Under no circumstances will we offer credit for files submitted in the incorrect area.

Submit each file as-is, without putting it into a Zip file or arranging it in any other way. If we asked for a PDF, for example, all we want is a PDF; no more, no less. If you submit something other than what we asked for, we will not be offering you any credit on the submission. There are no exceptions to this rule.

Of course, you should also be aware that you're responsible for submitting precisely the version of your work that you want graded. We won't regrade an exercise simply because you submitted the wrong version accidentally, and we won't be able to offer any credit on exercises that you forgot to submit.

Can I submit after the deadline?

Unlike some of the projects in this course, the reinforcement exercises cannot be submitted after the deadline; there is no late policy for these. Each is worth only 3% of your grade, so it's not a disaster if you miss one of them along the way.