Stories focus on the why, sharing the experience and context around the decision and results.
Stories also eliminate most of the least productive follow-up conversations after giving advice, where the advice-requester then argues against the advice. Stories relieve the advice-giver from the obligation to defend their advice. There’s nothing to agree or disagree with, just a recounting of past events.
Every line of code written comes at a price: maintenance. To avoid paying for a lot of code, we build reusable software. The problem with code re-use is that it gets in the way of changing your mind later on.
Building reusable code is something that’s easier to do in hindsight with a couple of examples of use in the code base, than foresight of ones you might want later.
(we look at) how to handle writes to two independent backends without using two-phase commits. Instead we can rely on using at-least-once delivery guarantees and ask other systems to deduplicate our messages.
Kent Beck comparing baskets of options to product roadmaps and goals:
I’ve come to hate the damage the “product roadmap” metaphor does to the brains of everyone involved in developing a product. When I use an actual map of actual roads, I assume that I know where I’m going and how I’m going to get there. This is never the case when developing a product.
When you encounter long lead times, you’re hearing option-on-a-basket thinking. “We need to know what features will be in the release in 8 months so Marketing has time to prepare.” What if product development doesn’t go according to plan? The value of the option on a basket falls to zero. What if the launch doesn’t come off? The value of the option on a basket falls to zero.
I read the majority of my books on my Kindle. The Kindle’s convenience is pretty hard to beat and I enjoy its highlighting and note-taking features.
With that said, I find I miss the context that a physical book provides. It’s much easier to breezily flick around a physical book to find previous sections you’ve read or peek ahead to see what’s coming up.
Recently I fired up the Kindle for Mac and found that I can get better context and a view of my highlights all at once. Open it up in widescreen, open the contents and notes and highlights sidebars, and boom baby, you can see a summary of where you are in the table of contents and what passages you’ve highlighted or bookmarked on the right.
I find this arrangement particularly helpful when reviewing a book I’ve previously read. Have a crack yourself, see if you like it.
it’s actually an unqualified good for engineers to be interacting with production on a daily basis, observing the code they wrote as it interacts with infrastructure and users in ways they could never have predicted.
A system’s resilience is not defined by its lack of errors; it’s defined by its ability to survive many, many, many errors. We build systems that are friendlier to humans and users alike not by decreasing our tolerance for errors, but by increasing it. Failure is not to be feared. Failure is to be embraced, practiced, and made your good friend.
When people have divided attention, work suffers. The area of code that you work for months is something that you understand deeply. The framework, off to the side, that you update just to facilitate your work may not seem as important. This is a function of distance: cognitive, temporal, and locational distance. In a way, these are all the same.
The cliché “celebrating failure” misses the point—we should be celebrating learning, not failure.
Without discipline, almost anything can be justified as an experiment. Discipline-oriented cultures select experiments carefully on the basis of their potential learning value, and they design them rigorously to yield as much information as possible relative to the costs.
The first step is acknowledging that our relationship is more important than the design of the system. As long as we have a productive working relationship we can move the design in any direction. When our relationship breaks down we don’t get anywhere.
Okay, so you just want to go implement the next feature and along I come and say no no no this should be designed completely differently. Even if you are right that the new structure will eventually make my behavior changes easier to implement it’s not eventually, it’s today.
First, acknowledge that our incentives diverge in this moment. It doesn’t help to pretend that we agree when we don’t.
Second, as the structure changer I need to acknowledge that I am placing a burden of learning on you. I think it’s worth it, but if I’m asking something of you I better be prepared to offer something to you.
Software design is a human relationship problem with interesting technical aspects. Geeks relating to geeks requires as much effort as geeks relating to their systems. Maintaining relationships may be hard and confusing and frustrating to geeks (I could be projecting here but yeah no I don’t think I am), but if you want your technical skills to matter you really have no choice but to improving your people skills.
We couldn’t just start replacing old code with new code willy-nilly; without some type of structure to keep the old and new code separate, they’d end up getting hopelessly tangled together and we’d never have our modern codebase. To solve this problem, we introduced a few rules and functions in a concept called legacy-interop:
old code cannot directly import new code: only new code that has been “exported” for use by the old code is available
new code cannot directly import old code: only old code that has been “adapted” for use by modern code is available.
The progressive approach to the rebuild is interesting. Especially the rules that enforced how the rewritten parts of the code base could interact with the old code they were ultimately replacing.
I often say that with knowledge workers, the biggest bottleneck is always getting up in the morning. Knowledge work requires not only our time and effort, but also our engagement and creativity. For that reason, personal motivation is the prime problem that supersedes all other problems.
Rough consensus relies on the distinction between two types of objections:
“Not the best choice” feedback: “I don’t believe Solution A is the best choice, because XYZ. I believe Solution B would be better, but I accept that Solution A can work too.”
Fundamental flaws: “I believe Solution A is unacceptable because XYZ.”
A chair who asks, “Is everyone OK with choice A?” is going to get objections. But a chair who asks, “Can anyone not live with choice A?” is more likely to only hear from folks who think that choice A is impossible to engineer given some constraints. The objector might convince the rest of the group that the objections are valid and the working group might choose a different path.
There are a handful of web pages that I use regularly throughout the day. Some are web apps that I keep pinned in Chrome while others come and go as I work.
I tend to close tabs when I’m done with them but I still end up with many open tabs. I’ve created an Alfred Workflow that opens a page I’m looking for so I don’t have to pick through my Chrome tabs by hand to find it.
The Find Page workflow takes a URL from a predefined list, runs an AppleScript that finds and activates the associated page if it’s already open in Chrome, otherwise it opens it in a new tab.
In my very first programming role my manager said to me “You can make any mistake you like once. You’ll have my full support the first time you screw anything up. If you’re not making mistakes, you’re not learning, and if you’re repeating mistakes you aren’t either”.
In order to succeed at production ownership, a team needs a roadmap for developing the necessary skills to run production systems. We don’t just need production ownership; we also need production excellence. Production excellence is a teachable set of skills that teams can use to adapt to changing circumstances with confidence. It requires changes to people, culture, and process rather than only tooling.
Even a perfect set of SLOs and instrumentation for observability do not necessarily result in a sustainable system. People are required to debug and run systems. Nobody is born knowing how to debug, so every engineer must learn that at some point. As systems and techniques evolve, everyone needs to continually update with new insights.
Standardizing technology is a powerful way to create leverage: improve tooling a bit and every engineer will get more productive. Adopting superior technology is, in the long run, an even more powerful force, with successes compounding over time. The tradeoffs and timing between standardizing on what works, exploring for superior technology, and supporting adoption of superior technology are at the core of engineering strategy.
An effective approach is to prioritize standardization, while explicitly pursuing a bounded number of explorations that are pre-validated to offer a minimum of an order of magnitude improvement over the current standard.
Ideas are funny things. It can take hours or days or months of noodling on a concept before you’re even able to start putting your thoughts into a shape that others will understand. And by then, you’ve explored the contours of the problem space enough that the end result of your noodling doesn’t seem interesting anymore: it seems obvious.
But as you get into more senior-type engineering roles, your most valuable contributions start to take the form not of concrete labor, but of conceptual labor. You’re able to draw on a rich mental library of abstractions, synthesizing and analyzing concepts in a way that only someone with your experience can do.