Opening the Door

Beware! This document needs cleaning up. Formatting may be messy or broken. Text may be inaccurate or in need of editing.

You can look at this preview, but be aware that the content will change before the instructor assigns this to the class.

This document is the result of an automated conversion. You can view the original version but again beware: that version too is not necessarily what will eventually be assigned.

Remember the activity from the first day of class? Today we will be returning to our classroom’s humble door, sketching out what a Door API might look like.

As on the first day of class, today’s activity involves no code. Later this week, you’ll have your head deep in details. Today we are focusing on abstract concepts. This activity’s learning goals:

  • Form a conceptual understanding of how APIs are designed
  • Practice designing an API using a day-to-day example
  • Be aware of decisions involved when designing APIs
  • Think about how APIs affect code compatibility
  • Think about how use cases shape API design

Time goal: <3 minutes

A great way to start designing an API is to first think about how you want the API to be used. What should code that uses this API look like? What terminology and usage patterns will make sense at the point of use?

Software developers often take this “outside in” approach when designing an API, sketching out hypothetical code that uses the API before the API actually exists. You’ll start today’s activity by practicing that same approach without code.

Create a new digital document for your group (Google Doc or other, doesn’t matter) and write in it (in natural language, not Java!) instructions for how to open the door to this classroom, following these guidelines:

  • You must not assume that the word “open” (or any synonym for it) is already defined. Defining the “open” action is your job.
  • You should assume that we already have definitions for all the parts of the door, and any actions that are possible with those parts.
  • You should also assume that the reader of the instructions knows their own body (e.g. “hand”) and how to use it (e.g. “hold”), and also knows general concepts of geometry and direction (e.g. “down”).
  • Don’t look at the instructions provided on the first day of class! Invent your own.

Your instructions should be around 30-40 words. If your instructions are any shorter, you need to spell things out just a little more. If they are getting much longer than that, then they are too precise or too pedantic for today’s exercise. The goal here is to build up the idea of “open the door” using building blocks that are just one level of abstraction lower.

Time goal: <10 minutes

Go through the instructions you wrote, and highlight in bold all of the terminology that would need a definition in order for a person to follow the instructions. Look for nouns, verbs, descriptive terms, whether door-related or not — anything that isn’t generic English connecting words like “the” or “until.”

Copy all the boldfaced terms into a new document (Google Doc or other, doesn’t matter), each term on a separate line.

(Do not write definitions for your terms! That is too much for this exercise. You are only listing what things will be part of the API, not working out their definition / implementation.)

Group your terms into 2-4 broad sections, such as “Door” and “Person.” (Those are only suggestions. You can make up section titles that fit whatever terms you came up with.)

Within each section, group words into entities (such as “handle” or “arm”), actions (such as “pull”), and constants (such as “clockwise”).

This list is now a sketch of the API your door-opening instructions would need in order to function. Your instructions are the client of this new, hypothetical API. What you have now is a picture of what the provider of the API would need to offer.

If you were designing an actual API for a door in code, you would need to think through all of this in far more detail: What are the specific classes? Is a single Door object composed of smaller objects, and if so, what are their classes? What are the has-a and is-a relationships? Are all the actions methods, or are they something else? What specific parameters does each method take? etc.

Despite the simplified form of this exercise, the thinking you are doing now resembles the real work a programmer might do when designing an API. People often create a sketch of classes and methods using an imprecise “boxes and arrows” diagram or similar, leaving out some details and not yet worrying about the code that actually implements any of those methods.

⚠️ Before you move on to the next task, flag the instructor and have them look at your work to make sure you’re on the right track. ⚠️

Time goal: 5 minutes

Ask another group to send you the text they wrote in Task 1 (their door opening instructions, not their API). Use email, Slack, Google Docs sharing — whatever works for you. (Note that it’s OK if they’re not up to Task 3 yet; they just need to have completed Task 1.)

Try to interpret their instructions using your API. Remember: the instructions can’t use any term that is not part of your API. Do their instructions work with your API? (The answer is almost certainly “no.” If they do work, either it’s an extraordinary coincidence, or you’re not reading very carefully!)

Note that you don’t need to change anything: not your API, not their instructions, not your instructions . Just notice how two attempts to create an API for the same thing can end up being different, and how those differences make instructions written for one API incompatible with instructions written for the other.

What stops their instructions from working with your API? Study that question. It’s easy to skip through this part fast. Don’t! Think it through. How much would their instructions have to change to fit your API? How much would your API have to change to fit their instructions?

