Jun 9, 2013
A new way of testing
There's a combinatorial explosion at the heart of writing tests: the more
coarse-grained the test, the more possible code paths to test, and the harder
it gets to cover every corner case. In response, conventional wisdom is to
test behavior at as fine a granularity as possible. The customary divide
between 'unit' and 'integration' tests exists for this reason. Integration
tests operate on the external interface to a program, while unit tests
directly invoke different sub-components.
But such fine-grained tests have a limitation: they make it harder to move
function boundaries around, whether it's splitting a helper out of its
original call-site, or coalescing a helper function into its caller. Such
transformations quickly outgrow the build/refactor partition that is at the
heart of modern test-based development; you end up either creating functions
without tests, or throwing away tests for functions that don't exist anymore,
or manually stitching tests to a new call-site. All these operations are
error-prone and stress-inducing. Does this function need to be test-driven
from scratch? Am I losing something valuable in those obsolete tests? In
practice, the emphasis on alternating phases of building (writing tests) and
refactoring (holding tests unchanged) causes certain kinds of global
reorganization to never happen. In the face of gradually shifting requirements
and emphasis, codebases sink deeper and deeper into a locally optimum
architecture that often has more to do with historical reasons than thoughtful
design.
I've been experimenting with a new approach to keep the organization of code
more fluid, and to keep tests from ossifying it. Rather than pass in specific
inputs and make assertions on the outputs, I modify code to judiciously print
to a trace and make assertions on the trace at the end of a run. As a
result, tests no longer need call fine-grained helpers directly.
Read more →
* *
Nov 26, 2012
Software libraries don't have to suck
When I said that libraries suck, I wasn't being
precise.1 Libraries do lots of things
well. They allow programmers to quickly prototype new ideas. They allow names
to have multiple meanings based on context. They speed up incremental
recompiles, they allow programs on a system to share code pages in RAM. Back
in the desktop era, they were even units of commerce. All this is good.
What's not good is the expectation they all-too-frequently set with their
users: go ahead, use me in production without understanding me. This
expectation has ill-effects for both producers and consumers. Authors of
libraries prematurely freeze their interfaces in a futile effort to spare
their consumers inconvenience. Consumers of libraries have gotten trained to
think that they can outsource parts of their craft to others, and that waiting
for 'upstream' to fill some gap is better than hacking a solution yourself and
risking a fork. Both of these are bad ideas.
Read more →
* *
Nov 24, 2012
Comments in code: the more we write, the less we want to highlight
That's my immediate reaction watching these programmers argue
about what color their comments should be when reading code. It seems those
who write sparse comments want them to pop out of the screen, and those who
comment more heavily like to provide a background hum of human commentary
that's useful to read in certain contexts and otherwise easy to filter out.
Now that I think about it, this matches my experience. I've experienced good
codebases commented both sparsely and heavily. The longer I spend with a
sparsely-commented codebase, the more I cling to the comments it does have.
They act as landmarks, concise reminders of invariants. However, as I grow
familiar with a heavily-commented codebase I tend to skip past the comments.
Code is non-linear and can be read in lots of ways, with lots of different
questions in mind. Inevitably, narrative comments only answer some of those
questions and are a drag the rest of the time.
I'm reminded of one of Lincoln's famous quotes,
a fore-shadowing of the CAP theorem.
Comments can be either detailed or salient, never both.
Comments are versatile. Perhaps we need two kinds of comments that can be
colored differently. Are there still other uses for them?
Read more →
* *
Nov 12, 2012
Software libraries suck
Here's why, in a sentence: they promise to be abstractions, but they
end up becoming services. An abstraction frees you from thinking
about its internals every time you use it. A service allows you to never learn
its internals. A service is not an abstraction. It isn't 'abstracting' away
the details. Somebody else is thinking about the details so you can remain
ignorant.
Programmers manage abstraction boundaries, that's our stock in trade. Managing
them requires bouncing around on both sides of them. If you restrict yourself
to one side of an abstraction, you're limiting your growth as a programmer.1
You're chopping off your strength and potential, one lock of hair at a time,
and sacrificing it on the altar of convenience.
A library you're ignorant of is a risk you're exposed to, a now-quiet frontier
that may suddenly face assault from some bug when you're on a deadline and can
least afford the distraction. Better to take a day or week now, when things
are quiet, to save that hour of life-shortening stress when it really
matters.
Read more →
* *
Aug 1, 2012
Marx's engines of plenty
From "Red Plenty" by Francis Spufford:
The problem was that Marx had predicted the wrong revolution. He had said that
socialism would come, not in backward agricultural Russia, but in the most
developed and advanced industrial countries. Capitalism (he'd argued) created
misery, but it also created progress, and the revolution that was going to
liberate mankind from misery would only happen once capitalism had contributed
all the progress that it could, and all the misery too. At that point the
infrastructure for producing things would have attained a state of
near-perfection. At the same time, the search for higher profits would have
driven the wages of the working class down to near-destitution. It would be a
world of wonderful machines and ragged humans. When the contradiction became
unbearable, the workers would act. And paradise would quickly lie within their
grasp, because Marx expected that the victorious socialists of the future
would be able to pick up the whole completed apparatus of capitalism and carry
it forward into the new society, still humming, still prodigally producing.
There might be a need for a brief period of decisive government during the
transition to the new world of plenty, but the 'dictatorship of the
proletariat' Marx imagined was modelled on the 'dictatorships' of ancient
Rome, when the republic would now and again draft some respected citizen to
give orders in an emergency. The dictatorship of Cincinnatus lasted one day;
then, having extracted the Roman army from the mess it was in, he went back to
his plough. The dictatorship of the proletariat would presumably last a little
longer, perhaps a few years. And of course there would also be an opportunity
to improve on the sleek technology inherited from capitalism, now that society
as a whole was pulling the levers of the engines of plenty. But it wouldn't
take long. There'd be no need to build up productive capacity for the new
world. Capitalism had already done that. Very soon it would no longer be
necessary even to share out the rewards of work in proportion to how much work
people did. All the 'springs of co-operative wealth' would flow abundantly,
and anyone could have anything, or be anything. No wonder that Marx's pictures
of the society to come were so vague: it was going to be an idyll, a rather
soft-focus gentlemanly idyll, in which the inherited production lines whirring
away in the background allowed the humans in the foreground to play, 'to hunt
in the morning, fish in the afternoon, rear cattle in the evening, criticise
after dinner, just as I have a mind…'
Read more →
* *
Jul 4, 2012
Homesteading
“In the enthusiasm of our rapid mechanical
conquests we have overlooked some things. We have perhaps driven men into the
service of the machine, instead of building machinery for the service of man.
But could anything be more natural? So long as we were engaged in conquest,
our spirit was the spirit of conquerors. The time has now come when we must be
colonists, must make this house habitable which is still without
character.
”
Read more →
* *
Jun 18, 2012
How to use a profiler
All of us programmers have at some point tried to speed up a large program.
We remember "measure before optimizing" and profile it, and end up (a few
hours later) with something intimidating like this and… what
next? If you're like me, you scratch your head at the prospect of optimizing
StringAppend, and the call-graph seems to tell you what
you already know: Your program spends most of its time in the main loop,
divided between the main subtasks.
I used to imagine the optimization process like this:
- Run a profiler
- Select a hot spot
- ...
- Speedup!
But the details were hazy. Especially in step 3. Michael Abrash was clearly
doing a lot more than this. What was it?
Read more →
* *
Mar 14, 2012
The opposite of exponential backoff
Every few days I'm on IM with some coworker from a different building. The
conversation goes something like this:
Them: Lunch?
(6 minutes)
Me: Sounds good! Meet downstairs?
(1 minute)
Me: Now?
(2 minutes)
Them: Yes!
(1 minute)
Them: You there?
(3 minutes)
Me: Oops, sorry. Heading down now.
Now I never know whether to wait for a response, or to run down because I'm
already late. But today I finally figured out the answer:
Me: New rule. Head down when both of us say 'ready' within 1 minute of each
other.
That's it. No more ambiguity. It's kind of a silly example, but the general
idea feels deep, complementary somehow to
exponential
backoff. Exponential backoff is the ideal game-theoretic strategy for
competitive situations where two people need to contend for a common resource,
like trying to call someone back after a dropped call and getting a busy
signal. Both try to diverge away from a network-defined window of conflict by
waiting longer and longer. Here both parties are trying to converge into an
agreed window of agreement. Defining the size of the window by diktat should be
handy anytime two parties (people, computers, ..) need to cooperate
synchronously atop an asynchronous channel.
I'm sure there's a paper on this idea, perhaps something like that one by Lamport
pdf on Buridan's
ass. If you have a pointer I'd love to hear about it.
permalink
* *
Jul 14, 2011
Evolution of a rails programmer
Idiomatic rails action for registering a user if he doesn't exist:
After a year of programming in lisp, I find it most natural to write:
Is this overly concise/obfuscated? I like it because it concisely expresses
the error case as an early exit; most of the space is devoted to the
successful save, which is straight-line code without distracting branches.
It's clearer that we either pick an existing user or create a new one. Form
follows function.
Read more →
* *
May 12, 2011
My latest project
Two of us have been building
hackerstream, a real-time UI for
Hacker News that a dozen addicts
have been using since March.
This won't matter to you if you don't frequent HN, or even if you swing by
just once a day. But try it out if you go to HN every couple of hours like I
do. You'll see comments on all the stories on the entire HN frontpage as they
stream in. You can slice and dice the stream by story or by author. You can
even set it up to highlight, say, all comments by security guy Thomas Ptacek and
all comments about today's
silicon valley brouhaha. If you use Twitter the UI will seem familiar.
Is such a firehose useful? Is it too much of a good thing? I find I see more
of HN for the same time investment, and I waste less time scanning stories
I've already read. What's more, when I started using it I found my comments
getting more votes and more responses. It turns out the biggest factor
affecting responses is not how good my comment is but just how early it shows
up on a story. By biasing my reading to be more timely I was giving my few
comments improved odds of a response.
It's not for everyone, but hackerstream
is geared to help you have higher-quality conversation on Hacker News. Try it
out and tell me what you think.
permalink
* *