FDE PulseFDE jobs open 632New in 7 days 57Companies hiring 95Remote-friendly 24%Median US pay $205kTop hirer Databricks 114
VI

The newspaper of the Forward Deployed Engineer

Books & courses

Effective Python, third edition: which items to read before you fix a client's Python code

The costliest bug in inherited client code is rarely a slow algorithm. More often it is an except block that swallows errors, and Brett Slatkin's book shows exactly where to look.

Cover of Effective Python: 125 Specific Ways to Write Better Python
Effective Python: 125 Specific Ways to Write Better Python · Brett Slatkin · Cover: Open Library
ShareLinkedInFacebookX

In brief

  • The third edition was published on 20 November 2024. It has 125 items, 35 of them new, and adds two chapters: Robustness and Performance.
  • FDEs should read Robustness and Functions first, then Testing and Collaboration, and leave Performance until last.
  • The three principles most worth keeping: do not let errors disappear, change code gradually once tests are in place, and measure before you optimise.
Two code panels side by side. On the left, "Before": an API-calling function catches except Exception and returns None, highlighted in orange because every error becomes None. On the right, "After": it catches only TimeoutError, then raises OrderFetchError from e, with a green note: other errors still surface, with a stack trace.
Fixing the fetch_orders function using the Robustness chapter and Item 32 of Effective Python, 3rd edition: catch only errors you understand, convert them into a named exception and keep the root cause with from e. Source: illustrative example in the article, based on Effective Python, 3rd edition (Brett Slatkin).

Picture your first week at a client. Their data pipeline occasionally writes empty rows, and nobody knows why. You open the code and find a function that calls an API, wrapped in except Exception:, returning None when anything goes wrong. No log records what happened.

Both habits have their own items in Effective Python: 125 Specific Ways to Write Better Python, third edition, by Brett Slatkin. Addison-Wesley Professional published the book on 20 November 2024 (ISBN-13 978-0-13-817218-3). The publisher describes Slatkin as having many years of experience at Google.

For an FDE, the book’s value is not in teaching you to write elegant Python. It gives you a checklist of what to inspect when you take over someone else’s code, and how to fix it without breaking a system that is already running.

What is new in the third edition?

The third edition grows from 90 items to 125, 35 of them entirely new. The content tracks Python releases up to 3.13, so topics such as match and dataclasses are written in modern syntax.

The parts most worth paying for are the two new chapters on Robustness and Performance. The book also goes deep on C extensions and calling native libraries, for when a performance problem cannot be solved in pure Python.

The author maintains an official GitHub repository, bslatkin/effectivepython, with a separate example file or folder for each item. That means you can use the book as a reference: when you hit a problem, open the relevant item and run the example straight away.

In what order should you read it?

Do not read it cover to cover. When you are about to fix a client’s code, start with the Robustness chapter. It covers using try/except/else/finally properly, why you should not catch the whole Exception class, and exception chaining.

Those are exactly the three things needed to fix the empty-row pipeline above. Next comes the Functions chapter: Item 32 advises raising exceptions instead of returning None, and Item 30 reminds you that arguments passed to a function can be mutated. Both are common sources of bugs when reading unfamiliar code.

After that, read the Testing and Collaboration chapters, and only then Performance and Concurrency. The order has a reason: before you can make code faster, you need to be sure you can change it without breaking something else.

First lesson: do not let errors disappear

Back to the API function. With except Exception: return None, an authentication failure, a timeout and a typo in the code all look identical: they are all None. The snippet below is an illustration, setting the old version beside one fixed in the spirit of the Robustness chapter and Item 32.

# Before: every error turns into None
def fetch_orders(client, day):
    try:
        return client.get_orders(day)
    except Exception:
        return None

# After: catch only the errors you understand, keep the exception chain
class OrderFetchError(Exception):
    pass

def fetch_orders(client, day):
    try:
        return client.get_orders(day)
    except TimeoutError as e:
        raise OrderFetchError(f"Timeout fetching orders for {day}") from e

In the second version, a timeout becomes a clearly named error, and from e preserves the root cause. Every other error, including a typo, surfaces instead of being swallowed. The next time an empty row appears, a stack trace will point straight at the cause.

When you start at a client, do this first: find every place that catches Exception and every function that returns None to signal failure. That list tells you what the system is hiding.

Second lesson: get tests in place, then change things gradually

Item 109 advises preferring integration tests over unit tests. For untested code this is practical advice: a test that runs through the whole flow from input to output pins down current behaviour, even before you understand every function inside it.

Item 112 covers encapsulating dependencies so they are easy to mock, which suits flows that call out to the client’s database or APIs.

The Collaboration chapter adds two tools for gradual change. Item 123 uses warnings to tell callers that a function’s usage is about to change, giving the client’s team time to migrate. Item 124 uses typing for static analysis, catching errors before the code runs.

Together, they let you refactor step by step without breaking the parts that are running.

Third lesson: measure first, optimise later

The Performance chapter opens with Item 92, “Profile Before Optimizing”. Item 93 explains microbenchmarking with timeit, and Item 94 discusses when to replace Python with another language. The sequence is a whole process: find where the code is really slow, measure before and after the fix, and consider C extensions only once you have run out of options in Python.

Concurrency calls for the same caution. Item 68 advises using threads for blocking I/O, not for parallelising computation. If a client wants to speed up a heavy data-processing job by adding threads, read this item before you agree.

Who should read it, and how can it help your career?

If you have written Python for a few years but mostly on your own code, this book is worth the most to you. Anyone preparing to move into an FDE role should read it too, because that work almost always begins with reading other people’s code.

On your CV, do not write “proficient in Python”. Describe something specific instead: for example, replacing overly broad Exception handlers with typed exceptions, adding integration tests to an untested flow, then profiling to find the real bottleneck.

In an interview, if you are handed unfamiliar code, ask how to measure it before proposing optimisations. That question shows the interviewer you have worked on real systems.

All 125 items are useful, but the ten or so mentioned above are enough to change how you work in your first week at a client.

Was this article useful?

Use with your AI assistantAsk Claude ↗Ask ChatGPT ↗
3 sources
Read next on the roadmap · Stage 1: FoundationsThe Odin Project: an open-source JavaScript and Node.js path for Python FDEsThe Odin Project's seven-course path is an open-source curriculum maintained by volunteers. It can teach a Python engineer to read a client's Express backend, as long as the courses are taken in order.