Are there terms that are essentially synonymous, but the two groups chose different words for the same thing? Did the other group do something your instructions didn’t, or vice versa? Did they take a fundamentally different approach, choose different building blocks? Did they decide to work at a different level of abstraction than you did?

If you truly don’t see many differences, try swapping your instructions with another group.

Swapping your instructions with the other group’s is analogous to copying and pasting code designed for one API into a context that expects a different API.

For example, if you search the web for “Java graphics” or “Java UI,” you might find code designed for Java2D, Swing, JavaFX, AWT, or Android. All of those are Java, but all of them provide different APIs for doing graphics and/or user interfaces. None of those APIs are the same as Kilt Graphics. If you try to paste example code that uses those other APIs into a Kilt Graphics project, it won’t work — even though the code is in the same language!

Why? It’s the same reason that another group’s door opening instructions won’t work with the API you came up with, even though your instructions and theirs are written in English.

Time goal: rest of class

Suppose Macalester facilities replaced the classroom door with an identical door. Would your instructions and your API still work?

What if facilities replaced the internal latch mechanism with a completely different newer model that lasts longer, but the door still looks and behaves the same from the outside. Would your instructions still work? Have you successfully decoupled interface from implementation?

Do your instructions work for going through the door in both directions (exiting and entering the classroom)? If not, try rewriting them so they do. Do you need to add anything new to your API for these updated instructions?

Now suppose you have to write instructions for opening each one of the following doors. (Study the mechanism of each one closely!)

Images 1-2 (top): Paul Cantrell; Image 3 (bottom left): Grainger; Image 4 (bottom right): Forestiere Underground Gardens.

Some difficult questions to consider (not to do yet, just to consider for now):

  • For each kind of door, could you adapt and generalize your existing instructions and API so that they work for this new kind of door and the classroom door? Could the same instructions handle all five kinds of door?
  • If you were to adapt your instructions for each door type, would you do it by broadening the terminology of your API? (For example, maybe you need a word that covers both “handle” and “knob” and anything else that opens a door by turning.) Or would you do it by making some portion of the instructions conditional?
  • At what point do the adapted instructions become so complicated that it would be better to simply write different instructions for different kinds of doors?

Now that you’ve considered all that, try out the following approach a little, not necessarily completing each one, but exploring each enough to see where it leads and what kinds of trouble it causes:

APPROACH 1: Separate APIs, separate instructions

  • Try listing out a new API for several (maybe 2-3) of the other doors, and write out separate instructions for opening each one.
  • Does this feel like a good fit? Does it create redundancy?

APPROACH 2: Single API, separate instructions

  • Try making a single unified API that can be used to open all of the doors. There might be some things in the API that only apply to some of the doors. That is OK! Just make sure there is enough in the API to describe how to open every one of the doors.
  • Write separate instructions using this unified API for at least 2-3 of the doors.
  • What is hard about making a single API describe all of them? Does this feel like a good fit? Does the API become awkward?

APPROACH 3: Single API, single instructions

  • Try using your unified API to write a single set of instructions that applies to all the doors. It might have to contain statements like “If the door has a knob….” That is fine, but remember that means that you would need to add something to your API that lets you ask whether the door has a knob!
  • Is this “single instructions” approach workable? How is it preferable to the choices above? How is it worse?

The questions you’re asking in this task are closely analogous to the difficult questions that software developers face when maintaining a software API. Whenever code gets used by new clients in new contexts, there is pressure to adapt existing code to handle new cases, and to expand existing APIs to describe additional things.

Sometimes incorporating new use cases can improve an API, or make the code more robust and more flexible. Sometimes incorporating new use cases can complicate the code, making it harder to maintain and more likely to break. Sometimes an API that tries to do too many things at once becomes too confusing for anyone to use.

Sometimes the best answer to a problem is to say, “No, we don’t handle that.” And sometimes saying that makes code cease to be useful.

Some of the most difficult and important questions a software team faces are not about what technology to use or how to use it, not about how to implement an algorithm or design an API, but rather about deciding what problem to solve in the first place.

Should the five doors in this assignment all have the same API, or are some (or all) of them fundamentally different things? Does your door-opening software need to handle all of these kinds of door? Will it in the future? Is it worth preparing for the future just in case, even if it makes things worse now?

Every possible answer to these questions is wrong in one way or another. As a software team, you have to pick one of those wrong answers. Then you have to live with it. That is the nature of software development.