Skip to content

Commit 81c8243

Browse files
authored
Merge branch 'main' into preface-review
2 parents d869c4e + f19e4b1 commit 81c8243

File tree

404 files changed

+4855
-5338
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

404 files changed

+4855
-5338
lines changed

.github/workflows/tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ jobs:
6464
git config --global user.name "Elspeth See-Eye"
6565
git config --global init.defaultBranch main
6666
67-
- name: Set up Python 3.13
68-
uses: actions/setup-python@v5
67+
- name: Set up Python 3.14
68+
uses: actions/setup-python@v6
6969
with:
70-
python-version: '3.13'
70+
python-version: '3.14'
7171

7272
- name: Install apt stuff and other dependencies
7373
shell: bash

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.13
1+
3.14

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ xmllint_%: %.asciidoc
8383
-e 's/’/\’/g' \
8484
-e 's/…/\…/g' \
8585
-e 's/ /\ /g' \
86+
-e 's/×/\×/g' \
8687
| xmllint --noent --noout -
8788

8889

acknowledgments.asciidoc

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Lots of people to thank, without whom this book would never have happened,
55
and/or would have been even worse than it is.
66

7-
Thanks first to "Greg" at $OTHER_PUBLISHER, who was the first person to
7+
Thanks first to "Greg" at `$OTHER_PUBLISHER`, who was the first person to
88
encourage me to believe it really could be done. Even though your employers
99
turned out to have overly regressive views on copyright, I'm forever grateful
1010
that you believed in me.
@@ -17,12 +17,12 @@ now changed the standard employment contract to say "no books"). Thanks also
1717
for your ongoing wisdom and for setting me off on the testing path.
1818

1919
Thanks to my other colleagues, Glenn Jones and Hansel Dunlop, for being
20-
invaluable sounding boards, and for your patience with my one-track record
20+
invaluable sounding boards, and for your patience with my one-track-record
2121
conversation over the last year.
2222

