Here’s a nice story on technology that isn’t startups: Unhappy truckers and other algorithmic problems. Logistic networks are a technology, just like smartphones. They make our world way better, but they do so invisibly and at a slower pace than the churn of mobile apps, web frameworks, and startups. But they’re still solving problems, moving the needle. They’re just, possibly, less obsessed with technology tribalism and fashion. Some days, that seems like a pretty useful space to find oneself in.
It wasn’t too long ago that other developers not knowing the things I know was really frustrating. “How could they not know this?!” I thought that I didn’t have time nor should I be expected to train other developers. If I could learn all this stuff, they can too.
At some point, my perspective on this did a complete turnaround. Now I’m eager to teach other developers things I don’t know. The major benefit is, now they know the things I know! A side benefit is now I know the thing better because I had to teach it.
I was completely wrong when I thought I didn’t have time to teach. Turns out, I don’t have time to not teach other developers the things I think are important.
Overtime is Morphine, Ernie Miller:
A developer who is truly concerned about the health of his or her company also must be careful to ensure the “patient” isn’t developing an unhealthy dependency on their heroics, allowing the company to limp along without experiencing the pain that should accompany unwise choices. Pain is how we learn to avoid repeating mistakes.
I’ve seen too many developers put in a heroic effort, only to repeat it the next day, sometimes without sleeping in. That’s “killing the patient”, to extend Ernie’s metaphor. It’s not the natural state of a business to notice the human cost it might have. The people inside the business have to assess that cost and do something about controlling it.
If your business, or the one you work at, requires regular heroics, consider that it is a broken system. Luckily, software developers are well equipped with mental routines for diagnosing and patching broken systems. Time to hack the organization.
The Scala folks are building newer, better cities on top of older cities, which is how things really work (e.g. Paris, Rome, Boston, etc.). The Clojure folks are building Dyson spheres in space, which is a little ambitious and maybe not entirely realistic.
That said, sometimes wouldn’t you rather live in a sci-fi fantasy world rather than on top of layer after layer of archaeology?
When software becomes successful, software often becomes large. More features, more support systems, more infrastructure, more people, etc. Therefore, software “in the large” seems like a good problem to solve: how can you work at the same pace with one person, one application, and one server when you reach a hundred people, ten applications and a thousand servers?
Right now, I think the only tool we have for reducing the overhead of large systems and organizations is language. Frameworks and libraries can help make larger applications plausible, but they don’t resist the forces that make a large application hard to work with. Tooling and process, like source control or CI, only help us keep large software going; they don’t slow us down on the path to producing huge software.
Better programming languages make it possible to produce software that does more things in a more concise statement. To some extent better “API language” makes that possible too, but it relies on the power of the host language.
Am I overlooking other tools that make software in the large a manageable endeavor?
Developers should care and feed for their systems, especially when they’re in production. Alerting, logging, and metrics are the tools you need. Further, you need to use actual production errors as a feedback loop to push you to write more fault tolerant code.
I’ve struggled with that part in the past. It’s tempting to think I can just code along, building beautiful code. Beautiful code is entirely different from production code. Handling errors, timeouts, partial failures, logging, instrumentation: it’s not exactly design pattern stuff. To wit:
Fault-tolerant code is ugly. It requires conditionals. It won’t look like code in programming books, screencasts, or blog entries. This is the way it has to be, I’m sorry.
Production is all that matters. Highly intelligent words from Dave Copeland. The beauty of code, as it appears in my text editor, is not as important as how it works when it runs on servers. New mantra!
Yesterday, I wanted to setup a quick feedback loop for writing some production code. But, I wasn’t entirely sure what that code should look like. Further, I hadn’t worked in the code base for several months, so I wasn’t sure how the new code would need to interact with other objects.
This is a scenario that often gets me in trouble. I end up spending too much time contemplating how things might be without the feedback of what’s possible and plausible.
What I ended up doing:
- Start a new test case for the code. I hardly know what it should do, so I ended up with
it "should do things".
- Write the kind of code I would run in a REPL to get started writing the production code. This was a service client, so I did things like setup a connection, invoke a request, and handle a response.
- Write a test assertion about what I think the side-effect or result of the production code should be. For this service client, I wanted to make sure a useful thing was returned.
- Run the test, see it fail, learn some things about the REPL-y code I wrote. Since I’m writing Ruby, my feedback rate goes way up here. Running a single test, which I can do with a keystroke in my editor, is way faster than switching over to an IRB, reloading code, and finding the right incantation to run again.
- Iterate on the code in the test case until I have something that passes. Think, type, feedback. Observe, orient, decide, act. Coding is fun.
- Once I have passing code, start rearranging so its closer to what I want as actual production code. Replace dummy values with real ones. Figure out how to remove any cheats I may have put in place for expediency.
- Once I know what the messages are, extract them into helper methods on the test case class. Now I’m starting to do actual design. After each change, I run the tests. If I break the test, I go back and fix it before I proceed. This is Legitimate Refactoring. Feels good.
- Once I know what the objects are, I go ahead and create their file in the production code, move the code out of the test and into the production code, and make sure the original test still passes. Now I switch back to a more typical test-driven design cycle; write a test case, watch it fail, make it pass, refactor, repeat.
This is sort of like the Saff Squeeze, but for exploratory coding rather than defect isolation. It kept me from spinning my wheels on design and organization before I even knew what the forces are that affect said design and organization. It also makes a new, strange, or messy code base less intimidating; I can incrementally integrate with the existing code as I’m ready to dive further into it.
Give this a try some time. It’s a great confidence booster.
How Shopify scales Rails was one of my favorite talks at Big Ruby. Therein, John Duff talks through what Shopify’s Rails stack looks like and why it works for them. What impressed me most was that Shopify has been running basically the same stack since they started. Ruby, Rails, MySQL, Memcached. They added Redis in for queuing at one point.
I’m so easily tempted and fascinated by The New Shiny, it’s refreshing to read about a shop getting by with The Old Trusted instead. There’s a lot to be said for using solid, well-known tools for as much as you can and working with the strengths and weaknesses those tools afford you. It’s a lot closer to craftsmanship than the temptation of science fiction New Shiny tools, and less likely to turn your guts inside out when something goes sideways.
Pet peeve 74: whenever I slip and focus on complaining about who and what instead of thinking about how and why to solve the problem. This is doubly frustrating because I enjoy solving puzzles (i.e. problems) more than I enjoy annoying people.
It’s so, so easy to kvetch. It feels good. But, it’s so much more useful to figure out why the problem happened and how to solve it or break the problem done to solvable subproblems.
Being human: it’s tricky.
Today’s the hundredth anniversary of premier of hometown favorite Igor Stravinsky’s Rite of Spring. The National Public Radios are all over this. NPR Music and WQXR are collecting a bunch of articles they’ve done in the run-up to the anniversary. My favorites: a visualization of the score and a list of essential recordings. The latter features this amazing image of Stravinsky, which I’ve already posted twice today and will continue posting it until it just doesn’t feel right anymore.
If you’re playing along today, WQXR is streaming twenty-four hours of nothing but the Rite. Highly recommended, if you have the means.