Programmers and Hand-Pulled Noodles
Making hand-pulled noodles is backbreaking work. A programmer who can make good hand-pulled noodles won’t write bad code either.
Charting the Recipe
Before you start, you need either a cookbook at hand or a recipe in your head. You can “see” and “smell” the dish that hasn’t taken shape yet: what color it will be, how much sauce it will hold — as though it were already at your lips, beckoning. Before you write a program, your recipe is your design: you know the goals and non-goals clearly, and you know exactly what the program will look like the moment it’s finished. Reading a recipe is hard work — you have to grasp the author’s intent, know the tools and ingredients required, and plan the order of operations so that execution flows in one unbroken breath. Design is hard work too: you simulate it again and again on paper, work it out in your chest, so that when the real writing begins you can move as the old texts describe — “where the hand touches, the shoulder leans, the foot treads, the knee presses; hiss and whir, the blade sings, and every sound falls in tune.”
Gathering the Ingredients
The ingredients for hand-pulled noodles are fiddly: the noodles come from flour and water; the toppings are tomato, green pepper, onion, and carrot; the aromatics are ginger, garlic, and raisins; and of course you can’t do without oil, salt, soy sauce, and vinegar. All of these are prepared by someone else and handed to you, plug-and-play — otherwise you’d have to grow your own wheat and mill your own flour just to make a plate of noodles, and life would be unlivable. Writing software is the same: it runs on an ecosystem. However brilliant a programmer is, without the support of libraries — without the raw materials in place — they can’t write code more, faster, better, and cheaper.
While gathering ingredients, you have to think about the schedule. The customer is waiting with mouth agape — you can’t hole up in the kitchen studying ingredients for three or five hours. At that point, even if you’re a master noodle-maker, you have to swallow the urge to knead dough and go buy a decent package of hand-rolled noodles from the supermarket. People in the noodle world are shrewd and decisive; their eyes are fixed on how the goal gets done, so they favor ready-made ingredients. People in the programming world are single-tracked, always convinced they’re the best, leaking pride at the drop of a hat, and picking fights with themselves: no onion (library)? Grow your own. Or even with an onion at hand, if it doesn’t look good, insist on making a new one from scratch — dignified with the name “reinventing the wheel.” So a veteran who has actually made noodles will think about integrating third-party tools when writing code, and will never insist on building everything in-house.
Of course, hand-rolled noodles aren’t always on sale, and then you have to make them yourself. But there are two ways to do it: give a fish, or teach to fish. The first is present-focused, solving a concrete problem — kneading and pulling dough entirely by hand. The second looks to the future: buy a dough mixer and a pasta roller, follow the instructions, and you’re set for good. Writing software is the same: you have to decide whether to treat the special case specially, or to abstract the special case into a machine (or buy one) that handles this whole class of problems. To build, or not to build, this is a question.
Getting to Work
The ingredients are ready; next comes the work. Making hand-pulled noodles is the grand process of turning hand-rolled dough into steaming-hot noodles, transforming a pile of ingredients into fragrant toppings, and then combining the two. Going from raw materials to finished dish requires a whole series of transformations; writing a program means completing a system, turning inputs into outputs through a whole series of transformations.
Look: chopping vegetables is a map. Carrot after carrot, green pepper after green pepper, gets mapped by a process called “rolling cut” or “push cut” into piles of diced carrot and shredded pepper — which then, together with beef and onion mapped into strips and tomatoes mapped into chunks, enter the wok one after another to undergo reduce.
Yes — stir-frying is a reduce. Ingredient after ingredient, alone or in combination, gets reduced by a process called “stir-fry,” “flash-fry,” or “braise” into one semi-finished dish after another; and finally these semi-finished dishes are transduced into the topping and, together with the cooked noodles, flatMapped into plate after plate of the hand-pulled noodles everyone loves.
Writing software is even more so. map / filter / reduce — basically, 90% of your code is doing something in this family.
Work shouldn’t be brute force; you need a pipeline to get twice the result with half the effort: when to chop vegetables, when to cut meat, when to add oil, bloom the Sichuan pepper, drop in the minced ginger and onion, when to stir-fry the meat, when the green peppers, when to boil water and drop in the noodles. You would never wait until the dish is fully cooked before putting water on to boil: standing at the stove, you spin up two processes — one handling the wok, one handling the pot — each with its own pipeline, converging at a single point (thread.join). Each process has its own fixed priority (while the water is boiling, stir-frying is highest priority), but sudden events (the water boils, the water is about to spill over) can preempt your processing capacity.
Writing software is the same: a program is essentially one big pipeline that decomposes into a series of smaller pipelines, piped onward again and again, until the CPU takes each instruction and drops it into its own pipeline to execute. Pipelines must synchronize with one another, and you can do that with locks, callbacks, CSP, actors, and so on.
Exceptions
Whether cooking or coding, you always have to face exception handling. A hapless chef is forever cutting their hand, scalding themselves with boiling water, burning themselves on the flame. When such an exception occurs, if you can’t calmly suspend the current process (turn off the flame, say) and instead flail about handling it, the consequences only grow. When writing software, if you don’t have the courage to let it crash (Erlang), you’d better handle exceptions obediently and airtight — otherwise the exception bubbles up layer by layer and finally hands you an error with no rhyme or reason that you can’t even begin to fix.
Requirement Changes
Annoying requirement changes rarely plague you when making hand-pulled noodles. If a customer says, when your dish is two-thirds done, “Oppa, I don’t like green peppers — could you swap in chili peppers?” — even if she were an empress of the highest station, you could shoot back: “You should’ve said so earlier. It is what it is. Eat it or leave it.”
Occasionally, though, a brat runs into the kitchen and demands you spin a top for her. This kind of small scope-creeping requirement change devours the project’s schedule and pushes back the moment the noodles come off the stove.
Talent and Effort
Finally, a word on talent. Making hand-pulled noodles doesn’t require much talent, just as writing code doesn’t require much talent. More than talent, the two demand hard practice, seasoned with enough thinking, until you grope your way into the knack — the so-called Way — and then you can do as you please. Just as Cook Ding told Lord Wenhui:
What I care about is the Way, which goes beyond skill. When I first began cutting up oxen, all I saw was the ox itself. After three years, I no longer saw the whole ox. And now — now I meet it with my spirit and do not look with my eyes. Perception and understanding have come to a stop, and spirit moves where it wants. I follow the natural grain, strike into the big hollows, guide the blade through the great openings, and go by things as they are.