Influencing outcomes through output

Dear new developer,

“Outcomes over output” is one of my favorite letters on this blog. In it, Mark, a guest poster, talks about what business actually values (outcomes) over what developers often focus upon (outputs).

Outcomes are things like:

  • more sales
  • happier customers
  • publicity
  • less customer churn

Outputs, on the other hand, are things like:

  • more features
  • test coverage
  • flexible code
  • customer retention analytics

The reason that I focus on outputs is that is what I can control. Outcomes, except in rare cases, are outside of my control. For instance, at a startup a while back, I wrote a lot of code, but couldn’t control how the sales process was going. I felt whipsawed between building things as fast as I could when sales seemed to be happening at a snail’s pace.

It’s important to recognize that business, like life, is a long game. You are the result of choices you (and those who have influenced you) have made.

So, also, are the outcomes upon which you are judged in your career. To square this circle and relate outcomes to outputs as best as I can, I do the following:

  • Recognize the tension. All I can control are the outputs; I can only, at best, influence outcomes. But people pay for results, not for effort.
  • Find best practices. If others have completed tasks or created outputs which produced desired outcomes, learn about them. I don’t follow the same paths uncritically (cargo culting) but need to know about them to make informed choices.
  • Be methodical. When I choose to produce an output, make it good. How good depends on the audience and possible payoff: a script to load data once deserves less care than code that will be run thousands or millions of times. But, I strive to make anything I do excellent.
  • Find ways to incrementally improve outputs over time. These can include automated tools, checklists, and incorporating new practices. I can also choose to stop. This is a strategic choice that shouldn’t be considered every day; once in a while, though, I ask myself if I need to keep producing this output.
  • Experiment. Tweak outputs and see if the outcomes change. Sometimes this is easy and quick, other times I’ll need months to see changes. This requires patience.

What can you do if you are in a situation where the outcomes and the outputs are totally divorced from each other? Where your effort isn’t going have any effect on desired results?

That’s a tough place to be. I would feel ineffectual and frustrated. I think if you are in this situation, you need to sit down on a weekend and spend some time thinking about how you want to spend your life. Of course, there are valid reasons to hang tough:

  • Desired outcomes might be shifting
  • New outputs are being tested
  • Your role is changing

If that is the case, hang on if you can; sometimes a job is stormy but it is better afterwards and therefore worthwhile to see through. After all, outcomes aren’t just hard for you to influence, they are hard for everyone.

But if you do some thinking and find that your efforts have been disconnected from outcomes for a while, and that your nerves are frayed, change the situation. Whether that is leaving a job or moving to a different town, changes can reset your life. And hopefully put you in a position where your outputs are more in line with desired outcomes.



Always leave the code better than you found it

Dear new developer,

I’ve spent a lot of my time maintaining working code. I think that is more typical of software developers than working in greenfield development. Yes, there are definitely jobs where you are writing more new code than maintaining, upgrading, bug fixing and improving old code (startups without product market fit being one, consulting being another) but in general code is expensive and folks want to run it for a long time.

Often you’ll jump into code to fix a bug, investigate an issue or answer a question.

When you do so, improve it. This doesn’t mean you rewrite it, or upgrade all the libraries it depends on, or rename all the variables.

You don’t need to transform it.

But you should make it better. Just clean it up a bit. Doing so makes everyone’s lives just a bit better, helps the codebase in a sustainable way, and assists the business by making its supporting infrastructure more flexible.

What are some ways to improve the code when you are in it?


Whether that is a comment that explains something tricky, a larger piece of documentation external to the code which explains how to interact with it, or fixing a typo, trustworthy documentation is key to interacting with code. This is a good way to start improving a codebase because it has minimal impact on the actual code. Therefore it is low risk. But if you’ve ever had a great comment explain a confusing bit of code, you’ll appreciate the time this effort can save.

You can also help documentation by removing old, crufty docs. If you see a comment that doesn’t apply, remove it. If there’s cut and paste documentation which doesn’t apply, get rid of it. That cleans up the code for the next person to come along (who might be you).

Write a test or improve a test

Tests help you write maintainable, extensible code that others can change fearlessly. If you run across code that isn’t tested and you have time and the supporting framework to write one, do so.

Even if it tests simple functionality such as “can I instantiate this object” or “how does this function react when I pass it two null values”, an additional test will help the robustness of the code.

Refactor it

This is one of the most flexible improvements. Refactoring code can range from renaming a variable to be more true to its nature to an overhaul of an entire module. Start small and don’t get wrapped up in perfection. Make the code clearer in intent.

It’s easy with refactoring to get wound around an axle and make too many changes and end up with broken things. Timeboxing is one technique I use to avoid, or at least minimize, my tendencies toward this when refactoring. If all I have is 30 minutes, I’ll make my changes smaller in scope.

