Syllabus Lesson 68 of 141 · APIs nobody can misuse
APIs nobody can misuse

Make states explicit

Why it matters Objects with a lifecycle (connections, files, transactions, payments) are where "it worked on my machine" lives. A call in the wrong order should fail right there, not corrupt something later.

You are wrapping a network transport for the rest of the team. The transport itself is low level: connect(), write(data), disconnect(), and it does whatever it is told. A postmortem from last quarter found a job that sent data after closing and silently reconnected to the wrong server. Your wrapper must make that impossible.

State machine: a small set of states (new, open, closed) and the calls allowed in each. Anything else is refused.

c = Connection(transport)
c.open()
c.send(b"hello")
c.close()

with Connection(transport) as c:   # opens, and always closes
    c.send(b"hello")
Your turn

Write class Connection with __init__(self, transport), open(), send(data), close(), and with support (open on entry, close on exit even if the block raises). They call the transport's connect(), write(data) and disconnect().

Hidden misuse scripts will try each of these. Each must raise at the wrong call, before anything reaches the transport:

  • RuntimeError (or a subclass): send or close before open; open twice; send, close or open again after close (a closed connection is finished; make a new one); send after a with block;
  • TypeError: send anything that is not bytes-like (bytes or bytearray). Do not encode strings for the caller.

Spotted a problem in this lesson? Report it · Ask about this lesson

This exercise opens soon

Finish the lesson before it and this one unlocks. The whole course is free, no account needed, and you can read this lesson right now.