Walking the Line
Brandon Rhodes
Opening Keynote
PyTexas 2023 • Austin
An example
Let’s start writing a quick Python script.
An example
Let’s start writing a quick Python script.
Given a sample program, consider editing it —
adding or deleting one character. How many of
all the possible edits produce valid code?
An example
Q: What sample program should the script edit?
An example
Q: What sample program should the script edit?
A: Have the program edit its own code!
An example
text = open(__file__).read()
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
Then, I stop.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
When I’m ready to move from one thought to the next,
I have a habit: quickly checking my code so far.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
I pause for ½ second.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
I pause for ½ second.
This triggers Emacs to syntax-check the script.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
I pause for ½ second.
This triggers Emacs to syntax-check the script.
The result?
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
I pause for ½ second.
This triggers Emacs to syntax-check the script.
The result?
No errors.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
Saving kicks off an automatic run of the script
over in my terminal window.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
In the old days, this was often not worth it,
because it would have meant polling.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
In the old days, this was often not worth it,
because it would have meant polling.
Polling is expensive when there are no edits.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
In the old days, this was often not worth it,
because it would have meant polling.
Polling is expensive when there are no edits.
Polling is slow when there are edits.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
But today, Linux offers `inotify`.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
But today, Linux offers `inotify`.
It lets a process sleep waiting for changes to a file.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
In my `homedir` GitHub repo:
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
In my `homedir` GitHub repo:
,watch python example.py -- **/*.py
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
So I hit Save.
In my `homedir` GitHub repo:
,watch python example.py -- **/*.py
,w example.py
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
Thanks to that automation, I hit Save, and can glance
over at my terminal window to see the output —
in this case, it worked!
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
print(deletes)
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
for code in deletes:
eval(code)
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
for code in deletes:
eval(code)
Expectation: syntax error.
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
for code in deletes:
eval(code)
Expectation: syntax error.
So, I hit Save.
An example
Traceback (most recent call last):
File "<string>", line 1
ext = open(__file__).read()
^
SyntaxError: invalid syntax
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
for code in deletes:
eval(code)
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
counts = {'syntax': 0, 'ok': 0}
for code in deletes:
try:
eval(code)
except SyntaxError:
counts['syntax'] += 1
else:
counts['ok'] += 1
print(counts)
An example
And, I hit Save.
An example
And, I hit Save.
{'syntax': 811, 'ok': 0}
An example
And, I hit Save.
{'syntax': 811, 'ok': 0}
Drat.
An example
So I briefly comment out the `try…except`.
An example
So I briefly comment out the `try…except`.
And hit Save.
An example
Traceback (most recent call last):
File "<string>", line 1
ext = open(__file__).read()
^
SyntaxError: invalid syntax
An example
Traceback (most recent call last):
File "<string>", line 1
ext = open(__file__).read()
^
SyntaxError: invalid syntax
Recall that the first line of the file is:
An example
Traceback (most recent call last):
File "<string>", line 1
ext = open(__file__).read()
^
SyntaxError: invalid syntax
Recall that the first line of the file is:
text = open(__file__).read()
An example
pydoc eval
‘The source may be
a string representing a Python expression
or a code object as returned by compile().’
An example
Traceback (most recent call last):
File "<string>", line 1
ext = open(__file__).read()
^
SyntaxError: invalid syntax
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
counts = {'syntax': 0, 'ok': 0}
for code in deletes:
try:
eval(code)
except SyntaxError:
counts['syntax'] += 1
else:
counts['ok'] += 1
print(counts)
An example
text = open(__file__).read()
r = range(len(text))
deletes = [text[:i] + text[i+1:] for i in r]
counts = {'syntax': 0, 'ok': 0}
for code in deletes:
try:
compile(code, 'src', 'exec')
except SyntaxError:
counts['syntax'] += 1
else:
counts['ok'] += 1
print(counts)
An example
And I hit Save.
An example
And I hit Save.
{'syntax': 107, 'ok': 191}
An example
And I hit Save.
{'syntax': 107, 'ok': 191}
Success!
An example
Let’s improve that diagram. My mistake with `eval()`
An example
didn’t feel like progress — it felt like a detour.
An example
didn’t feel like progress — it felt like a detour.
When my code breaks, I feel like I have
crossed an invisible line that separates
all working programs from all broken ones.
Hence the title of this talk —
‘Walking the line’
So let’s discuss the two states, red and green.
Green.
Developers ♥ green.
Green.
Developers ♥ green.
Green leaves us free to make more progress.
Green.
Developers ♥ green.
Green leaves us free to make more progress.
Red leaves us stuck until it’s fixed.
Green.
Developers ♥ green.
Green leaves us free to make more progress.
Red leaves us stuck until it’s fixed.
And coding for too long without stopping to detect
the difference can leave us stranded.
Green.
All other things being equal, fixing code early is cheap,
while fixing code later is expensive.
Green.
All other things being equal, fixing code early is cheap,
while fixing code later is expensive.
Q: So, why would you write lots of code at once?
Green.
All other things being equal, fixing code early is cheap,
while fixing code later is expensive.
Q: So, why would you write lots of code at once?
A: Side quests.
Green.
All other things being equal, fixing code early is cheap,
while fixing code later is expensive.
Q: So, why would you write lots of code at once?
A: Side quests.
You discover the change you are making requires other
changes, that themselves each require further changes.
Green.
You can wind up laboring over a huge diff
that tries to change everything at once.
Green.
You can wind up laboring over a huge diff
that tries to change everything at once.
Instead, when I see a side quest, I `git stash` what
I’m working on and solve the side quest first.
Green.
@KentBeck
‘make the change easy, then make the easy change’
Green.
@KentBeck
Few people remember: that’s not the full tweet.
Green.
@KentBeck
‘for each desired change,
make the change easy (warning: this may be hard),
then make the easy change’
Green.
The side quests will not necessarily be easy.
Green.
But at least you get to tackle one quest at a time,
and get natural stopping points at which you
can commit your work.
Green.
But at least you get to tackle one quest at a time,
and get natural stopping points at which you
can commit your work.
But we always want green, yeah, TODO.
Red.
Do we programmers ever starting wanting to break things?
Red.
One case is TDD — Test-Driven Development.
Red.
One case is TDD — Test-Driven Development.
It would be a whole talk of its own.
Red.
One case is TDD — Test-Driven Development.
1. Start by writing a failing test of a new feature.
Red.
One case is TDD — Test-Driven Development.
1. Start by writing a failing test of a new feature.
2. Then write the code to turn the test green.
Red.
One case is TDD — Test-Driven Development.
1. Start by writing a failing test of a new feature.
2. Then write the code to turn the test green.
• Gets the worst thing, writing the test, over with first.
Red.
One case is TDD — Test-Driven Development.
1. Start by writing a failing test of a new feature.
2. Then write the code to turn the test green.
• Gets the worst thing, writing the test, over with first.
• Arranges a nice instant reward for when you finish.
Red.
One case is TDD — Test-Driven Development.
1. Start by writing a failing test of a new feature.
2. Then write the code to turn the test green.
• Gets the worst thing, writing the test, over with first.
• Arranges a nice instant reward for when you finish.
• By its nature produces a decently well-tested codebase.
Red.
One case is TDD — Test-Driven Development.
For the purposes of this talk, let’s just note
that TDD leverages your usual negative emotions
about Red: you want the Red to go away, so you
write code that satisfies the new test.
Red.
But it is the claim of this talk that
emotions can also work the other way round —
Red.
But it is the claim of this talk that
emotions can also work the other way round —
it is the claim of this talk that there are
situations where you aren’t avoiding Red,
Red.
But it is the claim of this talk that
emotions can also work the other way round —
it is the claim of this talk that there are
situations where you aren’t avoiding Red,
you’re seeking it out.
Feelings of insecurity.
Let’s consider three.
Feelings of insecurity.
#1
Feelings of insecurity.
Too much green.
Feelings of insecurity.
Imagine that you’re performing extensive refactoring.
Feelings of insecurity.
Imagine that you’re performing extensive refactoring.
Each time you Save, you’re thrilled the result is still Green.
Feelings of insecurity.
Your streak of green runs longer and longer.
Feelings of insecurity.
Your streak of green runs longer and longer.
Until—
Feelings of insecurity.
Until—you become a tiny bit incredulous.
Feelings of insecurity.
Until—you become a tiny bit incredulous.
‘Am I really this good at refactoring?’
Feelings of insecurity.
Until—you become a tiny bit incredulous.
‘Am I really this good at refactoring?’
‘Hey — wait — the tests are running, right? Right?’
Feelings of insecurity.
Until—you become a tiny bit incredulous.
‘Am I really this good at refactoring?’
‘Hey — wait — the tests are running, right? Right?’
taps mic
Feelings of insecurity.
Until—you become a tiny bit incredulous.
‘Am I really this good at refactoring?’
‘Hey — wait — the tests are running, right? Right?’
taps mic
Is this on?
Feelings of insecurity.
So I invoke a maneuver: my `asdf` check!
Feelings of insecurity.
C-e RET a s d f C-x s
Feelings of insecurity.
asdf
Feelings of insecurity.
asdf
And then I hit Save.
Feelings of insecurity.
asdf
If all is well, then I will see the happy result:
Feelings of insecurity.
asdf
If all is well, then I will see the happy result:
NameError: name 'asdf' is not defined
Feelings of insecurity.
asdf
If all is well, then I will see the happy result:
NameError: name 'asdf' is not defined
—and I will keep coding.
Feelings of insecurity.
asdf
If all is well, then I will see the happy result:
NameError: name 'asdf' is not defined
But what if I don’t see it?
Feelings of insecurity.
But what could have gone wrong?
Feelings of insecurity.
But what could have gone wrong?
Among the possibilities are —
Feelings of insecurity.
But what could have gone wrong?
1. You’ve been editing the wrong function!
Turns out? There are two named `user_delete()`.
Feelings of insecurity.
But what could have gone wrong?
2. You need to hit Shift-Reload, not plain Reload, for
your browser to see that edit to the CSS.
Feelings of insecurity.
But what could have gone wrong?
3. The repository is checked out twice on your laptop
and you are editing one repo while running the other.
Feelings of insecurity.
But what could have gone wrong?
4. Your editor’s jump-to-definition shortcut decided
to jump into `site-packages/` instead of the repository.
Feelings of insecurity.
But what could have gone wrong?
4. Your editor’s jump-to-definition shortcut decided
to jump into `site-packages/` instead of the repository.
(So, you’re editing a pip-installed copy of the code)
Feelings of insecurity.
But what could have gone wrong?
4. Your editor’s jump-to-definition shortcut decided
to jump into `site-packages/` instead of the repository.
(Bonus points if you forget to remove `asdf` and, months
later, you run some other Python application and see—)
Feelings of insecurity.
But what could have gone wrong?
4. Your editor’s jump-to-definition shortcut decided
to jump into `site-packages/` instead of the repository.
(Bonus points if you forget to remove `asdf` and, months
later, you run some other Python application and see—)
NameError: name 'asdf' is not defined
Feelings of insecurity.
But what could have gone wrong?
5. You are editing local code, on your laptop,
but reloading a remote version of the site.
Feelings of insecurity.
But what could have gone wrong?
5. You are editing local code, on your laptop,
but reloading a remote version of the site.
http://localhost/shopping-cart
Feelings of insecurity.
But what could have gone wrong?
5. You are editing local code, on your laptop,
but reloading a remote version of the site.
https://canary.example.com/shopping-cart
Feelings of insecurity.
But what could have gone wrong?
6. You did open the remote copy of the file,
but your `sshfs` connection has gone down,
and your editor didn’t tell you.
Feelings of insecurity.
But what could have gone wrong?
7. A disk error forced your filesystem to remount
read-only, but your editor isn’t telling you.
Feelings of insecurity.
But what could have gone wrong?
7. A disk error forced your filesystem to remount
read-only, but your editor isn’t telling you.
Why? Because, the cool fancy new color-highlighted
error-report plugin you installed dies silently on a
read-only filesystem, and so can’t tell you about it.
Feelings of insecurity.
But what could have gone wrong?
Bonus Round!
Feelings of insecurity.
But what could have gone wrong?
8. Remember the end of the day last Friday?
Feelings of insecurity.
But what could have gone wrong?
8. Remember the end of the day last Friday?
When your boss asked if the app works on leap day?
Feelings of insecurity.
But what could have gone wrong?
8. Remember the end of the day last Friday?
When your boss asked if the app works on leap day?
So you set your system clock briefly to next February 29,
hit Restart, and Reload to show that the app still worked.
Feelings of insecurity.
But what could have gone wrong?
8. Remember the end of the day last Friday?
Turns out?
Feelings of insecurity.
But what could have gone wrong?
8. Remember the end of the day last Friday?
Turns out?
All the `*.pyc` files written during those five minutes
are dated 2024 February 29 — which is in the future.
Feelings of insecurity.
But what could have gone wrong?
8. Remember the end of the day last Friday?
Turns out?
All the `*.pyc` files written during those five minutes
are dated 2024 February 29 — which is in the future.
Which makes those `*.pyc` files more recent than anything
you save today, so Python is ignoring your new `*.py` edits.
Feelings of insecurity.
But what could have gone wrong?
8. Remember the end of the day last Friday?
Quick advice: turn off `*.pyc`.
Feelings of insecurity.
But what could have gone wrong?
8. Remember the end of the day last Friday?
Quick advice: turn off `*.pyc`.
/home/brandon/.bashenv:
export PYTHONDONTWRITEBYTECODE=PLEASE
Feelings of insecurity.
Any of these underlying causes
will make you want to cross the line.
Feelings of insecurity.
You will only be happy again once you’re assured
that the line is back in place, and once again ready
to hit you with consequences as you write code.
Feelings of insecurity.
#2
Feelings of insecurity.
My tests are running. But are they protecting me?
Feelings of insecurity.
My tests are running. But are they protecting me?
Especially important question before a big refactor.
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Feelings of insecurity.
My tests are running. But are they protecting me?
pandas
df.clip_upper(...)
df.clip_lower(...)
Feelings of insecurity.
My tests are running. But are they protecting me?
clip_upper = min
clip_lower = max
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Q: How do we know whether our tests cover both cases?
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Q: How do we know whether our tests cover both cases?
A: Let’s cross the line!
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Let’s do quick edits to remove `max()`.
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Let’s do quick edits to remove `max()`.
capital_gain = line_16
# or
capital_gain = -3000
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Let’s do quick edits to remove `max()`.
Hint: don’t experiment on the line itself!
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Let’s do quick edits to remove `max()`.
Hint: don’t experiment on the line itself!
Make a copy.
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
Feelings of insecurity.
My tests are running. But are they protecting me?
capital_gain = max(line_16, -3000)
capital_gain = max(line_16, -3000)
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = max(line_16, -3000)
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = max(line_16, -3000)
M-m '#' C-k C-y RET C-y
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = max(line_16, -3000)
No we’re free to break the code.
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = line_16
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
1. Use `#` with no space, so you’ll remember not to commit.
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
1. Use `#` with no space, so you’ll remember not to commit.
PEP-8 ‘Each line of a block comment
starts with a # and a single space’
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
1. Use `#` with no space, so you’ll remember not to commit.
PEP-8 ‘Inline comments…should start
with a # and a single space’
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
1. Use `#` with no space, so you’ll remember not to commit.
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
1. Use `#` with no space, so you’ll remember not to commit.
2. Makes it easy to undo.
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
1. Use `#` with no space, so you’ll remember not to commit.
2. Makes it easy to undo.
3. Lets you, as you edit, compare to the original.
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
Don’t leave feelings of insecurity unacknowledged.
Feelings of insecurity.
My tests are running. But are they protecting me?
#capital_gain = max(line_16, -3000)
capital_gain = -3000
Don’t leave feelings of insecurity unacknowledged.
Go ahead and quickly break the code, to be sure
that you are safely fenced in by your tests.
Feelings of insecurity.
My tests are running. But are they protecting me?
Breaking things.
Feelings of insecurity.
My tests are running. But are they protecting me?
Breaking things.
In real life — in a workplace, in a relationship — crossing
a line just to see if it’s really there is an anti-pattern.
Feelings of insecurity.
My tests are running. But are they protecting me?
So we must balance two philosophies.
Feelings of insecurity.
My tests are running. But are they protecting me?
Gandalf: ‘He that breaks a thing to find out what it is
has left the path of wisdom.’
Feelings of insecurity.
My tests are running. But are they protecting me?
Gandalf: ‘He that breaks a thing to find out what it is
has left the path of wisdom.’
Blake: ‘You never know what is enough
Feelings of insecurity.
My tests are running. But are they protecting me?
Gandalf: ‘He that breaks a thing to find out what it is
has left the path of wisdom.’
Blake: ‘You never know what is enough
unless you know what is more than enough.’
Feelings of insecurity.
#3
Feelings of insecurity.
Some of us are haunted by an insecurity—
Feelings of insecurity.
‘Wait! Maybe this code could be even simpler.’
Feelings of insecurity.
‘Wait! Maybe this code could be even simpler.’
Some of us suffer from a nagging fear that we might have
written slightly more code than is strictly necessary.
Feelings of insecurity.
‘Wait! Maybe this code could be even simpler.’
Some of us suffer from a nagging fear that we might have
written slightly more code than is strictly necessary.
Surprisingly, this can lead to non-optimal outcomes.
Feelings of insecurity.
A story.
Feelings of insecurity.
I once worked in Georgia Tech’s IT shop.
Feelings of insecurity.
Every night, our script would run `scp` to copy a CSV
from Human Resources that listed all 30k employees.
Feelings of insecurity.
Every night, our script would run `scp` to copy a CSV
from Human Resources that listed all 30k employees.
Any of yesterday’s employees that were missing
from today’s list received a goodbye email.
Feelings of insecurity.
Q: Guess what happened early one Monday morning when
the TCP connection died 3k lines before the end?
Feelings of insecurity.
Q: Guess what happened early one Monday morning when
the TCP connection died 3k lines before the end?
A: 3k employees were emailed ‘goodbye’.
Feelings of insecurity.
Q: Guess what happened early one Monday morning when
the TCP connection died 3k lines before the end?
A: 3k employees were emailed ‘goodbye’.
It was a bad day.
Feelings of insecurity.
What interests me now, looking back, is my inadequate
response to the problem.
Feelings of insecurity.
What did we developers do?
Feelings of insecurity.
What did we developers do?
We read some docs, did some tests, and switched
from `scp` to `rsync`.
Feelings of insecurity.
What did we developers do?
We read some docs, did some tests, and switched
from `scp` to `rsync`.
Done! Problem solved!
Feelings of insecurity.
What did we developers do?
We read some docs, did some tests, and switched
from `scp` to `rsync`.
Done! Problem solved!
Right?
Feelings of insecurity.
Well, we were then called into a meeting.
Feelings of insecurity.
Well, we were then called into a meeting.
With a VP.
Feelings of insecurity.
Well, we were then called into a meeting.
With a VP.
He ordered that HR append an `--END--` line to the file
and that we must check for it before using it.
Feelings of insecurity.
Of course, we were enraged.
Feelings of insecurity.
Of course, we were enraged.
1. We had already solved the problem. Ourselves!
Feelings of insecurity.
Of course, we were enraged.
1. We had already solved the problem. Ourselves!
2. The design of `rsync` made an extra check illogical.
Feelings of insecurity.
Of course, we were enraged.
1. We had already solved the problem. Ourselves!
2. The design of `rsync` made an extra check illogical.
3. The beautiful symmetry of the CSV file — every line,
the same number of commas, every line, the same number
of fields — is ruined by adding the extra line.
Feelings of insecurity.
Of course, we were enraged.
1. We had already solved the problem. Ourselves!
2. The design of `rsync` made an extra check illogical.
3. The beautiful symmetry of the CSV file — every line,
the same number of commas, every line, the same number
of fields — is ruined by adding the extra line.
So we wound up arguing — unsuccessfully — against
what strikes me today as an eminently sensible idea.
Feelings of insecurity.
What went wrong?
Feelings of insecurity.
What went wrong?
We were indulging in the pleasures of the mathematician —
Feelings of insecurity.
What went wrong?
We were indulging in the pleasures of the mathematician —
we wanted code to be minimal and concise, like a proof —
Feelings of insecurity.
What went wrong?
We were indulging in the pleasures of the mathematician —
we wanted code to be minimal and concise, like a proof —
when our role demanded the maturity of an engineer.
Feelings of insecurity.
Do engineers walk right against the line
between success and failure?
Feelings of insecurity.
Do engineers walk right against the line
between success and failure?
Do they build bridges that can support the rated
limit but not a single ton more?
Feelings of insecurity.
Do engineers walk right against the line
between success and failure?
Do they build bridges that can support the rated
limit but not a single ton more?
No.
Feelings of insecurity.
Do engineers walk right against the line
between success and failure?
Do they build bridges that can support the rated
limit but not a single ton more?
No.
Systems that are robust
Feelings of insecurity.
Do engineers walk right against the line
between success and failure?
Do they build bridges that can support the rated
limit but not a single ton more?
No.
Systems that are robust
are also, necessarily, redundant.
Feelings of insecurity.
I ought to have welcomed the chance to give the
machine two reasons to not disable 3k employee
accounts on a Monday morning.
Feelings of insecurity.
I ought to have welcomed the chance to give the
machine two reasons to not disable 3k employee
accounts on a Monday morning.
I ought to have been happy to take a deep breath and
step away from the line for once.
In conclusion—
As a programmer, I risk being driven by my emotions
In conclusion—
As a programmer, I risk being driven by my emotions
as if by a storm at sea.
In conclusion—
As a programmer, I risk being driven by my emotions
as if by a storm at sea.
They can lead me to a comfortable harbor of
double-checked code, cosseted amongst many tests.
In conclusion—
As a programmer, I risk being driven by my emotions
as if by a storm at sea.
They can lead me to a comfortable harbor of
double-checked code, cosseted amongst many tests.
Or they can lead me to overly fragile systems
that bring my customers to shipwreck.
In conclusion—
Even as we are typing our code, we ride a knife’s edge
In conclusion—
Even as we are typing our code, we ride a knife’s edge
between code that fails or runs,
In conclusion—
Even as we are typing our code, we ride a knife’s edge
between code that fails or runs,
tests that are spotty or thorough,
In conclusion—
Even as we are typing our code, we ride a knife’s edge
between code that fails or runs,
tests that are spotty or thorough,
systems that are fragile or robust.
In conclusion—
Whether we strain to stay on one side of line,
In conclusion—
Whether we strain to stay on one side of line,
or are compulsive in probing and stepping across,
In conclusion—
Whether we strain to stay on one side of line,
or are compulsive in probing and stepping across,
it’s always there, right alongside us.
In conclusion—
Whether we strain to stay on one side of line,
or are compulsive in probing and stepping across,
it’s always there, right alongside us.
For by the very nature of our art,
In conclusion—
Whether we strain to stay on one side of line,
or are compulsive in probing and stepping across,
it’s always there, right alongside us.
For by the very nature of our art,
we programmers always, always, always
In conclusion—
Whether we strain to stay on one side of line,
or are compulsive in probing and stepping across,
it’s always there, right alongside us.
For by the very nature of our art,
we programmers always, always, always
are walking the line.
@brandon_rhodes
@brandon_rhodes@mastodon.social
https://rhodesmill.org/brandon/