23-
Thanks to my wife Clementine, and to both my families, without whose support
23+
Thanks to my wife, Clementine, and to both my familieswithout whose support
2424
and patience I would never have made it. I apologise for all the time spent
25-
with nose in computer on what should have been memorable family occasions. I
25+
with my nose in the computer on what should have been memorable family occasions. I
2626
had no idea when I set out what the book would do to my life ("Write it in my
2727
spare time, you say? That sounds reasonable..."). I couldn't have done it
2828
without you.
@@ -32,18 +32,18 @@ Bache, for your encouragements and invaluable feedback. Especially Emily,
3232
who actually conscientiously read every single chapter. Partial credit
3333
to Nick and Jon, but that should still be read as eternal gratitude. Having
3434
y'all around made the whole thing less of a lonely endeavour. Without all of
35-
you the book would have been little more than the nonsensical ramblings of an
35+
you, the book would have been little more than the nonsensical ramblings of an
3636
idiot.
3737

38-
Thanks to everyone else who's given up some of their time to give some
38+
Thanks to everyone else who's given up their time to give some
3939
feedback on the book, out of nothing more than the goodness of their heart:
4040
Gary Bernhardt, Mark Lavin, Matt O'Donnell, Michael Foord, Hynek Schlawack,
4141
Russell Keith-Magee, Andrew Godwin, Kenneth Reitz, and Nathan Stocks. Thanks
4242
for being much smarter than I am, and for preventing me from saying several
4343
stupid things. Naturally, there are still plenty of stupid things left in the
4444
book, for which y'all can absolutely not be held responsible.
4545

46-
Thanks to my editor Meghan Blanchette, for being a very friendly and likeable
46+
Thanks to my editor, Meghan Blanchette, for being a very friendly and likeable
4747
slave driver, and for keeping the book on track, both in terms of timescales
4848
and by restraining my sillier ideas. Thanks to all the others at
4949
O'Reilly for your help, including Sarah Schneider, Kara Ebrahim, and
@@ -53,7 +53,7 @@ on the merits of Chicago School quotation/punctuation rules, but I sure am
5353
glad you were around. And thanks to the design department for giving us a goat
5454
for the cover!
5555

56-
And thanks most especially to all my Early Release readers, for all your help
56+
And thanks most especially to all my early release readers, for all your help
5757
picking out typos, for your feedback and suggestions, for all the ways in
5858
which you helped to smooth out the learning curve in the book, and most of
5959
all for your kind words of encouragement and support that kept me going.
@@ -79,6 +79,7 @@ and make it up to you in any way I can.
7979
And finally thanks to you, the latest reader, for deciding to check out
8080
the book! I hope you enjoy it.
8181

82+
[role="pagebreak-before less_space"]
8283
=== Additional Thanks for the Second Edition
8384

8485
Thanks to my wonderful editor for the second edition, Nan Barber, and to
@@ -101,15 +102,15 @@ and many, many more.
101102

102103
=== Additional Thanks for the Third Edition
103104

104-
Thanks to my editor Rita Fernando,
105+
Thanks to my editor, Rita Fernando,
105106
thanks to my tech reviewers
106107
Béres Csanád,
107108
David Seddon,
108109
Sebastian Buczyński,
109110
and Jan Giacomelli,
110-
and thanks to all the Early Release readers for your feedback,
111+
and thanks to all the early release readers for your feedback,
111112
big and small, including
112-
Jonathan H,
113+
Jonathan H.,
113114
James Evans,
114115
Patrick Cantwell,
115116
Devin Schumacher,
@@ -130,8 +131,9 @@ Lars Berberich,
130131
Rodrigo Jacznik,
131132
Tom Nguyen,
132133
rokbot,
134+
Nikita Durne,
133135
and to anyone I've missed off this list,
134-
my sincere apologies, ping me and i'll add you,
136+
my sincere apologies, ping me and I'll add you,
135137
and thank you thank you once again.
136138

137139

ai_preface.asciidoc

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[[ai_preface]]
22
[preface]
3-
== Preface to the Third Edition: TDD in the Age of AI
3+
== Preface to the Third Edition: [.keep-together]#TDD in the Age of AI#
44

55
Is there any point in learning TDD now that AI can write code for you?
66
A single prompt could probably generate the entire example application in this book,
@@ -10,13 +10,13 @@ The truth is that it's too early to tell. AI is still in its infancy,
1010
and who knows what it'll be able to do in a few years or even months' time.
1111

1212

13-
=== AI is Both Insanely Impressive and Incredibly Unreliable
13+
=== AI Is Both Insanely Impressive and Incredibly Unreliable
1414

1515
What we do know is that right now,
1616
AI is both insanely impressive and incredibly unreliable.
1717

18-
Beyond being able to understand and respond to prompts in normal human language --
19-
it's easy to forget how absolutely extraordinary that is; literally science-fiction
18+
Beyond being able to understand and respond to prompts in normal human language--it's
19+
easy to forget how absolutely extraordinary that is; literally science-fiction
2020
a few years ago--AI tools can generate working code, they can generate tests,
2121
they can help us to break down requirements, brainstorm solutions,
2222
quickly prototype new technologies. It's genuinely astonishing.
@@ -32,7 +32,7 @@ code that's filled with copy-paste and duplication, weird hacks,
3232
and undecipherable spaghetti code that spells a maintenance nightmare.
3333

3434

35-
=== Mitigations for AI's Shortcomings Sure Look A Lot Like TDD
35+
=== Mitigations for AI's Shortcomings Sure Look a Lot Like TDD
3636

3737
If you read the advice, even from AI companies themselves,
3838
about the best way to work with AI, you'll find that it
@@ -49,15 +49,15 @@ When we're thinking about code quality, the idea of having a human in the loop,
4949
with frequent pauses for review and refactoring,
5050
again seems like a key mitigation.
5151

52-
In short, all of the techniques of Test-Driven Development that are outlined in this book:
52+
In short, all of the techniques of test-driven development that are outlined in this book:
5353

5454
* Defining a test that describes each small change of functionality,
5555
before we write the code for it
5656

5757
* Breaking our problem down into small pieces and working incrementally,
5858
with frequent test runs to catch bugs, regressions, and hallucinations
5959

60-
* The "refactor" step in TDD's Red/Green/Refactor cycle,
60+
* The "refactor" step in TDD's red/green/refactor cycle,
6161
which gives us a regular reminder for the human in the loop to review and improve the code.
6262

6363

@@ -69,7 +69,7 @@ when working with AI.
6969

7070
=== Leaky Abstractions and the Importance of Experience
7171

72-
https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/["Leaky abstractions"]
72+
https://oreil.ly/PgWjL["Leaky abstractions"]
7373
are a diagnosis of a common problem in software development,
7474
whereby higher-level abstractions fail in subtle ways,
7575
and the complexities of the underlying system leak through.
@@ -84,7 +84,7 @@ In a similar way, AI offers us a new, higher-level abstraction around writing co
8484
but we can already see the "leaks" in the form of hallucinations and poor code quality.
8585
And by analogy to the 3GLs, the programmers who are going to be most effective with AI
8686
are going to be the ones who "know what good looks like",
87-
both in terms of code quality, test structure and so on,
87+
both in terms of code quality, test structure, and so on,
8888
but also in terms of what a safe and reliable workflow for software development looks like.
8989

9090

@@ -97,6 +97,10 @@ Its ability to write that _first_ test,
9797
the one where, as we'll see, a lot of the design (and thinking) happens in TDD,
9898
was much more mixed.
9999

100+
// SEBASTIAN: Idea for a frame with actionable advice: "Make sure there are at least few examples of tests before you'll make AI assistant write more. Show it what 'good' looks like."
101+
102+
// SEBASTIAN: Another idea for a frame with actionable advice: "Simple things like writing a meaningful test name or describing in comment what you want to test can help immensely AI working in autocomplete mode."
103+
100104
Similarly when working in a less "autocomplete" and more "agentic" mode,
101105
I saw AI tools do very well on simple problems with clear instructions,
102106
but when trying to deal with more complex logic and requirements with ambiguity,

appendix_CD.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
.Warning
66
*******************************************************************************
7-
🚧 Warning, this appendix is just a placeholder / rough sketch.
7+
This appendix is just a placeholder / rough sketch.
88
99
It should have the outline of what you need to set up automated deploys tho!
1010
Why not give it a try?
1111
1212
*******************************************************************************
1313

14-
((("Continuous Delivery (CD)")))
14+
((("continuous delivery (CD)")))
1515
This is the next step after CI.
1616
Once we have a server that automatically does things every time we push,
1717
we can take the next step in automating our deploys,

appendix_Django_Class-Based_Views.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def home_page(request):
7171
====
7272

7373

74-
https://docs.djangoproject.com/en/1.11/ref/class-based-views/[Looking through
74+
https://docs.djangoproject.com/en/5.2/ref/class-based-views/[Looking through
7575
the options], Django has a generic view called `FormView`—let's see how
7676
that goes:
7777