A warning about refactoring. Don’t refactor what you don’t understand. Don’t drive by refactor. Discuss your plan with someone more familiar with the code; git blame is your friend. Especially if the code is not well tested, you want to make sure you don’t do more harm than good.

Upgrade a dependency

It’s sometimes a winding path, but upgrading your dependencies regularly is a good way to maintain the code. I remember working in a fork of struts. It was an important application for the company, but we didn’t spend the time upgrading the dependencies, because it was too painful. Eventually, parts of the code became harder to update. The entire application couldn’t benefit from newer technologies and paradigms because of the older dependencies holding it back.

It never feels good to spend time updating a dependency; to me this always feels like running in place. But if you don’t do so, eventually dependencies will end of life and you’ll be forced to update. That’ll be even less pleasant.

How to do it

Based on feedback (this comment, among others), I added this section on Nov 28.

When you are making these changes to improve the code, you’ll help out code reviewers and your future self by making changes that are improving the code separate from changes that add functionality. Whether you do this in separate pull requests, tickets, or commits depends on your team culture. Ask about that. But such separation will make it easier for people who aren’t familiar with the changes to understand them and give feedback on them, whether that is a code review this week or someone reviewing this component two years from now.

Why do it

All of these actions not only help others because they improve the quality of the code, they also provide examples to other developers on how to do so. For example, it is far easier to write the second test in a suite than the first. You can cut and paste a lot of the setup code and tweak only what is different. The first bit of documentation will inspire more.

Code isn’t everything, but it is an important work output. Whenever you touch it, you should strive to leave it in a better place that it was before you did so.



Save off context

Dear new developer,

A key part of software development is being able to pick up where you left off. You are going to have interruptions during your day, and you want to be prepared for them. Whether you took a break to rest your eyes, stepped away for lunch or have left for the day, you’ll want to capture the context of whatever you were working on.

This is especially true if you are being interrupted in the middle of the day to help a teammate or go to a meeting. These tasks are crucial to being a good team member, but often halt progress on a technical problem.

We all have to handle this type of timeslicing, but it can be difficult to remember where we were just before we stopped. Oftentimes if you are building or debugging something, you need to remember many small bits of knowledge: how pieces of a system fit together, what that blog post recommended, what tasks remain to be done.

When someone says “Hey, gotta sec?” a lot of this knowledge gets evicted from my short term memory.

It’s worth taking a minute or two and capturing the most important pieces of information so that when you return to the task, you can jog your memory easily.

The first thing I do is prepare to make time for this. If a co-worker pings me on slack to see if I have a second, I’ll reply when I see it with “sure, give me a few minutes, please”. Side note, I am a big believer in turning off notifications for slack, email and anything else. I always provide my teammates with my cellphone number and ask that if there’s anything urgent, they contact me there. (Haven’t been called yet.)

When you know an interruption is impending, plan for a context recording buffer. For example, if I have a meeting scheduled, a few minutes before the meeting, I’ll stop what I’m doing to capture the context.

Next, use that time to record what you’ll need to pick the task back up. I like to do this in a few different ways. I sometimes write things down in a paper notebook. This is great because it is free form, portable, works when I’m away from the computer, and quick. However, my handwriting is atrocious and I’ve definitely peered at notes I’ve written trying to decipher them.

I’ll also open up a text document and write down a couple of lines of context. These could be tasks I need to undertake, something I need to research, someone I need to talk to, or something I know is half working and needs to be looked at. I often do these in standalone files, but have also put them in comments in the code as well. I usually save these off, just in case my computer crashes. I could do this in a Google doc or slack message to myself, but find that a local text file is durable enough.

You can also capture this context in a more formal manner, by writing a failing test. That way, when you return to the problem, you can re-run your tests and move right to the work in progress. This is great if you are in the middle of code, but doesn’t work so well for other types of knowledge.

Another formal way to capture the context of whatever task you are doing is to use a checklist. Write it initially, modify it as the task progresses, and keep your progress up to date. If this is a complicated, multi day task, I’ve found a checklist to be useful, but if it’s an hour long task, I find the overhead of keeping the checklist up to date outweighs the benefit I receive.

These notes, by the way, aren’t designed to be your knowledge base. They don’t need to be authoritative. You aren’t going to consult this later. This isn’t full fledged documentation, these are scrawled notes which will be tossed as soon as you pick the task back up. So don’t stress over capturing everything in a way that someone else could use. Doing so will take too long for the value you’ll get.

Now that the context of your current task is saved off somewhere more durable than your poor neurons, take care of the interruption. Help that teammate. Go take that walk. Attend that meeting. Head home for dinner.

When you return, whether in 15 minutes or after a week vacation, return to the flow as soon as you can.

Re-read your notes, re-run your tests, review your checklist. And get back to it.



Create Value for People

This is a guest post from Minh Pham. Enjoy.

Dear new developer,

I want to start off by saying Congrats and Good job. If you’re reading this, it’s likely you know how to code – and even if you’re still working on getting that first job, that means you have one of the most desirable skill sets in the world today. I congratulate you because getting here took work. You weren’t born with this knowledge, and even if you felt like it came naturally, it was still a journey of discovery, learning, and practice that got you where you are today.

As you look towards your first job – I want to offer you a single piece of advice that may act as your career’s guiding north star:

Create Value for People.

When you have the power to create anything, you begin to realize the importance isn’t on the code you’re writing but rather why you’re writing it in the first place. What value are you creating through your skill? This is why companies hire people like yourself. They are seeking out individuals who can ultimately deliver value to their customers, particularly through software. As you mature, you will realize that much of engineering has little to do with how fancy your solution is, and instead has everything to do with what problem it solves for the user. Once you accept this, you’ll begin to see that discussions of tech choice and code structure rarely matters outside the context of what business value it represents.

This is where your focus should stay.

Obsessions with patterns and algorithms don’t serve anyone’s mission by themselves. Ignore the constant pressure to assert yourself through syntactic cleverness and obscure trivia. These things don’t matter. These things don’t drive value for anyone. No matter how many “experienced” engineers tell you these are important, I promise you no company hires people simply for them to recite principles and algorithms.

While coding might be your latest skill set, it is by no means an engineer’s only skillset. Remember that at the end of the day, it doesn’t matter if your code is ugly, fancy, verbose or concise – the value you create matters. Strive to be an excellent communicator, a quality teammate, and an outstanding human. These attributes will guide your engineering efforts to ensure you bring value.

No matter where your career goes, if you focus on creating value for people, opportunities will never be in short supply. Desire for specific skills may rise and fall, but people will always look to those who can create value.

With that, I wish you the best of luck and may our journeys cross again,

Minh Pham

Minh Pham believes you should lead how you want to be led. This has been the guiding principle of his career since he started. As an Engineer, he always wished he had someone who would guide him – telling him what’s important, what he has to work on, and what he should ignore. Having gone through all that and then some, Minh now looks to be the positive influence he wishes he had.

As a manager, Minh’s greatest passion was teaching people the skills to create and drive the careers they want to have. Now as a career coach, he works to show people they have the power to build the life they want.

Minh believes anyone can do it – and he promises it doesn’t involve linked lists or graph traversals.

How to say I don’t know

Dear new developer,

The honest truth is that you won’t know everything. No one does. The CEO, CTO, the team lead, that really smart senior developer on your team, none of them know everything. In fact, I bet if you asked any one of them if they’d been stymied in the past week, they’d reveal that yes, they ran into something they didn’t know how to do or how to approach.

Encyclopedic knowledge isn’t a good goal. You need to know how to figure things out. But when someone asks you “can you do X?”, you need to be prepared with the right answer, even if you don’t know how to do X. For example, I was tasked with setting up a static IP for a heroku application. I didn’t know how to do this. Rather than say “I don’t know how to do that”, I said “let me do some research and get back to you.” I also asked about deadlines and how high a priority this was.

I did some research, read some docs and came up with a proposed solution. I discussed it at standup with my team, including my boss, and we came up with a path toward implementation.

When you don’t know something, and someone asks you about it, there are a few things you must do.

First, you should tell them you don’t know. They might have some clues for you, or pointers to documentation. These can all accelerate your ability to do what is asked of you.

Depending on the situation, they may assume you know, based on their experience. For example, I work in the authentication space right now, with standards like OAuth and OIDC. When I first started, I had to ask what every piece of jargon meant, but after a few months I got up to speed. Now when I talk to other audiences, I need to be careful not to use too much jargon or assume what others know. One favorite technique I use is repeating back what someone said: “Can I repeat back to you what said to make sure I understand it? What I heard is that the OAuth code grant redirects to the client application after the user authenticates. Is that right?”

When you say “I don’t know” don’t stop there. Say “I don’t know, but I’ll find out.” Again, they may point you in a direction, but by adding that second clause, you indicate that you’ll solve this problem. You should also ask about timeline and priority if that hasn’t been communicated (by story points, a task tracker or in some other fashion).

Finally, do what you say you’re going to do. Find out what you didn’t know. Don’t be afraid to ask questions of your team members, spend time on the internet searching, set up your dev environment and tweak settings, brainstorm, get frustrated, and write down hypotheses that you can test out. All of these are techniques I’ve used in trying to figure things out.

Saying I don’t know, honestly, with a plan to remedy your ignorance, is a key part of being a software developer.