appendix_IV_testing_migrations.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ sqlite3.IntegrityError: columns list_id, text are not unique
120120
Inserting a Data Migration
121121
~~~~~~~~~~~~~~~~~~~~~~~~~~
122122

123-
https://docs.djangoproject.com/en/1.11/topics/migrations/#data-migrations[Data
123+
https://docs.djangoproject.com/en/5.2/topics/migrations/#data-migrations[Data
124124
migrations] are a special type of migration that modifies data in the database
125125
rather than changing the schema. We need to create one that will run before
126126
we apply the integrity constraint, to preventively remove any duplicates.
@@ -135,7 +135,7 @@ Migrations for 'lists':
135135
$ pass:[<strong>mv lists/migrations/0005_*.py lists/migrations/0005_remove_duplicates.py</strong>]
136136
----
137137

138-
Check out https://docs.djangoproject.com/en/1.11/topics/migrations/#data-migrations[the
138+
Check out https://docs.djangoproject.com/en/5.2/topics/migrations/#data-migrations[the
139139
Django docs on data migrations] for more info, but here's how we add some
140140
instructions to change existing data:
141141

appendix_IX_cheat_sheet.asciidoc

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ I hope you find it useful!
1111

1212
=== Initial Project Setup
1313

14-
((("cheat sheet", "project setup")))
15-
((("Django framework", "set up", "project creation")))
16-
* Start with a _User Story_ and map it to a first _functional test_.
14+
15+
* Start with a _user story_ and map it to a first _functional test_.((("cheat sheet", "project setup")))((("Django framework", "set up", "project creation")))
1716

1817
* Pick a test framework&mdash;`unittest` is fine, and options like `py.test`,
1918
`nose`, or `Green` can also offer some advantages.
@@ -33,30 +32,22 @@ Relevant chapters:
3332
<<chapter_02_unittest>>,
3433
<<chapter_03_unit_test_first_view>>.
3534

36-
35+
[role="pagebreak-before less_space"]
3736
=== The Basic TDD Workflow: Red/Green/Refactor
3837

39-
((("cheat sheet", "TDD workflow")))
40-
((("Test-Driven Development (TDD)", "overall process of")))
41-
42-
* Red, Green, Refactor
43-
38+
[role="two-col"]
39+
* Red, Green, Refactor((("cheat sheet", "TDD workflow")))((("Test-Driven Development (TDD)", "overall process of")))
4440
* Double-loop TDD (<<Double-Loop-TDD-diagram2>>)
45-
4641
* Triangulation
47-
4842
* The scratchpad
49-
5043
* "3 Strikes and Refactor"
51-
5244
* "Working State to Working State"
53-
5445
* "YAGNI"
5546

5647

5748
[[Double-Loop-TDD-diagram2]]
5849
.Double-loop TDD
59-
image::images/double-loop-tdd-simpler.png["An inner red/green/refactor loop surrounded by an outer red/green of FTs"]
50+
image::images/tdd3_0405.png["An inner red/green/refactor loop surrounded by an outer red/green of FTs"]
6051

6152

6253
Relevant chapters:
@@ -68,15 +59,13 @@ Relevant chapters:
6859

6960
=== Moving Beyond Dev-Only Testing
7061

71-
((("cheat sheet", "moving beyond dev-only testing")))
72-
7362
* Start system testing early.
74-
Ensure your components work together: web server, static content, database.
63+
Ensure your components work together: web server, static content, database.((("cheat sheet", "moving beyond dev-only testing")))
7564

7665
* Build a production environment early, and automate deployment to it.
77-
- PaaS vs. VPS
66+
- PaaS versus VPS
7867
- Docker
79-
- Ansible vs Terraform
68+
- Ansible versus Terraform
8069

8170
* Think through deployment pain points: the database, static files,
8271
dependencies, how to customise settings, and so on.
@@ -88,13 +77,10 @@ Relevant chapters:
8877
<<part2>>,
8978
<<chapter_25_CI>>.
9079

91-
80+
[role="pagebreak-before less_space"]
9281
=== General Testing Best Practices
9382

94-
((("cheat sheet", "testing best practices")))
95-
((("testing best practices")))
96-
97-
* Each test should test one thing.
83+
* Each test should test one thing.((("cheat sheet", "testing best practices")))((("testing best practices")))
9884

9985
* Test behaviour rather than implementation.
10086

@@ -118,7 +104,7 @@ Relevant chapters:
118104
* Use explicit rather than implicit waits, and the interaction/wait pattern.
119105

120106
* Avoid duplication of test code--helper methods in a base class and the
121-
Page pattern are possible solutions.
107+
page pattern are possible solutions.
122108

123109
* Avoid double-testing functionality.
124110
If you have a test that covers a time-consuming process (e.g., login),
@@ -149,6 +135,6 @@ Be aware that integration tests will get slower and slower over time.
149135
Find ways to shift the bulk of your testing to unit tests
150136
as your project grows in size and complexity.
151137

152-
Relevant chapters:
138+
Relevant chapter:
153139
<<chapter_27_hot_lava>>.
154140

appendix_X_what_to_do_next.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ and compare how much faster they are than running against Postgres.
3636
Set it up so that your local machine uses SQLite for testing,
3737
but your CI server uses Postgres.
3838

39-
Does any of your functionality actually depend on postgres-specific features?
39+
Does any of your functionality actually depend on Postgres-specific features?
4040
What should you do then?
4141

4242

@@ -106,7 +106,7 @@ so if the other person adds an item to the list, you see it immediately?
106106
A persistent connection between client and server using websockets
107107
is the way to get this to work.
108108

109-
Check out Django's aysnc features see if you can them to implement dynamic notifications.
109+
Check out Django's async features and see if you can use them to implement dynamic notifications.
110110

111111
To test it, you'll need two browser instances
112112
(like we used for the list sharing tests),

0 commit comments

Comments
 (0)