The Imposters Roadmap - Rob Conery
The Imposters Roadmap - Rob Conery
ROB CONERY
The Imposter’s Roadmap
A guide for self-taught programmers to building your career in the tech industry.
ROB CONERY
All rights reserved. No part of this publication may be reproduced, distributed, or transmitted in any
form or by any means, including photocopying, recording, or other electronic or mechanical methods,
without the prior written permission of the publisher, except in the case of brief quotations embodied
in critical reviews and certain other noncommercial uses permitted by copyright law. For permission
requests, write to the publisher, addressed "Attention: Rob," at the address below.
Foreword v
Preface vii
Introduction xiii
PART ONE
PREPARATION
1. Your Career Journal 3
Keeping receipts, keeping your job
2. Essential Soft Skills 46
Because you will need to work with other people
3. Leading Your Team 69
You can change someone’s life and career with your actions
4. Simple Tools For Managing Projects 119
A look at tools and services for handling the details
5. Principles of Interface Design 160
Adding some polish can make all the difference
6. Creating User Stories 186
This Agile practice can help keep you focused on what’s important
7. Software Project Management Basics 207
Getting to know Agile and it’s various flavors
8. The First Sprint: Your Prototype 231
Action is the name of the game - get something in front of your boss or client
9. Summary: Buckle up 269
Shipping is winning; shipping gets you noticed
PART TWO
DEVELOPMENT
10. A Brief Review of Git 275
You will likely be using Git to manage your source control, so let’s have a
quick review
11. Flexing Git and GitHub 289
Your source history tells a story, let’s make it a good one
12. Trunk-based Development 323
When process gets in the way, throw it all out
13. Building Things Using Containers 338
Docker is essential to understand if you’re going to lead a team
14. Simple Container Orchestration 371
Digging in to Docker Compose
15. Formalizing Our Container Strategy 399
Commonly known as DevOps, this is where things get interesting
16. Kubernetes 423
A critical tool to understand so you can make someone else do it
17. Architectural Approaches 457
The structure of your application impacts more than you realize
18. Testing Strategies 499
Unit, Behavioral, Integration, User Acceptance, and Exploratory
19. Debugging 545
A wonderful skill to master
20. Congrats on Your MVP! 558
You’re in the spotlight now, friendo
PART THREE
DELIVERY
21. What It Means to Ship 571
We love shipping, but we don’t love the politics that come with it
22. The Build 586
Formalizing a critical process
23. Adding Features, Fixing Things 616
Change is the hardest part of any application lifetime
24. Code Reviews 639
In which we get to flex our people skills for great good
25. Oh, Right, Documentation 665
No one likes creating documentation, but when it’s done well, you’re a hero
26. Monitoring 699
Knowing what’s happening when so you can avoid problems
27. We’re Gonna Need a Bigger Boat 732
The art and science of scaling an your application
28. A Loud Bang, Then Silence 770
Creating a Disaster Plan for when things go very badly
29. Reporting, Once Again 790
Understanding how good data can save your job
30. And Here We Are 819
Go make some magic happen
FOREWORD
I'm telling you this for the same reason that Rob wrote the book.
Because it's important that you know that you're not alone. We're all
just doing our best and we are all just making it up as we go along.
Very rarely is there a plan. You can go to Instagram reels you'll find out
that the algorithm is designed to make you feel bad about yourself,
and all of the Hustle Culture Bros ( ) will tell you that the reason
that you're not successful is because you're not getting up at 5:00 in
the morning to do burpees. That’s not why.
vi FOREWORD
Imposters Unite!
Scott Hanselman
I have screwed up, a lot. You will screw up too, and that’s OK because
this is how we learn and grow. Don’t be afraid to fail because it will
happen. It’s how you fail that counts.
ABOUT ME
I’ve never met you, most likely, so I have to make a few assumptions.
This is dangerous ground given our social, cultural, and many other
backgrounds. Yet, we’re both working in the tech industry, so with
that, we share common ground.
That common ground is where I hope to plant the seeds in this book.
viii PREFACE
There are a few things you’re about to read that you’re going to find
challenging, especially in what people consider socially acceptable. Yet,
I would ask you to suspend your judgment until each chapter has
concluded because, you see, we live in a world of massive
contradiction between what we say publicly and what we think (and
sometimes do) privately.
Our private thoughts drive us, while our external presentation is what
allows us to execute that drive. For some people, it’s important to
align the two and present themselves exactly as they feel on the
inside. These people are exceedingly difficult to get along with.
What I’m trying to say is this: You will be playing a game and learning the
art of mastering perception. I know. It sounds duplicitous and slimy,
and you’re probably wondering if I’ve “flipped the Bozo bit” and about
to go off on some rant about contrails.
Yet, that’s what leadership is. As Martin Luther King Jr. once said:
As with so many things in life, the idea of taking a step forward into a
leadership position means that you believe you can actually lead, or, at
the very least, that you want to lead, and you have faith that you can
do things better than the person who’s leading you now.
Politics, innit.
If you’re going to move into a lead position, you will need to believe in
yourself and that you’re the wonderful person you are (hopefully). You
are, aren’t you? I have a feeling that, given this book’s title, you’re not
an egotistical ass that believes the position is yours for the taking.
I’m also going to assume you’re a good person, which means you
might struggle with the soft skills chapter, where I dig in to
x PREFACE
For some, that works. For others, not so much. By learning about the
“dark arts” of office politics, you can avoid quite a few clumsy
attempts to derail your project by unscrupulous scumbags. Don’t
avoid learning about these things — they can save your ass.
I do hope you read this book with an open mind, and if something
strikes you as challenging, try to see both the good, and the bad that
come with it. That’s one of the skills you’ll need to learn as you move
along.
If you do, and you feel like helping out, I have a GitHub repository
where I track the issues. If you have a general question, maybe email
me first. If you find a grammar problem, or you disagree with
something I’ve said, an issue would be super helpful. I’ll have some
templates in there as well, to help things along.
As I fix the issues that come in, I’ll push out a book update. When I
do, I’ll be sure to let you know.
RESOURCES
I use images throughout this book, some of them are for code
samples. The reason I use images for code is that I find that publishing
tools are horrible at rendering these things properly. I’ve tried just
about every tool out there, but I always come back to images because
they’re easy to read.
PREFACE xi
To that end, I have a code repository where you can download all the
code in this book, which is right here.
I also have several online courses that I’ve put together over the years
that you might find interesting:
I used to blog a lot, but I find that having a newsletter is more fun. It’s
the same idea, but you don’t need an RSS feed. I don’t send out
marketing stuff, and if you’re interested in reading about what I’m
learning, you can do so right here.
xii PREFACE
OK, off we go!
INTRODUCTION
same time there might be a solid leader inside you that just needs a
kick in the pants.
I assume you’re reading this book because you want more out of your
career. More challenges, more recognition, more meaning and, likely,
more money. Probably all of the above. If this is you, please embrace
these motives. These desires are human and the people who accept
that fact are usually the ones who end up in leadership positions,
which, I assume, is what you want because that’s what this book is all
about: helping you navigate into a leadership position.
DELIVERY IS A DRUG
There is nothing, nothing better than delivering a result on time and
exceeding the client’s expectations. The road may have been rough
getting there, but a successful launch will make everyone forget all of
that and you’ll be a hero.
Well, as we know, no software works perfectly the first time, does it?
As delivery neared, Brian, Dave and I would talk daily. We would go
over the demo that Brian was to give with Ballmer, and make sure it
all worked.
We found bugs, Dave and Brian freaked out, I fixed the bugs, rinse,
and repeat. Some of these meetings got tense, but I held my tongue
(for the most part), wrote things down and kept saying “trust me, I
got this”.
Execution and gravity have a lot in common: they draw people and
interest to you and you can get crushed if you’re not careful.
Reality, alas, is thick with nonsense. Once you start to truly execute
and actually deliver something you’ll be told “great work!” to your face
and shortly thereafter the deception starts from your envious
colleagues (meaning all of them) in the form of back-stabbing,
sabotage and outright aggression. If it sounds like I’m being hyperbolic
or otherwise overstating the power of execution, consider an example.
You and 4 of your friends are planning a night out over the weekend.
You’re not sure what you want to do but you’ve debated going to a
movie, perhaps bowling, Thai food or possibly a dinner party at
someone’s house. It’s summer, so something outdoors was also
discussed.
How would you feel if one of your friends or coworkers did something
like this? Some people might be happy – all of that sounds like good
fun! It’s also nice to not have to think through all the particulars while
trying to punch through group inertia.
And then you might have others who feel put out. Who is Kim to take
control of this situation? Your slightly sad friend might feel minimized
or worse, silenced, which is never a good feeling. A group effort is
exactly that… now it just feels like Kim is being a dictator.
I know more than a few Kims: the doers. People who realize the best
way forward is through. These people are treasured and despised at
the same time, and tend to either wreck a situation or knock the ball
cleanly out of the park. Perhaps you know some of these people too?
Equally annoying and lovable.
There’s more to the story, however, because Kim did some savvy
things. Little tactics she’s learned throughout her life that help avoid
the unpleasant side effects of her actions:
INTRODUCTION xix
In short: she molded consensus. You can’t lead a team without using your
elbows from time to time.
Bring it on.
xx INTRODUCTION
I’m not going to shy away from any of the “human nonsense” in this
book; in fact, I’m going to go right at it. If you feel resistance, that’s a
good thing. It means you’ve found a weak part of your game which
you need to strengthen if you’re going to move up in your career.
Even if you don’t intend to manage people, you will still need to
master the art of getting your way. That shouldn’t sound slimy to you!
After 20 years in this industry, you’re going to have a lot more
experience that others will try to ignore. Your experience is extremely
valuable; you owe it to your bosses and clients to push for yourself.
That’s what this book is about: you sharing your knowledge with the
world, building from the inside and using a solid set of tools on the
outside.
You will learn how to log your daily efforts through journaling.
Even if you keep a journal now, there might be some things
you’re missing.
INTRODUCTION xxi
In Part 2 we’ll dig into the development process. I’ll share with you
the strategies you’ll need to be certain your team delivers value when
all is said and done.
In Part 3 we’ll figure out where your application is going to live and
for how long. SHIP IT!
Finally, the last part of the book is about your success and what to do
with it. Do you want to manage other people, or do you want to be an
“Individual Contributor”? You should know this right now, before the
journey begins.
QUICK THOUGHTS ON AI
For some reason, I was hell-bent on not adding anything about AI to
this book because it’s an over saturated topic these days. That said, I
do feel that it’s worth noting the following:
Your opinions are groovy, but your job is to ship software. There is no
holy war happening here, at least not yet, and not using tools to your
project’s advantage is a function of your ego, not your client’s needs.
INTRODUCTION xxiii
Give yourself every advantage you can to deliver the thing you’ve been
asked to create.
So why the guarantee, then? Why did I start this section off with the
assertion that I didn’t use AI to write any of the content herein?
There’s a fine line between writing code and writing prose. I suppose
it’s like buying a hamburger and finding out it was grown in a lab: it’s
a synthetic experience.
But couldn’t you say the same about code? Writing code is a creative
endeavor, isn’t it? I think so. So why, then, is it important to me that
you know I wrote this entire thing by hand?
It’s simply this: because I care. Code can be expressive, but not as much
as prose on a page, fitted together line by line. I try to put my voice in
everything I write, not the synthetic voice of an LLM.
I
f you have a journaling system that captures your efforts at
work, and you’re happy with it, feel free to skip this section. If
you don’t have one, that needs to change.
There are so many journaling systems out there and I’m sure you’ve heard
of some of them. The king of the hill is Getting Things Done (or
GTD), but there’s also Bullet Journaling, Time Blocking, Pomodoro,
etc.
I have tried almost all of these and finally settled on one that I like
based on its flexibility. You might find other systems that resonate
with you, which is grand! Just make sure you pick one and stick
with it.
Why? Because a journal can keep you sane. It will be your best friend,
confidant, and long-term memory. It can be a source of joy and calm,
and a place you retreat to before and after work.
Your journal and notes are your life, and they’re immensely valuable.
4 ROB CONERY
I can’t tell you how many times this habit has saved my skin both
professionally and personally. Gaslighting is a very real thing, and
being able to document what was said and when is crucial.
Saying “keep a work journal” is one thing, but having a useful system
is another. Journaling is different from time and task management, but
if you’re careful, they can be one and the same. I’ll share what I do at
the end of this chapter.
If you pass those around, however, you will quickly lose trust, even
from your friends. If you become known as a screenshotter, people
will assume that’s what you’re doing in their conversation with you as
well, and you do not want that.
When you start writing things down, you quickly discover that there’s
a natural crossover between time and task management, planning, and
6 ROB CONERY
journaling. Some people prefer to keep these separate and others try
to integrate them. I’ve tried variations of each, and had some success.
Let’s discuss a few.
The system is incredibly simple: you have a series of “logs” that work
together, and the stuff that’s truly important becomes apparent, while
the stuff that isn’t is thrown away.
Tasks are bulleted items, events have circles, notes are dashes. When
you’ve executed a task, you cross it out. If you didn’t do it, you move
it to a different log (monthly or future) to be done another day.
The big breakthrough for me was understanding that your daily log,
which you see in the image above, is a plan for the day and it’s also a
bucket for catching anything that comes to mind during the day. At
the end of the day, you decide what to do with the things that
occurred to you, or that you need to plan.
All of these logs end up being just that: a visual track record of what
you’ve done, and what you’ve discarded over time. Using a pen and
paper also slows you down, which is on purpose, and encourages you
to doodle and have some creative fun.
You can also relate tasks and events into “collections”, which can take
whatever form you like, and that’s a major draw for me: the Bullet
Journal is yours to mold to your life, however you see fit. There are a
few simple rules, but the rest is left to you.
8 ROB CONERY
You will still need a system, however, and the best advice you’ll see
online and in books is to keep it as simple as you can. Friction in your
process will stop you from using it! Speaking of, let’s talk about
processes now.
The idea is that you have an inbox, where you dump everything you
need to do. You then follow a simple process at some point during
your day to categorize things as needed.
It’s a simple system and there are quite a few apps you can use that
will help you. I used Trello for this for a long time and it works really
well, and best of all, it’s free for single use.
GTD is great, but when it comes to looking over what you’ve done and
logging your efforts, it can be lacking because the focus isn’t on that,
it’s on, well, getting things done. Once they’re done, they’re gone unless
you impose your own system.
Time Blocking
This is a very intuitive way of planning your day, but like GTD it lacks
a focus on journaling and logging. I think that’s OK, however, use a
journal as a journal and no more.
10 ROB CONERY
The rules for this are simple: your focus for each block must be
complete. You can adjust these blocks, of course, as needed but your
goal should be something like “when I’m exercising, I should be at the
gym, on a walk, or on my bike”. You can then assign yourself those
tasks within that block for the day.
Google Calendar is excellent at this, if you use Google Tasks. You can
drag the tasks right into the calendar and see what you’re doing when
easily. You can also do this with other calendar systems, but I find
Google Calendar works great.
If you’re an Apple person (as I am), the built-in Reminders app along
with a capable calendaring app, like Fantastical, works great:
THE IMPOSTER’S ROADMAP 11
If you want to do that task during a given time block, however, you
can drag it down into the day and drop it at a given time, which will
add a time alert in Reminders. When you’re done with the task, you
can tick it off right in the calendar, or you can do it in your Reminders
app.
Here, I’m using Tasks together with my day view in Outlook to block
out my day. The tasks don’t overlap with the underlying calendar
event, however, which is a bummer but it’s also understandable.
One of the neat things about calendar apps that track tasks is that you
can use them as a pseudo journal, tracking what you did when:
THE IMPOSTER’S ROADMAP 13
What I did do was to drag those tasks from the top of the day down to
the time block that I actually did them in. They won’t remind me,
either, since they’ve been completed. As you can see from the red line,
the exact timing doesn’t line up but that doesn’t matter to me; I like
the idea that I know what I did in that given block.
I learned this trick from Ali Abdaal, and I like it a lot. Time blocking is
extremely useful, but how you go about blocking things can be
confusing. What Ali does is to create a new calendar called “Ideal
Week”, and then block out, with repeating tasks, what that might look
14 ROB CONERY
like. You can see mine above, in green and purple (blue is work). In
Outlook, the Ideal Week is purple.
You will adjust this at the start of each week, which is when you’re
supposed to do your planning. That’s OK, at least you start from
somewhere rather than an empty calendar. You can move things
around and adjust as you need, which then gives you a framework for
your tasks and when to do them.
When you time block your week, there are three very important
events that should be considered above all others: Weekly setup, morning
routine, nightly reflection. I probably don’t need to explain this too much,
but time blocking will only work if the blocks make sense, which is
where the Sunday setup comes in (or whatever day you choose). The
morning routine is the same process (fitting your daily events and
tasks to reality), and the nightly reflection is where you get to
consider your day and write a little journal entry.
The nightly reflection is the only event in my Ideal Week calendar with
an alert set. This is where I log what happened in life and in work,
screenshotting as I please because receipts are critical. This is the time
that you will save your job in the future, potentially, so take care to
make the time to actually do it!
I have used the Day One journaling app for years and I love it:
THE IMPOSTER’S ROADMAP 15
It’s Mac-only, but you can use your favorite note-taking system instead
of a journal like this one. I like the security and encryption here, which
is why I use it, and it also supports Markdown.
If you don’t have a journaling system and want to use Markdown, and
also want to keep everything as stupidly simple as you can, I got you!
Our goal is least-friction, so if don’t have a set up, let’s ease you
into one…
A digital version of Bullet Journal would solve this, but that goes
against one of the main selling points, which is to get your head out of
the digital world and slow down.
16 ROB CONERY
To me, the tradeoff is worth it. I have been using what I’m about to
show you successfully for a few months now, and I love it. I still have
the same peace of mind, but I do miss taking time away from a screen
to collect my thoughts. Ah well, life is compromise.
Hello Obsidian
It comes in every flavor, too: Mac, Windows, Linux, iOS, and Android.
If you store your files on a shared drive, you can sync mobile and
desktop easily. I use iCloud for this, but Dropbox works great too, or
whatever sync system you use. If you upgrade to the paid version, you
can use their syncing service.
THE IMPOSTER’S ROADMAP 17
Obsidian is completely free for personal use, but if you want to use
it “commercially”, it’s $50/year. Given how much I use this thing, I
don’t mind giving them money at all. There is also a one time
“Catalyst” license that gets you early access and helps support
development.
So, go get yourself Obsidian if you want to play along, and let’s do
this.
When you start Obsidian for the first time, you’ll be asked which
folder to use to store your “Vault”. You can have many vaults, which is
great if you intend to separate work from life. For me, a single vault is
fine.
Once you’ve done that, you should see something that looks like
this:
You can do all the normal things an editor can do, including setting up
a folder hierarchy, tagging documents, and more. I’m going to focus on
getting our journal set up, so play around on your own and watch the
many YouTube videos out there, but don’t get too sucked in to the
“systems” just yet… there are sooooo many and they’re very
academic. We need to remain focused, for now.
Organization Philosophy
I don’t really have a system because systems require mental space and
I find that any system is a form of friction, which will keep me from
keeping the notes I need to keep.
I do have a set of folders, which I’ll go into, but aside from the
calendar-based journal stuff, that’s the extent of any “system” I use.
The goal, for me, is to capture the flexibility of the Bullet Journal and
make my system bend to the way I think. It should reflect my brain, not
someone else’s.
The Folders
I don’t like to organize things by folder, but that’s just me. I use tags
instead, and link things together for a more “organic” structure, if you
will.
I’ll talk more about that in a minute - but my point is that I don’t like
to get hung up in a contrived structure; I’d rather build it out
organically.
I keep every daily note in the root until the end of the month, when I
move them all into their month folders for a given year. I’m getting
ahead of myself here - let’s back up a bit.
Bullet Journaling is all about putting your notes into a log somewhere.
The most common log is the Daily Log and, as you can see above,
mine has the date as the title along with the day of the week. The
Daily Log is something you’ll often use, as well as the Monthly and
Future Log.
For instance, you might get inspired watching a YouTube video and
want to remember it, so you log it in your daily log and add a link. It’s
THE IMPOSTER’S ROADMAP 21
This is where you might create a custom collection, and link it back to
your daily log:
This is a real note in my journal, by the way. I’m using the emoji here
because it’s a list, but it might turn into a pro/con list later on, which
is just fine because I can change things around as I need, when I need:
22 ROB CONERY
That’s the flexibility factor here: you’re not locked in to any system
but your own. I’m a visual person, so seeing icons like this really
helps.
At a glance, I can see my daily notes (no icon), the monthly log (has
the month number with the name), and each collection after that.
These collections are simply notes that I’ve taken during May, 2024.
They include books I’ve read, work I’ve done, ideas I’ve had, and
general inspirations. I don’t do long-form journaling here, as I use a
THE IMPOSTER’S ROADMAP 23
different app for that. This journal captures my work and life in stark
detail, which is the key.
The goal of Bullet Journaling is to clearly see what you spend your
time on so you can make more meaningful decisions in the future. If
you read the book (I listened to it on Audible and it’s outstanding),
one of the things they discuss is to be as concise as possible, without
embellishing.
That’s Ryder Carrol, the creator of the Bullet Journal method, and his
assertion is that your journal should be just that: the facts of your day.
Emotions tend to skew our perception - the 30th gray day in a row
may make you feel very gloomy about your life, so your journal might
naturally reflect that. Conversely, meeting someone new is exciting
and makes everything feel wonderful, and your journal could reflect
that as well.
Now think about reading back over those pages a year in the future.
You’re completely removed from the emotional element, so you might
be confused as to the “truth” of your day. Or be confused as to why
you neglected to write down something more important, such as the
phone call with a parent or friend whom you might not see anymore.
This is a daily log of mine from earlier this month. There is another
half, which I’ll show in a second:
24 ROB CONERY
My tasks are broken out into checkboxes and, as you can see, my
theme supports all kinds. Completed tasks are in green, pushed tasks
(meaning “do them tomorrow”) are blue arrows, red boxes are things
I decided to let go.
I’ve been focusing on physical fitness over the last month and I want
to keep myself responsible, so I make sure I log what I did. I also tag
the things I did so I can click on the tag and see the entries later on,
all of which are titled with the day, so I’ll know when I did them.
The final bit is important as it ties up your day and is the “reflection”
you look at when you examine your life. It’s easy to embellish here,
but keeping to bullets really helps. Here, it’s easy to see that my
battery wearing down on a 30 mile (ca. 48 km) bike ride after the gym
was quite taxing, so I didn’t do many of the things I was supposed to.
The goal with these daily notes is to give your future self a snapshot of
who you were on this day in your past. This could be a year from now,
or it could be next month!
We discussed this above, but let’s dig into this just a little more.
There’s a lot of repetition in the Bullet Journal, and that’s the point.
Your daily log is a place to plan your day, but it’s also a place to catch
thoughts, ideas, inspirations, and events that you need to remember.
This is key: when something hits you, drop it in your daily log and get
26 ROB CONERY
Boom. Write it down! I paused the show and grabbed my iPad which
was next to me and on my daily log added a task:
As I was writing the task out, I realized I would need to write down
what I found, so I just surrounded everything with [[ ]], which will
turn it into a “note placeholder”. The note doesn’t exist yet, but if I
click it, it will! This is a custom collection, which we discussed above,
but it’s such a powerful concept that I wanted to discuss it again.
This is how collections are born, and they’re one of the reasons I love
the Bullet Journal. If you’re using a physical book, a collection can
occupy the next empty page because flexibility is important. Obsidian
gives you the same idea.
was until later that night, when I went over the day. I do this before I
go to bed, but occasionally it slips to the next morning.
Reflecting on your day is crucial. This is where you write down things
that happened that you want to remember (just the fact, thanks), but
also where you triage your task list. Seeing an open task means one of
three things:
I do think it’s worth thinking about, but we’ll get to it at some point,
so I’ll dump it to the monthly log, which I signify with a little calendar
(the icon code for this is -[<] for “scheduled”):
You don’t want to mark things as scheduled and then forget about
them, however, so be certain you copy the thing over to your monthly
or future log:
28 ROB CONERY
There’s no calendar icon here - just a task that needs to be dealt with,
and I’ll do that when I migrate my May tasks to July, which I’ll get into
in just a minute.
Logging Events
If it’s a quick catch up or review, I’ll just add a header to my day (third
level header), something like “Meeting with Sonia” and under that,
add some bullets with the interesting points.
Bullets, again, underscore brevity and the need to record facts, not
meaning. A stream of notes is difficult to read, but quick bullets that
are bolded in places are very useful.
THE IMPOSTER’S ROADMAP 29
Your monthly log should be a concise summary of what you did over
the month. It’s also the place you put things that you don’t take care
of immediately during the day.
In addition, you can store all kinds of information that future you will
find useful. At the top of my monthly log, I have the tasks that I
wanted to get done this month, as well as the things “migrated” from
my daily logs, like my Singapore inspiration:
30 ROB CONERY
Below that, I also list out the collections I want to remember. Note
that this isn’t every one of them, because some of them are just
random notes or ideas that are “fleeting”. I can find them if I search,
but they’re not an important part of my month:
On the right side of the grid are my trackers: G is for gym, S is for
swimming and W is for 2 mile (3.22 km) walk. There are plugins you
can get for Obsidian that will actually create heat maps and charts for
you automatically based on note properties (the YAML front matter)
and tags. I think these are interesting, but I prefer my manual
approach because it keeps things more in your control, which is what I
like about Bullet Journal in general.
This is where you put your “year at a glance”, if you will. It works the
same as the monthly log, with a small difference:
32 ROB CONERY
This is the first thing you create for every new journal. For my
Obsidian system, you get one per year.
Things that won’t get done in a given month get popped into
the future log. If going to Singapore was a long way off, I
might pop that task into the future log instead of the monthly
log, knowing it’s a “someday” kind of thing.
This is also where you put your intentions for the year, your
high-level goals, and monthly “snapshots”.
As you can see, I’m also linking to each of the collections I created in
May that, I think, are important. This is another bit of redundancy, but
I don’t care, it keeps things just the way I want them. When I look
back at 2024, I want to scan this list and quickly see what was done
when, and what I was thinking about.
THE IMPOSTER’S ROADMAP 33
Note: when you change the title of a note, or move it, Obsidian will
automatically change all links for you.
That’s what your future log is: a roadmap of your year that you build
out as the year goes by. If it helps, you can liken this to GTD:
Today is your daily log. These are things that you want to get
done now.
Your inbox is also your daily log. Whatever comes to mind, for
now or in the future, goes there.
Upcoming is your monthly log. When you do your nightly
reflection (or whenever you do it), move things from your
daily to your monthly or future log depending on where it
feels better to go. Be sure to mark it in your daily log so that
you know it’s been scheduled.
Someday is your future log.
Every morning, when you’re setting up your day, scan your
future and monthly log to see what you might want to
“migrate” into the day, then do it.
Migrating Tasks
Bullet Journals are alive with tasks, events, and notes, which is why I
like them so much. You can even get meta about things, creating a
task to remind you to create a collection for a project you’re
working on.
Whenever you move things from one collection to another, it’s called
“migrating”. A common thing to do is to migrate tasks from one
month to another, because there’s very little chance you’re going to
finish everything that lands in your monthly log. This is totally fine
and, in fact, is one of the main points of the Bullet Journal.
34 ROB CONERY
I’ve done this with chapters for this book. I’ll get an idea for one and
drop it in my daily log, something like “outline a chapter for imposter
focused on programming languages”. At the time I had this idea, it
seemed like a good one.
Later that night, I decided it wasn’t going to happen any time soon, so
I pushed it to my monthly log. You might be wondering if I have a
dedicated collection for this book and all the things I needed to do for
it, and I don’t. I like to keep custom collections as targeted as I can.
Anyway, a few days went by and I would see this task sitting there on
the monthly log, and the more I looked at it, the less motivated I was
to actually do it. Programming languages are interesting, but
comparing and contrasting them is pointless. You could talk about
performance, syntax, and other tech topics, or you could discuss job
opportunities, pay scale and job security. To each their own, honestly.
You don’t “delete” tasks from your log - you strike them out if you
decide not to do them. Here, I’m using a - [-] in markdown to show
that I struck this out. It’s important to know what you decided not to
do, because you’ll probably want to do it again later! Seeing that
you’ve already thought about it (in your collection backlinks) is a
gigantic timesaver.
same impact as actually doing it, so if you try Bullet Journaling, you
can see for yourself.
For example, the collection I have in May for working on this book is a
simple checklist:
Everyone has a different way of tagging things, but for me, I follow a
simple rule. Tags should add:
36 ROB CONERY
It’s all about summarizing for me, personally, and Obsidian is great at
helping you see and track your tags.
The right sidebar has several helper commands, and one of them is to
“show backlinks”. When you click it, you can see where your current
document is referenced throughout your vault.
Right here I can see the dates that I was trying to finish this book, and
THE IMPOSTER’S ROADMAP 37
It won’t add the context, however, meaning you can’t see what was
done on Friday, May 10, but you can click through to find out quickly.
But wait, there’s more! You can click on “Open graph view” on your
left sidebar menu (called “The Ribbon”) and see all your notes,
connected:
38 ROB CONERY
This is an animated view, too, and you can set filters, sizes, and more.
I mean… just… look at how your days are connected to your
collections!
There’s even more goodness - but I’m leaving that for you to discover.
Obsidian is wonderful.
At the end of each month I take extra time and plan out the next one.
This is when you get to migrate your tasks to your future log, to the
next month, or just ditch them entirely.
Once I’m done “wrapping up” a given month, I drag all the notes
(daily logs, the monthly log, and any custom collections) and drop
them into their month folder inside the current year folder:
THE IMPOSTER’S ROADMAP 39
Which is why I love the Bullet Journal so much: it’s so flexible. You can
use the simple mechanics (daily logs, future logs, custom collections)
and go to town with your own bad self.
It’s not too difficult to set up the styling bits, give it a Google and
you’ll see how to do it. It’s not necessary at all, but if you like the
pretty rainbow colors, this is where and how you do it.
There are so many more, and everyone has their list of “must have”
plugins. Explore, add what you like, and freak out!
Templates
Templates work like code snippets and are simply markdown files
you’ve filled out a little bit to get you started. You type ⌘T and you
see a list of things you can inject in the current note. I have a few that
I like:
The same goes for your monthly log, but I added a monthly grid to
mine that I fill out with days:
THE IMPOSTER’S ROADMAP 43
The only properties I have here are where I am when the note is
created (I fill it in manually).
Once you have set up your templates, go to your settings and make
sure you have your Daily Note setup like this:
Of course, set this as you need, but the big thing is to make sure you
have the template set to /Templates/Daily.
Why? Because, at some point, you will need to quickly access things
you’ve done in the past. You might need some code snippets (great to
add to the end of the daily log. It’s just markdown, and fenced blocks
are supported), pictures, screen grabs (keep those receipts!), or
musings. If you’re asked why you should get a raise, you should be
able to search your notes and come up with a compelling answer.
If you’re blamed for something you had nothing to do with, your notes
should vindicate you. Conversely, if you kicked ass and delivered
something wonderful, celebrate it in your journal and add a few
pictures of the celebration.
Adding pictures, code, and video embeds is the final reason I like
Obsidian over the analog Bullet Journal. Being able to drop code on a
daily log and find it later by search is wonderful - and you can see the
context for it from your log, even tracking through to the collection,
and following the logic path from there.
Develop your journaling habit and make time for yourself during the
day. It’s a wonderful experience, and once it saves your ass, you’ll
never go back.
THE IMPOSTER’S ROADMAP 45
TWO
ESSENTIAL SOFT SKILLS
BECAUSE YOU WILL NEED TO WORK WITH
OTHER PEOPLE
I
love reading books on personal growth. Emotional,
motivational, psychological, and financial—all of it. It’s fun to
see how other people have done things and succeeded because if
you read enough of these things, you start to see overlapping patterns.
A few books have stood out to me, and I’ll share them with you in a
minute, but let’s get to the soft skills first. These are the “human”
skills you’re going to need as you move through your tech career.
I know of quite a few businesses that make over $1M/yr that are one
person with a laptop. That’s the business we’re in.
I mention this because, aside from the drug trade, there isn’t an
industry quite like ours anywhere. And, like the drug trade, the money
flying around can make otherwise good people do very unpleasant
things.
THE IMPOSTER’S ROADMAP 47
Before we get to the particulars, let’s revisit one of the themes of this
book: every situation has two sides. You could read a few of the
things I’m about to write about and sigh, “OK, Boomer”. I wouldn’t
blame you, many of these subjects are difficult to read about, let alone
write about.
In reply, I would first tell you that I am most definitely not a Boomer
and that much of what you’re about to read comes from my
observations of bosses I’ve had from across the spectrum of
identification. I have worked with some very, very high-powered
people, and they know these subjects very well.
Consider one of the “Laws” from this book: appeal to people’s self-
interest. Yeah, it’s like that throughout the book. On one hand, you
could read this statement and think it’s all about manipulating people
through lies and deceit, acting as if you care about them.
Or you could read this and see a call to empathy, putting yourself in
someone else’s shoes, and helping them to succeed, which is the
hallmark of a great boss, by the way. As a lead, if your team succeeds,
so do you.
What I’m trying to say here is this: have an open mind, understand there’s a
yin/yang balance in every interaction. “Taking the higher ground” is
actually a very judgmental, arrogant thing to do. Who are you to know
what the higher ground looks like? And if you do, why aren’t you
helping someone else get there?
Let’s be positive. I think you do know what the higher ground looks
like, and we’ll start there.
48 ROB CONERY
Your value is what you produce. No more, no less. I’m not talking
about conversations or emails here, I’m talking about an actual product
of your skillset. When is the last time you took stock of the things
you’ve done in your career? The code you’ve shipped, and the money
other people have made from your efforts. If you don’t know the
answer to that question, now’s the time!
Interviews are your time to shine, and it’s a good idea to write down
your accomplishments so that you understand your value. For
instance:
This is a personal resume for you so that you can understand the
tangible, measurable things you’ve done that have had an impact. You
built a major asset for your company and helped educate thousands of
people. You also pushed yourself to run a marathon for the first time
in your life! Personal achievements count!
If you find this exercise difficult, that’s a good sign. If you think you’re
awesome but are coming up short on accomplishments, it’s time for a
gut check.
When it comes to value, action will always produce far more than
motion. Talking is motion, walking is action. You can talk in a
meeting, or you can be the person to convert that motion into action
in the form of a plan, or action items.
Next time you’re in a meeting, observe the dynamic and see who is
playing the role of diplomat. They’re the person relating stories,
saying things like, “I think what Steve is suggesting reflects what
Sonia is expecting from us. I was in a meeting last week when Kim
also said that…” and the stories go on from there. Diplomats like
stories because that means they get to talk, and to them, talking
provides value.
Right, so, here’s the thing: you will only get as far as your network. The old
saying “it’s not what you know, but who you know” is absolutely true,
at least in the business world, and especially in the tech industry. If
you ever considered a powerful person in your company who is a
complete ass and wonder why they haven’t been fired, it’s because of
whom they know.
It’s human nature to seek alliances, and alliances are formed with
people who share common interests and backgrounds. This leads to a
natural, implicit bias that every human has: we’re more comfortable
around people who share our culture, background, and other traits.
THE IMPOSTER’S ROADMAP 51
I’ll sidestep the religious and political implications here, but if you’re
interested and want to read a book that will blow your mind, Sapiens
by Yuval Noah Harari is a book you should read. One quote from
this book has stuck with me, and made me realize the power of
implicit bias. I can’t find the exact wording, but it went something
like this:
Put 800 human beings in a room behind locked doors, and they
will quickly form into groups, with the singular goal of finding a
way out. Put 800 chimpanzees in a room with locked doors, it will
be a massacre.
Getting Tribal
52 ROB CONERY
This is where we get to the darker side of your network: your tribe. As
you meet people naturally at your job, some connections will be
stronger than others, for whatever reason. Perhaps you work well
together, or pulled together to get something shipped “against all
odds”.
These bonds are strong, and tend to last if they are cared for. In fact,
they tend to span companies and live on for years. I still get calls from
friends I worked with over a decade ago, trying to recruit me so we
could work together again. These are the friends you want. This is your
tribe.
The phrase “we worked together at” and “I followed them here” are
commonplace. As I write this, a good friend accepted an offer at a
company where 6 of her tribe currently work! They keep pulling each
other along, from company to company.
The trouble is, there are other people in this industry that want to do
the same as you. I could be mean about this and tell you they’re out to
get you, or we could be real about this, and understand that they want
the same thing as you, and every so often those goals conflict.
In fact, they often conflict. This is where empathy helps, and please
note that I’m not about to suggest you understand someone else’s
THE IMPOSTER’S ROADMAP 53
motives to convince yourself to roll over and not cause a problem. Far
from it and, in fact, quite the opposite.
Conflict will happen, and you will carry out the conflict as humans
have forever:
A perceived threat.
Posturing (my tribe is bigger than yours and I have the
backing of 5 managers).
Cold confrontation (aka backroom dealing, whispers, and
trying to get people fired)
Hostile confrontation, which usually results in someone being
fired, or their project canceled by a VP or CEO. Think of the
OpenAI nonsense from December 2023. Sam won because
Satya Nadella was in his tribe.
You will face conflict, it’s part of the deal, but there are ways to get
around this, and it involves understanding whether there really is a
threat to begin with. To achieve that, you have to have the ability to
truly understand the other side.
Empathy isn’t something that you can teach, it’s cultivated. You
practice by pretending you’re the other person, “switching sides” if
you will, and coming up with ways that you would propel what
they’re doing over what you’re doing. Fair warning: this can be
extremely stressful, especially if it involves your project and a team
whose jobs depend on you.
Emotional Kung Fu
If you’re feeling negative, it will come out and be used against you.
You’ll hear terms like “ah, yes, they're very passionate about their
54 ROB CONERY
Also: this is likely where you might find yourself muttering “OK,
Boomer” (I’m not a Boomer, dammit). If this is you, bookmark this
page and come back to this chapter as your career progresses and your
success grows. You will find things becoming more difficult and that
difficulty will likely be from your colleagues, who will smile and say
nice things to you, but cause trouble otherwise.
Assuming you accept the idea that success brings trouble, you can be
mindful of how you perceive and deal with that trouble. Having clear
thinking when you’re challenged in a meeting or email chain will help
you absorb whatever blow comes your way and carefully think about
your response.
Consider a meeting with your boss and peers. One of your peers, Jo,
has plans of their own and is about to let everyone know this:
You: “So, in short, the goal of our project is to increase the visibility of
our platform to non-Python developers, which could increase our
market share dramatically”.
Jo has a point, unfortunately, and has chosen this day to express it.
More than that, however, Jo has an agenda which you didn’t know
about until now. This will surprise you, and it will also frustrate you
because, as you mention, outreach to non-Python folks is the entire
goal of your project and Jo just stated that your project basically
shouldn’t exist.
What do you do? Here are two possible responses (of many):
THE IMPOSTER’S ROADMAP 55
You: (glaring slightly): “I’m sorry, what? We’ve been working on this
project for months, and you’re discussing this now? Has something
changed that I’m unaware of? We’ve put great effort into this effort,
and it’s frustrating to hear this, to say the least”.
Say hello to Rob, circa 2003. I didn’t care for conflict, but if it
happened, I tended to go right at it aggressively. This can work if
you’re the CEO, CTO, VP, or run your own company. It absolutely
does not work if you’re somewhere on the org chart that’s not the top.
Let’s use a little awareness, and see if we can adopt what I like to call
“Emotional Kung Fu”, which is to accept the barbs coming your way
and let them pass through you.
You: (taking notes, waiting until a count of five): “I agree, Jo, diluting
our efforts would be counterproductive. Where do you see the dilution
happening?”
We can do better:
Consider your group of friends, or your family. Do they get along all
the time? Doubtful they do because all of us have things we want out
of this life (and career) and will fight for it. Every so often that means
fighting each other, as unpleasant as it seems.
Yes, these interactions can be extremely annoying and make you want
to give up, but I would encourage you not to do this. Work is not real
life, it’s a strange blend of tribal politics and being an old-world
member of the royal court: people jockeying for position and trying to
gain power. Yes, work can be a social place too, but it is rarely just that.
that it helps you see your motivations when it comes to the workplace
and delivering software.
I’m sure there’s someone at your current job whom you regard as
brilliant and that you respect more than others. If that person told you
that learning Java was The Way, you would likely spend the following
weeks learning the Old Standard.
Your lead will assign you more work and depend on you more
because you’re capable of working through problems and
delivering.
You will take your lead’s job, garnering respect (and jealousy)
from others at your company.
You will become a director if you keep delivering value,
building out your network, your tribe, and your enemies.
In short: your influence on what happens to you, your team, and your
company will grow. This is power, and it’s OK to have as long as
you’re not a jerk.
That’s the critical part you need to understand: with great power comes
great responsibility, to borrow from Spiderman. It’s true. People will
depend on you, and your care of the principles you’re about to read
will mean everything for your growth as a person as well as a boss.
To that end: every one of the principles I’m going to discuss below has
a positive perspective and a negative one. Seeing both is critical, so
you can stay away from the negative and embrace the positive.
because I find it revolting that people can behave this way, but I also
find it eerily accurate.
Right, enough said, let’s do this. Here are some of the principles
discussed in the book, adjusted to our field. I’ve also added the
negative and positive aspects of each.
This, in simple terms, means you should never make your boss look
bad. The better they look, the better you look because you’re their go-
to. If your work outshines theirs, you look like a climber and your
boss, who might be thrilled at your efforts, will resent you for it
silently.
Either way: always make your boss look like a star. It’s good for you both.
Silence is power in just about every way. More than that, when you
open your mouth to protest (or write prickly emails and posts), it will
likely make you look weak, almost every time.
It’s all you have. Once it’s dented, it is almost impossible to recover,
even if you leave your job and go somewhere else. In 2009, I found
THE IMPOSTER’S ROADMAP 59
That’s the negative way of seeing it, the more positive way is “always
put on a good show” or “there is no ceiling” when it comes to being
dramatic. I read a funny story in a marketing book about a $100
hamburger, which seems utterly ridiculous, but a Las Vegas restaurant
wanted to make an impression and generate buzz, so they came up
with this overpriced burger.
Who the hell would pay that amount for a burger? Turns out that
everyone wanted to know the answer to that question—because there
were people who stepped up to the challenge. There always is.
The attention that this restaurant received for such a ridiculous stunt
put it on the map and made it stick in people’s minds. I’m writing
about it right now!
The point is: don’t just give a demo, give a Demo That People Will
Remember and Talk About. David Heinemeier Hansson (DHH) knows
this all too well. He famously dropped a slide in one of this talks with
the simple phrase “Fu— You” right in the middle. I don’t remember
what he was talking about, and it didn’t matter. The slide set the tone
60 ROB CONERY
for the rebellious Ruby on Rails community at the time and caused
many, myself included, to write about it.
This is a theme throughout this book: don’t talk, do. Action is power,
and it can, and will, get you into trouble if you’re not careful. But
that’s why you’re here, reading these “laws”!
The silence in the meeting when your colleague confronts you should
be followed by a successful deployment, or publication, or whatever
you’re delivering. One of my favorite quotes comes from David
Goggins’ book, Can’t Hurt Me:
This one feels slimy, to say the least, but there’s a more positive spin
here. It’s not about playing someone by faking what you care about,
it’s about aligning your interests with theirs. This is also called molding
consensus, which we discussed at the beginning of the chapter.
You have an idea: what if you could provide a 20% grooming discount
for people who shared pictures of their adorable, well-groomed dogs
on walks throughout the city while using the dog-walking app?
THE IMPOSTER’S ROADMAP 61
You’ve just won over an adversary and aligned your interests. You’ve
also expanded your network and your tribe if things work out.
Mediocrity Kills
This goes along with “Attention is a Good Thing”, but never waste an
opportunity to do outstanding work and blow people’s minds. You’ve
probably heard the term “underpromise and overdeliver”, and this is
why: mediocrity is toxic.
There’s no spinning this one: it’s slimy. That said, there is wisdom in
not letting everyone know your plans, especially the colleagues who
are trying to kill your project or your position in it. But… yeah, it still
feels slimy to me.
Consider this “law” and the ones that follow as a bit of warning. A
“this is what other people might do” kind of thing. In my experience,
it’s completely accurate. As you rise in the ranks of your company,
people are rarely fully transparent and if they spend time insisting that
they are, you know for sure they’re not.
Eww! Yeah, this one just doesn’t hit right, does it? And yet: this is the
very definition of being a good manager. You let the people you hire do the
work you hired them for. Give them autonomy and the ability to take
62 ROB CONERY
risks. The fact that you did so makes you a good manager, which
means you naturally get to accept some credit for the work that gets
done.
Many managers will do more than that, taking credit for your work
outright. In many companies, this is du jour and expected of you. I
think it’s horrible, but if you’re trying to get into a big company (a
FAANG, Microsoft, etc.) don’t be surprised when your boss, who has
seemed so kind and helpful, takes more than their share of your credit
and then gaslights you. The unspoken agreement here is that you’ll do
the same later on.
They will bring you down and, worse, you can be labeled simply by
befriending them. Also: working with these people is a downer!
It’s also a good thing to check yourself occasionally and see if you’re
becoming “unhappy or unlucky”. It’s nearly impossible to recover a
broken reputation (you can trust me on this one) so if you believe this
label has landed on you, it might be time to move on and try again.
This is why DBAs like being DBAs: everyone counts on them. It’s also
why people like to “own” information on “Holy Spreadsheets” (the
source of truth for a project or team)—information is power and if you
own the information, people must depend on you.
Let’s turn this more positive, shall we? If you’re good at what you do,
people will naturally depend on you to keep doing it. If you’re a good
leader, motivator, and consensus-builder, people will follow you and
be inspired by you. This is a good thing.
everywhere in the workplace and if you know what they’re doing, all
the better for you.
This is one of the true tests of leadership, and something most people
aren’t willing to do, which is very human. Most of us are brought up
to believe mercy is a good thing, and an enemy turned friend is a
powerful thing. We’ll discuss the latter assertion in a minute, but
usually an enemy that’s been defeated by you will make it their goal in
life to come back stronger and take you out completely.
Consider Jo from before, the person who didn’t think your project was
worth doing because they had other ideas. As it turns out, your
project did very well, and you received a promotion in the form of
becoming the group manager. Jo now reports to you.
There’s bad blood between the two of you, even though you kept your
cool each time and obeyed the laws, saying nothing most of the time,
and as little as possible other times. You also kept your intentions to
yourself, so Jo didn’t fully understand your plans.
Do you believe them? A better question is: should you believe them? If
I’m honest, I would believe them because I just don’t have it in me to
do anything more. I’ve had this conversation with so many people,
mostly managers, and 90% of the time, we would keep Jo around and
hope that they will become a trusted ally.
If you respect this law, you would ask Jo what their plan is for their
future at the company because it shouldn’t be in your group. You
would be honest: you don’t trust their intentions, regardless of what
they say, and your group is built on trust. You’ve been given full
control over the matter and arranged for Jo to transition to another
group, or out the door.
You might think this will brand you as unkind and a harsh boss. On
the contrary, it will gain you respect. Even if Jo leaves the company
and complains non-stop throughout the industry, posting on Reddit or
social media, they’re the one who will look weak.
Yeah, I know. I couldn’t do this either. I’ll be honest and say I wish I
could because it’s the people that can do this that rise to the level of
VP and beyond.
In martial arts, you’re most vulnerable when you attack. Your body
motion is given over to aggression and impact, and you have little to
no defense. If your enemy absorbs your blow, their counterattack will
likely do you in completely.
The same is true in professional life. When Jo comes after your project
(back before you were promoted, let’s say), saying very little, or
nothing at all, can give the impression that you’ve been beaten. Jo
might assume they’ve won, which means your counterattack (in the
form of successful delivery) will be all the more devastating.
So, let me ask you this: does all this conversation about conflict turn
you off? It’s difficult to write about because I’ve lived it far too many
THE IMPOSTER’S ROADMAP 65
times. And I hate to be a downer, but this is going to happen to you, even
if you decide to work on your own as a contractor or found your own
company. Conflict and competition are core to humans, it’s how we
grow and become stronger. It’s OK to not engage, but that also means
you won’t rise to your potential.
Gross. I hate this, yet it’s also true. There will be people at your
company who, occasionally, will inject chaos into the daily standup,
monthly meetings, or off-site retreat. They will sow doubt, backstab,
and flat out lie, all with the goal of causing a little chaos.
If there’s a positive to this, it’s that chaos will shake loose the
decaying parts of a project that should probably go anyway. This could
be features, entire products, or people themselves. The chaos could be
infighting, budget cuts, or layoffs. It could even be the lack of funding
moving forward, causing a pivot and downsizing of a bloated startup.
So, how do you make chaos your friend? Simply by knowing it’s
coming, regardless of what you do. Routinely interviewing at
companies you admire can help you take advantage of layoffs at your
company, before they happen. You could even explain to your boss you
know they’re coming and that you’ve been interviewing and have an
offer at a competitor. You never know, you might receive a guarantee,
or even a raise if you stay.
it’s fun to see the patterns and ride them. You can do the same at
work, it just takes patience.
A pretty standard thank you speech for a manager: recognize the team,
acknowledge the effort, strengthen the bonds.
Thank you so much for trusting us with this project. I know how
much it means to the company and everyone who works here; it is
a privilege to work with such a talented team, and I had every
faith in their ability to deliver.
I suppose you could call this a humblebrag, but then again, Terry is on
stage accepting praise for a job well done. It’s a very fine line when
you try to make a win look easy—you can easily be branded as
arrogant. If people come to expect excellence from you, however, it’s
worth it.
THE IMPOSTER’S ROADMAP 67
When he got there, however, he didn’t dance, spike the ball, point,
and shout. He just tossed the ball to the referee and made his way to
the sideline, with his teammates dancing all around him. To him, it
was just another set of downs ending up with him putting points on
the board. That was his job.
Barry retired at the height of his career, shocking every football fan
around the world, including me. He walked away, caring very little
what people thought. It was effortless for him, and the right thing
to do.
When you win, toss the ball to the ref and make your way to the
sidelines. Of course, you delivered, that’s what you’re here for.
Yet, there is value in knowing what other people are up to. There is
also value in understanding that they probably aren’t “evil” or
conniving either—they’re just looking out for their own self interests
and doing what comes naturally to them. Which is what you’ll do as
well.
If you see yourself doing something you think is slimy, and it makes
you feel slimy, then stop and ponder your motive. Reflect on these
laws here and consider how you could do better. Perhaps not sending
that email and saying less. Maybe you could push for a stronger demo
68 ROB CONERY
Building software is easy, getting it out the door and shipped is the
hard part, as it requires a masterful use of the soft skills of power.
THREE
LEADING YOUR TEAM
YOU CAN CHANGE SOMEONE’S LIFE AND
CAREER WITH YOUR ACTIONS
A
t some point in your career, it’s likely you’ll be asked to lead a
team of others. It’s OK not to do this, by the way, if
leadership isn’t something you’re comfortable with. Many
of my friends have decided to remain “IC”, or Individual Contributors,
and they have progressed their career just fine.
Leading a team, however, can fast track your career if you do it well.
This is all I did earlier in my career, and I loved it. These days I prefer
to work on my own, which may change in the future if the right role
presents itself.
As a team lead, you’re the captain of the ship. You don’t hoist the sails
or turn the wheel yourself, you let your team do it. A better way to put
that is that you enable your team to do it. Your role is to ensure the ship is
pointed where it’s supposed to be pointed, that you stay out of danger,
and that your crew is united in their effort.
That last bit can be difficult and, frankly, is why I don’t lead teams
anymore. We’ll get to that shortly.
Laws of Power, which we discussed in the Soft Skills chapter, but I truly
wish I had because I got eaten alive.
I had been in the business long enough to see that this person was
exceptionally toxic and superb at manipulating people, especially the
VPs and executives above them. I mentioned the overt toxic behavior
a few times to my direct boss, and the reply was always the same: “I
think everyone knows it, but there’s not much we can do about it”.
You’ll find that response is common.
I need to expand on this because at some point you will work for one of
these people. The tech industry seems to attract them more than other
industries, though I can’t prove that. It might be the money, the
status, who knows! But according to this study, 1 out of every 100
people have diagnosable psychopathic traits:
About 1.2% of U.S. adult men and 0.3% to 0.7% of U.S. adult
women are considered to have clinically significant levels of
psychopathic traits.
It gets worse when you consider that some people just have the traits,
but might not be a clinical case. And even worse than that:
psychopathic people tend to make “good leaders” in that they drive
people extremely difficult to deliver results, which they then take
credit for.
72 ROB CONERY
They never really look at you but, instead, look through you.
It’s a strange trait, but their face is almost devoid of
expression and the eyes seem lifeless. This is because they
have very little regard for you and probably aren’t listening to
what you’re saying anyway.
They say rehearsed things, as if reading from a script. If you’re
in conversation with them, they’ll take an extra beat or two
before they reply. When they do reply (in a meeting, perhaps),
they will sound as if they’re reading from the company manual
or saying something so rote or cliché that it’s almost comical.
Something like “I hear and validate your position, and I’m
interested to hear more. Perhaps you could make some time on
my calendar so we can discuss this further”.
They leave a trail of destruction. The thing with psychopaths
is that their words and perception of themselves does not
align with reality. Good people quitting, one after the other, is
always a sign.
That last bit is especially difficult to deal with. At this particular job,
about 40% of the group I was in left. 20% of them “rage-quit”, calling
out this toxic person in particular. Nothing was done.
At one point, I was offered a lead position that was vacated because of
this toxic manager. I was told that if I didn’t take the job, there might
not be a position for me at all — which is another sign that you’re
working for a psychopath (do what I want, or I’ll make your life hell).
I took the role and within 2 weeks I realized there was no way I was
going to succeed. Team dynamics, miserable morale, increased
workload without a promotion and a leadership structure that was
happy to take credit for any success the team had.
There’s a saying that I like and that I’ve found particularly true: Human
Resources is there to protect the company, not the employee. You’re always told
to “go to HR” whenever things get weird or challenging, but that
rarely works for people. What does work is a paper trail in your journal
and a good lawyer.
This is why you keep a journal. This is where you keep a solid
project trail with GitHub issues and PRs, relevant emails and chats,
your brag book, and more. You can’t be successful unless you have a
trail of facts about your actions, and that includes protecting yourself
from Not Nice People.
I booked a meeting with the Toxic Manager and asked that we record
it. This caught them off guard, but they agreed. I knew a trap was
waiting for me, that I would be asked to find a new team or leave the
company if I couldn’t do the job.
There were a few things that I had not agreed to with this position (to
keep this as anonymous as I can, I’m going to omit those details) but
had been assumed after the fact. There were also a few things said to
me that violated company policy and no, I would not be stepping
down, I will be resuming my old position.
harming everything else. A fun story from the article I linked explains
this well:
They never left and, instead, got promoted shortly thereafter. I stayed
another 6 months but finally left, fatigued and deflated.
Don’t hesitate to get the hell out of a bad situation. If you spot a
psychopath in your management chain, it won’t end well for you,
especially if they seem to select you as their pal. You won’t make this
situation work out, and you’ll end up burned out, never wanting to lead
a team again.
THE IMPOSTER’S ROADMAP 75
It’s not leading a team that’s hard, it’s the support you don’t have
from your managers. This is critical to understand.
One of the best leads I worked for started our very first conversation
with “let’s talk about why you’re not a lead yourself ”. They wanted to
know what “moving up” meant to me, and where I wanted to be in 3–
5 years. We talked for an hour and came up with a plan, and I talked
most of the time. They weren’t condescending at all, and no subject
was off limits.
Sadly, I only worked for them for a year before they left the company.
The “alignment” I felt was wonderful, like I was part of a greater
effort, truly making a difference and being recognized for it.
These are the people you want to work for and, yes, if you get a
chance to stay with them, do it. Your manager is everything when it
comes to your progress in a company, and if you think they’re not
doing their job, fire them.
You might have heard the term “managing up” before, and it’s a skill
you need to cultivate. Your boss is there primarily to guide the team to
success, and they should be doing that by empowering you and then
getting out of the way. They should also make sure you get the
recognition you deserve and, if they’re not, you should change roles,
change groups, or change jobs.
BUILDING A TEAM
You just stepped into a lead role at a company you respect, working
for a person who has a solid reputation as a great lead. You’re set up
for success, now let’s deal with your leadership skills.
If you’re excited to lead a team, ask yourself why. Are you looking for
validation? Perhaps a little power at your company? Respect? It’s
human to want these things, but if you find yourself needing them, we
should talk.
The terms “psychopath” and “sociopath” don’t sound good, but they
define a spectrum that everyone is on, somewhere. I’m not a
psychologist, but I’ve studied enough on the subject to realize that
these toxic people have armored themselves emotionally, usually as
the result of some type of trauma. They don’t feel things like a
“normal” person might and, instead, feel joy and fulfillment under
many different circumstances.
If you’re going into leadership hoping to feel validated in the work you
do, talk to a therapist about it. The job isn’t about you, it’s about your
project and your team. If this section is making you angry, that’s a
good sign that talking to a therapist is paramount for you.
OK, you’re emotionally ready to jump in, and you have a great
management chain above you. Let’s do this!
Now let’s get to the other side of the emotional needs spectrum: over-
compensation and over-attachment. Didn’t think we’d be discussing
THE IMPOSTER’S ROADMAP 77
emotional intelligence in a technical book, did you! And yet, it’s one
of the critical skills of any good leader.
From XKCD
When your team is humming, get yourself out of the way. This is
when you buy a round on a Friday night, give small spot bonuses for
hard work, and ensure that your door is always open for a drop-in
when people have a question.
It’s a delicate balance and a fun one to maintain, but there’s also the
temptation to jump in and resolve a problem you know how to fix,
rescuing a bad situation. This often comes up in a code review, where
you might see an N+1 problem (we’ll discuss this in the scaling
chapter). These are usually simple fixes with any ORM, one that you
could do quickly, so your team focuses on other things.
Making this fix, however, can deflate people. Avoid the temptation and
fill out an issue, assigning it to the last person to work on the file (use
git blame for that), and then move on. Your team needs to trust you
to lead, not to fix.
As the lead, you’re setting the tone for the team, and your leadership
informs the overall emotional health of everyone on it. If you’re
constantly stressed out and complaining, so is your team. If you’re
overly positive and lack sincerity, you won’t connect with them, and
they won’t connect with you. You’re a regular person tasked with
helping them be outstanding, which is a privilege! It should be fun,
but always remember to keep it real.
Leading a team means helping people do their best work. I could fill
an entire book on just this subject but, instead, I’ll point you to this
book right here by Sarah Drasner. I worked with Sarah at Microsoft
and, like so many will testify, she’s a fantastic person and ruthlessly
competent.
Our industry is also a very young industry, which means that, on top of
the neurodiversity you have people who are still maturing and
growing into themselves. This can make social interactions a
challenge, and interviewing an absolute nightmare.
This will be part of your job whether you like it or not: you will be
the coach that unites the team and, typically, the person who has to
push others to “do better” when it comes to working with their
colleagues.
THE IMPOSTER’S ROADMAP 81
The best way to do this is by example. How you care for yourself, the
words you choose, and the attention you pay to others when they
speak will be emulated. Scott Guthrie was my “skip” for a few years at
Microsoft (my boss’s boss) and every meeting we had was a study in
interpersonal communication. I still use some of his phrases to this
very day, including:
He didn’t do that. He gave you room to try things and would gently,
but firmly, suggest you also try what he wanted you to try.
Words matter and your careful use of them will set the tone for the
entire team.
It’s common to see “my opinions are my own and not those of my
employer” on social media sites, namely Twitter. Good luck with that:
We’ve all heard horror stories about people getting angry, tweeting
something inflammatory, and getting fired for it. This has happened to
82 ROB CONERY
But that’s not what you have to worry about! Employers will toss your
resume or overlook you completely if your Twitter/Facebook/LinkedIn
profile is overly challenging or, simply put, paints you as a jerk.
When someone tells you who they are, believe them the first time
I have worked with some extremely challenging people over the years,
and I’m sure a few would say the same about me. There are so many
factors that go into interpersonal conflicts — the trick for you is
figuring out what factors drive your potential team member.
Would I use this to get to know a candidate for my next big startup?
Honestly, I might look over their GitHub profile but wouldn’t put any
THE IMPOSTER’S ROADMAP 83
stock in Twitter. That platform drives people to do and say some weird
things. LinkedIn, on the other hand, is a corporate event, so I don’t
think I’d fully trust that either.
One thing I would never do, however, is ask friends of friends their
opinion…
Dave was a psychopath, you see. He got fired a few years later for
lying about numerous things and no, Dave isn’t his real name.
I called my old employer when I got home and, if you can believe it,
politely said to my old boss: “look, I understand I don’t work there
anymore, but could you please allow me to get another job?” And then
recounted what had happened.
84 ROB CONERY
He asked what I was talking about, and I told him, and within 15
minutes I was on a conference call with the company legal team. An
hour later, the legal team from the company I interviewed at was
calling me. Turns out that plenty of laws were broken, and I could
have sued both companies for a lot of money.
People don’t like being rejected, and that’s precisely what you’ll be
doing. Telling someone “no” is no fun, to be sure, but it can also get
you into hot water if you’re not careful.
I sense that all I’m doing is flinging horror stories at you, but it’s
essential that you understand just how bad this process can turn out!
The first thing to understand is likely the hardest: you don’t owe anyone
a reason why you passed on them. I’ll take it one step further: please don’t
tell them. Sounds cold, doesn’t it? It’s not. The truth is that you need to
protect yourself and your company.
Friend: Thank you for your time spent with us. I’m sorry to tell you that it’s a
‘no’. We’re going to move forward with another candidate.
Candidate: Darn, that’s unfortunate. May I ask what went into the decision? I
would like to make sure I study more and apply again in the future. Or perhaps it
wasn’t my skill level?
Look out! Any comment that is not directly related to technical skills
can and likely will get you into trouble. Consider the situation where
the interviewee’s social profile (Twitter, GitHub) was extremely
combative and disrespectful, suggesting they might not be the best fit
for your team. When this happens, the responses tend to be
something like “it just doesn’t seem like a good cultural fit”.
I’ve been told that before and it stings. I was honestly depressed and
angry for about a week. You’re basically being told that you’re not a
nice person, which would make anyone gear up for a fight. And that’s
usually what happens!
Friend: Technical skills are essential, but they’re not the only factor in our
hiring process. We consider your answers to all of our questions very carefully
and your answers were fine, but we decided to move on with someone else because
they fit the role better.
Candidate: It sounds like you’re telling me I’m lacking some personal skills.
Can you elaborate on that? This company doesn’t exactly have the best
reputation either, you know. I’ve been through numerous interviews and you guys
have taken up hours and hours of my time. I think it’s quite rude to reject me
after all this time without something I can work on in the future.
I mean… I can understand how this person felt. I’ve been there. You
go through a loop of 5 other 6 interviews plus a screening call, only to
hear “no thanks”. I will also add that my friend didn’t help themselves
much by using the phrase “consider your answers to all of our
questions”.
On the other hand, the candidate would be proving the point right
here, wouldn’t they? It’s one thing to get a rejection, but it shows a
lack of maturity and professionalism to put an interviewer on blast
like this.
Friend: Once again, I do appreciate the time you’ve spent with us. This position
is highly competitive, and we’ve had over 50 applications, yours being one that
rose to the top. I know it’s frustrating to hear a ‘no’, but I would encourage you
to apply once again in a few months. Now that you know the questions we ask,
you should have a leg up.
I’m happy to report that nothing more happened. I don’t know if the
interviewee ever applied again, but they did give a crystal clear
example of why you don’t give reasons for rejection: as much as you
THE IMPOSTER’S ROADMAP 87
Or worse. You could start into “cultural fit” and throw open the door
to discriminatory hiring practices, and then you’re in big trouble.
SCREENING
Hiring someone usually involves multiple interviews with multiple
folks on your end. Current members of your team, you, maybe your
manager as well. It’s important that you don’t waste anyone’s time,
especially the candidate’s, so doing a quick screening call is
paramount.
If you’re using a recruiter, they’ll do this for you with your guidance as
to what’s important.
Note: when I use the term “recruiter” here, I’m not necessarily talking about the
annoying spam emails you get trying to hook you up with a job. Yes, those are
recruiters too, but often a larger company will have a person whose sole job is to
facilitate hiring. They’re also called recruiters.
You can also use a service like Indeed, Glassdoor, Dice, and so many
more. You can set this process up to be as automated as you like, but
one thing they lack is the personal connection you’ll make when
talking to someone virtually or in person.
You have one question in mind for the screening interview: should we
move forward with a proper interview? To answer this, you need to know:
I know, I know, but soft skills are critically important! I’ll touch on
“Culture fit” last, as it’s likely the greatest challenge.
Everyone has a different way of doing this, but I’ll share what I’ve
done in the past as well as what other companies have done when I’ve
gone to interview.
Ask about the last project they worked on. You don’t want them to
go into detail or divulge secrets, of course, as that could get them into
trouble. If their last project didn’t involve the skills you need (no
React, for example), ask them about the last project they did using
React.
Ask for deeper technical explanations as they talk about their project.
You can usually assess whether they’re talking about the project in
general, or their contribution to it. Push to find out the latter. You can
THE IMPOSTER’S ROADMAP 89
also ask them about a challenging bug they might have solved or, if
they could do it all over again, what approach would they take.
They laughed and said “oh, the dreaded xyz issue. Yeah, they don’t
make it obvious, do they? I hit that so many times when I was starting
out that I now have a snippet I use to make sure I avoid the problem.”
I liked this person and I liked the way they handled the question.
Conversational, aware of the problem which meant they had the
experience they said they did, and they communicated their
experience well. And yes, we hired her. Her name is Kelly, and she
ended up being one of our top coders that people went to constantly
for help and advice.
Taking Notes
You want to be certain you come prepared with notes, outlining what
you intend to ask and also a few things to check off (see list above).
Your Journal works well for this, but also be sure to put something in
your company files, wherever you keep them.
Your candidate is also screening you, so be sure you give them time. If
they’re a junior level person, however, they might not have any
questions — so let’s help them out.
I’m sure you might be wondering what it’s like to work here. You
can then describe the everyday, some programs they might like, the
financial health of the company (which is important if you’re smaller
— let them know they’ll have a job for at least a few years), the other
team members and what they’re like, and so on.
Always keep in mind that the person you’re talking to could be your
next Kelly, and they’re interviewing you, too.
The idea is to avoid bias and make the interview process as even as
possible. I like this type of interview because it becomes a bit of a
game — one you can’t cheat at, by the way.
Here’s a typical question from AWS: tell me about a time you challenged
your team and management, putting the customer first. How can you cheat at
this one?
Note: I know that working at a big company like Amazon, Microsoft, Google,
etc. is not for everyone. The interview process, however, is fascinating to me,
which is why I’m detailing it here. I think preparing this way will help you for
any interview process.
All the AWS questions start with “tell me about a time that X” where
X is a thing you and your company care about. These are usually non-
technical things, but they can be made technical as long as everyone
you interview can answer them fairly.
Tell me about a time when you faced a scoping bug in your JavaScript code. How
did you identify and solve it? It’s almost inconceivable that someone
would never have faced one of these! If they tell you they’ve never
faced a scoping issue, that, in itself, is something to dig in to.
Tell me about a time when code you broke the build. How did you find out, and
how did you fix it? We’ve all broken the build! If you haven’t, that’s OK!
It could simply mean you were on a team that did things differently.
Some teams encourage you to commit right to the trunk, which we’ll
read about later on. Some teams actually expect you to break the build
and will think you’re not trying hard enough if you don’t.
Tell me about a time when you wrote a routine correctly the first time. How did
you know? If you’re working with a junior person, they might not have
92 ROB CONERY
Hopefully, you get the idea about a structured interview. Before you do
one, however, make sure that you and your team agree on scoring.
Each of these questions will draw a story out of the candidate that you
need to evaluate. What do you want to hear?
For the React job, you might want to understand what they think
about testing their code, which the second and third questions will
tell us. Communication skills and attention to detail: the second
question should tell us that too.
The ability to solve problems, ask for help, and researching — the first
question tells us this (ideally).
Code doesn’t lie, so let’s get into the toughest part of this whole
chapter.
CODING QUESTIONS
So here we are, asking someone to write code so we can decide what
they know. Honestly, I don’t know anyone who has ever felt good
about this, mainly because:
We all have our stories, I’m sure you have a few crazy ones too. Sitting
through an interview loop with people asking you to write an
algorithm on the fly that traverses a tree using depth-first search is
extremely annoying. What’s even worse is when someone asks you
something that you truly know, top to bottom, and they tell you that
you’re wrong!
I’m sure there are companies out there that still make you write code
on a whiteboard. So, so annoying. They’ll even take a picture so they
94 ROB CONERY
can see if it compiles! Google did this to me, and my code did not, in
fact, compile, and I didn’t get the job.
If you choose to do this, you can make the experience so much better
by asking someone to spot a bug and then fix it. You could also ask
them to write some tests to be sure the bug is fixed.
This is just slightly less annoying, but here’s a fun one: turn the code
below into a closure:
Seems silly, I know, but from there you can ask them to turn it into a
revealing module (which they might already have done), a class, or
some other pattern they should know.
Going with the React example, once again, you could ask if this code
will work, and if not, why not?
I’m not a React expert by any stretch, and I found out the hard way
that this won’t work because JSX isn’t HTML. I think most React
people would spot this immediately, and if they do, you might ask
how they could expand on this component to add team members,
maybe some company information, and so on.
THE IMPOSTER’S ROADMAP 95
The point is: coding interview questions can be painful, but they don’t
have to be.
I’ll be honest with you: I hate these. It feels like homework. I know
you have to study for interviews, but that feels different from
taking home an assignment. I would probably do what I normally
do: ask Google and find some suggestions on Stack Overflow. I’m
not a fan of copy/paste as I like to understand what I’m doing, but
that is a reality of what we do as programmers: we research. We
have to. There’s no way you’re going to know how to do
everything.
The funny thing is that this is precisely how I do things when I’m
working on a solo project. I love exploring and trying new ideas as you
never know when something will hit you, and you’ll be inspired. That
doesn’t work in a group setting.
Boring!
The risk you run with a take home assignment is that people will find
it boring, and you’ll lose your candidate who might otherwise be a
great fit for your company. This happened to me a few years back: I
was given a React project (I’m more of a Vue person but know React
well enough to get things done and was clear about this) and I needed
to … honestly I can’t even remember… and about 30 minutes in I just
threw my hands up and thought “this isn’t worth it”.
The problem was basic enough, I suppose, but I was missing context
and I didn’t know how to go the extra mile, which is what I normally
like to do. This might sound like chest-thumping, but I’ve made a
career out of going well beyond what’s expected (Mediocrity is Toxic,
after all), over-delivering and basically kicking ass.
Anyway: I was forced to be mediocre doing this and I tried to get over it
but… I just couldn’t. I suppose it's perfectionism, but not really. I don’t
like contrived nonsense, is the problem, and that’s precisely what this was.
I wrote back and asked if there was something else I could do and
tried to explain the problem, which, of course, didn’t work. They
98 ROB CONERY
would be making an exception for me, and that wasn’t fair to other
candidates. I thanked them for their time and that was that.
The last thing I’ll add here is that if you do decide to go with a take —
home test, be sure the candidate can do it in a reasonable amount of
time and make it clear what that timeframe is. Even then, they’re
probably going to spend twice as much time on it which, let’s face it,
is an imposition. It’s also stressful.
I almost immediately said no, but again, this was a job I really wanted.
Why did I almost say no? Because:
I knew this talk was going to take me 4–6 hours at least. Sure, I could
probably phone it in and do just fine, but that’s not who I am. I care a
THE IMPOSTER’S ROADMAP 99
lot about the content I create and the people I’m presenting it to. I try
to take it as far as I can, no matter the circumstances or context.
I did the presentation, which went over well, and I had a few
comments similar to “well that certainly exceeded our expectations. I
didn’t know about X and Y, thanks for that”. That’s why I care so
much — that reaction is wonderful. The fun part is that I didn’t know
X and Y either until I put the talk together!
The point: it might be convenient for you to do take home tests, but
they can be imposing and not nearly as fun and effective as the next
approach.
Pairing Sessions
It’s a simple process: one person is the coder, or “driver”, the other is
the “navigator” who watches what’s going on and catches bugs,
suggests changes and direction, and offers basic feedback. That’s
usually a senior person but doesn’t have to be.
In practice, which we’ll talk about in a later chapter, you can get a lot
done in a shorter time. And by “a lot” I mean code that’s much closer
to being ready to ship. In an interview setting, however, the social
element is missing because you’ve likely just met the person, and this
is where things get interesting.
100 ROB CONERY
The most common setup for a pair coding interview is for the
interviewer, you, to be the navigator and the candidate to be the coder.
You have a problem you need to solve, hopefully a short one, and you
do it together. This is barely a step above a typical coding problem
where the candidate asks a load of questions. It can be less stressful in
some ways (the candidate doesn’t feel like they’re in the spotlight so
much) but it can also be more stressful for the candidate because:
The skill gap. Pair coding is typically done with a peer, not a
lead, and you can easily end up pushing someone to a solution
that you think is correct, not allowing them to be creative. If
you have a lot of experience, this will be stressful for you to
watch, and that will come through in the session.
You don’t get along when coding. They might not start with
tests, and you might be a TDD fan. They might make a joke
about your age, or some quip about being a zealot — both of
which they likely won’t mean as insults. Tabs vs. spaces, Vim
or Emacs instead of Your Favorite Editor. Missing semicolons
and, worst of all, a light editor theme!
They know you know the answer. That last is tough and, I’ll
be honest, it would stress me out as well as make me feel like
a dancing puppet.
One way to address this is to change places — you code, they navigate.
Sounds a bit backwards, but you could purposely do things wrong and
see if they catch you, which I know sounds manipulative, but this
entire process is manipulative isn’t it!
Again, a good sentiment but rings insincere at times. You are the lead
of your group, and you set the tone, the pace, and the bar. If you find
someone more capable than you are, that’s great! They still need to
know you’re the boss, however, and passive-aggressive, self-effacing
“humor” should be at an absolute minimum.
You will indeed find a superstar outlier at some point, who will blow
past everyone in your group, by you, and probably by your boss. I
know a few of these people, and they’re really, superb. Your goal is to
help them and then get out of their way.
Common Processes
Above all: be transparent about all of this. Your report should know where
they stand, and what they can expect from you.
All of that said, sometimes a promotion just can’t happen. These are
called “discretionary factors” and this is where the problems live.
Discretionary Factors
push back and demand to know why. If you don’t get a solid
answer, go over their head and fight for your report to have a
fair chance.
That last one is tough. If your report is being blocked and there’s
nothing you can do about it, it’s only a matter of time until you’re
toyed with as well. The only thing you can do is to try to get this bad
person’s attitude changed, or walk in protest.
Microsoft has a formal “check in” process called the “Connect”, which
is a bit like a career journal. You document your goals, the impact
you’ve had, and the things where you think you could improve. You
also have a chance to discuss your commitment to diversity and
inclusion.
Your lead looks over the Connect and offers their thoughts as well,
and you might get a chance to redo parts of it before it becomes a
matter of record.
Your Connect is used to gauge readiness for promotion, and also your
rewards.
Promoting people is necessary if you want to keep the good ones, and
they need to know what you expect from them, as we’ve discussed.
You don’t need to use a grand, formal process, but you do need to
document what factors went into the promotion, or why they were
denied.
Don’t take no for an answer if your report is passed over, and they
deserve to get a raise or level bump. This is the main reason
companies lose good people!
You, as the lead, are the one to set the tone for your group. The way
you communicate, carry yourself, the words you use and (more
THE IMPOSTER’S ROADMAP 107
importantly) the words you don’t use. We’ll get into communication
styles later, for now, the thing you need to know is that you are the
primary guard against the Bad Apple.
Our professional situations will no doubt differ, but I’ll share with you
an approach that worked well for me when I was a team lead and
CTO. It’s an extension of the idea above, that I set the tone for the
team, but it goes even further into team dynamics and defusing the
Bad Apple Bomb.
Another person, Bill, who worked for me, was difficult to deal with.
He joined my team as a transfer from another department (IT) and I
was warned that he could be “challenging”. Bill had a history of
coming in late and missing deadlines, and also making quips during
meetings that would bring the mood down. He thought they were
funny, but soon enough most people ignored him, and he requested a
change of scene.
I sat with Bill on day one, remembering what Mike did for me many
years before. I asked Bill what he thought success looked like, and his
answer didn’t surprise me:
Me: what would success look and feel like for you in this role?
108 ROB CONERY
Bill: I guess that I just do what you tell me? Is there something else I need to
know?
Me: I’m not going to tell you what to do, Bill. That’s not how I work.
So that didn’t start off well, and I’ll be honest here that conversations
like this are frustrating to me. Bill clearly was burned out and likely
looking for another job. He was also extremely talented, and I felt that
with the right guardrails in place, he could do well.
Bill: I don’t know… I guess the project with the X, Y and Z stuff is pretty cool. I
was talking to Kelly about it the other day, and she mentioned you just shipped B
functionality, which sounds kind of cool.
Me: yeah, it was fun! I had Kelly study up on B, and she took some online
courses that we paid for so she could be ready for it. She learned enough to ship,
which is great.
Me: I’m not, Kelly is. She recommended it and came up with a plan that
included training, so we did it.
Bill: that sounds fun. Would you be into using C and maybe D too? I read about
those…
I need to substitute names here, for obvious reasons, and I hope it’s
not too confusing. Bill was a classic case of feeling like he was
“working for the man” and had no autonomy or authority. I made it
clear to him that his future was his own with me, but I wasn’t going
to tolerate BS (that’s an acronym, by the way).
GIVING FEEDBACK
This is where things become extremely tricky: how do you give someone
direct, meaningful feedback without making them defensive? I love the way
Sara Drasner explains this:
How do you get around this? Asking helps. I’ve started doing an
exercise with my team where I ask the group as a whole how they
would like to get feedback. Not only does it open up ideas, but it
also helps that each individual has to think for themselves how
they prefer to receive feedback. Normalizing this type of
vulnerability and self-reflection can help us all feel like partners,
instead of some top-down edict.
Sara’s article is all about mistakes she’s made as a manager, and it’s a
wonderful read. Sara recognizes something that takes a while to learn:
people will offer feedback in a much different way than they prefer to
receive it. This can be for personal, cultural, or social reasons, and we
should never expect that just because a person is direct with you that
they want you to be direct with them. Matching styles rarely works!
110 ROB CONERY
I took over a team at a big company once and within the first 4 days
one of my team members emailed me detailing precisely what they
expected from me: meeting cadence, how they offer feedback and how
they expect to receive it. Pretty extraordinary, the definition of
managing up.
The person stood up in their chair and let me have it. We had an open
office space that was now filled with F-bombs, reasons as to why I was
a horrible manager, if I knew the answer, why didn’t I just tell him
what to do instead of belittling him? He then yelled that I needed to
learn how to relate to people, which I found ironic, but I knew he was
right. It was scarring.
This person clearly had enough and no, he didn’t get fired, but he and
I went out for a beer that night and patched things up personally. I
didn’t realize how hard I had been pushing him, and he bottled up his
rage. We mutually agreed that working together was a bad idea and
since it was my company, he agreed to leave with a severance. I want
to be clear that he wasn’t fired or pushed out the door — it was his
choice. We simply did not get along.
There was a lot I could have done better, to be sure, and for months I
thought that I was a crap manager and the Bad Apple myself. I still
think about what happened, it made a massive impact on me. This
was one of my first times managing, and I was not paying attention to
this person’s needs.
Back to Bill’s story now. I had learned from getting yelled at, and
realized that I needed to be sure that expectations were clearly set,
and that Bill understood what it took to succeed and kick ass.
Bill: this actually sounds fun. What do you need me to do to get rolling with C
and D?
Me: that’s for you to define. We need to ship (thing) by the end of (month)
which means that we need to hit milestones (names). I’ll forward you the details
and the specs — see if that’s something that works for C and D. I’m happy to
help at any time, but I’m looking for you to drive this. If you can hit these dates
with some “reasonable” code, that’s all I ask.
Me: no one does things perfectly the first time, and I don’t expect that. The term
“reasonable” means that you’ve written tests for the common scenarios, it’s
commented with variable names that make sense. It’s readable so when we do go
in to debug something, we know what’s happening.
Me: the people who might be owning this code after you get promoted to lead.
Me: hopefully. If I do my job right, one of you will be sitting here at some point
in the future.
Over the following months I met with Bill on a routine basis, and we
went over his “plan”, which was an informal document with
summaries and bullet points. He fell behind in a few areas, which was
expected, and excelled in others. Change was welcome, so we added
and tweaked as we needed to, making sure to keep the original in
place.
I want to wrap this up with a bow and say that Bill was one of my best
coders and went on to lead a team of his own, but that didn’t happen.
He learned “C and D” and was hired by another company to run a
small team using these tools. A great opportunity for him, too.
112 ROB CONERY
I feel that this much is obvious: you need to maintain your position as lead.
You’re not there to make friends, necessarily, you’re there to guide
the ship and help your team kick ass. It’s not really that simple,
though.
People move around a lot in the tech industry, and it’s extremely
common to develop a solid network of peers that tend to hire each
other — your tribe. “I’m here because so-and-so recommended me for
the job” is the norm. What’s also the norm is that someone may work
for you and love you, and then hire you away a few years later so you
could come work for them at a different company.
FIRING PEOPLE
I’ve had to do this 7 times in my career, and it made me physically ill.
The first time I did it, I was an absolute wreck and handled it very
poorly. When the person came into the meeting they had no idea they
were about to be fired, and I just blurted it out because I couldn’t
handle the interaction: “I hate saying this to you right now, but I
THE IMPOSTER’S ROADMAP 113
didn’t make this decision, it came from above me, we have to let
you go…”
The other times were still horrible, but I built up a little armor and
lobbied for a better severance for the person each time. As a manager,
you should have the ability to fight for a severance for a person who’s
being let go for performance reasons. If they’re being fired “for cause”
(an incident that can harm the company or people within), no
severance is required.
I like the scene in Moneyball with Brad Pitt and Jonah Hill, where they
discuss how Brand (Jonah Hill) would cut someone from the team.
Brand doesn’t like the idea, but Beane (Brad Pitt) is pushing him,
telling him it’s part of the job. Brand begins a drawn out, “you’ve been
a huge part of this team, but sometimes you have to make decisions
that are best for the team…”.
At this point, Beane plays the role of the player being cut, working on
Brand’s emotions, telling him he just bought a house, his kids have
made friends, and Brand becomes very uncomfortable.
What the hell are you talking about? …. They’re professional ball
players, just be straight with them. No fluff, just facts.
This seems cold, but when you bumble your way through firing
someone, it can make everything worse. We work in one of the richest
industries in the world. There are always jobs to be found, and if
114 ROB CONERY
someone isn’t cutting it, or they’re bringing everyone else down (like
Bill, above), they have to go.
Some countries and US states have labor laws that require steps to be
performed before you fire someone, even if the employment contract
says employment is “at will”. These are typically good things to do
anyway:
There is no ‘good’ way to deliver this news, so be direct. The more direct you
are, the less backlash you’ll receive, but you should be ready for it. It’s
best to expect the worst, and if that happens, you need to stay calm
and remember that you’re not there to console, comfort, validate, or
sympathize. This sounds extremely cold, I know, but if you do this
you’re going to make it worse.
Them: “You’re seriously firing me? What the actual F@@K? Tell me
why, right now, tell me why”.
THE IMPOSTER’S ROADMAP 115
You: “You have 30 minutes to clear your desk, and please lower your
voice.”
You: “If you need help clearing your desk, I can have a security person
help you.”
It seems so inhuman, but at the same time, do not let yourself be abused.
This is work, after all, and there are other jobs out there. Most of us
have been laid off or fired at some point.
You: “The decision is final, and you’ve already been locked out of our
network and security system.”
You: “If you need help with your belongings, I can have security come
and help you.”
You’ll have one of these in your career, and it’s never easy. There’s also
no good time, either. Please trust me when I tell you that
commiserating, trying to be a friend, “letting them down gently” —
none of these work. Doing this might make you feel better, but it will
only offer false hope to the person getting fired and, if you say too
much, could land you in legal trouble.
116 ROB CONERY
Note: believe me, I know this sounds heartless and inhumane. If you do consider
this person a friend, offer to talk to them after work, or take them out for a beer.
Even then, your temptation to tell them more than they should know could end
up getting you fired, too. There’s no good way out of this.
Large companies, like Google, have begun firing people via email. This
is usually during a mass layoff, and it makes sense in a twisted,
corporate way: we have to fire 12,000 people, we need to automate this
message:
On one hand, I hate this. On the other, it’s clean, and I’m not
humiliated in front of others, and I also don’t have to see my boss’s
face, which would make everything worse. For the company, this
makes sense too because they control what’s being said, and don’t
open themselves to lawsuits.
Always remember the person sitting across from you might end up as
your boss someday, years down the line. Or worse, they might be the
THE IMPOSTER’S ROADMAP 117
one interviewing you for your next job. This might sound far-fetched,
believe me that it’s not!
RESOURCES
I could easily spend the next year writing a comprehensive book on
management, hiring, evaluation, leadership skills, and more. What I
would rather do is get down to specifics in the next chapters: the
tools, how to use them, and what to think about.
To that end, I’m going to offer you some resources that I have found
extremely valuable! These aren’t books on management (aside from
Sarah’s which is outstanding), but books on how to improve yourself.
Management is a very personal thing, and my style and perspective
won’t necessarily align with yours.
In the next chapter we’ll meet your team and your project, as we have
to have something to build, don’t we?
FOUR
SIMPLE TOOLS FOR MANAGING
PROJECTS
A LOOK AT TOOLS AND SERVICES FOR
HANDLING THE DETAILS
T
he emphasis for this chapter is on the word: simple. The
principles I’m going to discuss will scale to any team, but the
tools needed to manage that team will vary depending on
your company.
I’ll start off with GitHub and its new management features, and I’ll
move on to Notion, Airtable, and Trello — two other services that are
very popular for managing things.
I’m not going to do a deep dive on the services and how they work,
nor am I going to spend much time in this section on how you should
use them — otherwise this chapter would be massive. Instead, I’ll be
revisiting how to track and manage things throughout the book
which, to me, is more organic and natural.
For now, let’s get to know the tools available to us. I should add here
that yes, of course there are so many more out there (like Retool), but
I find these the simplest and most powerful. If you start here, you’ll do
just fine.
Note: I’ll be discussing features of GitHub below, specifically Issues and Pull
120 ROB CONERY
Requests (PRs). If you don’t know what these things are or how they work, fear
not, we’ll explore in a later chapter.
GITHUB
Programmers think of GitHub mostly in terms of centralized source
control. It is that, but there is much more to it.
Manage issues
Run code reviews and automated checks
Define a process for code contribution from your team or from
the public
Manage discussions
Create documentation
See the entire development health of your project at a single
glance
It’s a powerful site, and we’ll get into the details of how to use it to
manage the development process in the chapter on Project
Management Basics. For now, let’s focus on the tooling bits.
When you first set up your repository, it will look something like this:
THE IMPOSTER’S ROADMAP 121
Note that I’ve created an organization inside GitHub called red-4. This
is useful for businesses to use to segregate work, or for individuals to
use if they’re self-employed or have an open-source project.
Projects
In the last year, GitHub has added a feature to their site that allows
project leads like you to manage tasks and timelines. As far as
management tools go, it’s basic — but that’s OK, as we can change
things whenever we feel like it.
If you click on “Projects” in the menu for your repository, this is what
you’ll see as of the writing of this book in 2024:
THE IMPOSTER’S ROADMAP 123
You can choose your project template if you like, using automations
built into the GitHub workflow. These are useful, but a “Basic
Kanban” is all we need, and it looks like this:
THE IMPOSTER’S ROADMAP 125
This is called a Kanban Board, which consists of cards moved from one
column to the next. Each card represents a singular task, and the
columns represent the state of that task. I have the default column
names in place (To do, In Progress and Done) but you can change
them to be whatever you want.
What Is Kanban?
In early 2022, GitHub rolled out their new version of Projects. The
main differences are:
Different views and filters help leads like you better understand what’s
going on.
Note that you can change the column names too. Here I’ve added a
column “Needs Approval” as it fits what I’m doing right now. Later
on, however, we should be sailing through the process and I might
need “Needs Review” when we produce things that others need
to see.
Right now, this is mostly setting statuses, which moves cards around
the board. On the right side, there are changes coming soon which
will allow you to automate things in more detail.
There’s no builtin due date. You can use Milestones for this, which
do have a due date, or you can create your own new field with a date
data type which allows you to see an actual date next to the task.
Unfortunately, you can’t filter on these with something like < today.
130 ROB CONERY
There is one other data type which find interesting: the iteration. This
is a timespan selection that defines … well, iterations, I suppose:
So, what it comes down to is this: super tight automation and ease of
information management vs. flexible reporting. For me, a snapshot of
the current tasks queued, in progress and completed under a given
milestone would suffice.
BASECAMP
I loved this site back in the mid to late 2000s. No one had ever seen
anything like it: friendly, obvious, and human. It’s still that way, and
many organizations choose to use it over GitHub because its focus is
primarily on team collaboration and communication.
THE IMPOSTER’S ROADMAP 131
They don’t just offer you a Kanban board, either. It’s a “Card Table”
and improves on it (according to them):
The power of Basecamp is not just one tool, but all of them put together
in the context of a project. This image is from their home page, but it
nicely illustrates how teams can come together in a single space to
create and share documents and design assets, chat, work on tasks,
and post things to a general message board:
THE IMPOSTER’S ROADMAP 133
NOTION
Notion is one of those tools that you can’t help but love. It can do just
about anything you need:
134 ROB CONERY
There are templates to help you get going, but from there it’s all up to
you. You can literally store anything digital in Notion. Lists, tasks, docs,
calendars, project plans, messages… it’s kind of crazy.
The pricing is the same as Basecamp, although it’s free for individual
use. I have a few Notion boards of my own where I keep all kinds of
things.
The only problem with Notion is, as opposed to Basecamp, it’s a bit
unfocused. I like Basecamp’s structure — the idea is that all information
you can add to Basecamp pertains to a given project. With Notion,
it’s… whatever you want, really. If you’re a person with ADHD or
even think you have ADHD… well, you might find Notion challenging.
Each page has properties, as I mention that you can create to suit the
thing you’re putting into Notion. You don’t have to come up with
everything on your own, either — Notion has a pretty solid set of
templates for you to plug in as needed. This is where I got the “Brand
Assets” page from:
With Notion, it’s “pages all the way down”. Your top-level page can
represent an entire library of knowledge, some shortcuts, or an in-
depth system for managing your project and daily life.
This is Thomas Frank’s Ultimate Brain 2.0, which I bought last year,
believing that I could hopefully organize my life:
THE IMPOSTER’S ROADMAP 137
As a quick aside: I do love these ideas, but I find that unflattering my brain
ironically takes a lot of brainpower on the daily. I do create notes and lists, so I
don’t forget things, but sorting and sifting is… a challenge for me.
If you want to use Notion to run your project, you absolutely can.
Everything is web-based and shareable, so you just need to set
yourself up with a team and pay per seat, just like Basecamp, and
you’re off and running. They have a mess of templates for you as well:
138 ROB CONERY
Most of these are free, but there are some premium ones in there that
might be a little more comprehensive.
Notion is a tool that I want to love. It can represent any data and let
you work with it in ridiculous ways. I would say that it’s almost
perfect, except for the following:
You most likely need to be online. There are things you can
do offline, but it’s hit or miss whether it will work. I’ve tried
using it on an Airplane (seriously) and it was painful if I’m
honest. For most people and teams, this isn’t a showstopper.
It’s a Skyrim approach to working with data: a wide open
world. On one hand, this flexibility is wonderful and lets you
work however you want. On the other hand, if you have
ADHD (or ADHD tendencies)… the faffing with covers,
structure, rules, and so on is a major distraction to getting
work done. Your team can also destroy things or not know
where something goes, and just create their own silo of
information. It takes work to stay organized.
Your information is stored on their servers. It’s the web and
THE IMPOSTER’S ROADMAP 139
AIRTABLE
Airtable is one of those apps that is instantly appealing:
140 ROB CONERY
You can manage just about anything with Airtable. It’s a combination
online database, spreadsheet, and intelligence tool all rolled into one. I
use it for every non-coding project I work on, it’s that good.
Airtable is free, but there are paid upgrades that are definitely worth
the price. It starts at $24/month and goes up if you add people (such
as other team members) to your base.
These are databases to start out with, but are extremely flexible in
terms of data and how its represented.
Once again: keep it simple, stay focused. Our goal is to know what
we’re doing right now. We can always expand as we need to, but
presently we need to know how to go from nothing to something with
our new product, the Red:4 LMS.
If you don’t know what stories, sprints, and epics are, don’t worry.
We’ll get into that later. What is important is that we have a place to
start with some test data to help us out:
Here you can see the fields “App section”, “Stories” and “Epics” — all
of which relate to the other tabs.
The true power of Airtable comes with the ability to filter and view
data. The most common view is the spreadsheet, but you can also
view data using a Kanban if there’s a status field or a calendar if the
data is time-dependent. You can set up input forms for people to enter
their data, and you can also add fun “apps” that do interesting things
with your base:
THE IMPOSTER’S ROADMAP 145
The Pivot Table is great for exploring historical data, and SendGrid
will email a group of people based on whatever conditions you’ve
set up.
The power of Airtable lies with the way it can represent data. There
are the usual types (strings, numbers, dates, etc.) but you can also
attach files, barcodes, references to users, formulas (which are very,
very useful), long text with formatting, phone numbers, emails,
146 ROB CONERY
Here I’m adding a column called Status set to Single Select. I then
added the selections I wanted. When I added the column it was empty,
but I set the first to “To Do” and was able to drag/copy the choice
down in the same way you might do with Excel.
Now that I have the Status set, I can create a new Kanban view, using
Status as the column definition:
THE IMPOSTER’S ROADMAP 147
Cons of Airtable
I like Airtable a lot, if you couldn’t tell. It’s extremely flexible, and
you’re able to create reports and views easily. The only downside is
that data entry is much more manual and, likely, will have to be
done by you.
There is an integration with GitHub using Zapier, but I’m not a big fan
of stitching together what feels like a funky machine just to know
what’s going on. As I mention, I use Airtable for most of my non-
technical projects, like writing books or making videos. For these
tasks, it’s extremely useful and makes collaboration a breeze.
TRELLO
Trello is Kanban on steroids. They offer templates, just like Airtable,
but it’s all about the board:
Power Ups
Power Ups are essential “plugins” that extend your board in any
number of ways, and they’re totally free! Some integrate with other
services, others enhance cards so that specific information can be
embedded easily:
150 ROB CONERY
Here are some of the Product and Design Power Ups. You can add
User Testing information to your cards, wireframes, Figma diagrams
and a lot more. Like I said: overwhelming.
Let’s add one! I want to track what’s going on with our GitHub repo,
so I’ll add the GitHub Power Up:
Once I’ve added the GitHub Power Up and authorized Trello to access
my GitHub account, I can open a card and see GitHub in the Power
Up menu:
THE IMPOSTER’S ROADMAP 151
For instance, let’s say I have a card representing a task to fix the tab
alignment in our user interface. I created an issue for this on GitHub,
but I also want to track it in Trello — and I can:
Back in GitHub, the issue has been updated with a Trello link:
152 ROB CONERY
Notice that the label for the issue is also attached to the card!
Automations
THE IMPOSTER’S ROADMAP 153
You can even make the trigger time and date based, acting like a cron job:
Once again, I could spend the entire book on this one topic:
automating Trello. It’s unbelievable how powerful this tool is! It will
even send you periodic emails on the current state of your board that
you can review every Monday, for instance:
154 ROB CONERY
This is a “board snapshot”, but you can also have Trello send you
overdue tasks, tasks assigned to you, and tasks that are due soon.
The one major downside of the Trello automations is that they don’t
seem to work with Power Ups very well. For instance: when an issue
is closed on GitHub, it would be nice to move the card containing it to
“Completed”. I can’t find a way to do that as of this writing,
unfortunately.
Cons of Trello
WHERE’S JIRA?
If you’ve worked in an enterprise setting, then you’ve likely had to
work with JIRA at some point. I used it back in 2000-something and
let’s just say it was challenging. It started life as an open-source bug
tracker and morphed into a complex Agile project management tool
owned by Atlassian.
It has all the greatest hits that almost every tool in this chapter has:
Kanban boards.
Task tracking and reporting.
Issue triage and tracking.
Roadmaps and team structure.
As you can see, JIRA is focused on helping your team focus on Agile
156 ROB CONERY
OKRs? Elevator Pitch? These are things that you might end up caring
about later in your career, when you take over an organization,
perhaps, or you found your first startup.
Someday you might have a PM that will do this for you… for now, you
are the PM and that means you need to know your tools.
This tells me a lot and I might have some questions, but overall, it’s
where I might expect you to be as you’re just starting out.
Automated reports are nice, but the best reports offer a quick
summary at the beginning, hopefully stating “we’re right on schedule”
or “we’re ahead of schedule by a week” and then detailing the
feature/task progress. All I want to know, as your boss, are two
things:
That’s core project management right there and yes, it’s boring, but
it’s also the first step to a brighter, more exciting future when you can
hire a PM to do this stuff for you… and you can be the CTO.
For now, however, you’re the one generating reports and your tools
will need to help you, so whatever you choose needs to be able to
THE IMPOSTER’S ROADMAP 159
I think you can sense my thoughts on this topic: keep it simple, use
GitHub. At some point, you might outgrow GitHub completely and
that’s OK, nothing will be lost. Your status updates will be more
manual, but that’s OK too, as having an executive summary at the top
of your email with specific detail will be appreciated.
You can define tasks on your project board and turn them into issues
easily, and you can also see the progress of a PR directly on your
board. Unfortunately, as of this writing, you have to manually add
issues and PRs you want to track — it’s not automatic. I think this is
OK — that’s what triage is all about when issues come in. You don’t
want every issue automatically added to a work queue, as they often
require discussion and careful consideration.
For the rest of this book I’ll be focusing on GitHub as my PM tool, but
if you have a different tool, that’s fine too! Ideally, you can translate
what I’m doing to your tool of choice. And no, I’m not making this
choice because I work at Microsoft , it’s my choice for code-heavy
projects!
FIVE
PRINCIPLES OF INTERFACE
DESIGN
ADDING SOME POLISH CAN MAKE ALL THE
DIFFERENCE
T
here are two questions you might be pondering straight
away:
The reason it’s here is that we’re doers. We execute and deliver
something even when, especially when it’s not completely thought out.
Reflecting on our laws of power:
I’m not a designer, but I do know there are a few principles that are
easy to learn. This is extremely useful in the early stages of a new
project.
Notice that I have denied the use of a designer (sorry… not sorry)
because I would rather not spend money just yet if this thing doesn’t
work out, and you can’t deliver something useful!
Phi has been used in science and art for centuries, and many artists
have claimed that it holds the secrets of beauty. Scientists tend to scoff
at this stuff, and I won’t dig into the debate here — but the ratio is
useful to us when thinking about UI design.
I want a window that’s 800 pixels wide, but the question is, what
should the height be? If I’m using phi, I can divide 800/1.613 = 495,
so I stay “in ratio”:
164 ROB CONERY
Great. So now I want a header bar and I want it to be “in ratio”. I could
divide 495 by 1.613, but that would be far too big. If I keep dividing,
however, I’ll eventually get to a number that I can round to 45, which
looks pretty good in terms of proportion:
You can keep going in this way, or you could just use a grid system
that’s figured this out already.
The “container” for the bars you see here is 960 pixels wide. Each
pink column is 60 pixels and the gap between columns is 20 pixels.
There’s an offset at the beginning and end that are 10 pixels apiece.
While not exact, this spacing is based on phi.
You don’t need to whip out your calculator every time you do a page
layout! It is a good idea, however, to know if you’re looking at a grid
that’s part of a framework or someone’s arbitrary idea of what a grid
should be (that happens). As long as phi is in there somewhere, the
layout should look pleasing to the eye.
CHOOSING COLORS
It’s important to understand what you’re doing with color from the
very start of the project. People have an emotional reaction to color, so
you need to take care to get it right and have that reaction match your
project or company branding.
Red:4 has its own branding, but you’re free to do something more
creative and appropriate to an LMS, whatever that means. I suppose
I’m offloading the responsibility to you, so choose wisely!
166 ROB CONERY
Let’s explore the basics of color theory and why it matters to you.
Accessibility Concerns
The article linked above is a great first start when considering your
color choices. It’s difficult to get it right, but trying is everything.
We care about the color wheel because with it, we can work with color
in a straightforward way.
Using the color wheel, we can divide all the colors into two buckets,
warm and cool:
168 ROB CONERY
We’re helping programmers learn things using video and text. Ideally,
they should be calm and feel comfortable in a non-distracting
environment.
You’ll find 3 main colors for most brands, with an emphasis on one or
two “main” colors.
The main brand color is a sky blue. The secondary color is a variation
of the main color, and I suppose you could say there’s a third color in
there, represented by the muted “Tweet” button.
Twitter changed the tint and tone of its main color to produce its
secondary color. Tweaking shade, tint, and tone is a great way to come
up with your starting color, allowing you to pick complementary or
analogous colors from there.
You can get lost exploring this site, but let’s stay focused and head to
the palettes:
THE IMPOSTER’S ROADMAP 173
This is the “Most Loved” tab, and I can see why — these combinations
are wonderful! I wouldn’t say they are bold, so they fit what I’m after.
I like the blues and greens — cool tones that I’ve been looking for.
To me, the trick with choosing a color palette is to use the first one
that jumps out at you without thinking about it too much. Here’s one
that fits for me:
174 ROB CONERY
I only want three colors to start with, so I’ll choose the dark and
lighter blues with the lightest green as an accent color:
I might change this as time goes on, but this is a great first start,
mostly because we haven’t spent too much time on it!
THE IMPOSTER’S ROADMAP 175
I interviewed Bill in 2010 and if you have a moment, have a listen. The
entire episode is devoted to the power of typography, but Bill’s stories,
to me, were magnificent. His Scottish brogue coupled with his wild
excitement was something truly special.
Anyway: Bill had a theory that the hunting instinct inside of us saw
fonts as animal tracks laid down on a trail. We would find the shapes
pleasing and distinct, and our brains evolved an attraction to the
symmetry.
Obviously, our text needs to be legible, and font size is key. Users can,
of course, change the zoom on the screen to read what they want, but
that will throw off our layout. Legibility goes far beyond the main
body text as well: we need size gradients between headings that are
pleasing to the eye, with proportional margins.
You’ll never guess how we figure that out! That’s right: phi.
176 ROB CONERY
There’s no need to overthink this! The most legible body size we can
use is 16px, but that, of course, depends on the font.
Note: if you don’t know what Lorem Ipsum is: it’s placeholder text that designers
and copywriters use so that they can ‘block’ their designs with text. It’s very
useful, especially when showing your client something as they will often fixate on
what you’ve written, rather than the design itself.
It’s impossible to recreate 16px font size using an image and an ebook
reader, but do your best to imagine!
The headings and body that you see here were blocked out using the
Golden Ratio Typography Calculator. Go play around if you like — but
hopefully, you can see how the type flows easily from one heading to
the next and the lines are spaced evenly.
I’m using a typical approach to fonts here, which is pretty boring (but
very legible): Helvetica for the headers, Georgia for the body. Helvetica
is a sans serif, the word “sans” meaning “without” in French and
“serif ” coming from the Dutch word for “line”. Georgia is a serif font
THE IMPOSTER’S ROADMAP 177
because it has little “serifs” or lines on the tops and bottoms of each
letter.
The header here is Alpha Slab One and the body is Avenir. This font
choice is less “traditional” if you will, than Helvetica/Georgia, but that
could work in your favor if you’re trying to create something that
appears more “fun”.
Some fonts are bigger than others, or at least they appear that way.
Compare Alpha Slab One to Helvetica above it: it simply takes up
more space on the page.
178 ROB CONERY
You can use the GRT Calculator above, but a simpler resource is type-
scale.com, which will also generate the CSS for you. Easy-peasy!
Now we come to it: which fonts are the best? It’s impossible for me to
answer that because fonts convey so much to your reader. It’s like
asking me what the best shoes are! Some people wear trainers
everywhere, other people have a separate closet for their shoe choices.
It comes down to the feeling you want to convey. Bringing this home to
our project, I think a “playful ease” would work well. At least that’s
what I want our user to feel when using our site because learning is
fun and, if taught well, should also be easy.
A great resource to research font use is also the place that will likely
supply your fonts: Google Fonts.
They have extensive articles on what fonts to choose, why and when.
One article that I love is all about “Emotive considerations”:
THE IMPOSTER’S ROADMAP 179
Selecting the right font is not a simple matter, and you’ll likely go
through a few iterations before settling on the “right one” for your
project. What you consider playful vs. what I do is up for debate. As
your CTO, do I trust your judgement or do you just try to make me
happy?
This is Doppio One for the headers and Georgia for the body. I’m
using all caps on the headers for legibility, as they’re easy to find and
Georgia is easy to read. Doppio also has some playful geometry to it
that’s a little more rounded.
THE IMPOSTER’S ROADMAP 181
This is Rockwell for the header and Avenir for the body. I like it as
it’s a bit more bold than Doppio/Georgia.
This final set has been my go-to for book writing for years:
The headers are Bebas Neue and the body is Iowan Old Style, one of
the default fonts for reading on the iPad. To me, this font is extremely
legible and the slim, clean lines of Bebas Neue really stand out
against it.
Let’s decide and stop thinking about it, shall we? I like the second
choice of Rockwell and Avenir. It’s simple, straightforward with some
“clean whimsy”. How’s that for a description!
If you’re extremely clever about fonts, you might be able to get away
with using a script font as your header. If you try to use one as the
body, I’ll find you!
This is National Forest and (I hope) conveys why you don’t want to use
scripts:
The bottom line is this: scripted fonts are for decoration, not reading.
The most notorious misuse of a script font is Comic Sans, which you
see everywhere:
THE IMPOSTER’S ROADMAP 183
This font looks like it came from a comic book, thus the name. If used
in that context, OK sure, but it’s come to be recognized as the go-to
font used by people who try to liven up their corporate email template
with something “exciting”. It is, truly, the Rick-roll of the typographic
world.
Arial is the last font I would like to address. It was created as a knock-
off of Helvetica for various reasons that you can read about here.
Design-wise, this is a perfect summation of Arial:
heritage, Arial gets chosen because it’s cheap, not because it’s a
great typeface.
It’s not so much that it’s “bad”, it’s just… overused, watered-down
and kind of not good. It’s like wearing trainers everywhere…
SUMMARY
We’ve discussed layout, colors and typography, let’s update our board:
This might seem like overkill, what I’m doing here with the board, and
also more than a little contrived. Believe me it’s not: tracking your
work and communicating what you’re doing (and what you did) says a
lot about you as a leader.
them happy but not so much that they start to meddle in what we’re
doing. Meddling is the dark side of human kindness. People like to
help other people and sometimes get lost in their own needs. When
bosses get over-anxious and feel uninformed, they start to
micromanage and make your life difficult.
We now get to take the next step in our project: getting to know who
our users are through stories. This can be a highly orchestrated dance,
or it can be an hour’s exercise with a keyboard — either way, it’s a
crucial step.
SIX
CREATING USER STORIES
THIS AGILE PRACTICE CAN HELP KEEP YOU
FOCUSED ON WHAT’S IMPORTANT
W
e are about to step delicately into the world of software
development methodologies, namely Agile and the ideas
behind it. It’s been 20 years now and Agile’s footprint is
everywhere, even if smart people think they’re breaking away
from it, they’re not.
I flew out to Chicago every other week as we built The Plan. My client
insisted I start building things anyway, sort of in secret, as he sat
through meeting after meeting creating this beastly set of documents.
It was a funny way to build software.
So in 2002 the 17 dudes put together the “Agile Manifesto” and gifted
software developers with a better way to do things. I don’t mean that
sarcastically, it was a radical and very welcome shift. People complain
about Agile processes these days, but let me assure you that you do not
want to live through The Project Plan. It kills any desire to build anything.
In the next chapter we’re going to dig in to Agile and what it’s become
in the modern day because you will need to understand it if you
expect to be leading a team.
This created a problem. I’ll illustrate this issue using a story from my
experience.
Let’s revisit the Ameritech project with the gigantic Project Plan. My
company was hired along with 6 other consultants to help design and
THE IMPOSTER’S ROADMAP 189
Keep in mind that “the web” was just born a few years prior and
Google didn’t exist yet. Yahoo was the default search engine and
companies were making millions by putting things online. The public
was yet to catch up with the whole thing, but the wave was starting to
roll.
The requirements for the project came from another consultant who
frankly had very little experience with the web and just “wanted in” so
he did what consultants do: convinced you he knew what he was
talking about. His plan reflected that lack of experience and his design
for this information portal looked just like the DOS screens, but as a
web page. His idea was, basically, “let’s not shock our call center reps
too much”.
Dino liked the idea and absolutely loved the interface. But I took it
one step further and asked the IT team for a dump of sample
190 ROB CONERY
documents from the DOS system, and they gave me 6000! I took
those documents and had a Microsoft Server tool called IndexServer
scan over them, making them searchable by the web framework I was
using, classic ASP. When I showed a working prototype to Dino, he
almost lost his mind.
Mediocrity is toxic — put on a good show. That, and Make your wins look
easy. “Oh, and by the way, the search box works and uses your data.
Give it a try…”
I’ll tell you more about this story later, as it quite literally defined my
career — for now I need to get back to my point! Which is this: our
customers were the call center representatives and the three of us
(me, Dino and the unexperienced consultant) all had three separate
ideas in mind about what they wanted. That was messy, to say the
least.
THE CUSTOMER?
This is where we come back to Agile and reflect once again on the first
principle:
It’s a good principle, in principle. The idea is that you have as much
empathy as possible for the people who are about to use your
software, and then you show it to them as often as you can, asking for
feedback. You take that feedback and change things around and deploy
as often as possible until you “get it right” and the customer likes
what they have.
THE IMPOSTER’S ROADMAP 191
Sounds good, doesn’t it? “The customer is always right” and “give the
customer what they want” are rules of modern business… but then
again there’s a very famous quote from Steve Jobs that I like better:
Some people say give the customers what they want, but that's
not my approach. Our job is to figure out what they're going to
want before they do. I think Henry Ford once said, 'If I'd ask
customers what they wanted, they would've told me a faster
horse.' People don't know what they want until you show it to
them. That's why I never rely on market research. Our task is to
read things that are not yet on the page.
There’s a lot of truth to this. Let’s return to the Ameritech story, I’ll
share what I learned.
Back in the late 1990s, big companies like Ameritech had no problem
letting consultants go to war for them. In fact, that was expected and
business as usual. That’s what Dino did to my company and the
Unexperienced Consultant. I’ll never forget the day I demoed what we
had put together — a full working prototype that looked like a modern
web application — and what the consultant had put together — a
PowerPoint presentation that looked like crap.
Each rep had to sit in a small, glass booth about 4 meters wide and 8
meters tall with cameras pointing at their face, hands, and screen.
192 ROB CONERY
They had to pretend they were at work but instead of their DOS app,
they were using the site I created.
We weren’t allowed to tell them how to use it, they had to figure it
out based on what they saw. The first person got it instantly and
searched for the term “marina install” (for installing a phone line on a
boat at the marina on Lake Michigan). It came up instantly as the first
result (thank you IndexServer) and she clicked the link and read the
answer and, literally, started to cry.
Can I please have this right now? You don’t understand… this is
wonderful. The current system is so confusing … bless you…
bless you!
She really did say “bless you” twice and gave Dino a massive hug. She
had been with the company for 3 months and was really having a hard
time learning the system. Call center reps were rated based on the
number of calls they could successfully answer per hour, and their
knowledge of their system played right into that. If our first rep had
our system, she could answer more calls and get paid a lot more.
Is This Necessary?
The second rep had been at Ameritech for 8 years and was a
supervisor. His reaction was instantly negative, and he said something
I’ll never forget:
Is this necessary? Our system works fine right now, what’s the
problem?
THE IMPOSTER’S ROADMAP 193
Hard to argue with that. From Rep 2’s perspective, this entire effort
was a waste of time. He fumbled around the page a bit, read the help
document I hastily threw together based on Dino’s feedback, and
managed to answer the call professionally within a reasonable time.
He then told us he would have done far better with the old system.
The final rep that came in that day had some fire in her eyes. She
wasn’t exactly happy to be there, mostly because she worked in
downtown Chicago, and we were out at the corporate headquarters in
Hoffman Estates, about 45 minutes away. Her pay was the same, but
this was inconvenient.
She sat down, saw the screen and said, “what’s this?” Dino explained
over the monitor that it was a website and started to give her a little
more information, but she cut him off with “why do I need a
website?” At that point, Dino asked her to focus on the test call and
do her best, and we would try to answer her questions afterward.
He started the call, and she looked baffled, but then looked down to
her right and saw a mouse and rolled her eyes. “I hate these damn
things” she muttered, making sure the call was muted. The pointer
shot around the screen as she adjusted, and eventually, she made it
through the call and told Dino how he could order service for his boat
in the Lake Michigan marina.
Note: it’s always a good idea to empower keyboard warriors out there with
shortcuts. Extra credit for doing a keyboard command overlay too.
Why I gotta use a mouse? These things are hell on my wrists, and
it took me months to get the keystrokes down for the system we
use now. I don’t see how this is any better.
194 ROB CONERY
Dino was one of those “fun clients” who liked to geek out with you.
He was a trained musician and insanely smart, often buying books on
HTML, programming and databases (as that’s how you learned things
back then) so he could be sure he knew what we were up to. Together,
we figured out how to add keyboard shortcuts to the portal, and our
third rep was thrilled about that later on.
In short: we know our customers and what they think they’ll want. That’s a
bold statement and, in fact, I would say it’s pretty arrogant. Then
again, Apple’s product launches are famous for having lines around
the block, so they must understand something about people.
Putting on my CTO hat, I will tell you that I loathe mediocrity and no,
I don’t want an application built by committee that retreads
everything else out there because that’s what the user will be familiar
with. Yuck!
On the other hand, I’m not a visionary. You might be, and I’d be lucky
to have you in that case, but for now, let’s just say that both of us
might have some fun ideas about how to build a given application.
Let’s see if we can be human about this, and we’ll focus on the same
LMS system we discussed in a previous chapter, the Red:4 Developer
Portal.
Then comes the fun part: we synthesize our efforts and describe our
perfect user and just try to please them, forgetting the rest.
I also don’t want to confuse the hell out of them with something
completely unexpected. Let’s see how we can meet in the middle
somewhere with a set of user stories, something you’ve likely heard
about.
I like to be positive, so let’s lead off with Jill, our most excited user.
Jill has been working at X Corp for the last 15 years as an Oracle DBA
and has hit a point where the work has become routine, and she wants
to make a change in her career. She heard from a friend that
PostgreSQL is gaining in popularity and features, and she has decided
to stop dismissing it as trivial and to learn what she can about it.
Santosh has been offered a position at the new company, but he’ll
need to skill up on PostgreSQL, which he is not excited about. He has
invested an incredible amount of time getting to know SQL Server and
how to effectively administer it. He likes his company and the people
he works with and does not want to leave. He’s also been offered a
substantial raise if he stays and a healthy budget for training
materials.
THE IMPOSTER’S ROADMAP 197
Fen has been appointed the “Dev-DBA” as they know the most about
MySQL. Red:4’s PostgreSQL tutorial came up in discussion and looked
promising, and Fen decided to try it out.
Fen enjoys the job and doesn’t feel the need to look for another one.
The tech industry is about adapting to changes and learning new
things, so this is all in a day’s work.
It might seem like I’m being just a little cheeky with this example, but
it’s actually one of the better Agile-flavored user stories I’ve read!
You’ll see the word “empathy” often used in articles written about
user stories. This explanation is from Atlassian, the creators of Jira,
when discussing “As a”:
Who are we building this for? We’re not just after a job title,
we’re after the persona of the person. Max. Our team should have
a shared understanding of who Max is. We’ve hopefully
interviewed plenty of Max’s. We understand how that person
works, how they think and what they feel. We have empathy
for Max.
In spirit, I agree with everything said here, but in practice, this often
falls apart. Consider the examples given (same article):
important, but they don’t drive the story into the vision end of things.
That’s what we want to do with our next exercise.
Suppose you had a service you could offer that could save people
$100 a year. This is a service that could benefit anyone. It’s a
service you can perform and anyone can consume… If you don’t
tell people about this service, then you are cheating them out of
that $100. You owe it to them.
Chad talked about this at a conference in Poland that I was at, and it
really stuck with me. And, to be fair, this thought didn’t originate with
Chad — he is relaying it from an article he read once and try as I
might, I can’t find the link!
You don’t have to agree with me on this, and you can make whatever
you feel like making and hope that people use it, and you know what?
Maybe they will! In fact, I’ll pile on that sentiment and say that a
common thing you hear when successful entrepreneurs are asked
what their inspiration was for making Product X goes like this:
200 ROB CONERY
I dunno, I just made it for me. The fact that other people like it is
cool.
Let’s bring this back to Jill, Santosh, and Fen. Is one of them our
perfect customer? Let’s see:
Jill wants out of her job yesterday and is very excited to learn
PostgreSQL. It might seem like she’s our perfect customer, but
there are plenty of reasons why this might not be true,
including the fact that she might prefer books to videos or find
our presentations off-putting.
Santosh might seem like our nightmare customer, but then
again, he might be astounded by PostgreSQL after 10 minutes
and make a full turnaround, crediting us with changing his
career.
THE IMPOSTER’S ROADMAP 201
I think it’s clear that none of these people, as written here, is our
perfect customer, but there are parts of them that fit well. Jill’s
enthusiasm for PostgreSQL, the opportunity to change Santosh’s life,
and Fen’s desire to optimize their time.
I was reading the book Dotcom Secrets by serial hustler Russel Brunson
because, as I mention above, I finally gave in and realized that
understanding who was buying my stuff was critical (aka
“marketing”). Unfortunately for me, I normally thought about this
after I created things, not before. That’s OK too — but I could have
saved myself a ton of time if I had gone through the exercise of
figuring out who, I thought, would benefit the most from what I was
making.
Put another way: I should have figured out where my product would
have maximum impact. At this point, I need to ask for your patience
because yes, I know we’re veering into the non-programming realm,
but in truth, programmers began doing that with the rise of Agile. We
stepped out from behind our glowing monitors and asked to be part of
the project process… so here we are.
can probably guess: by focusing like this, he worked less and made
more sales. His “true fans” grew, and they did the sales work for him
through word of mouth, and life became better.
It’s important to note that you can’t do this alone, even if you’re the
project lead. Being the doer that you are, you can take a stab at it but
make sure your client (me) is clear that it’s a starting point and
validation is needed.
So, now, let’s pretend that you and I walked through that process and
“rounded out” our main character.
Meet Alex
While Alex is enthusiastic about the job, they also know their work
comes second to their personal life.
Alex found Red:4’s site through a friend and is excited about the
prospect of becoming a PostgreSQL DBA. The comprehensive video
library and book collection aren’t overwhelming at all, and the blog
posts are simple, focused and direct. Alex is excited to get started and
feels like they could be at the beginning of a major career shift.
THE IMPOSTER’S ROADMAP 203
Simple enough and a great place to get started. You’ll hear me say this
a lot through this book: simplicity at every step is the key to
shipping software. If something you’re doing is too complicated,
break it into smaller, simpler parts and make those your focus, one at
a time. I’ll come back to this, repeatedly.
Alex heard about Red:4 from a friend and was intrigued, so they
Googled us and found our site at the top of the search results. They
click the first link, which is our homepage, and are greeted with a
simple, elegant site and a compelling headline. The images are
engaging without being the typical corporate, bubbly vector artwork.
They’re images of smiling people of all ages, having fun writing code.
Alex scrolls down and sees a headline and some imagery that
describes choices for career paths: Data Professional, Machine
Learning, Backend Programmer, Frontend Specialist and more.
Alex clicks into the Data Professional career path and sees a headline,
description and 3-minute video at the very top. The video describes
the life of a data pro and what the work is like, and then shows how to
get started.
Alex sees the courses below and that the first lessons are free, so they
click through and watch for a few minutes. The videos are high quality
with great production value and the narrator has the most pleasing
voice. Alex is eager to know more.
They click on “About” in the top menu and instead of a wall of text,
Alex sees a picture of the entire Red:4 staff on a beach in Hawaii. The
page is broken into parts, including who they are individually, what
their purpose is, and who they hope to help.
Alex sees they have a blog as well, and the option to have it delivered
via email (a list service). Alex joins the mailing list and reads through
the blog posts, which are entertaining and personable. They like the
lack of corporate veneer and really appreciate the shared enthusiasm
the team seems to have.
Not ready to commit just yet (but very close), Alex decides to think
about it for a few days. Over the next week, a post is delivered via
email and at the bottom is a mention of a discount for being on the
mailing list. Alex uses the discount and signs up, delighted with their
choice.
If we were using Agile for our project process, I’d be in trouble with
that story. It’s too long and has far too many individual tasks. Agile
user stories tend to be extremely focused and spawn very few tasks,
perhaps 5 at most.
but I wanted to prepare you for the jargon blast that’s coming your
way, and arm you with a simple defense:
Agile is just a way to think about and organize what you and your
team need to do
That’s it. Things have names which come along with rules attached
and, like anything, adhering to the process does not guarantee success.
That said, being organized really does help. So we’re going to do our
best to comply.
What we know right now is that we need a few things to make Alex
happy, and those are:
A Home page
An About page with information about the team, our
vision, etc
Career Paths, which we can also think of as “Categories”
Technologies, which we can think of as “Tags”
A Blog
A Mailing List with a signup option somewhere on the site
SUMMARY
As you can probably tell, Alex is my perfect customer and who I gear
all of my content towards. Personally, I feel that the 5-year mark in the
career of a programmer is a “make or break” moment where you’re
206 ROB CONERY
either inspired to take a leap of faith or you shift into cruise control
and let the days roll out. There’s no way I can help the latter folks — I
like exploring far too much!
You can probably also tell that I like the Agile process in general, but
I’ve seen far too many projects fail because the process outweighed the
product. People can’t help themselves, they like to know what they’re
doing before they do it and will often take things too far. That’s a
people problem, not a process problem.
Onward!
SEVEN
SOFTWARE PROJECT
MANAGEMENT BASICS
GETTING TO KNOW AGILE AND IT’S
VARIOUS FLAVORS
W
e focused on our users in the last chapter, which is as it
should be. In this chapter, we’re going to use Alex’s story
to prepare for our first sprint: the initial demo. This is a
crucial time for us.
This is when things get real, and we can’t take a single step until we
have some process in place. This project will be reviewed someday,
right back to the first day, and every move we’ve made will need to be
documented and understandable without sloppy cowboy coder
nonsense.
In the next chapter, we’ll go through the steps to actually build the
demo. In this chapter, we’re going to figure out what those steps are
and wrap them in some kind of process.
208 ROB CONERY
To sum this up: Agile is about infusing software with humanity. At our
best, we’re messy, change our minds often as we learn new things,
enjoy building for a better future and generally try to improve
ourselves.
UBIQUITOUS TERMS
Like any good religion, Agile has a few denominations to go along
with it that muddy the waters. People have learned the how, but make
up their own reasons when it comes to the why, and arguments start.
One of the primary knocks on a team trying to be Agile is just that:
they’re trying, but not doing it right (according to the person leveling
the criticism).
210 ROB CONERY
I’m going to sidestep what “going Agile right” means, and get into the
terms that every Agile team needs to understand. You have probably
heard some of these terms before, and they are:
There are other terms used which are pretty obvious, and you tend to
pick these up as you go along. In addition, each framework might have
THE IMPOSTER’S ROADMAP 211
additional bits of jargon (like Scrum) as well, and we’ll discuss those
in due course.
Speaking of frameworks, there are two that dominate the Agile space:
Lean and Scrum. If you’ve been working as a programmer for any
length of time, you’ve probably had to deal with one of these, and it’s
likely that you followed Scrum, which I’ll discuss below. Lean is also
very popular, so let’s start with that.
LEAN / KANBAN
I remember when Lean started gaining popularity as a necessary
revision to Agile back in the mid/late 2000s. People began talking
about Toyota production lines and Kanban boards and the idea that
relentless focus on quality, minimalism, and eliminating “waste” was
the natural evolution of Agile. Given its roots in the Toyota production
lines, people began to infuse Japanese cultural practices and even Zen
principles into their software development process.
I worked on a team that was using Lean ideas, and the project
manager took it so seriously that he would never send an email longer
than a single sentence. His code review comments and issues were
famously terse — two sentences at most. Somehow this made him a
good Agile person, I guess.
Kaizen
212 ROB CONERY
These are fun ideas and take a committed team. The theory is good,
but, as we know, people tend to be people and dig chaos (Chaos is your
friend). This is where a strong lead, such as yourself, earns their
paycheck.
For instance, I’m trying to finish this book and can’t seem to do it. It’s
taking forever! If I was journaling this problem, I might ponder it
thus:
Why (1)? Because I can’t seem to find enough time in the day and
the mental strength.
THE IMPOSTER’S ROADMAP 213
Note: I like my job and the above conversation is just for example.
This process doesn’t take all five whys, it’s clear that my day job is
sucking the motivation out of me and my chosen writing time (the
evening) is the wrong time. I can solve this problem simply by
changing the times that I write.
I’m currently writing this in the morning, bright and early, right after
doing yoga for 20 minutes. Every so often, I go on a walk before I
write as well to make sure my brain is clear. I started waking up 90
minutes before I normally do, and I have a target of 2000 words/day.
So far, it’s working like a charm!
MVP
When you hear the term “MVP” it means “minimum viable product”
— the absolute least possible thing that will deliver value. You then
iterate on that (making sure you don’t waste effort and keystrokes)
until you reach product enlightenment.
It might be more apt to say that we build the factory… but even then,
that’s not entirely accurate. Creating software is an organic process
where an idea is conceived, grown internally over time and then
introduced to the world. It doesn’t stop there — growth continues,
followed by eventual decline. This, to me, doesn’t reconcile with the
idea of an assembly line that assembles parts and then everything is
finished. That’s not software development.
On the more concrete side of things: projects using Lean tend to lose
sight of the big picture and the opportunities that distraction and
inspiration can bring. The best features of any application are often
wild bits of inspiration that come in the middle of the night or while
on a walk at the end of the day. Twitter, for example, was a goofy side
project at Odeo and basically thrown together in a short timeframe.
Given time and room to grow, who knows what these things can turn
into.
There are plenty of good things about Lean, to be sure. The Five
Whys, constant, small improvement and a focus on positivity are all
things we can bring in to our project.
THE IMPOSTER’S ROADMAP 215
SCRUM
Probably the most popular Agile framework, Scrum is focused on
turning programming into a team sport. It’s almost a cult:
This person’s job is, basically, the “master of ceremonies”. The word
“master” might be in the title, but there is no actual authority in this
role. In fact, all the roles are equal in terms of authority.
The Scrum Master’s job is to make sure the entire team is following
the game plan and is playing by the rules. They are both coach and
referee, ensuring that the project scope and vision are understood by
all and that everyone is participating in the Agile process.
It’s more than that, however. The Scrum Master is there to support
and help, not to dictate policy. It’s a delicate role to play as there is a
lot of implied authority, yet no actual authority.
As the name implies, the Product Owner’s job is to make sure that
what gets shipped is what is intended. This doesn’t have to be strictly
what the customer wants, it can be somewhere along our Agile/Apple
spectrum: aligning with customer demand or with the CEO’s vision.
What gets shipped just has to comply with whatever vision has been
stated.
A Product Owner will guide the creation of user stories and epics (a
collection of user stories), work with the business
owner/founder/CEO to ensure that the stories align with the vision,
and also ensure that the team is executing according to the stories
given.
The team’s job is to build things within the scope and time given. If
the Product Owner and Scrum Master do their jobs, the team will have
a concise set of requirements to work on in a well-defined timeframe.
The cool part about a Scrum team is that they can self-organize to
execute as they see fit. This means that the team should be big enough
to organize into smaller “pods”, sort of like a caper flick where you
need a team to handle the crowd in the bank, a team to disable
security, and another to break into the safe.
THE IMPOSTER’S ROADMAP 217
The team has the sole authority to execute as they see fit, as long as
their goal is to execute against the sprint.
Sprints
In the Scrum sense, the Scrum Master and Product Owner work
together to define what goes into a sprint, favoring small, effective,
positive results. These are traditionally 2-week periods.
Scrum won’t work if the team isn’t united and sharing what they’re
doing and what they’ve learned. This is also called transparency and
must be in place from top to bottom.
The Retrospective
When a sprint has ended, the Scrum Master might call a meeting to
discuss how the spring went. A few things they’ll want to know are:
This kind of meeting can spiral if the Scrum Master does not focus
it. Even then, you can expect to be in this meeting for hours as
people dive into project process, communication and overall
improvement.
The first and, to me, most glaring problem with Scrum is that
programmers aren’t professional athletes competing on a team. It’s
critical to understand that what works for a professional rugby team is
entirely different from a group of developers.
to learn a few things, but it’s hardly the same. Your performance in
the daily standup won’t make or break an entire sprint!
I’m sure there are programmers (like myself) who enjoy competing in
organized sporting competitions. Personally speaking, that’s not the
way I want to build software.
I don’t think I’ve ever been part of a standup meeting with 10 or more
people that hasn’t gone over by at least 15 minutes. That’s usually a
function of the Scrum Master, but unless you have an experienced one
who is good at working with people (aka “managing perception”),
you’re doomed.
I have been on this team and it’s discouraging. You start to feel like
you’re acting out the process for the sake of saying you’re being Agile
without actually being agile!
the exception instead of the rule. I’ve been on many Scrum teams and
there are always people who bristle against the formality and boo-ya
sportiness of it.
That’s just the way people are. Give them a set of rules and the first
thing they’ll do is try to break them because chaos is your friend.
You don’t need to be terribly strict, and should feel free to drop what
doesn’t work for you. The daily standup can be done via email every
other day, or maybe you can host something for after work twice a
week — make it a social event!
At the very least, let’s organize our efforts using Agile so we know
what we’re doing.
You’ll notice that there are no user stories here, only issues. This is
where we start arguing about being “Agile”. A user story is one or
more tasks rewritten from a user’s perspective. The point of this is
that you put yourself in the user’s place and, using some empathy, try
to build something they want to use.
I like the way the ASP.NET team has adapted Agile to their culture and
project. If it works, it works.
Our first user story is what happens in the first 3 seconds of Alex’s
visit to our home page, which is the most crucial interaction we’re
224 ROB CONERY
going to have. This is especially true for our upcoming first demo —
we need to grab people for another 30 seconds after they get there.
Why 3 and then 30? It’s a marketing thing. You have up to 3 seconds
to grab someone’s attention with your site, and if they’re interested,
you have up to 30 more seconds to engage them. If they’re still
around after 30 seconds, your chances of converting them into a
customer are exponentially higher.
I could also have written this as “create a beautiful landing page with
nice fonts and an engaging headline” but I decided to keep with the
“Agile” way of doing things.
Notice that 13 on the bottom left? That represents the story points for
this story. I’m using a Fibonacci sequence with values 1, 2, 3, 5, 8, 13,
21, 34, 55.
Why Fibonacci? I suppose it’s a geeky thing, but I like the way it
represents actual difficulty: it’s never linear! Difficulty tends to grow
THE IMPOSTER’S ROADMAP 225
on an organic curve so, to keep things effective and simple, those are
my choices. I chose 13 because I suspect that I won’t be going with
static HTML to start off with, and will probably opt to use whatever
framework we’ll be using to build the app. Not sure yet.
Let’s create our next story, which is what happens when Alex stays
around for 30 seconds:
Same deal with this issue, but this time I have a score of 8 because I
think this will be a little simpler to implement. If I was on a Scrum
team, the Scrum Master might call a planning meeting and set up a
sprint (which we’ll do in a second). Instead of taking my 8 at face
value, would instead opt for a poker session so we get a better
estimate.
Right then, it’s time for our final story. What happens when Alex is
engaged for up to 5 minutes. This is now “investigation mode” and
Alex is seriously considering signing up for the service. There are
multiple things we can do at this point (get them on a mailing list,
offer a freebie, take a quiz, etc.) but we’re going to focus on simple:
226 ROB CONERY
This is much more in-depth and requires significant design work, thus
the 21 points. I do see value in just starting, which is what this story is
all about and if we decide it needs more work in the future (which we
will) we can add another story to it.
You might be wondering why I don’t break this story into separate
issues, and I definitely could. For some organizations, this would
make sense to do. For me, I like the simplicity of having checkboxes
right here. Opening separate issues feels like overkill, if I’m honest,
and like I keep saying: simplicity, simplicity, simplicity.
Least friction is our goal for getting things off the ground, as long as it
doesn’t come at a cost.
That said, there is one major upside to dividing tasks out as issues:
email notifications. If your boss (aka me) is keen to follow your progress,
then take some time and create an issue for each task. You can then
reference those issues from the story as I did with the epic.
But, as your boss, I have far too much email already, so just getting a
notification when you add a comment is fine.
We have 4 issues right now: 1 Epic and 3 Stories. Let’s roll those
stories back into our epic so we can keep track of them. We can do
this using GitHub’s editor, which will also tell us whether those
stories are completed:
If you go into edit mode on the issue, you’ll see a checkbox icon,
which will place the -[] markup in the body. This is “GitHub flavored
markdown”, which specifies that a checkbox will be rendered here. If
you add an X to it: -[X] then it will be checked.
We can then click the external link icon to reference another issue. I
want to reference our three stories and can do that using #11 where
11 is the number of the issue. If you click the external icon link, this
all becomes visual.
I created our first sprint and set the due date for two weeks from now.
I also attached our 3 stories to it:
You can attach issues to a milestone by selecting them in the list view
and clicking on “Milestones” in the list menu, which is what I did
here.
ENGAGE!
This is our first sprint! How exciting! We have stories to work against,
a due date, and people will receive notifications as the work goes on
over time.
they’re about to do. It’s not very fun to go to a party in a filthy house
with no chairs to sit in, is it?
Our repo looks professional and focused, which is precisely what you
want people to think of you. Managing perceptions and molding consensus,
look at you go!
EIGHT
THE FIRST SPRINT: YOUR
PROTOTYPE
ACTION IS THE NAME OF THE GAME - GET
SOMETHING IN FRONT OF YOUR BOSS OR
CLIENT
H
ey, we get to write some code! Well, soon anyway. One of
the more unsettling things about moving up in the
development world is that you code less, plan more. It’s
like any career: the more experienced people do the strategy and
planning and help everyone else. It can be a bummer, but that sad
feeling goes away when you ship something radical. Trust me.
You’re about to rock some boats, so get ready! Up to this point, we’ve
been dealing with words on a page and arms waving in the air, and
that’s about to change. If you ever wanted to know if your boss is a
micromanager, you’re about to find out.
We’re going to have some fun in this chapter, and in the next we will
discuss how to handle the fallout. It would be nice to think there
won’t be any, but in my experience there always is, and I’ll walk you
through some scenarios that you’ll probably encounter.
If that’s not the case and your team is ready to start with you (or has
already started), we need to be careful. You can easily burn bridges at
this point.
The emphasis in this book is execution, doing rather than talking (Win
through action). If it’s just you, then things are simpler, but if you have
a team working with you, your job is to help them execute, which
means you need to let them decide things for the most part.
For now, let’s ponder what this first sprint will produce.
THE PROTOTYPE
It’s human nature to want to tread lightly and carefully when starting
a new thing. “A fool rushes in” etc. This is true, but I think it’s a good
time to revisit my Ameritech Odyssey. I promised I would come back
to the story about using Microsoft’s IndexServer and how it shaped
my career, so here goes.
The next day, a warm Saturday morning in the Oakland hills, I was
scouring the web trying to find any blog posts on Microsoft’s
IndexServer. The web was pretty small back then and information was
THE IMPOSTER’S ROADMAP 233
I called my business partner at the time, Dave Nielsen, and told him
my discovery and how I was thinking we could create a prototype and
mock up the search results once I knew how it all worked what code I
needed to write. His response changed my life:
From https://balsamiq.com
For instance: if you were to show the image above to someone on the
marketing team, they might say something like “Is Winter Set a
playlist we have internally? Shouldn’t that be called out — whether
it’s ours or the user’s? Also, I think ‘Kidkanevil’ is spelled
‘Kidkaneival’…”
This is why we use Lorem Ipsum in this process and why blocks are used
in wireframes. If you ever want to get work done, do not show real
information in a mockup.
Figma
Note: when I first wrote this chapter in 2022, Figma was its own company. They
were subsequently bought by Adobe, and then in 2023 I got to change this note
once again as the deal fell through and Figma remained on its own.
It’s extraordinary what people can build with JavaScript these days and
if you want proof of that, visit Figma’s site and create a free account:
If you’re new to Figma, don’t bother trying to figure it out as you go, it
just won’t work. It’s truly overwhelming what’s possible with this
tool! Instead, head over to the learning section:
236 ROB CONERY
Or you can watch a video on YouTube — of which there are many. It’s
easy to see why this tool is so popular, it can do anything! Many have
called the “Adobe Killer” but I’m not sure about that.
This is from a template that I imported and as you can see, I don’t
need to worry about HTML or CSS to get the exact layout I want.
THE IMPOSTER’S ROADMAP 237
Things are blocked for me, which I like, and I can have multiple
screens that link together so when I click a button or a link — I’ll see
the new screen.
I like Figma a lot, but it’s overkill for what I need done. I would need
to spend 3–5 days learning the tool and then likely a week to get a
wireframe up. To be sure, a wireframe is not the same as a prototype,
but it does get the design in front of someone, which is what we want.
Sketch is one of my favorite design tools and I use it regularly for the
graphics on my site. Its true strength, however, is with prototyping an
interface:
238 ROB CONERY
It’s the same as Figma in so many ways, with one exception: it’s a Mac
app whereas Figma is web-based.
With Sketch, you work with “artboards” that are dedicated to specific
screens. You can choose mobile, tablet, desktop, and even watch. You
can animate things to bring across an experience, create a brand color
palette, collaborate with coworkers and so on.
I love this tool and I have taken the time to get to know it, but I’m
confronted with the same issue: I would rather have something that works
when I’m done.
I feel the same way about Balsamiq: neat tool, doesn’t fit what I want
at this stage. Balsamiq is a little more focused on structure and flow
vs. design:
THE IMPOSTER’S ROADMAP 239
I do think this is very useful and of all the tools I’ve tried out,
Balsamiq is by far the simplest.
All of that said: CSS kits and starter templates are so good that
sometimes it’s just easier to get rolling right away rather than go
through a big design process only to start again with CSS and HTML.
The downside is that your prototype can end up looking exactly like
someone else’s site.
I will share my choices with you, but there are so many more out
there that people love, and I encourage you to explore and come up
with your own selection. For now, here’s what I typically do.
Themeforest
Right away, we see some incredible templates for $20 to $30, which is
a steal!
For $24, you get every page your website needs, built with Bootstrap
(or so the sales page says), a popular CSS framework:
THE IMPOSTER’S ROADMAP 241
242 ROB CONERY
What I’ve shown here is just one of many templates that we can use to
get our prototype off the ground. As always: it’s a good idea to read
through the reviews to see what people have to say. You can also view
a demo of the theme and click around to see how it “feels”. I typically
will open up the developer tools to inspect the themes as well, just to
see how difficult it will be to figure things out:
THE IMPOSTER’S ROADMAP 243
Here I can see that the template is created using Tailwind, not
Bootstrap, which is OK because I know TailwindCSS very well and this
makes me happier. Another thing to be certain you check is which
JavaScript frameworks are used. Most notable to me are the use of a
Bootstrap script as well as UIKit.js, which is yet another CSS
framework!
It looks impressive, doesn’t it, but things are starting to get a little
weird. Why the use of so many different CSS frameworks? Most of
these toolkits (except Tailwind) come with their own JavaScript
support files to handle things like dropdown lists and animations. The
author of this template is using Tailwind for the bulk of the CSS while
also using these other framework’s JavaScript files to… do …
something?
What is all of this doing to the browser payload? Let’s take a look at
the dev tools one more time, under the Network tab:
244 ROB CONERY
YIKES, that’s 22Mb for what is a pretty simple page! But before we
have a complete freakout on this, that size is probably due to a lack of
optimization to images, JS and CSS files and so on. I’m not terribly
worried about the payload — but it is something to keep in mind:
designers aren't always concerned with page size.
I’ve used HTML templates before and will likely do so again because
they fit my business: I want to stay small. I’ve done the startup grind,
growing things to what some consider “mid-size”. I’ve worked the
corporate and enterprise projects too, but for me, the velocity and
simplicity of “doing my own thing” keeps me interested. I don’t see
one thing as better or worse than another, it’s just what I like.
months. Something always goes wrong with it, but dang it’s nice to get
your MVP up quickly.
The difficult part with using HTML templates from a service like
Themeforest is getting to know both them and the frameworks they
use because they all use CSS frameworks. If you know Bootstrap or
Tailwind (the most common), you’ve got a leg up, and you should be
able to customize things easily. Until you can’t.
That’s where the trouble comes in: when you change a thing in one
place, and it blows up your entire site. This has happened to me more
times than I care to remember, and it’s not because these designers
are bad people or bad designers for that matter — they just take a few
liberties.
I remember trying to dissect a template for use with a Node web app
which was using the Express framework. The view engine I was using
(EJS) allowed for the use of “partials” which are snippets of HTML
that can be reused throughout the app. The designer, however, just did
their thing and had special classes on the html and body which were
hierarchical, meaning that elements within the body of a given page
looked different based on the class set for the body. This included
headers and the site-wide nav component. To the designer, things
were just fine. As for me, a programmer, I was looking for abstraction.
It’s not always this way, of course, but it happens often enough that
it’s a good idea to make sure you can do things from scratch if you
have to. This is why many people prefer “UI Kits” which are more
modular and built on top of popular CSS frameworks.
I own a few Bootstrap Themes myself, and I really like them. Tons to
246 ROB CONERY
choose from, and they do just about everything you need, usually
surpassing templates you might find on Themeforest.
In the last year, however, I started using Tailwind CSS because I like
their “utility first” approach. This is a subjective thing, of course. I
know CSS just enough to truly damage any UI I work with, but
somehow Tailwind keeps me from doing that. I think it’s because they
don’t try to abstract the idea of CSS — just make it more apparent.
I would rather not get into a discussion about CSS frameworks; ideally
you have your favorite and if you do, I think that’s the one you should
use, assuming they have themes or UI kits.
Here’s the deal when you work with a UI Kit: you assemble pages from
components, customize later. For instance, consider my favorite: Tailwind
UI:
You figure out the pages you need and create the files for them
(index.html, about.html and so on).
You add the “harness” for your site, which includes the html,
head and body tags as well as CSS and JavaScript tags.
You add the components you want to each page. The home
page might have a hero section followed by a features section,
testimonials and so on.
How do you figure out which components and sections you need? A
great place to start is by reviewing the templates on Themeforest! The
designers who built those themes typically use former projects,
changing things just enough to not cause issues with their clients.
You could also look around at what other services offer. For instance:
Teachable is an online LMS that specializes in video. You could, if you
wanted, see what they have on their home and about pages and if you
felt inclined, you could do a free trial to see how they lay out their
courses and video page.
Personally, I don’t care for the design of Teachable. The font mix they
use for headlines is annoying to my eyes and the lack of transitions
between sections along with the oversized images remind me of…
something I would design… which is scary indeed!
You could drag and drop HTML “stuff ” to your heart’s content and
build a page that looked … well, like you dragged and dropped things
to your heart’s content.
Webflow is a bit easier on the eyes. You start by creating a project and
selecting a template for it:
THE IMPOSTER’S ROADMAP 249
They do the font selection, grid layout, effects, and animations as well
as the color scheme – all of which you can change.
You can customize everything on this page using both dedicated and
shared components, which will update across the site. Webflow also
offers tools to help you build a site that doesn’t suck as well, including
an auditor which can help you with accessibility and well-formed
HTML:
The crazy power of Webflow comes in, however, when you begin to
work with collections. Webflow has a built-in CMS that you pop your
data into and then show that data through template components.
THE IMPOSTER’S ROADMAP 251
For instance, I can define our LMS courses and lessons by adding a
new collection called “Courses”:
If you want to sell things, you can do that too. There’s a special area
for eCommerce on the left menu (a shopping cart) and when you click
it for a new store, two collections are added for you, as well as a few
more interesting things:
252 ROB CONERY
But what about an LMS like ours? This is where things get very, very
interesting indeed. Webflow is considered one of the main
components of the “No Code” movement, and as such, is trying to
embrace anything and everything that their users might need,
including Membership:
THE IMPOSTER’S ROADMAP 253
Thoughts on Webflow
The main issue I have with services like this is that you’re part of their
ecosystem and if they change something, you change something. I have
been burned by so many of these “No Code” apps in the past! Allow
me to share some sadness:
The point of all of this: aside from Shopify, these companies are a
funding round away from going away and taking a chunk of your
business with them. Webflow just hit $4 billion in valuation due to a
series C round of funding and has apparently been profitable for the
THE IMPOSTER’S ROADMAP 255
last few years, so that’s a good thing. But will they be around in 3, 5
or 10 years from now?
One day, I was reading CODE magazine and there was an article
written by Mike Gunderloy (I don’t have a link for him) and he was
talking about the longevity of a project. I can’t find the article either,
and I’ve tried, but the idea was simple enough: you should consider
what will happen to your project in a year from now, 5 years from
now, and then 10 years from now.
Software people have a hard time thinking this way, and I think it’s
because technology changes rapidly. New frameworks come about,
new trends, companies die or kill their products. It seems like a 3-year
shelf life is about the most you can expect.
Our project isn’t even off the ground yet, but the moves we make now
will be critical to its future health. There are many questions we need
to answer, and when I’m confronted with such things, I find it helpful
to look at what other successful projects have done. I also look at the
failures — but not as much as the successes.
Why, you ask? While I do believe there is a lot to learn from failure, I
find that seeing what someone else did right to be even better. It’s
common knowledge that most startups fail because they try to grow
256 ROB CONERY
GitHub is, to me, a company that did it their way. They didn’t go
public, but they have stayed true to themselves for over a decade. Let’s
use them as a case study.
And here is their launch announcement, which they still have on their
blog!
258 ROB CONERY
It did not, of course, look like this back then… but the words are the
same.
One Year
It’s hard to imagine, but just one year ago today we made the first
commit to the GitHub repository. We don’t have a baby book for
GitHub, so we’ll have to settle on the blog to record our handprint
and first words.
answers all your nuanced questions via email, IRC, and on the
forums. We’ve taken a grand total of $0 in venture capital or other
outside investment. Just recently we topped 20,000 public
repositories.
But we couldn’t have done it without you, our loyal users. You’ve
dared to try a new version control system and seen how much
better things can be. Thanks for joining us on this adventure, we
look forward to the upcoming year to make your life as a
developer even more amazing!
5 Years
Now let’s jump ahead to 5 years after the project launched. They have
matured as a company and solved many of their engineering issues.
My Phriend Phil joined GitHub in 2011 with the title of “Windows
Badass” and went on to become Director of Engineering, overseeing
the creation of the Atom text editor, Electron, and GitHub Desktop.
He retired in 2018 after Microsoft bought GitHub.
I wonder if Tom and his cofounders ever thought they would expand
into the enterprise, build a text editor, and change the entire landscape
of desktop development with Electron.
I don’t know, to be honest, and I don’t think Tom did either, but I’m
sure he had a dream.
Ten Years
THE IMPOSTER’S ROADMAP 261
The 10-year mark always seems so very far away, and at the risk of
sounding old… it really does get here much faster than you think it
will. In 2018, 4 years ago, GitHub turned 10:
The headline has changed as more and more developers, and the
businesses they work for, embrace Git. Microsoft has transferred all of
its open-source work there (which is a lot) and then bought the place
outright.
Tom’s cofounder and CEO for many years, Chris Wanstrath (defunct),
wrote a nice letter to the community to celebrate this 10th year:
When we look back at the last decade, it’s not any one individual
piece of software that we remember, it’s what people have done
with it. You’ve shared, taught, tinkered, and built on GitHub from
all around the world. At launch, we couldn’t have anticipated the
number of projects we’ve seen take shape, the one-line programs
and massive frameworks. We also never imagined that businesses
would become so deeply invested in the open source community
or that so many of you would learn from each other’s code.
THE IMPOSTER’S ROADMAP 263
As we look ahead, I’ll keep this simple. Together, you have defined
what software is today. And you’ll continue to shape its future in
the years to come. So what’s in store for the next 10 years of
software? We’ll follow your lead.
and they didn’t spin up multiple tangential projects that would dilute
their brand.
They stayed focused. Using GitHub today feels like using it 14 years
ago, and I think it’s pretty cool that 90% of the work I do uses the
same features that were available back then.
OK, case study over, let’s get to work and write some code!
Nowadays, I have more options than I can deal with. I can build
applications using Django (a Python web framework), Rails, Node
(with Express) and most frameworks build with Node, Vue and Nuxt,
the framework built on top of view. I’ve written applications using
static site generators as well, Jekyll, Hugo, and Middleman to name a
few. I’ve used Firebase as my storage and backend functions too…
Having so many options is not always a good thing, believe me! But I
mostly work on my own and build things for myself. When it comes
to working with a team, things become easier.
It’s still in production, which is great, and the developers who came
on after I left have been able to support the application easily. Or so I
hope!
For you, leading this effort, the first thing you need to consider is who
will be picking up for you as your team expands. And, of course,
where things will be in 1, 5, and 10 years from now. Rails and Django
have been around for 15 or so years, and they’ll probably be around
for a long time to come — those would be solid choices if you’re
looking to hire Ruby or Python people.
The thing is: you don’t want to kick off A Great Rewrite when your
brand is heating up and people are coming to your site. They like
what they see! Let them like it! Twitter was notorious for their “fail
whale” back in the late 2000s. They were trying to solve massive
scaling problems with their Ruby on Rails codebase and single
MySQL database. They stuck with it and let things crash occasionally
until the whole thing was rewritten in Scala in the early 2010s. They
took their time, hired the talent they needed, and set about fixing
things.
The point is: Twitter needed the rewrite. Developers will often rewrite
something just for the sake of “cleaning things up”. Joel Spolsky,
cofounder of StackOverflow, wrote:
probably wrong. The reason that they think the old code is a mess
is because of a cardinal, fundamental law of programming:
So, so very true and I have been guilty of this. The thing is: we are
indeed going to create something messy. It can’t be avoided. Early-stage
applications are subject to dramatic change and whimsical marketing
fantastical requests, all within the oppressive ramp up schedule. It’s
fun, but the code often pays the price.
This is the Denver Public Library. I’m sure there are some people in
the world that think this building is interesting. Next to the Seattle
Space Needle, I think this is one of the ugliest bits of architecture I’ve
ever seen. You can’t “fix” the organized visual chaos of this structure,
either. It needs to come down entirely and rebuilt from scratch…
nothing can improve this.
268 ROB CONERY
HELLO WORLD
The antidote to creating a colossal organized mess, to ship early and
iterate slowly. Easier said than done! If I were in your shoes, I would
take a deep breath and look 3 years in the future. What platform/lan-
guage/framework would I want to support?
To answer that question, I might think 3 years in the past: what was I
working on then? For me, I was working with Node a lot, Vue, Rails
and Firebase. I also worked with Django on a project and I had a great
time.
The key is to get off the ground quickly using the thing you know (or
can learn) the best:
This is our first prototype and it looks wonderful! No, this isn’t a
“draw the owl” moment, I promise. The entire next part of the book is
how I got here and the process I followed.
NINE
SUMMARY: BUCKLE UP
SHIPPING IS WINNING; SHIPPING GETS
YOU NOTICED
I
n this first part of the journey we focused on tools, philosophies
and sprinkled in some practical thoughts as well. We didn’t do a
lot of coding, but that’s what being a senior/lead developer is all
about: less coding, more shipping.
I paddled for 4 seasons many years ago before I blew out my shoulder,
and it was one of the most intensely relaxing things I’ve ever done.
There’s no time to let your mind wander, you had to focus and keep
your paddle in time with the person in front of you. You had to control
your breath as well, so you didn’t hyperventilate because your
diaphragm is getting compressed by leaning over too far. If you didn’t
make the mistake of extending too far forward, you run the risk of
pulling your arm out of its socket at the shoulder, which is what
happened to me.
Each person in this canoe has a job: the person in the very front is
called the “stroker” or just “stroke”. They set the pace and every other
person in the canoe has to follow their lead so you’re all stroking in
time. The person in the second seat paddles on the opposite site of the
stroker, so they keep time for their side of the boat.
Seats 3, 4, and 5 are the “wheelhouse”. These are usually the biggest,
strongest paddlers that generate the most power/stroke.
Seat 6 is where you sit: the ho’okele. You steer the boat and decide
where everyone is going by using your paddle (and skills) to steer the
boat. Every now and again you might paddle as well — when the boat
THE IMPOSTER’S ROADMAP 271
At this point, the thing is just a big, awkward bit of fiberglass that
requires a lot of care. Two of your crew need to hold up the amas, the
arms that extend to the side and connect to the outrigger, to make
sure they don’t drag, and you gently convey the boat to the water.
Once in the water, it’s a boat and you’re its crew. As my coach used
to say:
When she’s in the water, she’s a part of you, and you’re a part
of her
Our boat is now in the water. It’s launched for everyone to see and you’re
the steersman. But as we well know, there’s a lot more to paddling
this boat than just sticking our paddle in the water and pulling as hard
as we can.
Everyone on the team has a role to play which depends on their skill,
and no role is more critical than yours.
As the steersman of this project, you just spent some time reading up
on techniques, tools, and ideas on how to steer your project
successfully. Now it’s time to push off and win a race or two!
PART TWO
DEVELOPMENT
TEN
A BRIEF REVIEW OF GIT
YOU WILL LIKELY BE USING GIT TO
MANAGE YOUR SOURCE CONTROL, SO
LET’S HAVE A QUICK REVIEW
W
e are underway! In this part of the book we’re going to
focus on our first sprint and how it was executed.
Successfully, I might add (good job!).
I do feel that many of the processes are you’ll go through are the
same, regardless of where your source code is hosted. To that end,
many of the processes used with GitHub translate to other services,
such as GitLab, Bitbucket and yes, even Team Foundation Server.
276 ROB CONERY
If you’re not a GitHub person, I hope you can still find value in these
chapters as the processes are all based on Agile ideas (customer focus,
quick iteration, ongoing communication, etc.).
We’ll then dive in to tips and strategies for working with GitHub,
specifically the “GitHub Flow” (as it’s called) as well as the simpler
Trunk-Based Development that is gaining popularity.
Lastly, we’ll discuss job retention. Your job, to be specific. If you build an
application and ship it off without an analytics and reporting story,
you’re asking to be replaced. Your boss (me) will want to know how
the app is performing and whether we are doing the right things.
From customer interactions all the way to monitoring and logging, we
need to know what’s happening in there!
ASSUMPTIONS
I’m going to assume that you know and understand Git, at least to a
reasonable extent. If you don’t, I’ve added a small primer below, as
well as a history of source control as we know it. Believe it or not,
people used to argue about whether the use of source control was
useful!
Spoiler: it is.
THE IMPOSTER’S ROADMAP 277
For now, here are the essentials that you’ll need to know before
moving on. If you need to go deeper, I would suggest spending an
hour or two on YouTube so you understand the concepts at the very
least.
GIT ESSENTIALS
There are less than 10 commands that you must understand to
effectively use Git:
git merge will take the changes from one branch and do its
best to non-destructively merge them with another branch.
Occasionally, this doesn’t work, and you end up with a “merge
conflict” that you need to step through. We’ll talk about this
later on too.
git checkout allows you to move between branches in your
local repository. A common use of this is git checkout -b
which will create a branch if one doesn’t exist. An example
would be git checkout -b robconery/fix-something-broken-
#32. That’s a long branch name, but in a larger project it’s
extremely helpful to have descriptive branch names like this.
The #32 part references a GitHub issue number.
git branch shows you information about a given branch, but
the most common use of this command is git branch -d,
which deletes a branch from the repository.
There are, of course, a load of other commands, and I’m sure I’m
leaving a few out that some readers will find essential (such as stash).
There’s a lot to learn, and I suggest spending some time to master this
tool.
When using Git and writing code, it’s a good idea to be doing it inside
a branch. Many teams consider committing directly to main (the
default branch) a Very Bad Idea because main is only where tested,
deployed code lives. Others are just fine working in the trunk, and
we’ll see both ways in the next chapter.
There are different ways of dealing with Git and GitHub, flexing it to
tell a compelling story about your project. This is your job, and you need
to be certain you know your tooling! It could very well save your butt
in the coming months.
I invite you to read on and get lost in a fun story or, if you like, just
jump to the next chapter and we’ll get rolling with more exciting stuff.
Then there was Subversion, or I should say “is” because people still
use it. It came out in 2004 as an “update” to CVS and was a breath of
fresh air. This is the tool that finally got me using source control
routinely.
It’s difficult to admit this, but source control was much more of a
chore than it is today. I love how Mike Gunderloy puts it in “Coder to
Developer”, written back in 2004:
Most developers start out writing code without any sort of source
code control, except perhaps for making occasional backups of an
entire directory of stuff. But gradually, most of us realize that
having a tool help keep track of code changes and prevent code
loss is a good idea. We tend to go through three levels of
enlightenment in this process, starting as beginning users and
gradually developing expertise …
280 ROB CONERY
The 3rd level of source control is, essentially, mastery, but keep in
mind that this was 2004 and this stuff was a lot harder than it is
today. At least to me.
Back then, BitKeeper was proprietary and people needed to pay to use
it, but Linus worked out a deal with the company behind BitKeeper
(named “BitMover”) so that he and his contributors could use it for
free. This caused problems on the Linux kernel project because some
maintainers didn’t like that closed-source software was being used on
a free, open-source project. Others didn’t see how source control tools
affected anything and, simply put, there was nothing that worked as
well as BitKeeper for their project. Linus knew the tool well and he
liked it. Since he was responsible for maintaining the source history
and managing the patches, his decision was final.
To make matters more fun, the CEO of BitMover, Larry McVoy, was a
contributor to the Linux project. He wanted to help the project so he
decided to open up parts of the BitKeeper server so that bridges could
be made for project members using Subversion and CVS. In doing so,
he made it possible for “Tridge” to create his metadata reader.
This is where things blew up. BitMover didn’t like that OSDL was
accessing metadata they shouldn’t be, so in 2005 they stopped giving
free licenses to people that worked at OSDL. Unfortunately, one of the
names on that list was Linus Torvalds.
HELLO GIT
Linus’s design goals for the new system, which he called “Git” as a
self-deprecating joke, should be:
MERCURIAL
The history of Mercurial is tied directly to Git, so I think it’s worth
bringing it up here. It’s also a fascinating story. The original project
was kicked off by Olivia Mackall (historically Matt just in case you
look things up). She named the project Mercurial because:
Shortly before the first release, I read an article about the ongoing
Bitkeeper debacle that described Larry McVoy as mercurial (in the
sense of 'fickle'). Given the multiple meanings, the convenient
abbreviation, and the good fit with my pre-existing naming
scheme (see my email address), it clicked instantly. Mercurial is
thus named in Larry's honor. I do not know if the same is true
of Git
Larry McVoy (CEO of BitMover) didn’t like this at all and required
that commercial users of BitKeeper not use the tool to create a
competitor to BitKeeper, which seems like a very shortsighted decision
to me.
I don’t think this kind of thing could happen today, but who knows.
Mercurial is still around, but Git is far, far more popular. BitBucket, a
competitor to GitHub many years ago, made its name based on using
Mercurial instead of Git as many people felt that the Git API was too
“hostile” (whatever that means).
But Git adoption has grown over the years to become the default
system, helping teams of all sizes work faster as they become
more distributed.
SO LONG, BITKEEPER
Git made an immediate splash when it came out and has grown
massively ever since. Its popularity soon drove BitKeeper into the
dustbin, and it went open source in May 2016. This is what Larry
McVoy had to say about that:
THE IMPOSTER’S ROADMAP 285
"We've got about two years of money and we're trying to build up
some additional stuff that we can charge for. We're also open to
doing work for pay to add whatever it is that some company wants
to BK, that's more or less what we've been doing for the last 18
years.
During our lunch, John started talking about “Git” and then Phil
jumped in, talking about how much he loved it. We were eating Thai
food in Redmond, and I remember looking around, thinking to myself:
what did he just say? Git?
I asked John what he was talking about and described the idea of
“distributed source control” which, to me, sounded absolutely absurd.
I had been using Subversion for years and the idea of your trunk (the
source of truth) being everywhere was ridiculous! Where did the
trunk live!
EVERYTHING CHANGED
I never created branches in Subversion, it was just too cumbersome. If
I wanted to goof around and try something different, I would just copy
my code over to a different directory on my machine and try it out.
Git brought the idea of source control into the realm of project
management. You could, all of a sudden, track progress using
branches and commits and figure out who did what using blame. You
didn’t worry about losing your source server because everyone had a
copy of the repository!
Best of all: it was small and fast. Subversion (and tools like it) required a
THE IMPOSTER’S ROADMAP 287
Leaky abstraction
I think this is true. To delete a file in your repository you use git rm
and the file name. The rm echoes the bash command that does the
same thing: removes stuff. To delete a branch, however, you use git
branch mybranch -d. This one always gets me… I don’t know why.
Deleting isn’t an optional argument, is it? It’s a damn command!
288 ROB CONERY
I lean towards the latter idea. We’re talking about the source code for
a project worth a lot of money — I don’t want someone else’s abstraction
doing stuff to it. That’s me. I don’t mind spending a weekend reading up
on the commands and strategies as you’re about to do — I’m a coder
and I have mastered the ability to do things like this.
B
oth Git and GitHub are wide open and allow you to essentially
do what you want and/or need to get your work done. We can
either create a mess, or we can make something beautiful.
That last bit is crucial. If you’re a Git wizard that can do magic with
your repository — that’s great! But if your team doesn’t understand
what you’re doing nor why, you will quickly have a mess and all of
your efforts will be going into handling your tooling rather than
building our product.
RECOGNIZING YOURSELF
In this chapter, you’re going to be the coach: creating a game plan and
making sure your team can carry it out. In other words: creating tasks
and optionally assigning them to people, making sure they know
what’s expected and, most importantly, that your efforts are
recognized and recorded somewhere.
Did you feel a weird twinge reading that sentence, wondering why you
would also focus on yourself? Cultures around the world treat this
kind of thing differently, but I can share with you that when I grew up,
you simply did not focus on yourself in a group setting.
This is the worst part about being a lead or manager: treading the line
between toxic narcissism and toxic passive-aggressiveness. I think we
all know what a toxic narcissist can be like, everyone seems to have
had a boss at one time who stole credit for something, needed to be
the center of every decision and made the project more about them
than about the client (aka a “toxic psychopath”).
When you’re asked about the health of your project, you’re going to
need to list your achievements and failures, clearly understanding
what you’ve done well and what can improve. Your boss or client will
want to know they chose the right person, so go ahead and gloat if you
deserve to. It’s not arrogance if it’s deserved, and it’s not bragging if
you’re asked. It’s also not true if it’s not written down somewhere, so
make sure you have the answers at the ready if someone comes
looking.
And they will come looking. Especially when you start kicking butt
and succeeding. They’ll want to know who, how and why because
success is gravity and everyone will get pulled to you. It’s just the way
people are.
Enough with the pep talk. Let’s get into some real situations.
Allow me to explain.
One of the tasks that our team needs to perform is to come up with a
placeholder headline and subheading, along with a hero graphic. This
isn’t really “programmer stuff ” but, as my buddy used to say back in
our startup days: “everyone hangs white boards” (meaning: no task is
beneath any of us).
Let’s pretend you have a team and on this team is a great frontend
programmer named Sara. You know that Sara has a background in
copywriting and marketing, and she would be the ideal person to take
this task on. You also know that you want to use Scrum for the team,
and part of using Scrum is that teams can self-organize and choose
which tasks they wish to work on. This is a useful thing, but you
know that Sara is the right person for this particular task, so you
decide to just assign the task to her directly, removing the whole
“assign yourself what you want to work on thing”.
Oh, but Sara doesn’t like that! She’s been trying to get away from
copywriting for years and finally landed a job at Red:4 working on
JavaScript and Typescript stuff. This has made her happy, and your
assignment without asking first is rubbing her the wrong way. That
said, you’re the boss, aren’t you? You and the team need her expertise,
and it’s aggravating that she is having issues with this.
Ah, the joys of managing people. This is yet another point in the
project where your ability to manage perception and persuade people
will be extremely useful. Your goal is to ship this thing, which means
you need to push every so often. How much you push is up to you,
and it might not feel good to do so, but that’s the job. The trick is to
do it well.
I’ve had many managers over my career and there are two that I
respect more than all the others combined. I won’t share their names
as they are public figures, but I will say that the skill they shared was
the uncanny ability to get you to agree with them. Even if I went to a
meeting with a head full of steam thinking “there’s no way I’m going
to back down on this feature”, I would leave agreeing that their way
was the best way.
As the lead, you, friendo, must answer to your tribe repeatedly, and
you need to do it with evidence of your competence. You will also
need to answer to those above you, repeatedly, who will use your
success to further themselves and when you fail, you’ll be alone. This
is OK, however, because if you’re comfortable playing this very human
game, you’ll be after their head soon enough, won’t you? You’re not
going to admit that out loud… but that’s how these things are set up,
and it’s the game you’re playing when you choose to elevate your
career.
294 ROB CONERY
The good news for you is that you’re reading this book, and I’m telling
you this now, rather than you learning the hard way and having your
spirit crushed. And no, you don’t need to have shouting matches or
hatch wild plots to overthrow your superiors. What you do need to do
is get in the habit of tracking everything you and your team does,
highlighting the wins and correcting the mistakes. And also writing in
your journal daily, which I assume you’re doing already!
That’s why we have the mechanics I’m about to describe and why
they’re important: so you don’t have to fight. We’re going to make sure
that everything our team does is tracked with a timeline of execution.
We will blow people away with our reporting and communication skills
because the last person who anyone wants to tangle with is the person
who comes with receipts.
That will be you, and your success will bleed into the team and make
them love you and their jobs. This is the good part of being a leader:
believing in yourself, which makes your team believe in themselves.
As you can see, I set up the Red:4 organization a while ago, in one of
my first acts as CTO:
It’s a simple thing to do and worth the time to do it. There’s a free tier
which is pretty useful, but if you want to have tighter control on
things, it’s worth it to upgrade to the Team license, which is
$4/mo/user.
Note: GitLab supports the same concept, but they’re called ‘Groups’ and don’t
have quite the same control as GitHub
I’ll make sure I call out which features are premium and which aren’t
as we go through the “GitHub Flow” below.
296 ROB CONERY
The next setting is the Commit signoff, which will be important as the
team grows. In the open-source world, it’s critical that copyrighted
code isn’t added to an open-source project so they have what’s called a
“Developer Certificate of Origin” (DCO) and, believe it or not, the
same goes for the work you do.
As the lead of your project (or a senior reviewer), it’s critical to make
THE IMPOSTER’S ROADMAP 297
sure that whatever code is committed into your main branch complies
with the DCO sign off.
These next screens will make managers happy and coders cry. When
you’re on the paid plan for your organization, a little box will appear
at the top of your repository:
Clicking the link will take you here… where the fun starts:
298 ROB CONERY
As you can see, these are the rules you can put in place for how code
makes its way into the main branch — what I keep calling the “holiest
of holies”. It really should be treated with reverence and call it
whatever you want, but do respect it. Nothing’s worse than dealing
with bad code in main.
Why, you ask? Because this is “the state” of development and a direct
reflection of you as the lead. Commits to main are considered your
progress or “cadence”, which is a reflection of how well your team
knows what they’re doing and where they need to go.
Your boss or client, if they know GitHub, will likely head right to the
“Insights” screen so they know what’s going on, and they might see
something like this:
THE IMPOSTER’S ROADMAP 299
That’s your story. The commits to main are literally the product being
built, so you want to be sure the code is a vetted and clean as possible.
For now, let’s make a few sane and reasonable choices. I’ll start by
making sure that no commits can go directly into main without a pull
request (PR):
300 ROB CONERY
There’s also a section here where you can specify approval before a
merge can happen. I’m going with 1 for now — I’m the only dev and
lead — but two is a good number to start with that won’t slow things
down. I’m going to leave the rest of these boxes unchecked because
they will likely cause confusion and chaos later on. When it comes to
these types of decisions, I lean on a saying I learned while doing Ruby:
Also known as YAGNI. Let the problem present itself first, then fix it.
As such, I’m going to leave the rest of the boxes unchecked as well
until we feel the pain of a growing team:
THE IMPOSTER’S ROADMAP 301
Imagine your team in triage mode, the worst imaginable kind: it’s
4am, the app is offline and no one knows why. Alerts have woken you
and members of your team, and you’re trying to figure out, and fix,
what’s gone wrong.
someone from pushing a critical bug, but they did prevent the fix. The
more rules you have, the more this scenario is likely to happen.
Rules don’t stop people from being people. Instead, they force people
to create workarounds at the worst possible time.
Labels
It’s always nice to make sure the labels fit your organization. We’re
using an Agile-ish approach, so I’ve added Epic and Story as labels:
There are also “Topics” that you can add to each repository, which are
little descriptions, but that might be overkill. Don’t get too bogged
down in here — it’s easy to do!
Allowing Forks
When your team comes on, they’re likely going to use their personal
GitHub accounts to work on your project. This might seem weird, but
THE IMPOSTER’S ROADMAP 303
The private repo that we have will also be private for our team
members when they fork it, so we’re still safe. Oh, and if you don’t
know what a fork is, hold tight, I’m going to walk through everything
in just a minute.
This is a great start, and good enough if our team is just one person
(you). You have your checkboxes, and you can do tick them off as
you go:
Here’s an example:
This issue references our story, so we’ll see that in the story timeline.
There are clear directions here but, if they’re not, there’s plenty of
room for comment/discussion below.
Notice that I tagged the issue Up For Grabs too. You don’t need to be
that explicit — you can leave the label empty if you want — but I find
that tracking labeling is very useful. Notice on the bottom of the
graphic that it says I applied the label Up For Grabs? When the issue
is assigned, that will show up in the timeline too, and the label will be
removed. This says a lot about the process involved regarding getting
the work done.
Once the issue is assigned, the person doing the work should feel free
to label as needed.
No rule was given regarding the type of PR nor what it addressed. You
didn’t need to be solving any issues at all, just offering
“improvements”. It got so bad that a Twitter account was created,
devoted to tracking the crazy things happening to Open Source
projects during October:
308 ROB CONERY
It turns out that people will do just about anything to win a t-shirt,
which is weird. But as I keep saying: people will be people. This
phenomenon apparently happened because some person with over
600K YouTube followers decided to show how easy it was to game the
DigitalOcean contest. They thought it would be fun to flash mob
open-source projects, thus spamming them relentlessly:
THE IMPOSTER’S ROADMAP 309
310 ROB CONERY
To bring this back to the subject at hand — there is very little distance
between Hacktoberfest spam and someone offering a PR without first
creating an issue and getting the go ahead. You’re asking the project
owner to stop what they’re doing and come into your world to
understand what you think about their work.
I was asked to improve the dialog flow for a CLI project, and I realized
I could cut down on the 6 questions being asked by breaking the
single, general command into two more specific commands. To
achieve that, however, meant tweaking a few things.
I stopped what I was doing and submitted an issue with the tag
suggestion and outlined my ideas as clearly as I could. I’ll discuss
how to write a compelling issue/PR note in a later paragraph, for now
just know that it was pretty detailed.
Conflicts happen, and they’re going to happen on your project and will
probably involve you too. I’ll discuss that in a later chapter.
For now, a good rule to live by is: issue first, PR second. If an issue
isn’t assigned to you, and you have to create one, the ideal workflow
goes like this:
That’s the GitHub flow: everyone works in a branch, and all work is
tied to one or more issues.
Let’s see this in detail with the initial work I did for the Red:4 Portal.
Note: I’ll be using GitHub for my examples in this chapter, but GitLab has
312 ROB CONERY
corollaries for every practice. I had to choose one and GitHub is what I know, so I
went with that.
The first thing I did was to self-assign the issue for work on the home
page and change the label from Up For Grabs to enhancement:
It might not seem like it, but the history tracking here is critical to
understanding how and when work gets done, and it will save your
bacon on your projects.
I might have done this more times than I can remember. Maybe.
THE IMPOSTER’S ROADMAP 313
The better way to do this is to fork (or “create a copy of ”) the main
project, so I can work on it from my developer account. Before I do
that, however, I need to get clear on something.
It takes a few extra emails or Slack messages, but the next step that I
want to take as Rob the Dev is to know which branch I should be
working from. When you fork a repository, you fork all of its active
branches as well, as you can see here:
There are only two in our project: the holy main branch and the
initial-build branch, which was put in place just for our sprint. As a
314 ROB CONERY
lead, you need to be sure everyone knows which branch to clone from
for their work!
Now I’m ready to fork the project repository, and I do that from
anywhere in the repository — I just need to click on the Fork button:
I choose an owner (me) and wait for a second and boom! I have a
fresh repo to work from:
Naming things is hard, just do your best. Notice here that I’m using
my name followed by the work. I could have also done
robconery/issue-19 but to me, right now, this conveys what I’m
doing.
I’m not a copywriter, OK? I did the best I could here, and I do think
it’s a great placeholder until we can get some help. If the CTO doesn’t
like it, I’m sure I’ll hear about it during code review.
I was assigned a specific task: update the headline and lede on the
home page. That means that I get to change the home page and also
implies that I don’t get to change anything else. That last bit is
important!
By changing the .gitignore file the way I did, I open the door to a
merge conflict: when two files have been changed independently and
now need to be synchronized. This is the problem with doing GitHub
Flow: more branches, more possible merge conflicts.
We’ll see why this is when we get into the next chapter: Trunk-Based
Development.
Merge conflicts suck and can take days to unravel. They’re also a
“smell”, if you will, of a crappy process that is a direct reflection on
you. We want to avoid these as much as we can by impressing on our
team the importance of only working in the files you need to.
Creating a PR
THE IMPOSTER’S ROADMAP 317
The next part of the GitHub flow is to push our changes up to our
working branch and then submit it back to the sprint branch.
Great! I love how GitHub makes this so simple. I’ll click on “Compare
& pull request” and I’m taken to a new screen:
318 ROB CONERY
Notice that main is selected by default for the base branch — yikes!
We would rather not have our work merged directly into main, we
want it to go into the sprint branch, initial-build. If you screw up,
that’s OK. I’ve done this a million times myself. You’ll probably be
asked to resubmit and it’s not a big deal.
Two things every project lead loves: why you did the work and what
you changed. I explain both in direct and detailed language that’s not
overwhelming. It can take a while to get this down but these initial
PRs and issues will set the tone for the entire project.
We’re playing a silly game here, where I’m both developer and CTO,
but I’m also showing what I expect from others when they join the
project. I could spend days writing up documentation or trying to
explain what I’m looking for as a project lead when reading a commit
or an issue — but showing people is far easier and more effective.
This is good discussion. More work can happen here (with commit
links following in a timeline fashion) or other issues can be created,
which will also be referenced here.
Here’s what a pull request looks like in the wild, taken from the
firebase-tools project:
THE IMPOSTER’S ROADMAP 321
The timeline here shows everything that went into the changes
suggested. It’s a long list, but you can see the description is just
descriptive enough to drive the conversation, review, and coding
process.
This page says a ton but, most notably, that they’re fixing problems
and pushing code. So yes, mastering a tool like GitHub is critical!
W
hen working with a branch-based source control system
(which is just about all of them), you’re going to need to
come up with a merge strategy that doesn’t cause
problems as your team grows.
GitFlow has its advantages, but many teams find it a bit too
ceremonial and, more importantly, find themselves trying to figure out
how to merge massive feature or sprint branches.
The sprint is suspended for a few days and the issue is triaged and
fixed (in a bug branch) and then deployed. Now the fun begins.
should have studied more. Don’t worry, we’ll get to that in a few
chapters! For now, you’re stuck with a difficult situation.
The code your developers are working from has changed, and that
change is important to keep. This has caused what’s known as a merge
conflict.
MERGE CONFLICTS
You’ve probably been exposed to one of these beasties but, just in
case, let’s step through it.
git commit -am "Added some prompts for what I want to see"
The sad part is that I, as the developer, have no idea that this change
happened and the only time we find this out is during a merge:
326 ROB CONERY
This merge can happen as part of a PR, a “pull update” or any other
time when two branches have divergent histories. For instance: my
lead could have realized his mistake and sent me a note saying “oops, I
screwed up, can you pull from the feature branch and resolve this
conflict for me?”
Want to erode team trust and confidence? Create merge conflicts for
them and ask them to resolve them. This can be the result of direct
action (as with our contrived example) OR it can be the result of you
not understanding the codebase, assigning issues that overlap in
terms of code files.
The problem, however, was that this lead was also the first developer,
and decided that it was best to have a MasterContext object that was
passed around between objects and services. At some point, the
MasterContext began vacuuming up application settings,
configuration, and random instances of classes. I think his idea was
that we could inject this MasterContext easily, and mock it in our
tests. This was true, but it also made changing things an absolute
nightmare.
He would assign an issue to one developer, let’s call him Jason, which
was something like “Add an inventory check to the CartService on
add()”. He would then assign a different issue to Kim: “Debit
inventory on sale()”.
THE IMPOSTER’S ROADMAP 327
If you ever want to know if there’s too much coupling in your project,
constant merge conflicts will tell you that.
So what, exactly, happens with a merge conflict? Git will happily tell
us if we do a git diff, which compares the HEAD to the last commit:
This notation here might look strange, but it’s very likely you’ve
seen it before. This is called a DIFF and, simply put, shows two
different versions of a text file. On the top is the previous version,
the bottom is the current version, and they’re separated by a line:
=======. There are also labels which are prepended by
<<<<<<< denoting “previous” because they’re pointing to the
past and >>>>>>> denoting current (or later) because they’re
pointing forward.
A conflict can exist between two branches at a time, but multiple files
can be involved. This is important to understand because this file
could have been worked on by multiple developers and/or teams, and
each of them could have caused their merge conflict. READMEs are
particularly subject to these problems as developers, like me, like to
update project READMEs even when not asked to (adding clarity,
grammar, etc.). It’s a serious difficulty!
The point is: resolving a conflict means that you first need to
understand what happened and why. Here we have a simple situation:
my lead created a simple conflict with a change after my fork. If this
was a larger project, say 40 developers who are grammar nuts, the
potential merge conflict could take days to resolve!
previous change altogether. Tools like VS Code have this ability built
in, but I’m just going to do mine by hand:
To get out of a conflicted state, I just need to remove the DIFF text,
merging as I see fit, which is what I did. I can then commit this change
to get out of the conflicted state, making sure I describe what I did:
Here’s a tip: you can also tag this commit for quick reference later on.
It’s good to know how many merge conflicts arise during a project, as
they are the very definition of “friction” in a development project.
To get around this, many teams have started using what’s known as
“trunk-based development” where “trunk” refers to the main or
master branch… the thing I called “holiest of holies” in the last
chapter. To many developers, this is complete heresy — you don’t
develop in main! I used to be one of these people… and then you live
330 ROB CONERY
through “merge hell” and wonder if you’ve been wrong about this
perspective.
Sounds exciting, doesn’t it? Let’s go through the demo exercise above
and see if it really is.
THE BASICS
Let’s get our heads into the right space for this exercise. What we’re
going to want to focus on is:
Put these together, and you get fewer merges, at least in practice. If
you do end up with a conflict then, theoretically, it should be easier to
merge given the smaller updates.
Forking Main
We can see that my CTO self (robred4) created the initial bits and, for
now, let’s assume that I saw the issue, assigned it to me and off we go.
This time I’ll just do my work right in main, and I’ll do it by editing
the file directly in GitHub’s editor. Once finished I’ll commit right
there through the web interface:
Once committed, I head back to the code window and see that I can
open a PR:
THE IMPOSTER’S ROADMAP 333
As you can see, the merge is blocked because a code review is required
before the merge can happen. I’ll get to this in a second, but one thing
to notice is that I moved too quickly for Rob the CTO to make the
conflicting change!
I know, I know, this is so contrived, but it’s also so real. The velocity of
development is the point — it keeps conflicts to a minimum.
In our case, Rob was notified for a review and will hopefully respond
right now.
I ping Rob on Slack, and he’s able to review this quickly — he knows
that quick commits are the name of the game and can get my code
into main within 10 minutes of my PR. He heads over to the repo and
sees my PR:
THE IMPOSTER’S ROADMAP 335
He can do the review with a diff straight away, approving the changes:
Notice, too, that simple comments and a request for changes can be
made, right here, if needed. No need for changes here, however, and
CTO Rob approves the PR, which I see immediately:
336 ROB CONERY
The merge is now ready to go, directly into main. Your organization
may vary, but the projects I’m on typically allow the developer to
merge their PR, which I do:
as “the build”. This is where the code is compiled, tests are run, and
any other quality tests are implemented.
SUMMARY
Velocity is magical with development teams and, most of all, removes
the tedium of dealing with the problems that arise due to your process
in the first place.
D
ocker has revolutionized software development, especially
when it comes to deployment. It still has a ways to go in
terms of adoption, but I think that will change as the years
go by. It’s a technology you need to know, especially if you’re leading a
development team.
Given all this, I’m going to assume a few things about you:
If that’s you, let me address each point quickly and then we can get to
the good stuff:
Let’s dig in and see how we can use Docker in our project. As you’re
about to see, Docker can do a lot more than just handle deployments
for you.
This was a powerful thing to me! The ability to version and deploy my
site automatically was something I had never seen before and, if I’m
honest, was one of the main reasons I wanted to use Rails.
I felt the same thing when I learned Docker many years later. I was
trying to deploy an Elixir app to Heroku, which was supposed to be
easy, but I found myself troubleshooting build packs and wishing life
could be easier.
Well, most of the time. There are some things you need to know
before you get the point of everything “just working”, but we’ll
get into all that in a minute. The point is: little specialty
containers, orchestrated just so, opened up a whole new world
for me.
THE IMPOSTER’S ROADMAP 341
Docker has changed the way people build software, and also how they
write their code daily. For it to work properly, however, you’ll need to
know the basics as well as the little tricks Docker people have
developed over the years.
These commands tell Docker to go get the latest build of Node.js from
Dockerhub and, when it’s run, to execute the command node if no
other command is given.
We can then build this image using the Docker CLI, making sure we
tag the image (which is like naming it) so we can use it easily later on.
We do that with the -t flag:
It might be hard to miss, but that little dot at the end is a file
specification, letting Docker know where the Dockerfile is. You would
think that . would be the default (meaning “this directory” in Unix
terms) but it’s not, and you’ll get an error if you try to do things
without it.
don’t — but even if you did, this is what you’d likely need to
remember.
Here’s the super fun radical fantastic part: I didn’t have to install anything
to get this to work, aside from Docker itself. I have a functioning Linux
server running node, and I didn’t need to install anything in my OS to
do so.
That’s outstanding! Want to learn Redis but don’t want to deal with
installing it?
Docker won’t find the Redis image locally, so it will scan Dockerhub
for it, pull it down, and then run it:
344 ROB CONERY
You might think this would take a few minutes, but I was able to get
everything up and running within 8 seconds.
goal here is to show you the practical side of using Docker so you can
ship things.
OK, back to the show. Here’s a common task you’ll likely have to
deal with in the future: getting your application to run in a
container.
We’ve already seen how Docker will pull an image from Dockerhub in
the same way you might clone things using Git. But that’s just the
start!
All of this is to say: we need to be certain we install our packages inside the
container, not copy them in. In our custom Node.js image, I’m copying
over the package.json and the package-lock.json (thus the package*
wildcard). Once that’s done, I execute a command inside the container
using RUN, and that tells NPM to go out and do its thing.
Once that’s done, I run COPY one more time to pull in my code. This
command assumes I’m executing the Dockerfile in my application
root, which is common practice.
Finally, I expose the port I expect the app to run on. With Node.js, this
is typically port 3000, but some cloud providers (such as Azure)
expect your container to expose port 8080. I could do both, but I
chose 8080. All other ports in the container are closed by default.
I set the default command to be npm start and that’s that! To create a
container from this image, I can use docker run like before:
Here’s the thing: Docker is simple until you try to use it. Let’s get past
that initial confusion and see what we just did.
The first line creates an image using FROM. The second command
sets the working directory for a new image that is based on the one
created from the FROM command, but this one has the working
directory (or pwd in the Unix world) set to /usr/src/app.
The COPY command creates yet another image based on the one
created before it, and so on, and the net result is a set of layered
images that make up our final one.
Docker does a good job optimizing things for size as well: each layer is
only a delta on top of the previous layer — just the changed bits — not
a whole new layer. This is the way Git works under the covers, too:
each commit is a delta from the last.
348 ROB CONERY
For instance, I might want to a custom NPM task for setting up the
environment for first use:
The RUN command is usually where layers are abused the most, so
be mindful of how you’re using it, so your image stays nimble. Your
team will thank you!
aren’t that many hard and fast rules in the Docker world, but there are
some things you should know, so your applications run in the
smallest, most secure image possible.
FROM node:latest
FROM robconery/node:latest
This would tell Docker to go to my Dockerhub repo and pull down the
latest image of Node.js… and alarm bells should start ringing in your
mind! While I like the idea of you trusting me, it’s generally not a
good idea to trust any image that’s not the official one.
You’re setting up to use Docker locally and create the image above,
write some code, and then put the book down for a year or so. When
you come back, you want to redo the demos because you’re
interviewing and POW! Nothing works! The image built, and the
container started just fine — but one of the packages I’m using doesn’t
work with the latest version of Node.js.
350 ROB CONERY
When you specify :latest as the tag, it will go get whatever version is
the very latest, and this could break everything. It’s better to make
sure you know what version you’re starting from — regardless of what
build your Dockerfile is based on.
Small Builds
We’ve already seen how Docker works with layers and how we should
keep our custom images small, but there’s more we can do to ensure
that we get the smallest image possible — this includes making sure
our FROM image is the lightest weight we can find.
When running our application code, we don’t need all the tools and
utilities that come preinstalled with the more popular distributions
like Fedora, CentOS, or Ubuntu. These distributions of Linux are built
to handle a wide variety of workloads, including hosting one or more
users.
Like so many things in the Linux world, you can specify which version
of Debian you want using a specific tag:
These are the full operating systems, but if you want the trimmed
down version, you’ll want to find the -slim tag. These versions have
only what it takes to run the thing you want to run.
The question then becomes: which one do you use! The answer isn’t
as casual as “it depends”, believe it or not. You might encounter
compatibility problems with one image vs. another, depending on
what you’re trying to do and what machine/processor you’re trying to
do it on.
I’ve found success most often with -alpine images, so if you’re stuck
and just want someone to tell you what to do, then there you go!
352 ROB CONERY
This is a big issue and, once again, I could fill an entire book on just
this subject. Instead, I’ll summarize what I’ve researched, and I’ll leave
it to you to dig in deeper if you like.
As you can see, it’s running as me (I’m rob if you didn’t know). This
process is really two processes in one: the Docker client (the CLI and
GUI) and the Docker Engine.
This can be confusing, as you often read that “Docker isn’t a VM!”,
which is true — it has full and complete access to the resources on
whatever host is running it. Unfortunately, Macs don’t run Linux (it’s
FreeBSD which is a bit different) and neither does Windows, so we
need a Linux VM for this.
Why am I bringing all this up? Because as you can see in the images
above, Docker and all the subprocesses are running as rob, and rob is
an administrator on this machine. I’m not root, but I can still do
admin things.
The upshot is this: if you found your way into one of my container
instances (and I didn’t take precautions) then you would have full
access to my machine! Yikes!
So what do we do?
The most common thing people do is to ensure that the user the
container is running is not root. I can do that with our Node.js
image by specifying a USER:
354 ROB CONERY
The official Node.js image, like so many other official images, already
has a user created that has locked down privileges. With the node
images, that user is node. When I specify USER node toward the end
of the Dockerfile, I’m telling Docker that every command following
should use that user account. I set it at the end because I need to do
root-y things above, like install packages, copy files and so on.
If the official image you’re using doesn’t have a user already created,
you can use the adduser and addgroup commands:
This works, but there is another way, believe it or not, and you can do
it by going without a Linux distribution at all.
Distroless Images
What if we could strip out everything except for the exact packages and
processes we need to run the thing our image is designed to run?
That’s what a distroless image is.
The only way this can be done with Docker is to have a multi-stage
image, which is, essentially, two FROM commands:
356 ROB CONERY
The first stage of the build uses an alias, AS build, that will let us
copy things from it. We don’t need NPM (Node’s package manager) in
our container, so let’s use the first stage to install and build everything
we need and then copy it into the second stage, which is built FROM
a special distroless image created by Google.
This will run our Node.js code in a container that has a Linux kernel, a
running node process and the libraries that are needed to make it run.
That’s it. Weird, wild and interesting if you ask me. The resulting
image is slightly larger given the layers involved, but it’s also
extremely locked down, which is a good thing!
Right now, there are only 5 distroless images you can choose from:
Java
Python3
Go
Node.js
Rust
That’s the power of Docker: you ship the entire environment, not just
your code! Even better: you can remove yourself entirely from the
process and have your build tools (GitHub Actions, for instance) build
the image for you.
We’ve been building our image without the use of tags, despite using
the -t flag, which looks like it should mean “tag” but doesn’t. Well,
sort of doesn’t. It’s confusing, I suppose.
If you ask for help using docker build --help, you’ll see the -t (or --
tag) command:
So, as you can see, if we want to tag our image we need to use a
specific command, something like docker build red4app:1.0.0, where
1.0.0 might be our version number. This is a common approach, but
there are others you might think about.
Tagging Strategies
course, have different concerns than you do as their images are built
for specific purposes.
For us, it’s a different story. I think using semantic versioning should
be enough. If, by the way, that’s the first time you’ve encountered that
term, you should click that link and have a read. “Semver”, as it’s
called, is the “1.0.0” format we use for software versioning, which is
deciphered as “major.minor.patch”. Major versions are allowed to break
previous versions. Minor versions add features that are backwards
compatible, and patches are bug fixes. Fun stuff! But off-topic.
I think all of that is confusing, if you ask me, and I would suggest
using SemVer unless you have a good reason not to, such as your
company Docker naming policy.
Pushing to DockerHub
The first thing we need to do is tag our image with some meaningful
name. As it stands, our Dockerfile is building on top of node:16,
which is a good start, but I think it’s more helpful to use a specific
platform too. Now that we know more about the naming of things,
let’s go with Alpine, since it’s one we know and like:
THE IMPOSTER’S ROADMAP 359
Groovy. Now we just need to name our image in the same manner, if
it’s important to us, which it very well could be! I think the tag
red4app:0.0.1-alpine is a good one, don’t you?
Right then, now we need to push this to docker hub! For this, we use
docker push:
Oh man! Well, I suppose that makes sense, doesn’t it. I haven’t told
DockerHub who I am, which is simple to do. You first need an
account, however, and that’s free.
To login, we use docker login of course, and are guided gently along:
You also have to have a repository to push your image to, which you
can do through the DockerHub we site.
THE IMPOSTER’S ROADMAP 361
You can also have a single private repo too, which is nice.
Now that this is done, we should be able to push our image! Well…
sort of. Actually, not really because if we try:
Crap! What the hell! This can be frustrating, but I suppose it’s also a
good thing too: your image name needs to match the path to your
DockerHub repository, which means we need to rename things:
362 ROB CONERY
Notice that little blurb at the end there? Our image name resolves to
the default container registry, which is docker.io. We haven’t discussed
registries just yet, but as you might be able to figure out, these are
places that host Docker images for you, and there are a lot of them.
Your local Docker install will default to docker.io (DockerHub) if you
don’t specify otherwise. We’ll change that in the next section.
I use Digital Ocean and have been for years. I know it well, so I will
show you how I do this kind of thing up there, but you can translate
everything I’m doing to other cloud providers as well. AWS, Azure,
and GCP will probably be a little more complex, but hopefully, you can
work out what goes where easily.
364 ROB CONERY
So I’ll click that big blue button there and create my first registry.
They have a free tier, which is pretty darn good if you ask me, and it
gives you 500Mb of space. Our container is a bit smaller than that,
coming in at 40.5Mb (according to DockerHub) and we could
probably make it even smaller if we wanted but, for now, I’ll leave it.
More space is extremely cheap, however, and tops out at $20/mo for
unlimited repositories and 100G of storage. That’s a lot.
THE IMPOSTER’S ROADMAP 365
One of the things I like about Digital Ocean is how friendly it is. They
make things plain and easy to follow, for the most part, including
logging in:
I won’t walk you through all the instructions, but it took me about 20
seconds to get logged in to Digital Ocean’s registry, and I’m now good
to go!
Anyway: I’m all set now, and can tag a new image for deployment to
Digital Ocean:
I’ll admit, that registry address is confusing, isn’t it? This kind of
naming is common in the Docker world: registry/reposito-
ry/image:tag. It can get pretty verbose but, again, we’ll fix that in a
second!
Now we push!
THE IMPOSTER’S ROADMAP 367
Just like that, our image is up and ready to be pulled wherever we’re
going to deploy it.
To remind you: Make is a build tool that I like to abuse. It works like
most build tools do, with targets and recipes, and is older than the
hills. In many ways, it’s perfect to use with Docker because we are,
indeed, building things!
I can automate the steps we’ve been going through using 3 targets in a
Makefile:
368 ROB CONERY
You can see the command that’s being run. Yay! Notice, however, that
I’m not naming the image using the registry. We haven’t discussed
that yet, but I figure I would mention it now.
You can tag an image using a naming convention, or you can just use
the tag command, which is docker tag [name] [tag]. We need our
image tagged with the registry address, so that’s what that command
does.
Now we push!
370 ROB CONERY
Glorious! As you can see, we’re rejected here because our image
exists. If we want to rev that image, we just need to tweak the TAG
variable in our Makefile, and we’re good to go.
FLEX! Make is one of those things what, when done will, will set you
apart.
SUMMARY
Right then! If you have an interview with a team tomorrow that uses
Docker, hopefully you’ll be just a little more prepared than you were
before you started this chapter.
Now comes the fun part: getting containers to work happily together.
FOURTEEN
SIMPLE CONTAINER
ORCHESTRATION
DIGGING IN TO DOCKER COMPOSE
T
he power of Docker lies in its speed and simplicity. You can
create a container to do just about anything, from running
Node, Python or Ruby scripts to housing your application
data. In fact, you can do it all at once!
Each service can do its thing and communicate with other services
using some kind of message transport. Perhaps it’s a queueing system
like RabbitMQ or a data routing system like Kafka. You could also use
an event-based backend and have your services listen for events and
then do their thing, causing yet more events.
but I felt it was a good example of how Docker has upended software
development and created entirely new ways to build an application.
THIS IS IT
To get the most out of working with Docker, it’s important to
understand that you’re not in the happy land of code anymore. This is your
application infrastructure — IT!
It’s easy to get overwhelmed, but Docker Compose takes a lot of this
off our shoulders, letting us happily create our containerized
applications. We, on the other hand, trust that Docker Compose won’t
blow our foot off with its default settings.
Are you happy with that idea? Me neither. Let’s get to know Docker
Compose and what it’s doing for us. We don’t need to go that deep —
THE IMPOSTER’S ROADMAP 373
just deep enough to get below the abstraction a bit and understand
what’s being done.
That’s a lot of stuff and, as I mentioned, for simpler apps this is all
you need, and you can trust Compose to do the right thing. But what
if you’re not working on a common scenario? Maybe you’re creating a
logging service that is constantly receiving input from apps in your
enterprise.
Let’s take a look at what the application directory structure might look
like for an e-commerce application, and how Docker Compose might
work with it:
Here we have an app directory that contains our services, cache, and
frontend code. Let’s say we’re building a Vue storefront with a Flask
THE IMPOSTER’S ROADMAP 375
API for the cart written in Python that uses a Redis cache. The
checkout api also uses Flask but saves its data in PostgreSQL.
Let’s stop here and take a breath. I would rather not overwhelm you,
but I also don’t want to start off with a HelloWorld microservices
app, either. If you find this bewildering and strange — welcome to
DevOps. There’s a lot that goes on in this joint, but if we move at a
pace, hopefully we won’t fall into any weird holes.
Let’s assume that we’ve already created the Dockerfile for the cart
API. Here’s how we can now use that image, together with a Redis
image, orchestrated by Docker Compose:
376 ROB CONERY
The cart service specifies that the Dockerfile to be used to build the
cart image and container are in the relative directory ../cart. When
Compose sees this build directive, it will go and grab that Dockerfile
and build it.
This doesn’t mean that one container can instantly go rocking around
in another — remember, each port is locked down unless you specify
that it should be open. Indeed: if you look at the redis service down
below, you can see that ports are mapped specifically for the Redis
default port of 6379.
The final bit is depends_on. This tells Compose that the redis service
should be started before the cart service.
One final thing to notice: we didn’t use a Dockerfile for the Redis
service here. We definitely could have, but instead I used image,
which tells Compose to go out to DockerHub (or other registry) and
pull down whatever image I specified.
THE IMPOSTER’S ROADMAP 377
Understanding Volumes
Volumes are simply mapped directories back to the host and are used
if things need to be persisted between containers. For instance, if
Redis crashes, we don’t want the data to be lost, so we ensure that it’s
stored in a volume.
The Redis image stores its data in a /data directory, so if I map that to
my local Docker volumes directory, it will be saved. I can also map a
volume somewhere else on my hard drive if I like.
you were to pull this repository and want to get started working on it,
you could just use docker-compose up right in the root and your
development environment would start right up. Neat!
In theory, this works great, but in practice it’s a different story. If you
have a part of your application that requires extensive builds (like
Nuxt, for example, which is a Vue.js frontend framework), Docker
(and Compose) can be quite slow. This is due to everything running in
a virtual machine rather than using your computer’s resources
directly.
The biggest place you’ll notice this is with file input and output, aka
“I/O”. Running something like npm install inside a container can be
massively slow, especially if you need to install for the first time.
STARTING THINGS UP
Here is the code for our cart, which, for now, is just an express
application. We don’t have any routes just yet, but we can add those
later:
As you can see, we’re using the redis service to store the cart data. To
keep things brief and on-target, I’m going to ask you to imagine that
code exists :). The main thing to notice is the url of the Redis client:
redis://redis:6379
If you’re not familiar with URL connection strings, they’re built the
same everywhere, including the web:
protocol://user:password@server:port/resource
Pretty handy for connecting to things, but let’s not get caught up in
this either — so many little rabbit holes to fall into! The main thing I
want you to notice is that our Redis connection URL is
380 ROB CONERY
When the cart container starts, the default command will be npm
start, which will simply call node index.js — standard stuff for
Node.js. Express will spin up and so will our Redis client — and off
we go:
As you can see, our Redis server was started first because we specified
depends_on: redis for our cart service. The npm start command was
called, and our app spun up!
THE IMPOSTER’S ROADMAP 381
It’s pretty wild to see this happen for the very first time, isn’t it? The
output shows the STDOUT from our running containers, which
suggests we’re good to go.
Each service we define will be accessible from the other services in our
docker-compose.yml file using the name of the service. For instance,
if I wanted to use my cart API over HTTPS, I would just need to make
sure I exposed port 443 (using EXPOSE in the Dockerfile or expose
in the docker-compose.yml service definition) and that’s that.
This will be the same for every service we specify in our docker-
compose.yml file: each one will have a name that resolves to the name of the
service, which means we can access any one of them from the others.
This does not mean that the ports are open and access is easy! All
ports are locked down by default, and you have to explicitly open
them. Still, each container is on the same subnet.
That said, we are doing “IT stuff ” and we definitely should not take
that lightly, as tempting as it might be. Networking is a massive topic,
and we could get lost easily, but rather than do that, let’s dip our toe
into the networking world so we begin to know what we don’t know,
going deeper as we need.
Now, I realize that for anyone out there with IT experience… well,
you’re probably jumping out of your chair screaming right now.
Setting up a network is NOT something you normally leave to a tool!
Routers, switches, subnets, external access vs, internal, not to
mention DHCP and DNS! How is it possible that Compose can do all
of this and do it correctly?
That is a great question. The answer is simply this: Compose tries its best
but leaves many choices up to you. I know, sounds wishy-washy, doesn’t it?
Let’s dig in and see what’s going on.
If you don’t specify any network, this is the one that will be created
for you. The idea is that you have containers that want to talk to
each other — so a lot goes on in the background to allow this to
happen.
Now that our containers are started and networked together, let’s see
what’s going on using docker network ls:
There’s a lot going on here, and networking geeks might find all of
this fascinating. I’m not a networking geek, but I know enough to
realize that we have a full, virtual network happening here with a
switch, subnet and DNS. It’s OK if you don’t know what those things
are — the point I’m trying to make is that this is a full, real network
running virtually behind the scenes.
Should we care about this at a deeper level? I say we should, and the
first question we might want to ask is “what about other Docker
Compose files… are they on the same network!?!”
I was going to demo this and show you that no, every network is
isolated, but I thought it's easier to just say it. When Docker Compose
384 ROB CONERY
starts, it looks at the existing networks and increments the subnet IPs.
Our subnet looks like this:
But if I started up a new container set, the subnet would start with
172.28.0.0/16 — notice the “28” rather than the “27”.
By the way, if you don’t understand routing, subnets, DHCP and NAT
stuff — take a second and have a Google. If you set up wifi in your
house or apartment, you’ve worked with all of this stuff. Every
machine on your home network talks to your router, which is your
gateway to the outside world. Internally, your home machines (and
phones, Xboxes and so on) are given an IP address within a certain
range defined by the subnet. In our config, our subnet is defined by
the IP addresses 172.27.0.0 - 172.27.0.16. The subnet ends at 16
because the /16 at the end specifies that.
Let’s look back at the services we’re eventually going to define for our
application:
THE IMPOSTER’S ROADMAP 385
There are many services here! The question becomes this: do they need
to have access to each other, or should they be isolated?
We can now inspect our networks again using docker network ls and
here’s what we would see:
For now, let’s move on and discuss a few more network types.
MacVLAN
Fair warning: if you’re a twiddler, you might lose the rest of your day
messing around with Docker networking. It’s so interesting!
MacVLAN networking is where we leave the comfortable world of
defaults and get into the customizations that you might need if you’re
running your own IT setup.
The MacVLAN has one purpose: bind your containers to your local
network. You give it a subnet, ip range, and the gateway address, and
each container is treated as a peer on that network. Like a bunch of
little VMs!
That’s crazy. You might be thinking: why in the world would I ever do this?
Good question! If you’re the “network person” at your company, you
might want to expose a service to everyone in your subnet — maybe
it’s the dev team, and they need a centralized PostgreSQL or Redis
service — MacVLAN makes this simple to do.
You need to understand your network first, however, before you can
set up your MacVLAN, specifically you’ll need to know:
388 ROB CONERY
Device: en0
You can find your MAC address by going to the “Hardware” tab in the network
settings.
Here I see that my network interface is en0, which is pretty typical for
Apple machines. You might have to Google a bit to figure out how to
get this information on your machine, but it should take 10 minutes
to get your answer.
I have both wireless and wired connections, and for this example I’m
going to use my wired connection, eth0. Here’s the new docker-
compose.yml network setting:
390 ROB CONERY
Now I just need to update the services to use this network setup:
You’ll notice here, too, that I have to assign a manual IP address for
my services, making sure they’re outside my router’s DHCP range
(auto-assigned IP pool). You can also let Docker assign these IP
addresses for you, using ip_range: in the network setup, but I prefer
doing it manually.
Long story short: MacVLAN doesn’t have the ability to use Dynamic
Host Configuration Protocol, or DHCP, which is how your computer
connects to a network and is configured automatically by the router.
For that reason, we have to assign IP addresses manually, and we also
have to be sure that those assignments fall outside the router’s DHCP
range to avoid collisions.
Let’s say we do that — like I did above — we’re still not out of the
woods! Docker containers have virtualized everything, including a
Media Access Control (or MAC) address. These things are meant to
identify hardware — physical things on our network — but our MAC
THE IMPOSTER’S ROADMAP 391
addresses are virtual. This should be OK, but the problem comes when
these MAC addresses are all using the same Network Interface Card,
or NIC.
Three machines using the same network card? Our router might take
exception to that and issues can arise, including lack of access to the
network and the outside world.
There are ways around this, including tweaking your router and telling
it to stop being so strict — but that’s beyond the scope of this book. If
your services can’t connect, for some reason, this would be the reason.
IPVLAN
Wild.
That’s… kind of nuts. Doing this allows machines outside our Docker
network to talk to our containers using typical routing rules that we
set up with the host. Port-forwarding, default responses — all the
stuff you currently do with your home internet router can be done
with your IPVLAN L3.
To get this to work properly, you need to let your existing network
know that a new router is in town, setting up routing and traffic rules
(and more subnets) so that everything works…
This is where I need to gracefully step back from the subject. I am not a
networking person, though I’ve done enough of it in the past when
running my first business. I think it’s good enough if you know this is
possible — and you can go dig in on your own if you would like to
know more. I am, honestly, uncomfortably over the edge of a
knowledge cliff here — even though I’ve spent days studying this stuff!
Overlay
Overlay networks are for people who are, basically, managing an entire
Docker-based infrastructure or an on-premises “cloud”. I’m not going
THE IMPOSTER’S ROADMAP 393
None
Here you can see the ones we’ve been playing with, including the
default bridge network. If you don’t want a network, you have to use
the last one there: none.
It’s the most secure, to be sure, but also a bit useless unless you really
need to be sure no one can get in and snoop your containers! As you
might have guessed, you just specify network: none for your service,
and you’re good to go.
394 ROB CONERY
It still blows my mind that you can share an image like this, complete
with Linux, Go and a web server. But how is that done?
There are other registries, of course. In fact, you can create your very
own registry by using Docker itself, which is wild. Doing this is a tad
out of scope for this book, but here’s a great article on how to do it
from Digital Ocean, who will also set one up for you with their one-
click deployments.
If I’m honest, there really is no need to run your own registry. Every
cloud has this ability and makes deploying applications from their
registries effortless. GitHub also has a registry that you can tie to a
repository, building a new image as part of a workflow. I would
suggest you use one of these unless you have a good reason not to —
it’s just another thing you would have to maintain!
That said, there are some elementary ways you can put your
development environment completely inside Docker. Seamlessly, I
might add.
I work at Microsoft, so I get to see things before the public does, and
I’ll never forget when my friend Burke Holland showed me Dev
Containers. You have to have VS Code, of course, with the Dev
Containers extension. You also need Docker up and running.
Now it’s a matter of telling VS Code that you need a container for
396 ROB CONERY
your environment. You can do this by using the command palette (⌘-
shift-P on a Mac, ctrl-shift-P on Windows). You should then see this:
The second choice will walk you through the setup for your dev
container image. There are some easy “quick starts”, including .NET,
Node, Go and various database combinations, and you can customize
things as you need to once you get started.
The fascinating thing is that you can also store information from VS Code
itself in there! Extensions you need only for a given project, a special
theme, and even project-specific snippets. If you want to see more
about all of this, I did a talk at NDC London in 2022 all about it!
proper key settings so you can push your code to GitHub, and nginx
so you can serve your app properly.
For some people who know Docker, this is a breeze, which makes
working on a team simple. For other dev leads out there, velocity is key
and, being extremely honest here: Docker slows you down because it’s
another thing between your developers and your application code.
I’ve tried to make the jump to Docker for development 4 times now. It
really does help with things like making sure you have the correct
ruby gems for your Rails app, or the right Python version and
environment for your Django app.
Database tools such as Postgres.app and DBngin for the Mac make
setting up databases simple too.
Balance all of this, however, with your knowledge and comfort with
Docker. If you’re good at it and know what you’re doing,
environment tools and software installation just to support
development seems extremely silly. I get this, I really do. I don’t have
a definitive answer for you on this — it comes down to you and your
team!
SUMMARY
Docker Compose does a lot, but it lacks one thing, which can be
important: logic. When you create your docker-compose.yml file, you
can, indeed, specify some rules such as “restart on failure” and scale,
which will create multiple instances of a service for you.
If you’ve worked with Erlang in the past, you might be sensing we’re
about to enter some familiar ground.
W
hen I started my programming career, there was only
one way to get your web application in front of other
people: through an IT department somewhere. It could be
your own at the company you work at, or a host of some kind.
Either way: you dealt with Information Technology types that typically
enjoyed their job having power over you.
Turns out that developers like to tweak and twiddle things, constantly
inventing and reinventing, hoping to keep improving whatever it is
they’re twiddling. Orchestrating containers is a twiddler honeypot!
In the “old” days, we bought two Dell servers: one for the web, one for
the database. We SSH’d (or remote desktop) into the database, ran
some SQL files after installing whatever database we were going to
use, and crossed our fingers.
This, in summary, is our process: we write code, sometimes compile it, and
push it to a machine that executes it for our users. This was true then, and
it’s true now. The difference is that fewer people are involved and IT
departments are slowly going away.
like, your code must be compiled before it’s even run, with the
compiler throwing errors if you break the rules.
Some platforms, such as Java and .NET, use threading internally. If you
know how to use these, then you can write code a bit more
defensively and let a thread die instead of the entire application going
down. This makes these platforms a bit more resilient and “self-
healing”.
Our goal here, therefore, is to ensure that our application stays up and
happy. We understand how our runtimes work (and don’t, for that
matter), so we can come up with a plan.
PROCESS MANAGEMENT
I need to pick a platform here, so let’s use Node. Let’s say we have an
Express web application that uses Postgres to store data and Redis as
a cache. Right now, we have no idea what a Redis “cache” does nor
how to use it to make our application more efficient, aside from
storing user sessions, but I’ll get there.
it, but errors always happen and, as Alan Turing explained with The
Halting Problem: you just can’t say if a program will exit. The corollary
there is also true: you can’t say if a program will stay running!
I’ve used PM2 many times and really like it. In fact, Azure (and other
cloud providers) use PM2 behind the scenes to run their Node
applications. It’s simple to configure, can scale your app if needed,
provide monitoring information, and also restart a crashed process. It
can also do simple load balancing, which is wild.
The short answer is “no”. PM2 handles the application service, which
is Node, but doesn’t handle scaling anything else. Often, this might be
all you require, but as we’re going to see in a few chapters: CPU-
bound processes (like the Node service) don’t typically slow things
down, it’s the I/O stuff that hits the disk or network.
Services
Messaging
Reporting and Analytics
Event tracking
Monitoring
404 ROB CONERY
Logging
One or more databases (Postgres, Redis, Cloud of some kind)
The rewrite takes a few months, but eventually, you get things
working. The container images are up on GitHub and your
deployment process is now, basically, pushing a Docker Compose file
to your host.
But did you do these things correctly? Having tried (and failed,
multiple times) to set up my books using Quickbooks, I know that
dread feeling! Having all of these systems running is wonderful… but
having them siloed like this is unsettling.
At its core, Dokku uses Git, Docker, and a mighty set of shell scripts
to create your application’s runtime environment. If the CLI doesn’t
scare you, Dokku might be something interesting to look into.
For most applications, you can create the Dokku “stuff ” you need
using various plugins, then tie them together with a few commands.
The steps are as simple as you can imagine. You’ll need a Linux VM
somewhere, and it should have some resources, as it’s going to power
406 ROB CONERY
your entire infrastructure. I use DigitalOcean for this, but you can set
up a Dokku server effortlessly, just about anywhere.
If you have a Linux machine with Dokku installed, you simply need to
SSH in and run some commands:
There it is — that’s all you need to get started! Ha ha, YOU WISH.
There are quite a few more things we need to do here, namely:
It’s incredible how many things you can do with Dokku, as long you as
spend a little time reading the docs and memorizing the mantra
“there’s a plugin for that” or “there’s a setting for that”. The people
THE IMPOSTER’S ROADMAP 407
who made Dokku wanted to copy what it’s like using Heroku, and I
think they did a good job!
This fires off a post-receive hook in our remote Git repo that was set
up for us when we created our application. This hook does the needful
and deploys our code for us.
Simple.
Our application has been broken out into a set of services, and Dokku
can handle this for us just fine — it’s just a little manual. There are a
few approaches we can use to approximate what we put together with
Docker Compose:
Create a set of apps for the services we need and add them to
a Dokku network.
Create a single app with workers that do things
asynchronously, using some type of asynchronous processing,
such as Redis pub/sub.
Skip microservices altogether and scale things using Dokku
directly.
We’ll talk about this more later on, but managing microservices is
tricky business, and one that you really need to justify vs. “just scale
the entire damned thing out”. Services like Heroku are good at this,
but it’s also a bit simplistic for many designs.
I don’t have an answer on this. I like Dokku and I know it can do a lot
and I prefer the simplicity. That said, if I was leading a team that
wasn’t comfortable doing “server stuff ”, I would be a bit hesitant.
I feel that Docker is a needed skill for every developer these days.
Using Dokku, however, is kind of niche. You would need to be very
408 ROB CONERY
sure the entire team knew what the setup was and why, just in case
you found a new job and were walked out the door where you are now
(it happens).
If you do this, however, you’re limiting your experience and jobs will
be harder to find. And for what? Bragging rights?
AWS is by far the most popular, and most complex, of the Big Clouds.
If you had to pick one, I would suggest AWS. If you’re a Microsoft
person (.NET, Office apps, etc.) go with Azure. If you choose AWS,
then start with this video from NetworkChuck (Charles Keith). He is
one of my heroes in terms of teaching people things online; so good.
His video should be enough to get you started on your journey.
Those are the bigger services, now let’s discuss the smaller, cheaper,
and simpler services that are super focused with their offerings.
Firebase
410 ROB CONERY
I’ve been using Firebase for years and I love it. It gives you (almost)
everything you need to run a web or mobile application, and it’s
extremely simple to use.
You can also integrate pretty easily with the main GCP services if you
like.
AWS Amplify
The goal of AWS Amplify is to wrap the most commonly used AWS
services for frontend and mobile applications, and make it “easy” for
you as the developer to build things.
I’m not sure what I think of this approach. Trying to simplify a service
like AWS down into a drag and drop interface seems… overly
ambitious. That said, it also looks extremely compelling:
Most applications that you’ll build in your career are some version of
“forms over data”, which means you spend most of your time figuring
out how to get user input (forms) into a database. Amplify is focusing
on that, and trying to “help” you move faster:
THE IMPOSTER’S ROADMAP 413
I’ll be honest: I really hate abstractions like this. This is one of those
opinions that builds over time, by the way, and each person’s
experience will be unique, I suppose.
Frameworks and tools that try to hide massive complexity (and AWS
qualifies as that) tend to do things that will surprise you, in both good
and bad ways. Right off the top of my head, I’m wondering what AWS
services Amplify will create for me, and how I’ll be paying for it. Every
month, AWS charges my credit card right around $1, and I have yet to
figure out why. I’ve tried to shut down all of my services, too, but
nothing seems to work.
The last thing you want is a surprise AWS bill, and if you click that
link, you’ll see quite a few stories about how people did a tutorial or
forgot to turn something off when they were goofing around. This can
sink your new company! Thankfully, AWS is pretty good at helping
out with unexpected charges, you just need to navigate a phone tree
and get a real person to help you out.
Financial issues aside, the problem with Big Abstractions like this is
that you have to play by their rules if you want to get the most out of
the tool. Ruby on Rails is the same way: play along, you’ll get a lot of
414 ROB CONERY
work done. Come up against an edge case when Rails gets in your
way, it’s painful.
These tools and frameworks are great for getting started, but if you
decide to use them, know what they cost and how much workarounds
will hurt.
There are fun “middle ground” cloud services, and two of my favorites
are Digital Ocean and Linode, which was recently bought by Akamai.
I’ve been a customer of both for years, but have used Digital Ocean
the most.
Indeed. Dokku orchestrates Docker using Git, and Ruby on Rails is…
well, it’s Ruby on Rails. I know them both, which is to say I know
where, when, and how I’ll need to use workarounds and when both
things will become too hard to maintain as the complexity of my
application grows.
Back to the point, however: simple VMs with prebuilt images can take
you a long, long way. That’s what you get with Digital Ocean and
Linode, with a sprinkling of other services like managed databases,
storage, functions, and monitoring.
Digital Ocean will also run Kubernetes for you, which we’ll see in the
next chapter.
Supabase
One of the challenges I have writing a book like this is that it takes a
long time to pull the content together, and things will inevitably
change.
Figma, for instance, was bought by Adobe right after I wrote about it
in chapter 7, so I had to reconsider if it was going to be part of the
book. Nothing against Adobe, but they might be planning to absorb it,
the team, or just kill it outright. Recently, however, the deal fell
through, so Figma is back on its own.
All of that said, it’s a service I’ve been using for almost a year now,
and I love it. They have managed to hit a very tight niche, and they’re
doing it extremely well.
THE IMPOSTER’S ROADMAP 417
Using the copy/paste analogy once again, imagine you copied Firebase
and pasted it on top of Postgres, running on managed AWS services:
The only reason I don’t like Supabase is because I wanted to build this
exact service a few years ago (minus the row-level security) and
decided against it!
Not so funny aside: our server rack was in the recreation area of our office, which
I suppose, in retrospect, was a terrible idea. One day, 2 of our core programmers
were playing foosball and one of them absent-mindedly put their can of Diet
Coke on top of the switch while they joined a game. I saw it, and launched the
can across the office, against the wall. No, I didn’t apologize for it. People tried
to tease me about it too… which wasn’t a good idea either, as I would remind
them, every time, how much money was represented by those machines.
This is the problem if you decide to host your own servers: people will
put cokes on the rack. The power will go out. You (or someone on your team) will
need to physically protect your machines from other humans.
Case in point:
The fire sprinkler system was activated in the Colo space above
row 4 and was limited to row 4 with some exposure to adjacent
rows, according to a report from Digital Realty. Power was cut off
to the Colo 3 and 4 spaces.
Is it worth it?
The back of the napkin math is that we'll save at least $1.5 million
per year by owning our own hardware rather than renting it from
Amazon. And crucially, we've been able to do this without
changing the size of the operations team at all. Running our
applications in the cloud just never provided the promised
productivity gains to do with any smaller of a team anyway.
They’re smart people over there, and I’m sure they figured all of this.
DHH also offers a bit of caution to his readers, that this isn’t a
solution for everyone:
As I've mentioned before, I still think the cloud has a place for
companies early enough in their lifecycle that the spend is either
immaterial or the risk that they won't be around in 24 months is
high. Just be careful that you don't look at those lavish cloud
credits as a gift! It's a hook. And if you tie yourself too much to
their proprietary managed services or serverless offerings, you'll
find it very difficult to escape, once the bills start going to the
moon.
Should you rack your own servers? To me, the question feels like
422 ROB CONERY
I don’t know if I could stand the stress, myself. But then again, I’m
not paying out millions a month in cloud fees!
Speaking of, in the next chapter we’ll dig into Kubernetes, which you
can use in the cloud or your own datacenter.
SIXTEEN
KUBERNETES
A CRITICAL TOOL TO UNDERSTAND SO
YOU CAN MAKE SOMEONE ELSE DO IT
D
ocker Compose does a lot for our container-based setup,
but there are limitations. For instance:
The bottom line is this: Kubernetes sets you up for massive scaling from
day one. It has a vibrant community, and is a miracle of engineering. It
is, as we’re about to see, a data center in a box, and it requires the
same level of understanding as any IT department used to.
To that end, we’ll start at a high level and work our way down. There
are quite a few concepts and terms you’ll need to learn, but hopefully,
it won’t be too bad. Kubernetes is dense, very dense, and the people
who know it are in extremely high demand.
Kubernetes gives you control over your deployment and scaling. You
have an entire datacenter at your fingertips, and there is almost no
limit to how high you can scale your stuff. That said, you will be
bathing in YAML regularly, learning new terms and plugins hourly,
and lining your office walls with cheatsheets. Or, I don’t know, maybe
you have a great memory? My notes on Kubernetes go for pages and
pages…
That’s it, really. If you want my personal advice on this — get to MVP
(Minimum Viable Product) first and make sure you have users and
potential to grow. Dokku and Heroku are outstanding at facilitating
this! Growing pains are good pains to have, and if you experience
THE IMPOSTER’S ROADMAP 425
This is called a cluster, and it needs to be set up first. Once that’s done,
we can start playing with YAML, and we get to understand one of the
main concepts behind Kubernetes: desired state.
If something happens that puts our cluster out of sync with the
desired state, such as a container crash, Kubernetes will do it’s best to
heal itself, back to that state.
That’s Kubernetes at a high level, but wow there is so much more, and
we must move slowly if you’re new to the whole thing. If you’re a
Kubernetes person, feel free to move on, what comes next is for
people (like me) who only have the slightest knowledge of
Kubernetes, namely that it exists.
CREATING A CLUSTER
You can play around with Kubernetes locally, provided you have Linux
running somewhere, or you can play around online. I’m going to do
the latter.
426 ROB CONERY
There’s a simple site you can go to that will let you play with
Kubernetes for a few hours. It will set up a cluster for you, and you
can play around for a bit. You do need to log in, but that’s just to keep
people from causing problems:
As you can see, we can play for a few hours and then everything is
wiped out.
We’re given a few warnings and also instructions, the first of which is
to initialize our cluster with kubeadmin, which manages our cluster.
This is the first of two binary tools that we care about, the second is
kubectl, which manages the Kubernetes state.
Good. Lord. There is a lot you have to learn, and it’s all good if you
want to dig in to the administrative bits and bobs of Kubernetes. For
some applications, this could be a good idea as you have a lot more
control and know what’s going on at any given moment. If you’re just
starting out… well, there are simpler options.
I’ve been using Digital Ocean for years and like them a lot. Linode is
great too, as are so many other services (Azure, Google, AWS, etc.). It
just comes down to “how detailed and in control do I want to be?”
For me, I’m happy to have Digital Ocean do the first parts for me. I’ll
show you how they do it, but just know that most other cloud
providers do the same kind of thing. I’m honestly not trying to send
them business — but you should see the difference.
You can see at the bottom there that my monthly bill will range
between $24 and $60/month, which I’m fine with. For starting out,
I'm in favor of knowing just how much I’ll be spending, so I’m going
with “Fixed size”.
This has changed, of course, and there are a few ways to run a
database reliably right inside Kubernetes. Or you can do a managed
thing with Digital Ocean, which I’ll skip for now.
Again, this is what Digital Ocean does, but other cloud providers will
do something similar for you, including letting you download the
configuration file:
Find a place on your local drive to work from. Ideally, this won’t be in
your project’s code directory because you do not want this stuff in source
control. Our config file that we just downloaded are the keys to our
Kubernetes kingdom, which you should view as your personal, virtual
data center.
Boom! You should see something like this come back quickly:
434 ROB CONERY
Don’t you love it when things just work? Let’s tighten this up a bit so
we don’t need to keep adding the --kubeconfig flag, shall we? To
achieve that, we can create an environment variable to hold that info:
KUBECONFIG=./do_kube_config.yaml
That makes things just a bit easier, doesn’t it? If you’re using a shell
plugin that autoloads environment stuff from a .env file, you can set
the variable above right there. If you’re new to environment variables,
they’re settings in your terminal session that your shell can use when
executing commands.
I love Make. I know I abuse it because it’s really meant for building
software, but you can also use it to execute shell commands (and
scripts) in an orchestrated way. It’s super helpful when it comes to
remembering commands, like get nodes:
This step, is, of course, optional. But it’s also extremely fun and
useful! You can create a Makefile in your project root, adding a
variable for our config:
THE IMPOSTER’S ROADMAP 435
Kind of looks like YAML, doesn’t it? It’s not, and it can be frustrating
if you don’t know the particulars, which are:
We’ll keep playing around with this and see if it’s worth it as we
go on.
We have been working with the idea of a “master node” along with
“child nodes”, or just “nodes”, but obviously things are more
complicated than that.
436 ROB CONERY
Our master node is also referred to as the control plane, which is a funky
term describing a collection of services at the heart of Kubernetes:
All of these services work to ensure our nodes are in a desired state.
THE IMPOSTER’S ROADMAP 437
If you don’t know Kubernetes, many of these things won’t mean much
to you, which is OK as I’m about to go over them. For now, know that
this file represents the desired state that we want our cluster to
change to.
438 ROB CONERY
The app label. This helps us keep track of things for our
needs, but doesn’t really impact the system.
The spec:replicas setting. This will create containers for us
and evenly distribute those containers across our cluster.
The template:spec:containers section, which contains the
Docker settings we’ll be using for each container. Looks like
Docker Compose in there, doesn’t it? Aside from
containerPort which, hopefully, you can figure out!
It’s ridiculous how fast this is! It should take well under a second to
issue the command to our API Server, which hands it off to the
Controller Manager and Scheduler.
But, did it work? We can find out by asking kubctl to give us a little
more info than get returns. For that, we’ll use describe pods :
THE IMPOSTER’S ROADMAP 439
It’s unnerving how fast Kubernetes is! There is a TON of info dumped
on us here, but I highlighted the big things we need to know, namely
that our deployment was honored and that our image was applied
properly. The services are running, yay!
Before we get to that, it’s a good idea for us to start using the term
pod instead of container because that’s what the replicas setting
refers to: the number of pods we want running across our nodes.
That’s one of the neat things about Kubernetes: you can have (almost)
as many pods as you want! They don’t correspond at all to the number
of nodes you have in your cluster (hopefully these terms are sinking
in). The Scheduler knows the workload of each node, so when we
440 ROB CONERY
Kubernetes Services
That wasn’t too hard, was it! The main differences from our first
deployment are the kind, which is of course a Service. From there we
had to describe the type as LoadBalancer and then which pods to
balance things with.
For that, we use the selector setting. This is where our app labels are
useful from our deployment above! We specified that each of the pods
would have the label nginx, hoorah for us!
Let’s see if it worked. We can do this using the command kubectl get
services:
It’s running, yay! This is a service that sits outside our nodes, as you
can see, and it will be assigned an external IP once one becomes
available.
That was almost too easy! Let’s see if we can hit our site:
442 ROB CONERY
I’ll talk about Cloudflare in more detail later on, but one of the
services they provide is “proxying” your domain settings if you want
them to. I do this with every site I own, including bigmachine.io. If
you proxy your domain, you get a free SSL certificate, and you don’t
have to do a damned thing to your server.
Check it out:
I was having issues with this demo and my friend Aaron Wislang
jumped to my rescue by reminding me of this setting. I had it set to
“Full” which didn’t work because my server doesn’t have a self-signed
certificate.
Note: some services do have this when you create a site with them. They’ll
typically offer you a preset site URL that’s something like “https://youraccount.
theirservice.something.come” which will already have an SSL certificate. In that
case, using “Full” mode with Cloudflare works great. If that’s not the case, you’ll
need to ensure “Flexible” is selected.
Et voila!
444 ROB CONERY
You know, I used to spend days, sometimes weeks, waiting for SSL
certificates. You had to prove who you were, send in business and
banking documents, and then you’d get a PEM file with some
(typically) lame instructions on how to set the certificate up with your
server.
I can understand why someone might not want to use Cloudflare for
everything they do, depending on a service that much is scary. If I was
leading a project, however, Cloudflare would definitely be a hill I
would die on. They simply do everything better than any service I have
used.
Your Kubernetes host/cloud provider will likely have an SSL option for
you, or at the very least, instructions for how to set up SSL in your
cluster using something like CertBot or CertManager. Digital Ocean,
which is where my Kubernetes cluster is hosted, has several
walkthroughs for how to set up SSL with them using Lets Encrypt.
Now we just need to run apply one more time and off we go!
How easy was that? Let’s take a look at the state of our cluster again,
using kubectl describe pods:
It still amazes me every time I see this. The Scheduler decides where
things should go, and the Controller Manager makes it happen. Here
you can see that the image for Nginx 1.25.3 is being pulled and
applied across our pods, gracefully rolling out one by one, ensuring
there’s no downtime.
446 ROB CONERY
Finish your sprint and build your new image, tagging it with
something meaningful, such as the name of the sprint.
Push your image to your registry.
Update your deployment manifest with the latest image and
apply.
What’s worse is that this is a mess you created, and you’ll have to tell
your boss about it. All they’re going to hear is “blah blah blah I have
to figure out this process I created before I can fix things blah blah
blah so it’ll take another few hours”.
I can’t tell you just how disastrous it feels when your development
process gets in your way, and I speak from experience on this one. I
used to have automated deployments happening from my GitHub repo
for my publishing site, bigmachine.io. I would push, a process would
THE IMPOSTER’S ROADMAP 447
I could have fixed this within a few hours. In fact, thinking about it
now I think I might have chosen the ARM image which, of course,
wouldn’t work on an Intel processor which… ah whatever.
My site exists to show customers the stuff I’ve made: Books and
Videos. If that doesn’t happen, I don’t have a business. This is a good
argument for using Kubernetes, but it’s an even better argument for
having some way of keeping your site alive if it fails. Kubernetes will
keep your site up, but so will PM2 if you’re running Node, or any
process manager, really, including Dokku!
If Kubernetes has a downside, it’s the psychic weight of the thing and
the process it creates in your project. If you have a team that can
handle that, Kubernetes is rad! If not, it could be a disastrous choice
for you and your team.
Let’s look over the Nginx deployment, once again, but with more
comments:
If you ignore the top bits and only read from spec onward, it makes
reasonable sense. We know how important selectors are now because
we added a load balancer that used those labels.
THE IMPOSTER’S ROADMAP 449
Each pod has a spec applied to it as well, configuring the images and
their settings as needed.
API version, what the manifest is describing, a name and some labels.
Then a configuration specification for the thing we’re asking for.
The Spec Spec: Docker info, which typically aligns with Docker
Compose.
It’s one of those things you get used to and need to exercise from time
to time. Kubernetes is all about the YAML and understanding the keys
and switches.
There are other “one-click” setups that will run the YAML for you as
well, which you can see here. Monitoring, networking, and even
WordPress!
That said…
THE IMPOSTER’S ROADMAP 451
MEET HELM
Kubernetes is hard, so we need more abstractions to make it less hard!
Apparently. Yes, I’m being snarky, but consider:
That’s what Helm does. It’s a CLI tool that works off things called
“charts”, which are recipes for Kubernetes. If you understand
Kubernetes, you will jump to Helm quickly because it just makes
sense.
Here’s a Helm chart for the Ghost CMS that I love! You can view the
templates that go into this as well, so you’re not just blindly trusting
someone else to build things for you.
452 ROB CONERY
13 manifests for setting up all the Ghost goodies. I think that’s pretty
neat!
CLEANING THINGS UP
Let’s drop our deployment, shall we? It’s a good idea to understand
how to clean things up, and as you might expect, you can do this with
a simple command:
Now let’s do the same for our load balancer. Can you guess what that
command would be?
THE IMPOSTER’S ROADMAP 453
We’ve deleted our pods… but our cluster is still sitting there idle, with
nothing to do! Qué horrible! We’re going to get billed for all of this, so
let’s make sure we drop the cluster at our cloud provider too, which
you can do with Digital Ocean right in the settings screen.
What now!
Your manifests still exist in your working directory, so all you need to
do to get your environment back up is create a new cluster and apply
your deployment and services.
It’s at this point you’ll probably be delighted you decided to put your
data into a managed service!
WHAT ABOUT…?
Imagine you’re on a plane, flying far away, and you fall asleep during
the flight, happily passing the hours with Morpheus in the Dream.
Boom! You land. You were happily asleep, and now you’re groggy and
don’t quite know what happened. You see that you’re in an airplane
and can’t remember how you got there. People are now getting off the
plane, and you pick up your stuff and as you walk down the aisle, a
flight attendant comes up behind you and hands you your backpack
with your laptop in it and your phone — both of which you forgot as
you stumbled toward the exit.
You walk down the jetway and still can’t remember where you are,
THE IMPOSTER’S ROADMAP 455
and then you see the signs. Oh, right. The Big Trip. I forgot that I’m
starting out here… in a big country I’ve never been to…
If you’ve never used Kubernetes before, that person is you (me too!),
landing in Kubernetes Land with only the slightest notion of what’s
going on.
I wish I could fill this chapter with loads of examples and use cases,
but others have done this so much better than I can. If I had to
recommend one, it would be Nigel Poulton. I don’t know Nigel, but
I’ve watched his Pluralsight courses and also read his book. He’s
excellent.
In the time that I’ve been writing this book, the major cloud services
have launched over 100 new services, each of which is trying to make
the cloud easier for you as the person who needs your application in
front of people. And it’s going to keep growing and churning.
You can host your Kubernetes cluster on each of the services, or you
can approximate Kubernetes using a collection of offerings, a so-called
“Cloud Native” approach.
456 ROB CONERY
This is a massive topic and one that is frankly out of the scope of this
book. I work in the Cloud Native advocacy group at Microsoft, and I’m
still learning about our services!
P
utting a book together is hard work. Aside from the planning
and the writing of the thing, there’s also organizing and
editing. I struggled with this chapter in terms of where to put
it: before DevOps or after DevOps.
On one hand, you have to know how your application will be deployed
and where it will ultimately live before you build it. If your company
has Azure credits you’ll probably go with Azure, which means that
you’re most likely a .NET shop, which means you’re going to build a
certain style of application.
Maybe you like Rails and want to move extra fast, so you go with the
Big Monolith. In that case, Dokku or Heroku (or services like them)
are going to work better for you.
For some teams, velocity is key. For others, it’s clarity and structure. It
all depends on your context, but do keep this question in mind,
always. In fact, write it down in a README somewhere, or at least in
your personal journal.
Knowing why you’re doing a thing is critical, because you will be asked
why you’re doing what you’re doing. You should have quite a few
answers at the ready.
I’m going to assume that you’re familiar with the startup landscape vs.
“the enterprise”. I’ve worked both, and one thing I’ve never entirely
understood is why so much ceremony and structure go into
“enterprise” applications. If you’re talking about accounting, HR,
inventory, or payroll systems, then yes, I can understand that.
Startups move fast and “break things”, which is fun and exciting until
it’s not. They really do expect you to work 10 to 12 hours a day, even
if they publicly say “we believe in work/life balance”, the rest of that
THE IMPOSTER’S ROADMAP 459
Velocity and structure are on sliders here, but one thing isn’t, and it’s
the common thread through the rest of this chapter: the ease of fixing
and changing things. Bad architectural choices are easy to spot: “fixing
this bug means we need to change X, which means we need to change
how we Y and ultimately Z.” I’ve been there so many times.
In the startup world, no one cares. Build it, ship it, let’s go go go go!
It’s all about MVP and MRR (monthly recurring revenue) and getting
profitable so we can get another round of funding… so we’re not
profitable anymore.
In the enterprise world you plan, diagram things in UML, sit through
design meetings and, sometimes, write code.
I do wonder if it’s in our DNA: we become the alpha person and want
460 ROB CONERY
UNDERSTANDING TTR
Every time I write an application, I wonder how long it will be until I
replace it. The last one I shipped was 3 months ago, and it was for my
side hustle. An insidious bug crept in, and it took me 3 hours to both
figure out what I had written and then resolve the issue. The old site
was a big frontend application written in Vue 3 and the backend was
Firebase and, after 7 years of this setup, I finally had enough.
But I know I’m going to redo it again someday. I always do. The
question becomes: what’s my Time to Rewrite, or TTR? You can calculate
this by figuring out:
That last one gets me every time. When framework developers discuss
productivity, they’re usually referring to the initial build of the
application, which is NOT where the bulk of your time will be spent.
Nope, that’s maintenance, which we’ll get into in the next part of this
book.
Technical Debt
THE IMPOSTER’S ROADMAP 461
Every so often, I get angry with data access tools (OK, very often) so I
end up writing queries by hand because I know SQL and love it. This
is fine, until something crashes, and you realize the query you wrote
sidestepped the validation rule you have in your model code.
That’s technical debt: making decisions for the sake of speed or efficiency that
build up until you’re technically bankrupt.
Testing is your primary defense against too much technical debt, and
your style of testing will help you find and “adjust” it as time goes on.
We’ll discuss this more in the next chapter, but for now, it’s important
to understand that a “well-written” suite of tests can help you sleep
so, so much better at night.
I’m able to find and fix a bug quickly… but when that thing goes off
it’s like the dentist saying “hmm, we’re going to have to do something
about this aren’t we?”
This is the danger zone for technical debt. The app is down or some
bit of core functionality is doing weird things, and a slow panic sets in.
You throw some code at the problem, building in a workaround of
some kind, and promise to return to the issue when you have more
time.
A day goes by and things look normal. “Guess I fixed it… weird” is a
phrase I’ve used in the past. A week and then maybe a month. And
then your boss asks to see you: why are these reports showing 0 sales tax
collected?
Again: this is where your tests can keep you from stepping on a rusty
nail. As long as you run them, that is, which is why having CI/CD
builds are so important — and we’ll talk about that in the next
section.
Never let a workaround stay in place. It’s a bit of rot in the walls of
your application, and you need to get in there and cut it out, replacing
the problem carefully.
Ooh! Shiny!
Ruby on Rails 7 shipped in 2021 with… well, let’s just say its creator,
DHH, can be a bit dramatic (among other things):
This version of Rails has been years in the conceptual making. It’s
the fulfillment of a vision to present a truly full-stack approach to
web development that tackles both the front- and back-end
challenges with equal vigor. An omakase menu that includes
everything from the aperitif to the dessert.
THE IMPOSTER’S ROADMAP 463
When you’re first building your site, there is nothing as fast as Ruby on
Rails in terms of developer velocity. Django is probably the closest, and
I’m sure Python people will be jumping up and down right now, which
is fine — imagine I wrote “Django” up there.
Either way: it’s fun to see your site come together with tests written
for you, you don’t have to think about what goes where and if you
understand the conventions, you’re flying!
Velocity is fun, isn’t it? For personal or side projects, yes. In fact, I’ll
add to that by saying fun and simple are critical if you’re a small team.
For bigger teams, more discipline is needed.
Tests and Discipline, that’s what it takes. We’ll talk about writing
easily changeable code down below here, and good testing strategies
in the next chapter — but these will help save you from building up
technical debt.
uses generators that put the code in the places it’s supposed to go,
and you don’t need to think about it. It does this by creating several
directories with reasonable naming conventions, and then popping
Ruby files in them:
Honestly, if I had an idea for a startup (and I have many), this is the
framework I would go with. I can build a pretty solid MVP with this
thing, and get it out the door fast.
That’s the core of it, really. The goal here is to get to market fast, fail
early, and I support it completely. Unfortunately, it’s easy to start
piling up technical debt.
When working with Rails, you eventually come to the idea of a service
class, something that wraps other classes into some kind of process.
My favorite example of this is the Shopping class. Let’s discuss.
Our use case is that a Customer comes to our site and wants to buy a
Product. We might think something like “well, let’s have the
Customer add a Product to a Cart using Cart.addItem method”, and
that’s a pretty typical approach.
This works, but soon you feel that you might be getting lost a bit
because you’re adding a bunch of “business” logic into your model,
which is there to represent a database table.
And you would be right. This is called a “fat model” in the Rails
world, and it can work, but your time to rewrite will be weeks, maybe
a month or two, as you simply won’t be able to remember what went
where.
This setup can last you about a year, until your business needs to
expand into marketing campaigns, “Buy Now” deals, coupons and
other marketplaces that resell your stuff for you.
All of that said, I have friends who are working on Rails applications
that are 10+ years old. They do a rewrite every other year or so, and
it’s mostly a migration to the newest version of Rails.
All in all, I would say you have a year, possibly two, before you redo
your Rails (or other ‘batteries included’ framework) application.
That’s honestly not bad!
Here I have my Rails app, but I also have a Vue.js app that I use within
the Rails app, some shared libraries that might include ruby gems and
client libraries. Playwright (the frontend testing service) can stand on
its own as well, so let’s pop it right here.
All of this stuff is in a single repository, too, and it represents the state
of my project at any given time. This makes sense to me because all of
these projects depend on one another, so they should also share a
version history.
As you can see, this type of setup is very team-friendly and allows
468 ROB CONERY
Here, I’ve split my main Rails application into 3 smaller ones, each
performing a service that needs performing. They can all work off the
same database (which I can change later, if I want), but I might want
to use a static site generator for the catalog since it doesn’t change all
that often. I like Rails for invoicing and fulfillment, but I might want
to go with something else for the administrative stuff, like Retool or
JetAdmin.
Shoot, I could even use Django, just for its built-in admin tool!
This structure offers a lot of flexibility, right from the start, and allows
you to plug in what you need, and remove what you don’t. The
downside is that it allows you to tinker.
TTR: Monorepo
Will you rewrite things? Yes, of course! Instead of one big rewrite,
however, we might have 2 smaller ones now. This can be more
manageable with a team, of course, but you will still do it!
Same timeframe here: within a year. This time, however, there will
probably be smaller ones at a shorter cadence.
MICROSERVICES
As the name implies: microservices are individual applications that
operate independently of one another. This approach is applicable for
distributed, highly scalable applications and the complexity that goes
into it is everything you’ve heard.
In short: he broke everything apart and scaled the things that needed
scaling. He insisted that each “cell” (his term for each service) be as
small as possible, preferably a single file that could be read without
scrolling.
That’s the problem with Microservices, in summary. Only you and your
team will understand what’s going on. Maybe. Let’s see, shall we?
I think this is a fun read and, for the most part, it’s approachable. The
hard part, for me, is that demos like this either lean way too far into
architectural wonderland or they tell a fun fairy tale. This is the latter.
Having read the Kubernetes section, hopefully you can see how
microservices and K8s go hand in hand. Microservices is all about
scaling out instead of up (get a bigger machine), and the patterns that
emerge follow functional programming pretty closely.
Note: if you’re a bit hazy on functional programming, I made a fun video for you.
THE IMPOSTER’S ROADMAP 473
The one thing that will destroy your project or your startup is over-
engineering from the start. We’ll go into this more when we discuss
stress testing and benchmarking in the next chapter, but having a
solid understanding of where your application could fail and having a
plan for that is far, far better than spending the extra days, weeks, and
months orchestrating a site that could easily have been a monolith.
The first thing I notice is that these services are not independent at all.
The checkout service, for instance, depends on productcatalog,
shipping, currency, cart, payment, and email. The frontend service
(which is written in Go) also depends on shipping, currency, cart
and productcatalog.
Pretend that you now own this application and the marketing team
comes to you and says:
THE IMPOSTER’S ROADMAP 475
We would like to know more about how people are using our site,
and want to track cart behavior. How hard is it to add event
tracking?
I don’t know about you, but my first instinct would be to jump right
into the cart service to implement this change. Here’s what we have
to work with (it’s C# if you’re wondering):
Our next task is to figure out that context. What other services are
calling these endpoints… and how? Are they event-driven, or
synchronous?
476 ROB CONERY
At this point, I would probably throw my hands in the air and say
“let’s create a logging service that we can build behavioral stuff on top
of ” which sounds like it should have been there all along, right? I
think there’s a reason it’s not there, and I can illustrate it using a little
AI fun:
I’ve been using (and abusing) Microsoft Designer, and it’s pretty
damned fun! I like thinking of services as robots, I don’t know why.
Or your entire team will quit and go get jobs doing Rails.
THE IMPOSTER’S ROADMAP 477
EVENTED ARCHITECTURE
This is where our architectural approach is going to depend on our
infrastructure. The two simply go hand in hand! To see what I mean,
let’s recap how we got here.
One thing that event-driven architecture can do for you is remove the
ridiculous infrastructure spaghetti that we created above. To see what
I mean, let’s see how our checkout service might interact with the
cart service using events.
Services don’t talk to each other directly when you’re using events, as
we are now. You use a broker to send messages back and forth, and
that broker can be set up with routing rules that are actually quite
amazing. We’ll discuss those later on.
I only have experience with one broker, RabbitMQ, and I was able to
orchestrate some pretty intense message queues with it. And, for full
disclosure, I did this for fun over a weekend, not for production use.
This is the RPC pattern in its most basic form, and the only way that
it works properly is if the messages sent back and forth adhere to a
given structure. This is referred to as a “service” or “messaging”
contract and can be as simple, or complex, as you like. Using a tool
like RabbitMQ can help with this, as it will prevent random messages
being sent into a channel.
Firestore Events
I’ve been using Firebase for many, many years and I love it. It does
take some getting used to, especially if you lean into their event
system.
You can get data snapshots (one and done), or you can set up a
listener for a particular document, which may or may not exist. That’s
what I did for my checkout!
You would choose the thing you want to buy and head to the
checkout page, where you would pop in your credit card using
Stripe.
When Stripe returned with a successful response, I would set
up a listener for the orders collection, using a GUID that I
passed to Stripe on the initial call. This was my order number.
I set up Stripe to send out a webhook on the
payment.received event, which would ping my first Firebase
480 ROB CONERY
I tell ya, there’s nothing like watching these dominoes fall as an order
is processed. Your customer knows exactly what’s going on as well,
which is also a bonus.
Two actually only problem one there’s: race conditions (that sentence is
a joke, by the way). That and unintended triggers.
When I first set this up, emails would show up with empty invoice
numbers, and I couldn’t figure out why. Can you see why? When
Firebase queues these function calls, there’s no guarantee of what will
happen when, so in some cases a fulfillment would happen before an
THE IMPOSTER’S ROADMAP 481
That’s the downside of doing “event stuff ”: debugging. We’ve gotten rid
of the spaghetti, but we’ve introduced some fantastic misdirection and
concealment.
As we’re going to see in the next chapter, the idea behind writing tests
for your application is that if you write enough of them, you can sleep better
at night. I believe that. I wrote a lot of tests for my checkout routine,
making sure each handler did as little as possible, and called out to
service classes that I could isolate and test independently.
482 ROB CONERY
Everything was great with my application until I deployed it, and then
that race condition hit, and I was completely vexed for a few hours.
That kind of thing happens a lot: you’ve spent hours setting your stack
of dominos only to realize, too late, that your design won’t work once
you’ve tipped the first piece:
This isn’t the first time the Firebase scheduler got the best of me. I
had a function that synchronized customer information with Shopify
once, and it turns out that executing thousands of function calls in the
background will slow down your entire service (the initial run had to
synchronize my historical data too).
That’s not something you want to say when you’re the lead!
If you have a capable team that’s onboard with this setup, an event-
based system can last for years… unless there’s major trouble that
results because of the use of events. Like my scheduler issue, or
having to solve one-too-many race conditions.
I feel sorry for the Apple engineers who have to solve those problems.
I think it just happens with the complexity curve. More services, more
events, more event wiring… and boom, no music for you when you
come home!
I’m getting pretty good at my prompting, I think! OK, I’ll stop now.
THE IMPOSTER’S ROADMAP 485
Why does code purity and immutability go so well together with The
Actor Model? Because it helps you do concurrent things without
worrying about destabilizing your system. Race conditions don’t
matter (ideally), because a running process never relies on another
running process.
In reality, it’s difficult to pull off, but with languages like Erlang, Elixir,
F#, and Haskell, it becomes a bit easier given the way the language
compilers keep you honest.
The Erlang runtime, called the BEAM, is considered one of the most
bullet-proof and resilient runtimes on the planet. This has to do with
the way people write code with it using The Actor Model and the
framework for writing Erlang applications called OTP.
Every bit of code you write in Erlang runs inside a process, which is
managed by the BEAM. Processes can spawn other processes, kill
them, and resurrect them as needed. This leads to an “organic” design
process, where you create the cells of a thing and naturally expect
them to die and then regrow anew. I know, sounds super theoretical,
but let’s see an example.
The session would probably also have a supervisor process too. All
the data would likely get stored somewhere like etc.d using built-in
Erlang storage libraries, just in case the entire system went down, and
the processes needed to come back up with their state data intact.
Note: I believe he said this on the Elixir Fountain podcast and, try as I might, I
can’t find the episode nor the transcript! I hope I got close there.
Joe liked to speak his mind. I hung out with him and his family on two
different occasions at NDC London. Kind, funny, incredibly smart, and
a prime example of someone who’s written word cuts sharply, but in
person is caring and lovely.
Joe’s point about databases is, “why care, if you build a system that
embraces failure?” You don’t catch errors in Erlang, you let them
happen and move on. This isn’t a careless approach, it’s quite the
488 ROB CONERY
Of all the patterns discussed, I think this one has the most longevity,
and it’s not due to “sunk costs” (meaning: you’ve put so much effort
into your application that you can’t give up on it). Distributed systems
require dedication and a clear choice made when starting out. It would
be like discussing replacing your family car for you, partner, and 2
kids, with a motorcycle. It could work just fine, but your context would
have to be completely replaced.
Unless everyone else was cool taking the bus. If you live in a city… it
could actually work out.
Erlang is a bit creaky as a language goes, with syntax rules that take
some getting used to. I have a few friends who are quite skilled at
Erlang and don’t mind it one bit.
Finally: as you can probably tell, I have some experience with Elixir
and the BEAM, and I do love it and wish I could work with it more.
We’re talking about The Actor Model, however, and I want to stay on
THE IMPOSTER’S ROADMAP 489
target and address the questions you might have, such as “should I do
this?”
If you’re building a system that can work concurrently, and you have
the skill on your team to build something like that, then I think it’s a
solid choice. Systems are scaling outward more and more thanks to
Docker and Kubernetes, and if you build something that embraces that
idea from day one, it’s great!
WHAT ABOUT…
I can’t cover every approach in detail, and I know I’m going to leave a
few out. I have tried to detail the more common approaches, but there
are, of course, many others. Some of these aren’t full application
architectural approaches; some could be considered strategies or
techniques.
Reading data, however, has its own model that, once again, is
dedicated to the need. You might do a rollup query on sales, need a
single product with associated vendors, tags, and technical
specifications, or just a list of customers. Each of these concerns gets
its own model.
CQRS can use a data access tool to work with the data, or, what I’ve
actually seen a lot of, is people writing the exact SQL they need in
each model. I’ll sidestep that argument and say that I like CQRS, but
I’m a data person, so I’m a bit biased. I don’t care much for ORMs.
Event Sourcing
This is an interesting one that’s popular in the .NET and Java worlds.
The idea is that you embrace the idea of changing application state,
rather than isolated database transactions.
Each state change is triggered by an Event, which is the data you keep.
AddItemToCart would be an event, as would
RemoveItemFromCart, Checkout, ShipItems and so on.
The benefit to this is that you have an audit log, and you know
precisely what happened when. This is great for reporting, because
you (typically) have time-based data, which can help you understand
your user’s behavior.
Service-Oriented Architecture
THE IMPOSTER’S ROADMAP 491
With SOA, you break your application into independent services that
do a thing. This aligns with the monorepo idea pretty well, and also
corresponds to The Actor Model and microservices discussed above.
Back in the early 2000s, the idea of Web Services gained popularity
and the idea was that you could build an entire application to be a
single service that other applications could consume. In our e-
commerce example, a ShippingService could be a SOA service. Its
sole job is to calculate shipping rates and setup shipments to
customers.
Ah, the memories. I made quite a few Web Services back in the day,
and my cofounder was convinced that Web Services were going to
replace the web as we knew it. I can see why.
And no, I won’t be talking about REST in this book. REST is the web
and “what it is” has become a rather heated argument which most
modern programmers think of as “sending JSON over HTTPS” which
is fine with me.
MVC
MVC doesn’t help an application scale by its very nature. In fact, you
could even argue that it can prevent scaling and increase cohesion
because all the parts work together. This is left to the developer to
solve; MVC, on its own, doesn’t enforce architectural ideas.
You can, of course, separate a larger Rails app into smaller ones, each
using the MVC pattern, and some people do this when their apps get
large enough. That puts us back into microservices land.
With MVC frameworks like Rails and Django, you have to specify
which HTTP endpoints are handled by which controller. In Rails, this
is done in a routes.yaml file and if you follow their naming
conventions, you can get away with very little code in that routes file.
But you still need to specify some kind of route, even if you’re using a
built-in helper.
In the Good Old Days, requests that came in were for literal files on
disk, so you might ask for /some/directory/doc.html and that file
would be returned to you. MVC frameworks made this more of an
“RPC” (Remote Procedure Call) kind of thing by using controllers.
With the shift to frontend frameworks over the years, and frameworks
like ASP.NET embracing file-based routing, the need for a Controller
went away. The need for arranging and orchestrating UI logic didn’t go
away, however, which is where ViewModels and Presenters come in.
As you can see, the CartViewModel gives the view the data it
requires in terms of the cart and supporting methods. You could, if
you wanted, shield the model entirely if your language supports
private properties.
here, well… it’s complicated. Here’s what the Vue.js team has to say
on the matter:
On the other hand, you might be working with Firebase and your logic
is handled in your application using a Presenter or ViewModel
(usually something like Pinia, the state store). I guess. It’s confusing
and honestly, if I could offer any advice here… just go with it and
don’t ask questions.
Onion
If you’re doing work in .NET or Java, you might come across various
terms like “Hexagonal” or “Onion” architecture, and then you’ll
Google what they are and see many drawings of concentric circles,
discussion on “separation of concerns”, “layering”, “encapsulation”
and more. All the buzzwords can be confusing, but overall the concept
is familiar if you’re into operating systems.
The core idea of Onion stems from Linux: a series of shells protecting
a kernel, or domain model. This is where your business rules live in
code form, and are protected from every other part of your application
by various service classes. From there, you have application services,
which handle user requests, and then, of course, your user interface.
You can make this as simple or as complex as you like, but I find it
oddly straightforward. I’m not an enterprise person, but I do love the
idea of a domain model (the classes you create to represent the
business you’re modeling) being hidden from everything else.
SUMMARY
Let’s end where we began: your choices here reflect where you work
as much as the application you’re working on. Your team setup, your
company policies, and the support from your manager and
stakeholders.
I know it sounds like I’m winding up with an “it depends”, and I hate
that! So I’ll end this chapter with this.
If I’m starting a project from scratch and I have complete control, I’m
using Ruby on Rails. The idea needs to take form quickly, and the
people who hired me will want to see progress right from the start.
After 1.0 is shipped, I’ll do some profiling and tweaking if there are
any scaling issues, and I’ll hold tight to “it’s not a problem until it’s a
problem”.
If I’m taking over a project that’s working well, I’ll get to know the
team and the codebase, make sure everyone is happy in what they’re
doing. I would then focus my time on ensuring they know what
they’re working on and where we’re going as a company. Finally, I
would get out of their way.
If I’m taking over a project that’s not working well in terms of team
satisfaction, I’ll do the same thing: get to know the codebase and the
problems, see what the common patterns are, and write it all down.
Any changes made need justification and buy-in from your
manager/stakeholder, and a rewrite is extremely costly! However,
sometimes they are justified and if one is, I’ll go with Ruby on Rails
every time.
In every case, you need to deliver, or you’re not being a good lead.
Whatever architecture you choose needs to lead to you and your team
shipping software; otherwise it’s useless.
In the next chapter, we’re going to dig into testing, which is one of the
primary ways you can get to know your application. A well-made test
suite can also act as documentation, helping new folks to the team get
up to speed quickly.
EIGHTEEN
TESTING STRATEGIES
UNIT, BEHAVIORAL, INTEGRATION, USER
ACCEPTANCE, AND EXPLORATORY
I
f you’ve been coding for a while now, you’ve hopefully been
writing tests to ensure your code is as correct as possible.
Notice the word correct here — it’s an intentional choice. You’re
not testing that your code works because the compiler or runtime will
tell you that pretty quickly.
AUTOMATED TESTING?
I don’t know where you are in your career, so I would rather not make
any assumptions. If you’re a few years in, you know all about testing.
At least, I hope you do. If you’re just out of a bootcamp (welcome!),
then testing may or may not have been covered much. Hopefully,
it was.
When you write code, you want to know that it works, so you might
try it out in a script or by hitting “Run” in your IDE of choice. Maybe
the debugger? Either way — it’s manual and not a good way to test
your code.
500 ROB CONERY
Rather than you hitting “Run”, you tell the test framework to execute
your test suite, which are dedicated bits of code that make sure things
“work” the way you want them to. I put “work” in quotes because, as
you’re going to find out, testing your code is a terribly difficult thing
to get “right”. Bias, crap testing strategies, bad code — so many things
can derail your testing efforts.
Now, let’s discuss fun ways to torture your code and your application.
You can clearly read my bias here, and there’s a reason for that, which
I’ll explain below. That said, unit testing does have a place, but it
involves a bit more work.
Your application should have all the test styles below, as each one has
a specific focus:
Unit Tests are fine-grained and help you isolate and debug
problems.
Behavioral tests are more generalized and focus on
specifications, rather than implementation. These tests are user-
focused.
Integration testing is a full run through of your application,
using every service (or integration) without mocks of any
kind. This is typically a scripted process using scenarios and
stories.
Acceptance testing is more rigorous and typically involves
your users. This can include focus groups, scripted testing
scenarios, alpha, and beta releases.
Stress testing is, as it sounds, when you load your app to see
where it breaks.
502 ROB CONERY
Allow me to explain that last bit just a little more. When it comes to
scaling your application and looking for code improvements, the first
place to look, always, is input/output (IO). Reading things from disk,
writing to disk, or sending/receiving over a network is always going to
slow things down. This is why Node became so popular: they made
that asynchronous.
We’ll talk about this more in the scaling chapter, but you should know
what your data story is right from the start. If you’re going to be
writing constantly, you’ll need a strategy from day one as to how to
handle that in the best way (connection pooling, where your
transaction boundaries are, etc.). If you’re reading constantly, caching
is your friend but also a nightmare.
There are ways to plan for these things before they become a problem,
so stress testing may or may not be useful for you. I’ll discuss this
more down below.
PATIENCE. DISCIPLINE.
You hear it a lot from test-driven development (TDD) fans: it takes a
good measure of self-discipline to create useful tests, and to also see
the benefits of testing in general. I agree with this, for the most part.
It’s at this point where you realize just how valuable tests are. It’s also
the point where you wish you didn’t have so many tests! Double-
edged sword, that. A “good” test suite will help you isolate bugs if you
can get your hands on a reasonable crash report, which your logs will
hopefully provide. Once you reproduce the bug, you can (hopefully)
easily resolve the problem so your tests pass. You can then push that
fix, so the error goes away.
504 ROB CONERY
Here’s a truth that you’ll discover over your career as a lead: the true
challenge of software development is keeping your app alive, not writing it in the
first place.
When people think about writing software, they think about the
creation process. I think that’s where the fun is, honestly, because
you’re watching an idea come to life! After you launch, however, is
where the game truly starts. I remember a friend saying that about
World of Warcraft (a popular MMO game) many, many years ago. It
was such a long, arduous slog to get to max level but, once you did…
wow, there was a lot to do.
Same goes for your application! Once deployed, you’ll be focused on:
Planning the next version, using what you’ve learned with the
existing version.
Scaling as your users grow.
And so much more. Not the most exciting thing, but absolutely the
bulk of your development career will be spent here.
So, why do I mention this now? Because the only way you’re going to
know what’s going on with your application and your users is through
logging and reporting. We’ll get to reporting later, as it’s much more
of a data concern than logging is.
Logging is an art form, and if you do it well, your coworkers will love
you forever. A log entry has one job: to convey what happened when,
how, and where. You’re the one who gets to figure out why — isn’t
that lovely and simple!
Informational log entries are great because they let you know that
people are, in fact, using your application. A good logging system can
actually be used to recover lost data, too, which is an interesting
rabbit hole to fall into… but let’s not.
The entry above is an info entry, but the ones we care about most
when things go wrong are the error and warning logs:
This is a reasonably detailed error log that should help you track the
error quickly. It tells you:
Using this information, we can see that our user is using the app the
way it’s intended, and that nothing necessarily is out of order… which
is when our heart starts racing.
Looking at the product_id, it’s the same one that’s in the info log, so
THE IMPOSTER’S ROADMAP 507
how could it not exist? It’s at this point where we realize that our
logging strategy is a bit incomplete.
At this point, we know the problem, but we now have an even bigger
question: how is this even possible?” So yes, this happened to me, and I
was mad at myself for creating a set of logs that contradicted
themselves.
My first thought sent a chill down my spine: what if the product table is
just… gone? Maybe all the records are deleted or, worse, the table got dropped!
I run tests locally against a test database, and every time I do, I drop
and recreate my tables to keep everything in sync. If I somehow
messed up an environment variable… it’s entirely likely that this
could have happened. If you ever “drop prod” in your career, I can
almost guarantee it will be due to environment variables.
The terror only got worse when I realized that the way I coded the
getProduct() method was with a single try/catch, and I wasn’t
evaluating the caught error. Any error would have been treated as a
“product doesn’t exist” error! ROB!
I was certain I had dropped production, but thankfully that wasn’t the
case. A frantic 10 minutes later, I figured out that what I was missing
was a log entry that says, “product out of stock”:
508 ROB CONERY
This log entry, which should have appeared right above the error above,
would have told me something critically important: the error only
happened when the product went on backorder. That would suggest an
edge case where my customer had the item in their cart, but while
they were bopping around my site, someone else bought the last one.
This happens a lot, believe it or not. But this raises an even bigger
question: I only sell digital products, why is this going out of stock?!?!
Yes, this really did happen to me. Long story short: when I created the
product I didn’t set its type to digital, so the default inventory was set
to 100 (bad idea) and it was being debited during every sale… and you
get the idea.
If It Changes, Record It
You can obviously dump far too much information in a log entry,
though there are those who say that’s not possible. My rule of thumb
is this:
Logging errors properly is a challenge, and I’ll get into that more in
the logging chapter. For now, let’s focus on how our logs can help us
with our tests.
THE IMPOSTER’S ROADMAP 509
UNIT TESTS
Unit testing is how a programmer thinks about the application they’re
writing or maintaining. They’re a bit more mechanical and have the
singular purpose of helping you isolate and fix errors as they arise.
Some people call the example above “Sad Path, Happy Path” testing,
where you think of as many things as possible that can go wrong,
ensuring that you also have a guard in place: the “Happy Path” test.
It’s entirely possible, in fact, it’s highly likely, that you can focus on the
negative so much that you end up creating a function that doesn’t
actually work. The happy path is critical, and defines “the truth”, if
you will, of what the function should do.
If I had unit tests for every service and every method, like this project
510 ROB CONERY
Test-driven Design
One of the problems of unit testing is that you end up with so many
tests that can easily break when you change something, causing
friction. We hate friction!
Test-driven design, or TDD, flips this notion on its head: your tests
dictate your application design.
and if a given test fails, you know exactly where and what to fix. That
is the strength of unit testing: fine-grained control, speedy fixes.
But would this have worked for my missing product problem? A TDD
person would say, “of course, because that condition wouldn’t exist in
your code.”
Imagine you find a bug in this project, yet all the tests pass. This is
normal, by the way, and frequently happens. You decide you’re going to
help out, and you fork the project and clone it to your local machine.
Debugging is an art form, which we’ll get into in the next section, but
let’s pretend you go old school and pop console.log(...) everywhere
as it’s a Node.js project, and why not (pretend you’re using the
debugger if you want). Finally, you find the culprit: a certain character
present in an environment variable (let’s say it’s an equality sign =) is
causing things to break.
Fun. Where does this fix go? You open an issue, some suggestions
come in, there’s debate about whether this is a valid bug, and then a
few suggestions on how to fix. You have some ideas, and decide to
create a few local branches to try them out.
You tweak the way the environment variable is read and set, replacing
a split() operation with a more comprehensive use substring(). 82
tests failed as a result.
You look over the output and realize that there is additional work
being done on the environment variable setting somewhere else in the
application, so you decide to follow the trail and do what you can to
resolve the problem. 96 tests are now failing.
512 ROB CONERY
You get the idea. And this part I’m not making up, as it just happened
to me. Not with this project, but with another one I was working on.
My database connection string had an = character in it and … yeah,
everything choked when I messed with the code to read the values in.
The point is: when you build up a unit test suite and try for the most
code coverage possible, it makes life difficult when it comes to making
changes. In fact, it gets worse: you avoid making changes because you would
rather not break your tests.
I’ve been locked in that cycle before and it’s horrible. 82 tests are
failing when I try to resolve this issue? #WONTFIX, thank you.
One of the problems you face with a big test suite like this one is that
you start adding packages and code to avoid working with external
systems. External systems, like mail services, databases, caches, etc.,
can fail or take too long to respond. In that case, people resort to using
mocks or stubs, also known as “test doubles” (like stunt doubles).
This chapter isn’t about how to test, I cover that in The Imposter’s
Handbook. Rather, it’s about testing approaches and strategies. In other
words: how you should think about testing in a team context. To that
end, I’m not going to dive into the wild world of proper mocking and
stubbing. It’s highly argumentative anyway and, if you ask me, a waste
of time.
A mock is there to avoid using an external service, with the idea that
your test should be isolated as much as possible. Looking at this test,
however, are you sure we’re properly testing things?
I know, I know. You could use an ORM that has validations built in,
which is a fine way to go! Sequelize is one of my favorites, and you can
define your database schema right in your code. Doing this allows you
to run a validate() method on your model to see if it can be saved,
which is what we might do in our mock. Or, better yet, we could use
an in-memory instance of our database (SQLite does such a thing)…
but then we’re involving the database in our test, aren’t we?
514 ROB CONERY
The point is: mocks can work well if you’re super focused on making
sure they don’t interfere with your tests.
It’s a dumb trap people fall into easily: you write code to “verify” that
a service or package does what it’s supposed to do. A 32-bit GUID, for
instance, is your primary key type in your database. You don’t want
the default values that your platform provides, so you download a
package that will create sequential GUIDs so you have ordered keys
that are (supposedly) easier to index.
In one of your tests, you ensure the key is 32-bit and that one record
has a “greater” key than the next record. You’re paranoid, which is
fine, I would be too. Unfortunately, you’re testing the package for the
package developers, which is a waste of your time. If you can’t trust
the package, then you shouldn’t be using it.
This happens with things like commerce services (Stripe, for instance)
that are going to generate an order and a customer record for you. You
want to be sure the totals add up, so you write a quick test against the
Test Account… (I’ve done this).
Mocking can keep you from testing what you don’t own as far as unit
tests go, but successfully mocking something is an art form that also
depends on the language and frameworks you’re using. Rails, for
instance, strongly suggests you just give in to things and use a test
database. It also gives you the ability to “turn off ” sending email at
the framework level during testing, so you don’t need to worry about
spamming [email protected].
THE IMPOSTER’S ROADMAP 515
If you’re using .NET, you have quite a few blog posts and YouTube
videos to support you on your mocking journey. And there are quite a
few opinions too. With Node, there are tools and packages to do just
about every kind of testing you need. Mocking, intercepts, in-memory,
and more. Nock and Sinon are two of the most common, with Sinon
adding a very useful ability to check for asynchronous callbacks.
Your strategy will depend on the language and platform you use, just
have the question “am I testing what I own?” running on repeat as
you build out your test suite.
If you find, however, that you have a few too many tests that change
when your code changes (aka “brittle”), it might be time to think
about a different approach.
BEHAVIORAL TESTING
Behavioral testing and Behavior-driven Development (BDD) is a
fascinating way to think about testing. The good part is that you test
things from a usage perspective, not a mechanical one. The downside
is that it’s easy to write tests with bias in them that don’t actually test
what you think they’re testing.
Let’s consider my cart situation once again. If I were to test this using
simple behavioral testing or BDD, I would write specifications that I
would test against:
BDD has plenty of jargon, and you can use that jargon all you like, but
it doesn’t mean you’re doing BDD. I know, I know! It sounds like I’m
gatekeeping here, but it’s so important — you would be amazed at how
many BDD “tutorials” are out there that completely miss the dang
point.
It’s critical to take your brain out of engineering and coding land and
take on more of a product focus. You’re not testing classes and methods,
you’re specifying how a feature works given some scenario.
When you think in terms of features and scenarios, it frees your mind
a bit, and you can come up with several scenarios that may or may not
happen. That last bullet would have caught my problem, most likely,
but once again that’s more about me and not the style of testing I’m
using. I will say, however, that writing specs like this without thinking
about code makes stumbling on that scenario much easier.
I think that programmers have a difficult time doing BDD because you
have to think like a Project/Product Manager, not a coder. I think
that’s a good thing, because it’s always good to remember why you’re
building the thing you’re building.
If, however, you need a nudge, there is a handy cadence you can use
THE IMPOSTER’S ROADMAP 517
I’m using JavaScript here, with the Mocha testing framework, but
hopefully the language doesn’t matter and you can get the idea. The
code doesn’t matter anyway — it’s how you describe your tests and
specifications. You want to be as clear as possible with each thing,
ensuring that your assumptions are clear and as precise as possible.
It’s a lofty goal, and you’ll be accused of being a total nerd (I am, all
the time), but if you create pretty test reports like this, you’ll boss or
client will be thrilled. That’s the theory, anyway, they’re still going to
make fun of you.
I have a friend I used to work with at Microsoft that printed his test
runs out and taped them to his door, so people wouldn’t bother him.
This is the goal of BDD: executable specifications, and it’s usually at this
point that most people have their AHA! moment. We don’t write code
in a vacuum… well, at least not most of the time. As a programmer,
you have a specification that you work against, like anyone who builds
anything. So why not formalize it and make it executable?
Having a bit of trouble with the cart’s item count… but I’ll get there.
Your testing framework might look different, but most languages and
testing tools support some descriptive output like this. I even made it
work in C# using XUnit with the Trait attribute!
This is the thing with BDD: your application specifications will likely stay
the same, so your test suite will be far less brittle. That’s a huge deal! Unit
tests, like the first example we use with a class and testing every
method, tend to break when you refactor your code or change things
around. BDD specs don’t, unless the features and specifications
themselves change.
Pro: You Will Think More Clearly About What Your App Is Doing
When creating your specs, you have to think through how your
application will be used. This aligns your thinking with the
Project/Product Managers and helps you understand the value of the
thing you’re creating.
520 ROB CONERY
If you understand the value, you will likely have some input on how to
increase that value, which is always a good thing.
The benefit of Unit Testing and code coverage tools is that more of
your code tends to get tested, especially if you have test generators in
the framework you’re using (such as Rails).
With BDD, you’re focused on specs, not coverage. It’s a little harder to
ensure that every part of your application is exercised. Ideally, your
scenarios will cover your codebase as completely as possible, but I
have yet to have that happen in my case!
You will encounter other developers who will throw their hands in the
air and tell you that you’re being a cult leader and adhering to syntax
rules rather than a solid testing strategy. They will have a point, and
that’s OK. BDD does have a place and the jargon is there to keep your
head in the right place, with your attention focused on specifying
features rather than testing method implementations.
There are some things that are best tested with a simple unit test. A
snowflake generator, for instance, is a simple numerical
transformation that you can test directly with a unit test, not worrying
about behavior because it really doesn’t have any.
BDD is great for describing the way your application behaves when a
user interacts with it, thus the name, but occasionally, you’ll want
something a bit more targeted and fine-grained, so feel free to pop in a
few unit tests here and there, as needed!
You don’t have to commit to a single style, and in fact you shouldn’t!
Just know which tests are tests and which are specs, and you should
have a happier team.
THE IMPOSTER’S ROADMAP 521
You’re probably using one of these, but if you’re not, that’s perfectly
fine. As long as your framework keeps you thinking about tests and
not the test framework, you’re good to go.
Once you write the tests, you need to run them and there are quite a
few opinions on this, which usually go something like:
“We use Blah Blah IDE which has testing built in, so use
that.”
“Our favorite testing extension for VS Code is Bloop Bloop, so
use that.”
“Testing tool? You mean the CLI?”
I typically find myself testing in the CLI; however, there are some
wonderful testing tools out there that can speed your “feedback loop”
tremendously. This is our goal if we’re doing TDD or BDD: fast
feedback and iteration. Sometimes the CLI just doesn’t cut it for
people who want the most speed possible.
Here’s the WebStorm IDE (from JetBrains) test runner (image from
their site):
522 ROB CONERY
You can pop this out and let it float in the corner, setting it to watch
your code files. When something changes, the tests will automatically
run again, showing you quickly if you screwed something up.
If you have the Enterprise edition, you get “Live Testing”, which will
show you test results right next to your code:
THE IMPOSTER’S ROADMAP 523
I used this once before, about 3 years ago, and it was unbelievably fun
to see things change in real time.
I like these as they’re nice and visual, but I tend to try to keep things
as simple as possible. To that end, I’ll have a CLI open on my right
monitor while I code on my left. If I’m just using my laptop, I’ll create
a new desktop and swipe over to it occasionally to see how the tests
are doing.
INTEGRATION TESTING
You’ll reach a point in the development process where you’re going to
need to make sure everything works as intended. In our e-commerce
example, for instance, I might need to ensure that:
524 ROB CONERY
The only way you can be confident that everything is working is to run
a full integration test, and that’s stressful.
I’ll share with you what I’ve done, and then we’ll get into the
theoretical approaches after that. Normally, I would do this the other
way around (theory first, my thoughts second), but I tend to do
integration tests right from the start, which I find simpler, and I think
it’s useful to start there.
This is what I have done in the past, and it works well for me. I won’t
claim that it’s The One True Way, but you might find it useful.
For instance: let’s say I want to ensure that the “Happy Path” works
for my e-commerce checkout, which is:
As you can see, this is just a straight-up script that isn’t using a
testing framework. I could be more formal about it, but (this is just
me, again) I don’t run these tests all that often. I only run them if I
refactor something big, add some features, or think that something
might break because of a change to the codebase.
Hopefully, you get the idea. I’ve written my service class methods so
they return whatever things they’ve changed or created, so I can
interrogate them using Node’s assert library. My service classes also
526 ROB CONERY
log what they’re doing, so I can see it as it all happens, but I can also
use the debugger here if I want to know more.
There are some key considerations when doing this simple approach:
I run these tests against my local development database, so I’m not all
that worried about filling it with test data. That said, it can be very
annoying when tests like this fail because of a data validation error
(duplicate key, etc.).
Hopefully, the external services you use can run in test mode too.
Most payment systems allow for this, and there are also email testing
services out there that won’t actually send any email and, instead, will
show you a nice interface. One that I like a lot is Ethereal Mail, which
is free and gives you a set of SMTP credentials that you can plug in as
you need.
For now, let’s talk about the different styles of Integration Tests.
Bottom Up
The idea with bottom up is that you test your data access bits first,
then weave in your models, then services, and finally UI stuff, working
your way from the bottom to the top. You can do this like I did, using
a script, or you can use some type of testing tool.
By focusing on your layers, you can find problems easier when things
go wrong, and if you do this bottom up, you can find problems that
could ripple throughout the application first, rather than get surprised
later.
Top Down
As the name implies, you test the layers of your application from the
top (or outside) down to the bottom, which is usually some type of
data interaction. Personally, I find this type of testing a bit weird, but I
do understand why it’s there.
You’ll need test doubles (mocks, stubs) to if you do this, and as you
progress down the layers, you remove those doubles and let the
integration happen. I think that’s strange, and a bit contrived, yet I can
THE IMPOSTER’S ROADMAP 529
also see how it might be valuable to know that your service logic is
sound, but your data access logic has issues. You’ll find that out
quickly if you use this approach.
Big Bang
As the name implies: you just do everything, all at once, just like I did
in the test above. The shopping and checkout services do their thing
and use models that hit the database. They also send emails, and
so on.
The benefit here is that you exercise everything and don’t need to
work in stubs. The downside is that finding and killing any bugs can
be tedious, since you’re doing everything at once. For instance: if I
have a problem in my fulfillment routine, I’ll need to write more tests
and possibly a test double or two to isolate the issue. This takes time
during testing, whereas doing top-down, I would naturally stumble on
this issue during the test creation process.
If I’m honest, I find that this type of testing is a bit tedious. It sits in
the middle of unit/behavioral testing and the thing that’s coming
next: fully scripted acceptance tests. To me, having a solid set of
unit/behavior tests as well as acceptance tests covers just about
everything I need.
ACCEPTANCE TESTING
This one’s tricky. For some organizations (like where I work at
Microsoft), this means getting users in a room to try a thing you’re
creating. You take notes, measure things like eye-movement, clicks,
frustration and happiness levels, and so on. These are usually
conducted by a specialized team and if you’re involved, it’s likely just
as a spectator.
Before we go further, it’s a good idea to go all the way back to the
chapter where we thought about our application users (Getting To Know
Our Users). We had to flex our empathy but, more importantly, we had
530 ROB CONERY
to involve our entire team. This is a very hard thing to do because you
ride the line between groupthink vs. a singular perspective (aka
“bias”).
Right then! Now that you have your users, let’s consider our testing
tool. For you, it’s more likely you’ll use a dedicated testing tool for the
platform you’re building for:
There are others, of course, but they all basically do the same thing:
interact with your application based on a script of some kind.
For this chapter, I’ll discuss Playwright, as it’s the tool I have the most
experience with. Full disclosure as well: I’m a Microsoft employee as
of this writing, and Playwright is a Microsoft project. That’s not why
I’m writing about it, however; I genuinely love this thing.
Each test you create is a scripted interaction, which means you need
to fully develop one or more target end users. This isn’t easy to do,
and you can easily build in your biases to these tests. In fact, I can
guarantee that you will.
I’ve discussed this throughout the chapter: your biases will almost
always be the thing that undermines your tests, and that is especially
true here. I’ll go further: your initial tests will probably be marginally
useful, but if you’re willing to change them to reflect actual user
interactions, they will organically improve.
THE IMPOSTER’S ROADMAP 531
How do you do that? Logs, baby! A good set of logs tell your
application’s story, which always involves your users. The Logging
chapter comes in the next part, where everything will, hopefully, start
coming together.
So, to start, know that each script has a beginning, middle, and end
and, ideally, ends with some outcome that you can measure. For our e-
commerce application, we can script out the cart interaction which
ends with one of our users buying one of our books.
This is easy enough, but is it useful? Nope. Why not? Because we’ve
already tested this! Duh! We need to shift our thinking here because
we’re going after the experience, not the mechanics.
This is the first thing that I love about Playwright: it’s headless. It will
test your site, but it does so using headless browsers (you can choose
from the major ones), which puts you in a very interesting position as
the test creator. How do you write code for a non-visual interaction?
That’s my blog, and you can see how the DOM is viewed in a different
“dimension”. Rather than a tree of elements, it’s now a tree of roles
which help people with vision challenges interact with your site.
This is how Playwright works: you make your pages more accessible,
which increases your ability to write scripts for it. There are other
ways, of course, but this is a “best of both worlds” thing and I think
it’s wonderful!
That’s the goal with Acceptance, or “End to End” testing: you want to go
after the experience of the site, and what better way to do it than to try
to visualize it in your mind, thinking about the colors and what you see.
If you would like to know more about Playwright, I made a free hour-
long video that you can watch right here.
Your scripts need to answer a simple question: will my users like what
I’ve made. The users, of course, are the ones we defined during our
Agile spin up, way, way long ago. If we’re serious about these users,
who they are, and what they care about, then we need to imagine
them using our site and being happy, sad, critical, excited, and bored.
THE IMPOSTER’S ROADMAP 533
Beginning, middle, and end. Why is Santosh here, and what does he
care about? Will Fen be pissed off and write another email
complaining about our fonts? You can have some fun with these
scripts, but it’s critical that they tell the intended story so you and
your team understand when you’re actually done building the version
of the app you’re creating.
That’s the thing: these tests tell you when you’re done. How would you
know otherwise? I wish I could go deeper technically here, but it’s not
really a technical issue, it’s a human issue. Your application needs to
deliver value to your users, which means you need to understand who
those users are and what they care about.
ALPHA TESTING
You’ve built out a well-tested codebase, and your Integration and
Acceptance tests look respectable. In short: you feel good about what
you’ve made… which should always make you feel uneasy.
Now comes the fun: letting someone else use what you’ve made. This
typically involves dedicated groups internally and, at a later point, the
actual users who will use the application.
With alpha testing, you gather people who know nothing about your
code and, ideally, know very little about your application. These could
be folks internal to your company or your friends. Maybe your
“insiders” group. Either way: these should be people you trust to keep
the rough edges to themselves and understand that this is a very early
launch.
The alpha test period is only as good as the group doing the testing. If
they’re your friends, you might get a text with a screenshot or an
email saying something like “I tried this, and it didn’t work”, which is
always a good time.
534 ROB CONERY
If you’re lucky, however, you might have access to a team that does
this kind of thing for a living. Yes, there are people who do this kind of
thing as their job! And you know what, it looks like a lot of fun if I’m
honest.
And orders:
a beer.
2 beers.
0 beers.
99999999 beers.
-1 beer.
”qwertyuiop" beers.
THE IMPOSTER’S ROADMAP 535
Testing complete.
A real customer walks into the bar and asks where the bathroom
is.
One of the comments from this post also sums up the perfect
developer response:
I’ve had a few popular open-source projects over the years, and every
now and again a tester would drop by and dump gold in my issues list.
A complete, well-documented description of what they did, why, and
what happened.
Exploratory Testing
When I first wrote publicly about putting this book together, one of
my blog readers offered this suggestion:
If I’m honest, that’s the first time I’ve ever heard the term
“exploratory testing”, which makes sense because I’m not a dedicated
536 ROB CONERY
tester, and it’s been a long time since I’ve had access to a QA
department that wasn’t the general public.
When you hand your app over to a QA team, they will probably do
some form of Exploratory Testing, which treats your application like a
crime scene. That’s how Cem Kaner, the creator of the process,
describes it: “Testing is like CSI” (CSI is a television show that deals
with crime scene investigation and I used to watch it religiously).
During that time, they’ll take numerous notes, might document their
Charter and Oracles, and of course document any risks they come
across — all while treating your application like a crime scene.
BETA TESTING
Beta testing is a bit more unstructured, unless your users are testers:
fewer bugs, fewer rapid changes. A “we think this is ready” statement,
but understanding that your users tell you when you’re ready.
But, in reality, beta can mean whatever you want it to mean, but one
understanding that everyone agrees on is that any release that’s less
than 1.0.0 (using SemVer here) is allowed to change and break things.
Moving your app from 0.4.3 to 0.5.0, for instance, probably will break
any other services relying on it. These are called “breaking changes”
and are really a pain in the butt.
Gmail was released on April 1st (April Fools' Day… which is weird) of
2004 and stayed in beta until July 2009, which is also weird. It was in
beta for so long that it became a bit of a joke.
I asked José Valim about this. He’s the creator of Elixir and a
maintainer of the driver (among many others), and he responded that
they’re evolving the tooling for Elixir so rapidly that it makes life
much easier if you don’t go past 1.0.0, which means you don’t get to
break things as often.
Unfortunately for me, I created a data access project for Elixir called
Moebius, which used Postgrex. When it broke, my stuff broke (if I
upgraded). Eventually, I stopped upgrading the driver, which was a
problem because Elixir itself was changing as well… and you get the
idea. The most significant change was when they added date support
to Elixir, which meant they added it to Postgrex too, which meant I
needed to change my code and bump to version 4 or just give up. I
hate giving up, but this was such a massive change, I didn’t know
what else to do.
Alpha and beta stages are a great idea if you want to involve your
users. They’re not so great if you want a free license to change things
on an ongoing basis.
THE IMPOSTER’S ROADMAP 539
But how do you get that feedback? There are a few ways, of course,
depending on who your users will be and how much you want to
spend… which all leads to the same question: what quality of
feedback do you want?
I know most developers hate the idea of email, especially mass email,
but trust me, email services can be your absolutely best friend.
Note: I’ve used quite a few list services, including MailChimp, Drip,
ActiveCampaign, Mautic, etc. ConvertKit has worked great for me, consistently
and no, I get no consideration for this.
You can create landing pages with ConvertKit and use that to do all
kinds of interesting things with your beta users, including not
bothering them at all! When they sign up, you tag them with beta-
user or something like that, and then thank them for signing up, and
that you’ll let them know when the beta is open for them.
When you’re ready, you can send out a broadcast email to everyone on
the list that you want to let in to your beta. You can do this in waves,
if you like, or all at once — up to you.
540 ROB CONERY
One really nice thing about using ConvertKit is that it works well with
automation sites like Zapier, and you can add your user directly to
your system when they sign up, or pop them into a Google
spreadsheet!
I’m not going to get into the details of how Zapier works. It’s super
simple to learn and, in summary, connects APIs together.
Here’s a “zap” (their term) that I used to have running for when an
order came in from Stripe. I hooked up my Stripe API to Zapier, and
also Google Sheets, and then put the two of them together like so:
You can do the same with ConvertKit: add a beta invite person to a
spreadsheet, and when you’re ready, export a CSV and import those
users into your application.
Each email can be a “did you know that our app does X?” Another
could be, “here’s an invitation code to send out to your friends.”. The
one you care about, however, is “hit reply and let us know how we’re
doing!”
You would be surprised at how effective that is, as long as your email
is 1) helpful and 2) sincere. Instead of asking directly (“Please tell us
how we’re doing”), consider making it more personal with a story that
offers some value:
The idea for this application came to me in a dream, if you can believe
it. I think it was because I always wanted to use an app that helped
me do X in half the time and do Y at the same time. I’m a big believer
in the Z Theory, which tells us that A, B, and C can happen if you take
the time to journal every day, do yoga, and eat nothing but pork chops
for 36 hours. That might sound extreme, but I guess that’s just me.
Hopefully, you see the benefit like I do, and if so, have fun! If not,
I would love to hear from you to know more. Don’t worry about
hurting my feelings, I do yoga. Just hit reply and let it rip!
The person you really want to hear from and the one who will make
all the difference is the one who’s just flat out confused. Maybe they
542 ROB CONERY
tried your app and shut it within seconds. They didn’t understand
what you were trying to say, and so on.
Many times you can reply to them, and they’ll help you out — they
wanted to be on your beta list to begin with, so there’s some perceived
value on their part! Other times, you’ll need to get creative.
One way to lure them is to offer a free subscription, if your site’s for
pay, or a gift certificate for coffee or similar, if you have the budget.
That might sound extreme, but people will appreciate your gesture
and probably decline it anyway. The point is: if they feel you’re
genuinely curious about what they think, they’ll answer you.
When you get your valuable feedback, pop it into a to-do list or notes
application, or even fill out a GitHub issue straight away!
Speaking of…
This works great if your audience is technical, and it’s good for you,
too, because comments might not be as pointed as an email reply.
You still want to use an email service to reach out to people, but you
don’t have to and, instead, you can pop “see a problem?” links
everywhere and hope people click on them. You’ll want to be certain
you have an issue template in place for your beta period (see the
GitHub chapters earlier), but don’t be overbearing! People would
rather not give you their time, unless they really love you and want
you to succeed, but don’t count on that.
Asking your users to fill out a GitHub issue can save you time and
energy, but you’re asking a lot. If you think you’ll have a big invite list,
this can be just fine.
service for this, instead they just sent out an invitation list and wired
up a service called UserVoice. You can read the entire process here.
I’ve used UserVoice in the past, and it worked pretty well. If you’re
familiar with the Discourse forum system or (once again)
StackOverflow, then you’ll understand UserVoice. At least the way it
used to work, back when Jeff was using it.
It’s a much different service these days, of course, but it’s difficult to
tell as the price is extreme and there’s no demo content there. Oh
well.
Intercom was another service I used that had the interesting approach
of popping a chat window right on your site as an overlay. People
could chat with you in realtime, or leave a message that you reply to
when you had a moment. I liked it, but it was expensive.
If you have the budget for a service like this, it can save you a lot of
time and also raise the quality of feedback you receive. The starting
price is pretty reasonable, which as of this writing is $39/mo in
the US.
SUMMARY
I can’t tell you how to test, there are quite a few tutorials for that.
Similarly, I can’t tell you what to test — these are things you learn as
you gain experience.
What I can do is nudge you down the right paths, and if you leave this
chapter with only one thing, it’s this: don’t limit yourself to a single way of
testing your application. Every approach is “good”, and also has its
drawbacks. Overlap it, and you can “prove” (notice the quotes) that
you’ve done what you have set out to do.
You’re working hard to get to a place in your career where you can
enable a team to deliver. Let’s stay focused. This isn’t about ego, this
is about you doing a good job and making sure people notice you.
You’re good at your job. You’re reading this book so you can improve,
aren’t you? That says a lot.
NINETEEN
DEBUGGING
A WONDERFUL SKILL TO MASTER
I
love debugging, I really do. I think it’s the clarity of purpose and
sense of urgency that focuses my entire mind on to one task: fix
the damned problem.
Dave is a good guy, through and through, and his comment hit me
pretty hard. I wasn’t angry, just ashamed. Computers are never wrong is a
good mantra to have. Sure, sometimes you’ll find a weird bug or
language behavior, especially if you use JavaScript, but 99.999% of the
time, it will be your fault (or whoever wrote the code).
I used to think the patience and resolve needed to find and fix a bug
was something you gained with experience, but I am not convinced
that’s necessarily true. Experience comes with time, sure, but patience
is something you can cultivate at any point in your life.
Before you start debugging anything, clear your mind. I know it’s easy
to say, but it’s critical because often the answer is right in front of you,
if only you would let it come to you.
Imagine that you can’t find your keys. The first thing you probably do
is check your pockets (which is reasonable), and then search the area
where you think your keys should be. Maybe they fell? Might be I put
them just… next to the place I normally put them? And then your
search radius widens as you check places near where your keys
should be.
THE IMPOSTER’S ROADMAP 547
We believe so strongly that our keys should be where we left them that
we can’t free our minds to think “maybe they’re still in the front
door” (most likely, for me at least), or “I bet I dropped them on the
way up the steps”. These are far more likely than you breaking a
pattern and setting your keys near where you think you set them.
My point is: the best bug killers that I know of can clear their mind
and come up with 3 scenarios within seconds, and one of them usually
involves DNS.
From https://www.cyberciti.biz/humour/a-haiku-about-dns/
Let’s start here because why not. If your site is down because it’s not
responding, immediately check your DNS settings:
Been there, too many times. I set up email through AWS Simple Email
Service, which is an amazingly cheap email sender, but to work
properly you have to ensure that your DNS is set correctly (eek that
last bit sent shivers). I did. In fact, I verified my settings four times
before rolling things over… and yet email still failed to send at least 3
out of 10 times.
I bring up DNS because it’s a great example of built-in bias, and one
that you can get over by cultivating the ability to empty your brain. I’ll
offer some step by step ideas in a minute, but for now, understand
that often the answer will be something completely unexpected that’s
also obvious once you figure it out.
WORK IT BACKWARDS
If you’re debugging your code, you are the problem, not the code. You
wrote the bug, you’re also going to be in your own way as you try to
debug the issue. By “in your own way” I mean that your bias for
“what should happen” will absolutely cause issues.
I claim that the primary reason that the so-called “bug slayers” on any
team are so good, is because the code they’re looking at is not
their own.
Think about the last major bug you had that took time to solve. At
some point, you probably, like I did in the last chapter, sat back and
said some variation of “right, we have a product. I know it’s there. It’s
THE IMPOSTER’S ROADMAP 549
being added to the cart here because I can see it in the logs… and then
it’s not being added there!”
Clear your mind, take a shower to engage your body and relieve the
tension. Then work your way backwards from the problem. Don’t
explain what should happen. Just explain what is happening and
how we got to this point.
You might be wondering: why a shower? Don’t skip that. The body
holds emotion and if the body is busy, it means the mind can be freer
from emotional interference. Solving tough bugs is extremely
frustrating, and anger can quickly fire up and next thing you know
your buddy is telling you that you sound ignorant.
The mental and emotional break you’re on will help you to understand
an essential truth: you’re being lied to.
Debuggers typically work the same way. Here’s what VS Code offers
for debugging JavaScript using Node.js:
You probably know this, but for the sake of completeness, the idea
here is that you step through your code, line by line, and watch the
variables change. The call stack grows and reminds you how you got
to where you are, and the output of your program is on the right side
in the Debug Console. This is pretty standard fare for IDE debuggers.
They work pretty well when it comes to “why is this thing set this
way”, but they can also waste your time and lie to you. That might
sound a bit harsh, but it’s absolutely true.
When you walk through a debug session, you’re working the problem
forward and reinforcing your bias as a developer. “This should work!!!”
is a common exclamation from people using debuggers. They can help,
of course, especially in the example above where I’m trying to reassign
552 ROB CONERY
a constant variable. The debug console will tell me this and my debug
session will end right where the error happened.
If you’re dealing with a data error, as I was, a debugger can be all but
useless. Worse than useless: it keeps you running in circles, looking for your
keys where they should be, rather than where they’re likely to be. If you’ve
convinced yourself you have a logic bug, you’ll work that debugger for
hours before you drop everything and start over, and wow that’s
frustrating.
That’s why I say debuggers lie: they keep telling you what you want
to hear.
I’ve stopped on line 3, which is great, and then I manually changed the
local variable today to “Boxing Day” right in the Variables pane. I also
added my today variable to the Watch window, and you can see how
today has changed in memory, but it didn’t cause an error to happen
as I didn’t reassign today, I changed its value in memory.
The only difference now between my local application and the one my
customer is using is the data. Once this realization hits, I can narrow
the differences quickly… or that’s how you’re supposed to do it. What
I actually ended up doing was pulling down a backup of my production
system and running it locally… but let’s pretend I didn’t do that.
The only data that should be different in this scenario is the Product.
My logs show the same SKU, price, and name… what else could be
there? Let’s see what the debugger says:
things can change the way an application behaves and, as you can see,
I have a type set to “digital”.
Now obviously this isn’t the same code I was using — that’s long gone
— so I had to recreate a few things to highlight this debugging
THE IMPOSTER’S ROADMAP 555
This is a fine first step, however, especially if it keeps you from using
your production database to locate the issue! Mine was pretty small,
so it was easy, but in The Real World this is typically never an option.
Changing the variable data is a great way to tweak the state of things
and see where stuff blows up. Once you find a problem, as we did, you
can write your tests based on your findings.
We talked about bias in the last chapter, and this is where bias lives: in
the logs. I’ve heard developers claim “the logs never lie”, and it makes
me laugh, every time. Of course they do! You set them up!
What’s that? Did you skip the gym today? Oh, and got up late, too?
Here’s a fun exercise: imagine you’re at the store and looking to buy a
new pair of pants, maybe a shirt or a sweater. You put it on in the
dressing room (seriously: try to imagine yourself doing this) and turn
to the left or the right.
Which side did you turn to? I’m going to bet it was the side of your
body that you liked best. The way your hair parts, maybe you (like me)
have a more developed right arm than left.
The point is: we do weird stuff when it comes to our reflection, and
your application logs are, indeed, a reflection of you and your team.
It’s only human to want them to look as good as possible, isn’t it?
Even when it comes to errors.
556 ROB CONERY
Hey! Look at me, I’m reporting this error here, which means I’m a good
developer!
The thing is: it takes a few months for your logs to start telling a
reasonable story. They’ll never be free of bias, but they will get closer
to objectivity as time goes on.
One way to adjust your logs once your application is up and running is
to have a weekly log review with your team. This can be tedious, but
ideally, you’re going to use a log service (which we’ll cover in a later
chapter) that will enable you to sift, sort, and query in some online
interface.
What do these logs tell you? What do they tell the team? It’s a fun
exercise to go through and compare stories and then compare them
with actual reporting data to see if things make sense.
I’ll talk more about that in the Logging chapter. For now: trusting your
logs takes time, and they are indispensable when it comes to
debugging.
We’ll talk about writing docs for our application in a later chapter. The
docs I’m referring to for this section are the ones for the frameworks
you’re using. If you Google “the docs are wrong” you’ll see what I
mean.
If you haven’t had a problem like this hit you yet, you will. If you’re a
frontend JavaScript person, you know this all too well! These
THE IMPOSTER’S ROADMAP 557
I created a fun course for the frontend framework Nuxt 3, and I used
the Vuetify component framework for the UI. Long story short: the
Vuetify documentation was ridiculously wrong in several places. It’s
an open-source project and I don’t want to give them too much of a
hard time, but all the same: I wasted hours trying to figure out how to
do the littlest things.
Debuggers work great for this part, but so does logging — even
console.log! I constantly use that, but I don’t trust it all that much.
T
here is nothing like the rush of deploying your application
for the very first time. I don’t mean to staging or to test out
your production environment — I mean deploying your
Minimum Viable Product. The thing you feel OK charging money for.
LAUNCH DAY
One of the best things about alpha and beta testing is that you get to
“harden” your production environment, to an extent. It’s tempting to
put scaling measures in place before you launch, but that amounts to
wasted effort and money, for the most part.
THE IMPOSTER’S ROADMAP 559
The simple reason is that you simply have no idea about your real-
world traffic and usage patterns. No one wants to see their app crash,
and I’m certainly not suggesting that you YOLO your launch! At the
same time, it will crash, and you need to be prepared for that.
We’ll get into monitoring, disaster plans, and more in the next part of
the book but, for now, let’s talk about you, your team, and launch day.
It’s a big day!
Launching your app means letting people know that your app is now
generally available, or “GA”. If you have a marketing team, they’re
going to be making a big deal out of this. If you don’t, then you need
to understand how this process works.
The first term you need to understand is “channel”. You reach out to
potential customers where they live, which means you need to find a
way to get your message in front of their eyes, which usually involves:
Email. That beta signup list is where you have to start when
announcing your app’s launch. These are your insiders, your
favs, your BFFs — let them know first! If you charge money,
offer a discount if they sign up and make sure they know it’s
only for them.
YouTube. Post some videos that are tangential to what your
app does, and make sure they’re full of value and not some
masqueraded advertising. For instance: if you sell videos or
books, do a video that goes into detail on one of the topics. Or
do a video on how to write a book. Just make sure you offer
value!
Ads. Marketing is all about figuring out where your potential
customers are, and then letting them know you exist. I know, I
know! Programmers think marketing is slimy — but that’s not
a good take. It’s the slimy marketers that are slimy! Scraping
emails from GitHub, crapping on competitors in public,
dropping in to social media threads to shill. That’s clumsy and
560 ROB CONERY
Marketing is a lot of work, and this is all I’m going to say about it
here. If you’re on your own, you’ll need to study up on this stuff. If
you’re not, and you have a marketing team, lucky you!
We had 3000 signups within 24 hours, which might not seem like a
lot, but for us, it was far more than we expected!
When you “soft launch” you let a select group know that you’re live,
and you hope for “organic” growth via word of mouth. Your email list
could be considered a soft launch.
Tekpub stayed up just fine and our traffic spiked as our tweets were
retweeted, and we went semi-viral. I remember discussing financials
with James, and we were absolutely blown away. We hadn’t planned
on reaching that number for another 6 months!
THE IMPOSTER’S ROADMAP 561
I suppose if I had invented the iPhone, I might do the same thing. I’m
not a fan of big productions like that because it makes failing appear
that much more dramatic.
A launch like that can destroy your company and, for me, it’s just not
worth the risk.
Do It On a Tuesday
Long story short: that’s when I found out that Tuesdays are the best
days to let people know a thing. 10am Pacific time, to be precise,
which of course depends on where your audience is, but if it’s a tech
audience, it’s 10am on Tuesday.
562 ROB CONERY
I don’t know if it’s still the case, but for some reason when you
announce on Tuesday at 10am (making sure you’re not colliding with
some other event like a conference or Apple announcement), people
will be far more likely to read what you have to say. Email, social,
blog, whatever. Even if you’re going for a soft launch — you want that
announcement to be read.
Buckle Up
It’s always stressful, but just be ready to fix, quickly, anything that
comes up. A crash shouldn’t happen — it’s usually some type of
confusion or a setting you forgot to change. Just make sure your build
is set up so deployment takes the least amount of time possible, and
that you have tests in place so you don’t push more bugs.
It’s nerve wracking, but with some good fortune, you should be
through the process in 24 hours, feeling good about yourself and your
future.
You’ve shipped your MVP, you have tests in place. You’ve chosen a
solid strategy for scaling your application in terms of both architecture
and infrastructure, and your GitHub repo looks clean and solid.
Now we have to focus on you. That last sentence might make you feel:
THE IMPOSTER’S ROADMAP 563
I think most people cycle between these reactions when they do good
work. It’s human, I suppose, but I think it’s also good to check
yourself. There are plenty of toxic egos in the programming world, and
not one of these people thinks of themselves as toxic. Or egotistical.
There’s an easy check on this: who are you thinking about most often when
it comes to recognition? If it’s you, you’re being toxic. That goes for a
complete cringe reaction too. Passive-aggressive people define
themselves by focusing on negative things they see in others. I’m not
like that person and never will be, is a common thought with these toxic
people.
You did good work, it’s OK to own that. Take a second and write down
how you feel about being recognized, or close your eyes and consider
what you would write. We’ll come back to this at the end of the
chapter.
564 ROB CONERY
I wasn’t sure where to stick this section. If I added it too early, you
would probably forget about it because programmers don’t like to
think about reporting. Marketing people love it, so do sales and
managers. Coders… not so much. That’s a general statement, but I
find it to be accurate.
Think of the project you’re working on now. Have you thought about
how you’re going to report viability and value? I love reports and
analytics, it’s how I got into this business! Yet even with my own side
business, reports are something that I consider once a quarter, which
is weird.
Why is it weird? Because reports are how you will be evaluated as the
project lead. Most programmers laugh at this statement, and I can see
why: their job is to deliver software, not make sales.
You don’t need to worry about the actual reports, just yet, but you do
need to think about the data that goes into those reports. Specifically:
Reporting and analytics veers heavily into the sales and marketing
realm, and you need to be OK with that. As I mentioned, you will get
thrown under the bus if you can’t prove how valuable your application
is or if others can’t prove it with the data you’re collecting.
Let’s flip this into the practical, shall we? I’ll use the e-commerce
example once again, as I find this scenario relates to just about
everything. Translate as you need.
As the lead, you want to be certain you’re collecting and storing all the
data you need to answer as many questions as possible, without
violating people’s privacy. Let’s start with the results, identifying what
they are:
Note: the people who will keep your business going are the Valued Customers.
The people who love your service and will come back for anything you sell.
Just the fact that you’re asking these questions is going to make
people happy, especially your marketing team. If you don’t have one,
or you are the marketing team, you’ll thank yourself later, I promise.
This is a great start. We’ll talk more about reporting in a later chapter,
THE IMPOSTER’S ROADMAP 567
but just know that the data your application creates will almost
certainly end up here (or something just like it):
Ah Excel, how I love/hate thee! It’s funny, you can provide all the
graphs, tables, and rollups you can think of to your web app, but it
will never be enough! You will soon be asked to provide CSV download
support too, so the Excel jockeys at your company can do their thing.
SUPERSTAR!
You’re there to ship, yes, but shipping doesn’t simply mean putting
your code on a server somewhere. It means putting an application in
front of users, which offers value in return for revenue. That is
your job!
And hey, you’re kicking butt! Sort of — the fun has just begun. Now
we need to make sure our applications stays up and can change as
needed.
I
cannot overstate the importance of shipping an application,
especially when you launch 1.0. Yes, it feels good for you and
your team, but the most important thing for you is that you’ve
just strapped a rocket to your back.
I’m not going to assume anything about your motives reading this
book, but if you’ve made it this far, you must at least understand what
just happened.
Some people do see it that way, however, and you need to know how
their brains work. I talked about this briefly a few chapters back, when
discussing sociopaths, but do keep in mind: they’re everywhere. When
you ship, you become a target.
This next section might be a little cringy for some of you, but if you
choose to raise your profile and influence by shipping software, you’re
going to have to understand human motivation to a deeper level.
These are ones I like because they’re mostly honest and make good
sense. There are some negative ones, however, and it’s imperative that
you learn them so you can spot them. They are:
Let your enemy think you’ve been beaten, then destroy them
completely. Nothing is worse in sports than thinking you’ve
won handily at the halfway point. That’s when you’re at your
weakest.
Hide your mistakes, or blame someone else, but don’t make
it obvious. Gross.
Chaos is your friend. Also gross.
Make your wins look easy.
Yep, still makes me cringe. Remember: you can (and should) use this
as armor. Do the things that align with your moral compass, but
always know that some other folks don’t have one.
So much has been written about the “need” to be “evil” when it comes
to being in a position of authority. Those are simplistic terms for an
incredibly nuanced topic, but if you’re going to do well as your career
takes off, whether you want to lead a team or not, you will have to
shake loose a few things inside your mind.
If you wish to lead a team, for example, helping and supporting them
is your primary goal, but right next to that is keeping your project
moving forward and preventing sabotage from other teams. Another
way to put that last point is you’ll have to carefully manage interest
and understand whether collaboration will help your project or not.
That’s what happens when you ship. You hear a ping in Slack or
Teams and then: I think our projects are very compatible. Let’s pick a time and
hop on a call and see what we can do together.
Let’s spin that around now. You might find that someone else in your
company is running a project that has a sizable amount of overlap
THE IMPOSTER’S ROADMAP 575
with yours. They’ve shipped too, and done a good job. You realize that
it’s wasteful to overlap like this, so you ping them and ask if they have
time for a call.
Politics are incredibly subtle, and I want, terribly, to tell you that you
can, indeed, spin things positively so you don’t think everyone is out
to get you. You can also lean on your “evil” side, if you will, and be
suspicious of people’s motives and, if required for your team and
project, take action that might not feel “good”.
That was a call I had a few years back when I was running a very
visible project for a client. I was given full control of the team and the
product, yet here I was on a call with someone whom I just met, and
they were making demands. People do this, and it’s weird.
And yet. If there’s a way that someone can flex on you, they will.
Usually, it’s because of a higher level or longer tenure, anything that
puts them “above” you.
I was told, in short, that I had to use a product this person supported
because the “entire company was going to be moving to it” and if I
would be one of the first projects to adopt it, my boss and everyone
else would be pleased.
576 ROB CONERY
Oh, and Rob, I’m going to need to review your disaster plan as
that’s my role here in Division X, and we have to ensure that your
project will meet company standards.
I still can’t quite believe it when these things happen, and I’m sure
you’re wondering if, in fact, this really happened. It’s just so clumsily
aggressive, don’t you think? And yes, it did happen. That’s the way
these things always seem to happen: right there in the open.
There are a few ways to handle this, politically speaking. But take a
second and think what your gut reaction would be if this happened to
you. Remember: you’ve been given full control of your team and
project.
Now think about how you would handle this situation using the laws
above, without worrying about losing your soul. This is just a thought
exercise, so pretend you’re playing a game.
OK, here are some choices that I came up with when this happened:
There are, of course, a few variations, and I’m sure some of you are
extremely clever and could probably navigate this situation with ease.
So what did I do? I used two of the “evil” rules above: never commit and
cause chaos. I also added a dash of conceal your intentions with fake
THE IMPOSTER’S ROADMAP 577
surrender. Wow, writing it here makes me feel gross, but then consider
that I’m trying to fend off someone who could very well cause
problems for the project. This would upend our work and cause us to
rip out entire chunks of functionality for their benefit.
I ended the call as quickly as I could using some vague excuse and let
them know I would follow up in an email as soon as I did a little
more investigation on my own. Seriously: it was extremely abrupt, as
I didn’t want them to try to leverage the disaster plan threat, as I
didn’t actually have a disaster plan for an application with 4 total
users.
I then pinged my client and let them know I had interest from that
team and that, at some point, I might need their help clearing a few
things up. I waited until then end of the week (this happened on a
Tuesday) and wrote to them on Friday, letting them know I was still
trying to assess the impact of replacing our stuff with theirs.
And then I ignored them and did nothing. Which didn’t work.
I worked the details with my client, and she agreed to grant extra time
and budget to do this. It was, as it turns out, important for the
company. This allowed me to instantly pivot and say whatever you need.
I worked with the clumsy, aggressive person over the following
months and, unfortunately, they had enough influence to eventually
take the project over and end my contract.
A negative view of this would be that I flat lost this battle and, if I was
more clever, I could have rescued my project and my job. A more
positive view is that the company saved money by merging the
projects, going in a direction that was the plan all along. A very
natural ending, and everyone is happy.
578 ROB CONERY
I’ll go with the last one, I guess. That’s the essential thing: my
reputation remained intact.
KEEPING TRACK
I also mentioned at the beginning of this book that you should get in
the habit of keeping a journal. Personal journals are great for catching
yourself turning into an asshole (power corrupts, etc.) but you should
also be keeping a professional one as well.
By journaling what was said when, and in what context, you can refer
to it when you’re being told “I never said that” or “I don’t think we
had that conversation”. Who knows, they might be right! Either way:
my journals have kept me from thinking I was losing my mind due to
some not-so-nice behavior from other people.
Having a journal is like having a dash cam: looks like overkill until the
day you need it, then it’s worth 100 times the effort and cost.
What you journal is up to you, but “notable” things, like your boss
asking you to go fishing with them in Montana, is typically what I
shoot for.
Keep the receipts, friends. When you catch someone, which you will,
always give them an out (don’t outshine the boss). We had a laugh over
this and, of course, the conversation turned to assurances I needed to
give so we could meet the deadline.
This is how sociopaths work, by the way: ensuring that you owe them
something. Back then, I just played the game and reassured my boss
that we’re on target and not to worry. Today, I’m not sure.
Keeping boundaries is a solid way to go. Pick your battles and all.
I just learned this term a month ago, and it seems like such an obvious
thing! A Brag Book is where you keep your “wins”, which can be:
These are only starting points — the book is yours, so add whatever
you think defines “good work”. It’s also not bragging if it’s for you, by
you, so brag away.
No one likes the idea of bragging until they need to bring the receipts
into a discussion, which you will. Someday, you’ll have conversations
where you’re asked:
Your professional life is not your personal life, and your reputation is
everything. As the laws state: guard your reputation with your life. On a
more positive note, build your reputation at every opportunity. If we were
talking about being social and dealing with friends, yeah, this would
be weird. But we’re not. This is work, and you have to be rigorous
with it!
The phrase “let’s hop on a call” is one such problematic area. Things
said via voice can so easily be manipulated and misconstrued. In fact,
I’ll go so far as to say they will be manipulated, especially if you keep
582 ROB CONERY
racking up the wins. Some people hate a winner and will just come
after you. It’s why most American Football lovers hate the New
England Patriots and are starting to loathe the Kansas City Chiefs.
MANAGING UP
Managing your manager is always tricky, and it takes experience to get
it right. If they’re good, they will hopefully follow the same points laid
out in this book in that they:
Bosses require reminding, from time to time, just like you do. These
conversations can be difficult, but I’ve found that being direct while
also personal can really help.
I sat in a group meeting a few years ago and the group manager was
asking us what our core priorities were and how they were helping the
group. This person had a lot of experience, but didn’t have too many
management roles under their belt at the time.
Case in point: when the meeting started, they summarized the goal
(describe your core priorities and how they help) and then said, “let’s
start with you, Sue” (pseudonym).
THE IMPOSTER’S ROADMAP 583
Note: If you’re the one running the meeting, try this fun trick: send out a quick
message (Slack, Teams, whatever) and ask, “does everyone know what they’re
working on? If so, reply with a quick summary, and we can skip the meeting”.
You’ll see applause emojis from everywhere.
The thing is, there were no group priorities. We, as a group, had a loose
direction that my manager’s manager had put in place and my
manager decided to hand that down to us.
That’s not our job. Setting direction is your manager’s job, and often
you’ll find yourself in a situation where that’s delegated to you. Never
accept this because, once again citing the rules of power, you can
easily be blamed if the priorities of the group are off.
Good and evil are vague and shifting concepts, if you’re a person who
sees the world in those rigid, contrasting terms, you might want to
check yourself. This is called “Black and White thinking”, and is an
extreme way of looking at the world that ends in hatred, prejudice,
and war. That’s a bold statement, but when has “us vs. them” ever
worked out for anyone?
You will need to learn how to manipulate people and circumstances to ship
software. This doesn’t mean being “evil”, it means being diplomatic,
fending off aggressive folks, assessing risks, managing your boss or
client, and being professional.
We all manage what we think vs. what we say, every single day. This is
called society, but you could also see it as manipulation if you chose.
THE IMPOSTER’S ROADMAP 585
Your clothes, your hair, your smile, and your choice of words are all
designed, by you, to give the best impression possible — or at least
the impression you want others to have of you.
L
et’s jump back into the world of programming now because
we need to set up the all important Build. You probably know
what “the build” is and what it means, but just in case you’re
new around here: the build is the process that goes off when you build
the software for your project. This is typically done in steps, including:
Your build tool should tell you that. If you use GitHub, you’ll see
pretty accurate results, depending on how you set things up, and how
to fix things before you submit a PR. If you’re doing trunk-based
development, the build is there to keep things safe so you don’t push
bugs into production, or worse: send bugs to your coworkers so they
need to stop working until you fix your mess!
Breaking the build happens, but you should expect it to happen and
not freak out when it does. It’s there for a reason, so we need to be
sure that we set things up to help those who need it.
Yes, you can test on your dev box just fine, but what happens when
you want to run those tests on another machine, in a container? Using
a service like GitHub, that’s precisely what you’re going to be doing.
This is where things might get interesting for you!
For example: I have no problem writing tests that hit a database, but I
know plenty of people who avoid it at all costs, so they will create test
doubles and use software patterns (Dependency Inversion/Injection,
e.g.) to avoid touching the database. They do this to isolate the tests
as completely as possible in an environment that’s easily reproducible,
such as a test container running on a build server.
588 ROB CONERY
I’ll use C# for this example, as the patterns I’m about to show are very
common with that language. If you’re a .NET person, I’ll discuss
patterns with Entity Framework later on.
So, this might be a very typical setup using C# and .NET (TypeScript
as well):
That’s a good first step, but our class is still dependent on a specific
repository interface, the ICustomerRepository. This might be
acceptable, or we might go one step further and create a base class or
a more generalized interface such as IQuery or something.
I’ll leave this up to you. It’s easy to get lost in the architectural forest
and for some, it’s fun to see just how loose you can make your class
associations. For me, I like to use the phrase “it’s not a problem until
it’s a problem”, which is something I learned doing Ruby. A .NET
person might tell me that’s a great way to pile on technical debt, to
which I would counter that it’s also a great way to ship software.
The reason I like it for testing is because you can use it to emulate your
database if you’re using some type of object-relational modeler, or
THE IMPOSTER’S ROADMAP 591
ORM. Just about every ORM out there will support SQLite, which
means you can run your tests with it and not have to worry about
hitting your database.
Let’s switch to Node.js for this one. I’m using the Sequelize ORM,
which I really like, with the following schema definition:
I can use this class with most database platforms, but my app will use
PostgreSQL for development and production, but SQLite for testing:
I’m not a huge ORM fan because they tend to be difficult to debug,
and also (at times) create horrendous SQL that causes very slow
queries. That said, this use case is wonderful.
I don’t do this myself, but I have quite a few friends who work on
larger projects that use this technique regularly: just put everything into
test containers.
THE IMPOSTER’S ROADMAP 593
The idea is straightforward: every time you run a test, you start a
dedicated set of Docker containers using something like Docker
Compose. It spins up your code and all the services your application
needs (PostgreSQL, Redis, etc.). Once the tests are done, the
containers are destroyed.
This might sound slow, but Docker is ridiculously fast and can start up
incredibly quickly. If you’re a TDD person, it won’t be quick enough,
which I agree with (friction is the enemy when you’re doing TDD). If
you embrace testing, but do it on a slower cadence, this could work
out for you really well.
Instead of using fixtures and doubles, you might want to just have the
data exist in your database before you run your tests. Since we’re
using Docker, we can do whatever we want because we know the
environment will be set just so, for every test suite we want to create
594 ROB CONERY
containers for.
Your container startup script can execute the SQL file directly, but
with MySQL and PostgreSQL, we have a fun shortcut! You can copy an
initialization file (plain SQL) to a special directory, which will be run
right when the container starts for the first time. Here’s what that
looks like:
For SQLite, you can just copy in the binary database file directly, and
you’re good to go. This (oddly) works for SQL Server as well, but
you’re probably better off initializing your data using a RUN
command.
If you don’t use GitHub Actions, you should be able to translate what
you read here. Most of the packages and tools are the same, and use
containers under the hood to run things in a given environment. The
“Just Use Containers” section above is, essentially, how builds work at
GitHub and other services.
THE IMPOSTER’S ROADMAP 595
I don’t have a build for this repository, but I can add one quickly by
clicking on “Actions” in the tab menu (fourth from the left).
You can build and deploy Docker images whenever you push to a
given branch, publish your code as a package, and so much more.
The ones you see here are just the recommended ones based on the
code in my repository. If I had a Rails application, or maybe Django or
.NET, I would see those suggestions here instead.
I’m using Node.js, so let’s see what type of CI/CD I can do with the
Node.js action. I’ll click on Configure:
THE IMPOSTER’S ROADMAP 597
This is where things get confusing for many people. You might expect
some checkboxes, radio buttons and other form selection things, but
instead, you’re given a blob of YAML. DevOps!
At the end is the main part: the commands we will run within the
container, which are:
The first step checks our code out using a built-in GitHub action,
which will use whatever branch you set for the action on push.
The next step sets up Node.js, and as you can see, we’re building
against 3 different versions of Node, which isn’t strictly necessary
unless you need to do that.
Reviewing this YAML file, it doesn’t look like there’s anything I need
to do, which is exciting! Let’s commit the change and see what
happens, shall we?
Hey, it’s our first workflow! As you can see, it’s triggered on a given
THE IMPOSTER’S ROADMAP 599
push, which was the addition of the workflow YAML file (“Create
node.js.yml”), The status is “Queued”, which means it’s waiting
to run.
Crap. We broke the build! That red X there means that there’s a
problem, and if I check my email, I’ll see that yes, indeed, there’s a
problem:
600 ROB CONERY
Here, I’m being told that my database connection string URL is invalid
(I know this error all too well). This makes sense! I don’t have a
PostgreSQL database to run my tests against, so of course things will
fall over!
I never thought I would write these words, but thankfully, I’m using
an ORM. That means I can easily switch over to SQLite for testing,
which doesn’t need a dedicated service and can run directly from
Node.js.
THE IMPOSTER’S ROADMAP 601
I just need to install the SQLite package for Node.js and update my
data access code:
Here, you can see that I’m using SQLite in memory. Let’s see if this
fixes the build! I’ll commit the change and push.
Note: I need to do a git pull before I do a git push because I added the YAML
file to my repo using the GitHub website. You’ll get an error if you try to push
straight away, so don’t forget to pull down the changes and merge them in.
Woohoo! Green checks are always exciting. As you can see, I had to
merge the changes (addition of YAML file) to my codebase, which is
why the commit title is a bit weird, but everything works. Hurrah!
The fun thing about the GitHub action containers is that they have
Docker installed because they’re already running Docker! That means
we can use Docker to build our test containers as we need.
For this, we’ll replace our run directives with a single run, and have it
execute some Docker commands as well as shell scripts:
This might look a bit crazy, but what we’re doing here is creating a
PostgreSQL container on the fly and setting things up as we require.
We have to wait a bit for the container to start, that’s why we have an
until loop in there.
Hey, it worked! Unfortunately, doing things the way we’re doing them
here will take longer given the Docker gymnastics — but often that
doesn’t matter, as a timely build feedback isn’t really a necessity for
most projects. Obviously, you would rather not wait hours, but an
extra minute or two tends to be acceptable.
I like this idea, but if using SQLite is an option, I’ll just do that.
Hopefully, you can see how your application’s architecture has a direct
impact on your ability to safeguard your production environment
using a CI/CD build.
I also want to reiterate: breaking the build is not a bad thing and is
to be expected. Trying, failing, fixing, succeeding: this is how we
604 ROB CONERY
learn and grow as programmers on a team. The thing you don’t want is
a delay getting a fix in, so it’s imperative that everyone is subscribed
to notifications.
This can get a little overwhelming if you have a large company with
numerous repositories. If you’re part of an organization at GitHub,
notifications are turned on by default for every repository in that
organization. Some people (like me) reflexively turn off their GitHub
notifications, which is a bad thing because you never want a ping at
the end of the day asking if you fixed your broken build.
Ideally, you won’t get to a point where a single PR will stop the
development process. Unfortunately for me, I was on a team with a
snarled mess of a codebase (which we were trying to fix) so my PR
touched about 60% of the application. This is how poor architecture
can impact your team: one change ripples throughout the codebase,
which is disastrous!
You might need to send emails during an integration test, but you
don’t want to send actual emails to some test account. Instead, you’ve
decided to use a service like Ethereal, which stores the email as a
record that you can browse in a web interface.
You can store secrets that are used for your application, or for your
repository. It might not seem obvious what the difference is, so let’s
take a look.
Environment Secrets
You can access your environments from the side menu as well.
The next step is to set up the secrets for the environment, which again
is a matter of clicking a button or two and adding the values you need.
Repository Secrets
At some point, we might create a GitHub action that deploys our code
to a cloud provider such as AWS, Azure, or GCP. Doing so will require
API keys, which aren’t part of our application, just our infrastructure.
These don’t work in any environment — they work across the entire
repository and are accessible from your Actions.
When you start playing with GitHub Actions, it’s hard to stop. There’s
so much you can do, and we’ve barely scratched the surface.
Compiling, building, linting, and running your tests is just the start —
THE IMPOSTER’S ROADMAP 607
you can also create and deploy a Docker image to whatever registry
you like.
A very typical Node application, which we could build and then push
to our registry using a CLI or some kind of build tool, or we could let
GitHub do it for us!
inherited from your repository, which means there’s very little setup.
You can change this, of course, if you need to.
You can also use whichever registry you like, whether it’s your own,
your companies, or DockerHub. To see this in action, let’s click
“Configure” in that Docker Image box:
Here, you can see that we’re taken directly to an editor for a new
YAML file called docker-publish.yml. The registry is defaulted to
GitHub’s (ghcr.io), but you can change this, as needed.
Note: if you’re deploying to Azure, AWS, or some other cloud, it’s likely there’s
a prebuilt workflow for you, which is what you should use rather than trying to
alter this file.
I’m not going to do a thing to this file — let’s see if it works! I’ll
commit the change, which will kick off the workflow:
THE IMPOSTER’S ROADMAP 609
If we head back now to the repository home page (or just click “<>
Code”), you’ll see our image as a “package”:
Clicking on that link will bring us to the image page, which has our
Docker details:
610 ROB CONERY
That said, building and deploying are only some of the things you can
do. You can also do “maintenance” stuff, such as scanning your issues
list or welcoming new committers:
THE IMPOSTER’S ROADMAP 611
You can also create and run frontend web applications or static web
apps to GitHub Pages:
If you don’t know what GitHub Pages is, it’s a way to use GitHub to
host your HTML files and display them as a website. You can also
create a pages site using Markdown files and the Jekyll or mdBook
frameworks. It’s great for documentation or a personal site.
612 ROB CONERY
Now I know that people have opinions on linting and “the style
police”, and I’m going to sidestep this argument by saying that you
can, typically, configure these tools to be as strict as you need — or
just not use them at all.
Either way: you have the choice of plugging in a GitHub workflow that
can do this for you. I believe that you might want to discuss this with
your team first, however.
All the tools mentioned above can be run locally, and they can also be
run as part of your build step. For Node.js, it’s common to run a linter
locally, or as part of your editor’s IDE (such as a plugin for VS Code,
or a bigger IDE like Jetbrains WebStorm). The reason you might want
to consider doing this is simple: pride and, more directly, avoiding
humiliation.
I think these tools are interesting, but they also beg to be ignored.
One such tool is dependabot, which GitHub enables by default.
Sounds like a good idea, doesn’t it?
THE IMPOSTER’S ROADMAP 613
Well…
This is for the repository I was just working with (the Node/PG
starter), and honestly this is tame when compared to some
applications. What makes this even more frustrating is that these PRs
will stay there, even if I bump my dependencies locally (which I did
last year).
All of that said: security is a big deal and should be annoying. As far as
which tool you use — well that’s up to you. There are quite a few to
choose from, and it’s a bit out of scope for this chapter to talk about
scanning tools; just know that GitHub has quite a few to choose from.
SUMMARY
There are so many CI/CD tools out there that help you create a build,
including GitHub’s alter ego: Gitlab. They all work in roughly the
same way, applying workflows (or “jobs”) to your codebase, building,
linting, compiling, securing, and even deploying it to wherever your
code will live out in the wild.
Ultimately, a build is your safeguard from pushing crap into the world,
which already has far too much crap to deal with (software and
otherwise). It’s an essential part of a healthy team, and will help you
deal with the storms of change that will inevitably crash your good
time.
I
remember when I first played World of Warcraft right after it
came out of beta. It was hard. It took me months to get to level
30. I kept on, and after 4 months of playing semi-casually with
friends, I hit max level which, at the time, was 60.
Anyway: that’s where we are now. Our MVP is out the door, and our
initial build out is done. Now comes the endgame, which is the
hardest part of building software: keeping it running, which is balanced
by an equally pressing need: avoiding rewrites.
THE IMPOSTER’S ROADMAP 617
My specialty has always been the MVP effort. I’m good at it. I have,
typically, found the “long haul, steady as she goes” ensuing years to be
rather dull. I think it’s because I came up during the first Dotcom
boom, when money was falling from the sky and my clients were
getting wealthy.
The problem you face, when technical debt stacks up too high, is fighting
off the urge to crave out massive sections of the application, or perhaps
the entire thing, and rebuilding them. The promise you make yourself is
that “this time, I know the problem space better, can lose a lot of code,
and make things more efficient.” Occasionally this is true! Typically,
however, you waste effort on replacing something instead of expanding
and enhancing your application, which increases the value to your users.
I know this all too well. When I ran Tekpub, many years ago, and
even more recently with my publishing company Big Machine, I could
not resist the temptation to rebuild. I like coding and building things,
and I love the idea of making things more efficient. Unfortunately for
me, that came at the expense of creating content for my customers.
You will face this problem, many times, from yourself and also from
your team. A platform upgrade, a new framework, a bug that you keep
618 ROB CONERY
trying to patch but, somehow, keeps coming back. We should just redo
this entire module…
No! Spend the time it takes to understand, clearly, what the issues are
in your codebase; especially the ones that keep recurring. Take the
time to do a clear cost/benefit on a new framework, and you’ll almost
always come away with the understanding that it’s not worth it.
I played around with Nuxt for a day or so, and like I do, I decided to
see how long it would take me to rebuild my bigmachine.io site. It’s a
problem space I know well, and I usually stop after an hour of messing
around. It’s a great way to find the edges of a framework, and my
feeling is, typically, that if I don’t stop, then that’s a good thing!
That’s what happened with Nuxt. I just… kept going. It made things
so much simpler than what I was doing (combination of static site and
Firebase).
I tried upgrading to Nuxt 3, which I also liked a lot. That helped, but
then I started running into problems where answers that I found
online were 2 or 3 years old, and out of date. The newer stuff (a year
old by the time I was working with it) wasn’t documented very well,
and I snapped.
Over the course of two weekends, I ported the entire site to Node.js,
Express, and Sequelize. It didn’t take long at all, and I can’t tell you
how freeing it was. I no longer had that visceral reaction, and fixing
things was straightforward.
But you also need to recognize the lingering 10%, and you can only do
that by taking notes and carefully thinking through the cost/benefit
with your team.
REFACTORING
Typically, what you have to do (instead of rewriting) is to refactor your
approach, which is a fancy word for “reducing and simplifying”. This
is where your careful attention to your testing strategy starts to
pay off.
Every team faces this problem at some point: a given change is just
too hard. This is almost always the driver for a refactor. The other big
driver is, frankly, vanity. Change might not be an issue, but opening a
file that’s 1200 lines long just looks… eww.
THE IMPOSTER’S ROADMAP 621
Code editors are pretty good at summarizing what you’re seeing, and
there’s always the find function if you need it. Ugly code that works
isn’t really a problem, is it? Or is it? This depends on so many things,
and you usually hear the argument “well if code is ugly then we won’t
understand the intent of the thing” which I think is a load of bollocks.
This is where we get into tabs vs. spaces, where you put your braces,
and how you name your variables, which should be in a style guide, by
the way. If the style guide was followed, you are probably wasting your
time trying to make the code “prettier”.
Fun fact: one of the data access tools I created was called Massive. I introduced it
as a single file data access solution for .NET that used dynamic data. Jeff Atwood
and team, who were building out Stack Overflow, liked the idea and considered
it, briefly, for the site. They ended up making their own solution, however, which
became known as Dapper.
After a brief discussion, the choice became clear: we’ll use Dapper.
I allowed myself 2 hours to see just how much work the refactor
would take. I created a local branch, using Git, and jumped right in.
I left my tests the way they were and added a new one. My old
solution was still in place, but I decided to create new code that used
Dapper directly. Within 2 hours I was able to replace, entirely, 2 of my
existing commands.
It’s a go!
This is a trick that I learned many years back: don’t replace, rebuild. It’s
tempting to jump into the files that we need to update and start
hacking away. That will inevitably lead to test failures, a lot of them,
and cause you to comment things out and make a mess.
Instead, create new files in a new directory, and rebuild the existing
things using the new way of doing things. In my case, I had the old
command open on my right monitor, and the new one on my left. I
changed the class name, of course, so the compiler wouldn’t freak out,
and then I rebuilt things with the Dapper code.
The entire process took about 4 hours, which is great. I added a few
more tests and also took the time to ensure that database connections
were managed better, and I refactored a few tests for readability.
That’s it! I merged the changes in, pushed to my personal GitHub, and
then opened a PR for review. We’ll discuss code reviews in the next
chapter, but I will mention this here: a major downside of a refactor
like this is that I touched quite a few files. I also went a little extra by
refactoring the tests and connection code.
Hopefully, you can see the role your tests play during a refactor. If
they’re too precise (or “brittle”, as we discussed in the testing
chapter), then refactoring means changing tests, too, which is a major
drag. When you change, or as is often the case, delete a test, you can
never be certain you’ll get that test coverage back. In fact, you
probably won’t.
DATABASE CHANGES
When creating an application, you typically build out the database at
the same time as the application code. Rails, for example, ties these
concepts together with its generators and database migrations. Same
with Django and other “batteries included” frameworks.
This is great during the initial build, but as time goes on, you’ll need
to separate the idea of database maintenance from application
maintenance.
I can’t tell you how many times I’ve had arguments over this.
Programmers hate to hear that the application they built is not the
business priority! I guess I understand. It’s a lot of work putting all
that code together.
You’ve heard me say this throughout the book and, yes, it’s my
opinion, but then again, it’s really not. Ask yourself: what would
happen if your application code (the source, repository, everything) just
vanished one day? Panic, surely, but outages do happen and if your
company is OK with being transparent, you could rebuild everything in
the open and slowly get back on your feet. I know this might sound like
I’m just glossing over the details, but the truth is, you could probably
get your app up and running again within a month if you had to.
OK, maybe you still don’t believe me. Let’s try another question!
What’s worse: a code breach or a data breach? I think I’ve read about
source being stolen perhaps twice in the last year, and that was for a
THE IMPOSTER’S ROADMAP 625
video game. I read about data breaches every day, and as a user at
some of these companies, let me say that it’s horrifying. Do I care if
their source is stolen? Not at all. My data? Oh yes.
Moving Forward
I will say this, however: you must have a backup plan! One that runs on a
timer (nightly is a good idea) and one that runs when you require it.
Backing up before you make any changes is critical.
Any time you change a database, even when there’s a problem, you
need to think about moving forward instead of “rolling back”. I know I
just spent time telling you to back up your database nightly, but that’s
for complete disasters where your database is in a terminal state (aka
“dead”). That happens if you forget a where clause a delete or update
statement, and data is lost forever.
Or is it?
Let’s consider the time that Rob forgot a where clause on an update
626 ROB CONERY
It’s true. I was trying to update the expiration dates for my annual
subscribers because, as luck would have it, my date management skills
were off. I lived in Hawaii at the time, which is GMT-10, and my users
in Europe and Australia didn’t like that their subscription ended a day
early. So I decided to just make the subs last a year and a day,
why not?
I’ll spare you the SQL, but I’ll summarize by saying that running
update users set... without a where condition is one of the oldest,
dumbest problems that you can run into.
In general, when you’re faced with this dilemma, you should always
look to fix forward, which some people call “version forward”. Your
database is a fluid thing and, usually, you can resolve the problem
you’re having by understanding precisely what happened, and creating
a fix.
I did option 3, but not before I thoroughly investigated and made sure
that nothing else happened that I was unaware of. Thank goodness, I
hate triggers!
Fixing forward takes time, and it can be difficult to shed the panic and
get your brain into the right space. You can, usually, build a forward
fix from your last backup instead of doing a full restore. If you can’t,
well, we’ll talk about disasters in a few chapters.
Let’s say you have a table with 10,000,000 rows in it. For some, that’s
not all that much data. For others, like me, it’s huge. Let’s say that’s
your users table, which holds their login credentials. If you have
10,000,000 users, you’re in pretty good shape, friend!
In your last sprint, you and your team decided to add IP address
tracking to your user logs, and to add last_ip_address to your users
table:
You run this script locally and it works fine. You ask for a code review,
everyone asks if the syntax is correct, you say it is and you get the
green lights.
You run the script and production goes down for 40 minutes. Uh
oh. You look at your database application and the spinner is still
spinning… should you kill it? Let it run?
Every query was halted during the lock, which meant users couldn’t
tweet nor could they see any tweets at all. Ah the good old days!
THE IMPOSTER’S ROADMAP 629
So, what should have happened here? To be honest, I’m not sure. At
that time, MySQL required table locks when altering the schema, so I
suppose the best choice would have been to make the change as fast
as possible (no defaults), with an announced maintenance period.
They could have also decided not to do the column addition, deciding
it might not be completely essential.
These are things you need to consider as you change your table
schema:
How large the table is, and how many reads/writes happen per
second. If there’s a lot, you’ll need to schedule a maintenance
window and let your users know you’re going down for a
while.
Is that default value necessary? Defaults can put a strain on
the system as it’s one more write that must go in.
Can we do this concurrently? Some systems, like PostgreSQL,
allow you to apply indexing in the “background”, which won’t
lock your table as the index builds.
630 ROB CONERY
There are alternatives here. I’ll show you some tools, and then I’ll tell
you what I do. Let me say this right here, too: I do what I do because
it works for me. It’s critical that your change plans work for you and
your team.
Don’t get me wrong, I do think it’s worth it! I, however, like to have
my scripts. I like SQL, it’s powerful, and if I’m disciplined in what I do
and make sure I capture the SQL changes needed, I don’t need to
spend the extra money.
You can see that I also have a seed file, which I generated because I
needed 10,000 users to go in. Believe it or not, this all happens in
milliseconds!
Doing things in this way requires idempotency, which means that every
SQL file can be run repeatedly with the same results. This is one
reason I like working with table schemas because dropping and
reloading is pretty simple:
634 ROB CONERY
This goes right at the top, and wipes out everything in the mail
schema. All the create statements are down below, and all the data is
in the seed.sql file.
For the changes, you have a choice: keep rebuilding everything from
scratch (using db.sql and then change.sql, which means tweaking our
Makefile a bit:
This little change will ensure that everything goes in at the right time,
and we can layer in our changes on top of our database initialization
script.
THE IMPOSTER’S ROADMAP 635
Or, we could make sure that our change.sql script can be rerun
consistently without problems by ensuring the changes don’t exist
before adding them:
This is clunky, but it does give you a way to “undo”, if you will, the
changes that go in.
One of the major benefits of doing things this way is that you can ask
for code reviews on your change scripts, and ensure that you know
precisely what will happen and how. It’s good to be a control freak
when it comes to databases.
I could go on — but I think you get it. You cannot rely completely on
external services or dependencies. This doesn’t mean you have to create
everything yourself. You just need to have a backup plan for every
dependency you take and service that you rely on.
My focus is always the data. If I own the data, I’m happy. No matter what
service I use, I set up webhooks to update a centralized data store
(PostgreSQL), which I use for reports and customer fulfillment.
I have two main applications: my main site and my checkout site. The
main site runs on Rails (currently) but I also have Ghost CMS site
that I can deploy quickly should something happen to my Rails app.
You don’t need to do all of this: just protect your data and be ready to
deploy to a different host/cloud/service within an hour if anything
happens.
638 ROB CONERY
STEADY ON!
Changing, updating, and versioning your application is the long haul
and if you do it for years, that’s a great sign of success. As you go on,
your change process becomes your business process, and can only be
as healthy as your organization and leadership. This is where I will
leave off, as this isn’t a book about building a company or
organization.
Stripe and GitHub, for instance, are companies that started with
simple ideas that were unremarkable at the time. Over the years,
however, The Collison brothers built Stripe into a multi-billion dollar
company trusted by developers around the world. Tom Preston-
Werner, Chris Wanstrath, PJ Hyett, and Scott Chacon thought it would
be fun to create a website that let you see your Git repository
information in a centralized place. That idea grew into another multi-
billion dollar company as the founders adapted to what customers
liked and needed.
Y
our job now is to manage change, as we discussed in the
previous chapter. You’ve probably been doing code reviews as
you and your team ramped up the MVP, but they were most
likely a bit rushed. Which is fine — MVP is about getting your code
out and into the hands of users with as few bugs as possible.
Thereafter, it’s all about pace and rigor. This is the endgame!
Before we get into the details, it’s important to break things down so
you understand the context for what you’re about to read.
The first, and most important, thing is this: all of this is highly subjective.
Some people have a “right between the eyes” approach to a code
review, and see it as a way to challenge their colleagues (and
640 ROB CONERY
Many people like to flex and play domination games, while others like
to give out hugs and boost others however they possibly can.
So, to the point: there is no one true way to do a code review. Your
approach will shift based on whom you’re reviewing and what type of
feedback they prefer. This will also have to align with what type of
feedback you like to give.
There is one bit of solid truth here, however: you’re here to keep shipping.
This might push you right out of your comfort zone, especially when
reviewing someone else’s code who is clearly in over their head. What
do you do then? Encourage them and try to help? Or give them a
nudge toward the door. The latter might seem harsh, but teams that
lose a bad apple can transform overnight (see the law about avoiding
negative people).
I’m going to start out with the human part of code reviews, but I will
keep us on track with the singular goal of getting the code out the
door and into the hands of our customer. It’s critical to remember,
that’s why you’re here.
We’ll then take a look at code review tools that you can use, and as
usual, I’m going to go with the most widely used tool: GitHub. Other
source control platforms (TFS, GitLab) work roughly the same way, so
hopefully you can translate as you need.
It’s so easy to lapse into horror stories when it comes to code reviews
(and there are many), but let’s start out on a positive footing,
shall we?
I’ve written quite a few books over the years and I can tell you, as a
fact, that a good editor is a profound gift from the gods. One of my
books, A Curious Moon, was edited by my friend Dian M. Faye and the
process was surreal. She saw what I was trying to say with this book,
and focused her time on helping me say it. I don’t quite understand
what magic she possesses, but the joy I felt as this book took shape
with her deft skills… it was, as Mr. King states, divine.
That’s how I see code reviews. You’re there to help someone shape
their code into something spectacular. Who knows? Maybe it already
is, and your vote of confidence can make a wonderful difference in
their day.
On the other hand, you can also suggest some small tweaks here and
there that your review partner might have overlooked, like we all do,
and quite literally change their life.
I have found that most companies will adopt a tone and style from one
of the senior managers or leads, which can be a good thing… or not.
Always remember that the “style” you use should be your own, as long
as it’s effective.
Let’s consider a few styles that you might consider on a case by case
basis. They each have their pros and cons — your job is to figure out
which to use, when.
The Gatekeeper
I both love and hate this type of code review. On one hand, as a coder,
it pushes you to “measure up” and make sure you lint, comment, and
follow the style guides to avoid “PR ping pong”. I think this is a good
thing.
The main problem with gatekeeper code reviews is that the reviewer
might not be as skilled as the coder, even if (sometimes especially if)
they’re senior. I have been in this position far too many times.
We like nice people, don’t we? We like to be liked and often hate the
idea of conflict, especially at work. I was talking to a good friend just
the other day about code reviews, and he told me “that’s why I never
made it as a manger”, which I found odd! He was simply too nice and
didn’t give solid feedback that could help someone grow.
In fact, it will almost guarantee it, making more work for you or the
future code reviewer, and not helping out your colleague.
Something more direct will likely help: thanks for taking the time to add
the comment, but I would like to see it follow our guidelines, so the
documentation reads the way we decided as a team.
Cold Reality
Using our comments example, one more time, let’s imagine that I
forgot to add one (for the 40th time) and you catch it. You decide to
be direct:
644 ROB CONERY
This, of course, is just me. I know others that would read this and
think you’re being unduly harsh. Terseness has that effect, but you can
mitigate the damage by sending an email before you do the review:
You might also want to follow up with the person to ensure you
haven’t gone over the top, which is easy to do. Good relations on your
team, especially if you’re the lead, is critical!
The Coach
A few years ago, I was on a project that required me to learn Go. The
syntax of the language was simple enough as it is C-style (braces, etc.)
but the idioms escaped me (null checks everywhere? Really?)
Thankfully, my good friend Aaron Schlesinger, a Go expert, was the
one reviewing my code fairly often.
Aaron and I are peers, yet Aaron knows a lot more about Go than I do,
and it was critical that he took the time to encourage me to learn more
about a topic. To that end, he took extra time to explain concepts that I
was obviously missing.
THE IMPOSTER’S ROADMAP 645
While I can’t show you the exact comments, I can show you a
representation:
That said, I have also had “coaches” review my code and offer advice
on how to “properly” query PostgreSQL. This usually involves the
strong suggestion that I use a data access tool instead of writing inline
SQL, which is “prone to SQL injection attacks”.
It’s critical for each person (coder and reviewer) to understand the
other’s strengths. It’s also critical to know when you know something,
or are just repeating dogma. We’ll talk more about that in a bit.
The Hero
Here’s a scenario: you’re the senior lead on your team, and you’ve
been given a PR to review from one of the junior developers on the
team. It’s for a React application, and the PR is for adding a feature
that uses the application state to store some data and update a status
element. Simple stuff, at least to you, because you know React (let’s
assume you do in case you don’t).
What you see is instantly confusing, and also alarming. The style is
dated, and it’s clear they wrote their own components and functions
instead of reusing the core bits the team has been using the entire
time.
This is the first time you’ve worked with this person, and you realize
they were hired a month ago. You look at their profile, and they claim
to have 6 years of active React experience, but they clearly don’t, and
you start to feel that the entire PR is probably a waste of time.
might have a good reason for this, but by taking on the hero role,
you’re involving yourself unduly in someone else’s problem.
You never want to make someone feel erased. That said, you’re here to
ship something, not wait while someone who clearly lied on their
resume fumbles around with a feature required for your sprint.
We’re going to discuss the ups and downs of politics in the future, and
how you will need to sometimes flip the evil switch — now is one of
those times, although “evil” is far too strong a word.
You can crush someone doing this, and that’s never a good thing.
People quit all the time because of bad code reviews; quite a few give
up on coding altogether. I don’t quite know what to say about this
because, on one hand, it could be a good thing. Quite a few people get
into programming because it pays well, not fully understanding the
commitment they’re making, only to realize after a few months they
hate it.
648 ROB CONERY
Other people just need a little more time to get up to speed, and find
themselves in the deep end, sitting opposite you at their first code
review trying not to break into tears.
But what if this person was desperate for work? We’ve all been there.
Maybe they have kids to feed, or a sick relative, and they were forced
into a tough decision. They try to convince you that they are a fast
learner, and that they can get the job done. They promise to study,
take an online course or two, and put themselves on 30 day probation.
The truth of the situation remains: this team member is letting you
and everyone else down and, moreover, is taking the place of someone
else who needs a job. Someone who’s qualified and much more
deserving.
I don’t have an answer for you. “Fake it ’til you make it” people are
extremely challenging, yet I also understand that work is work and
when times are hard, people do weird things. They are typically
discovered during code reviews, however, and how you handle it is up
to you, of course.
I felt good walking into my first code review with one of the company
engineers, who’s first comment was:
I let him finish, of course, and didn’t say a word during the process
(always say less than necessary). My client was on the call as well, and I
could tell she was absolutely mortified.
The problem here is straightforward: this isn’t the way he learned how to
use C#. This happens in the Ruby community too, especially when it
comes to Rails. Pythonistas and gophers have their idioms too, and if
you go against that, you’re probably wrong.
This is toxic.
I do think it’s true that certain patterns can help with a complex
codebase. Factory methods can make things much, much clearer, and
Builder objects can be used when Factory methods get out of control.
650 ROB CONERY
There was nothing tricky or weird about what I was doing with my
fluent interface. It worked, and the API discovery (if you use
intellisense) can be extremely helpful. That said, there are people who
dislike it because it seems verbose, like my friend Jimmy Bogard:
You can take any coding “style” too far, which goes without saying,
and if you see someone doing that, do let them know. That’s when
code reviews work best: when you take the time to offer substantive
feedback, such as:
This will likely cause some discussion, which may or may not be
constructive. No one likes to hear that their code doesn’t measure up,
especially when they’re proud of it. That said, I’ll end this discussion,
before we get to the tools and more practical stuff, with another quote
that I like, which is targeted at aspiring writers:
This has to do with the editing process, when it becomes obvious that
a character or plot point should be cut to tighten up the story. As a
writer, you tend to fall in love with your characters and, often, the
scenes or plot elements you put them through. Your editor will likely
tell you, more than once, “time to kill this little darling” (darling,
here, is the thing you fell in love with).
The same goes for code. People fall in love with what they write and
will defend it, even though it might not be needed or could be made
more powerful and clear by refactoring or just cutting it out altogether
in favor of a simpler approach.
AUTOMATING THINGS
Code reviews used to be done in person, not so long ago. In fact, they
still are done in person at many large companies, and even startups.
There’s a good reason for that: in-person communication tends to be
much smoother than written.
To be clear: I’m not saying automatic code review — there are still
humans involved. An automated code review simply tracks what was
said, when, about code that’s under review.
I’ve been using GitHub throughout this book, and I’ll keep on going
for this example, because code reviews with GitHub are powerful. If
you’re using GitLab, Atlassian Crucible, or BitBucket — the code
review process is basically identical to this.
I have a bit of an issue with my current codebase. Can you spot the
problem?
I’m not sure why I did this if I’m honest. I know better.
The reason I’m showing you this is because of the link, right above the
image. If you click it, you’ll be taken right to that line in the code. This
is one really nice thing about GitHub: they allow you to navigate
directly to a place in your codebase.
https://github.com/robconery/node-pg-start/blob/master/mail/
index.js#L43
The end bit there, #L43, highlights the line so you can see it better.
This is extremely useful when creating an issue, which my very
considerate alter ego just did:
THE IMPOSTER’S ROADMAP 653
Lucky for us, my alter ego is on the job. I read the issue and gave a
thumbs up, so a PR followed shortly after:
654 ROB CONERY
Code reviews with GitHub (and most other Git-based tools) are
isolated to the files that change for a given commit, which is
wonderful. As a reviewer, you know exactly what has changed and can
assume that all other code has remained the same.
When you receive a PR, you’re given the change to review the changes
if you like. If you don’t have time or want a second pair of eyes, you
can also request that someone else add their review too, by clicking on
“Request” under the “Reviewers” section:
THE IMPOSTER’S ROADMAP 655
The incoming PR has two separate commits, each with a link. When I
click those links, I’m taken to a diff that shows exactly what was
changed and how:
Here, I can see exactly what’s going on. Line 47 is checking for a
variable named SEND_FROM on the environment, and I think the
only response I might have here for that variable name.
Right now, I’m looking at the changes for just one commit, but I can
view them all by changing the selection:
This can make reviews much easier to navigate as you can see
everything at once.
THE IMPOSTER’S ROADMAP 657
Let’s take a look at the code changes. This red and green striped file is
called a “diff ”, which you’ve probably heard of, and is the “difference”,
or before and after, for this file. The red lines are ones that have been
changed, and the green lines are the changes.
If I hover over a line number (any color), I’ll see a big blue plus icon
appear, which tells me I can add a comment:
I’ll add a message here, and make sure that I click “Start a review” as
that’s what I’m doing.
Note: if someone requested a review from me, the review would already be
started, assuming I accept. Also: you can leave a comment on the code without
doing a formal review, which will hold up the merge, by using “Add single
comment”.
There’s only one change with this commit, so I don’t need to add any
more comments, and I’m done reviewing this commit.
Up on the top right of the page, there’s a button that will wrap things
up and let my alter ego know that I’ve reviewed the code and that I
have some change requests:
658 ROB CONERY
This is where diplomacy and the “styles” discussed above come into
play. Let’s go through a few different responses:
Each of these represent a valid code review, even if they have a tinge of
negativity. Let’s discuss!
people) to do all code reviews. GitHub lets you set policies on this,
which we discussed in a previous chapter, one of which is “each PR
must have two reviews”.
Note: This is where AI can really help you. If you’re unsure of your tone, throw it
into ChatGPT (or whatever you use) and see if it can be reworded. If you’re
unsure, just use fewer words and be direct with an emoji at the end. Never fails!
inline comment. Super useful! My alter ego can reply here, or just get
to work.
Tip: just get to work. Replying with a thumbs up or OK isn’t needed unless you
work for someone who has asked you to acknowledge their comments. If you’re
unsure, let your lead know (or your team) that no reply on a PR is implied
acknowledgment.
My alter ego made the changes I asked for and updated the PR, adding
a comment for me:
They also clicked “Resolve conversation” as they did what I asked. You
can change who has the right to do this, but in general, it’s good form
to let the reviewer resolve any change requests. For small changes like
this, it can save time if the coder resolves instead.
You might wonder why outdated is there next to the file name. This
is letting us know that the code in that diff no longer represents the
actual code in the codebase.
Here, I can navigate each commit, including the latest one, to see what
has changed. The very last commit is what I’m interested in:
662 ROB CONERY
Looks good! Before I close out this review, I might want to navigate
through the commits using the dropdown in the top left (outlined).
This is, once again, why small, targeted commits are always a good
thing — they’re easy to review! The smaller they are, the quicker they
get approved.
Speaking of: let’s approve this. Once again, I’ll click the “Review
changes” button in the top right, but this time I’ll toggle “Approve”.
There’s no need for a comment here — so I’ll keep things terse and
speedy and just let it rip!
THE IMPOSTER’S ROADMAP 663
Back on the PR, you can see the timeline has updated, including a build
run, which we’ll discuss in a few chapters! We wouldn’t want to
accept a PR that broke the build, would we? If the build failed, we
could address it in the same way — using the review tools.
Add a Dash of AI
As I write this chapter, GitHub just rolled out Copilot for comments
and PRs if you’re a maintainer of a project. It works pretty well, and
I’m sure it will evolve.
It takes a second, but once it’s finished, the comment box is filled with
a detailed explanation, complete with links:
664 ROB CONERY
Not a bad summary, even if it’s a bit verbose. If I'm a maintainer, this
can be incredibly useful for creating PRs from the start.
SUMMARY
You’re here to ship code, which is the biggest impact you can have on
your company. The next biggest impact you can have is to help others
do their best work.
As a lead or senior developer, that’s one of the major roles you will
play. By mastering the art of the code review, you can, quite literally,
change the course of your project and also change someone’s career
and therefore their life.
This isn’t hyperbole! It’s tempting to think that I’m exhorting you to
be kind and thoughtful, but I am absolutely not! The captain of a ship
does not need to be kind to be a good captain — they need to be effective.
That doesn’t mean yelling at people either, it means clearing blocks for
them and helping them to write their best possible code.
If people start requesting code reviews from you, it means they trust
you. Which means you will be the boss in short order.
TWENTY-FIVE
OH, RIGHT, DOCUMENTATION
NO ONE LIKES CREATING
DOCUMENTATION, BUT WHEN IT’S DONE
WELL, YOU’RE A HERO
P
lease don’t skip this chapter. I know you’re tempted to
because I was tempted to not write it. The only thing worse
than writing docs is writing about docs!
That said, I think I can make this more interesting for you and your
project. Good docs are a sign of a healthy project, which is a sign of a
healthy process, and that means good leadership.
I know, it’s probably not motivating you, still. Let’s keep at it, though,
and see what I can come up with, which will be in two parts:
Types of documentation.
Tools for documenting things.
Simple enough! And yes, I’ll keep this chapter short, but hopefully, I
will also make it exciting!
future who are going to work with your application. This is a different
concern than end user documentation, which describes how to
actually use what you’ve made. That’s important too! But I’m not
going to get into that here, as that is an entirely different discipline,
and a valuable one at that.
Tailwind CSS) and I’m writing about things that I think the end user
(the public) will want to know, when using the application we’ve
created.
I’ve gone through this tutorial, which is famous for being thorough
and written by a human for other humans.
I have read all of these as well. Like Django, the text is straightforward
and human, not a dry wall of procedural nonsense.
My point: let your freak flag fly! Have some style (without trying to be
too cute, of course) and remember that your readers have no idea
what’s in your head, but are here because they like what you’ve put
together and want to know more!
STRATEGIES
The guides above, including the site I created, are online documentation,
but that’s only one type, or “strategy”, that you need to consider. Let’s
take a look at a few more.
Code Comments
That’s it. Short, concise text that lets the person reading the code,
often the reviewer, why that code exists, written the way it was. This
is a time-saving feature, mostly because reviewers (if they agree with
you) won’t create an issue, and we all save time.
Tagging your code helps you remember where you need to go back and
fix things. Most editors and IDEs will help you with this, adding
bookmarks that help you click your way back fast.
670 ROB CONERY
Long form comments are there to help future you understand what
you’ve created. They’re a journal, of sorts, which is a great way to
think about it.
Stepping back into a project after a long time away can be difficult,
frustrating, and discouraging. I think this is why so many people
rewrite their applications so much. They can’t remember what they
did (nor why), and they hate their code, like many people can’t stand
the sound of their voice.
This is still a bit terse, but it does convey why the Checkout class
exists, that it’s a Model, and what fields do what.
That might seem like a lot of effort, not mention extra noise in the
code, but look at the results:
If you publish your code to Hex, the Elixir package manager, you get a
“Hexdoc” that’s generated for you, so people can read all the fun
things you added in your long form comment.
THE IMPOSTER’S ROADMAP 673
It is, however, better than nothing. Barely. Let’s see what other
choices we have.
README files
Dapper is built around the idea that writing the SQL you need, in your
code, is just fine. I like SQL and I don’t disagree with this idea, but I
also like a little help now and again, building SQL from classes,
structs, or maybe a dynamic object or two.
As it turns out, there are some plugins you can add to Dapper, one of
which is Dapper.Rainbow. Let’s take a look.
Welp… there goes that idea. In the team’s defense: Dapper is pretty
dang simple and if you “get it”, you can likely figure out what it’s
going to do. I could install this package and probably use intellisense
to figure out how the CRUD (Create, Read, Update, Delete) functions
work. On the other hand… it doesn’t take that much time to kick up a
README, does it?
README Tools
THE IMPOSTER’S ROADMAP 675
This is interesting and useful, as are the options to add a license and a
.gitignore file… but it’s also a bit lacking:
Just the name of the repo and my description. What comes next?
676 ROB CONERY
If you need some more help, try a tool like readme.so from Katherine
Oelsner, a senior engineer at GitHub:
THE IMPOSTER’S ROADMAP 677
USING AI
Most code editors have some form of AI to help you, such as Copilot
for VS Code. You can ask Copilot to generate the start of a README
for you by using the @workspace chat participant:
678 ROB CONERY
This is a good start, but you’ll probably want to work on the prompt
and keep generating a few more times to get something useful. Which
you should then augment to sound human.
The Wiki
The first thing you want to do is head over to Settings for your
repository and make sure that Wikis is turned on:
THE IMPOSTER’S ROADMAP 679
This can be scary, but as with most things, it’s only a problem when
it’s a problem, right? Also: contributors have to be logged in to
GitHub, so if someone defaces your documentation you can report
them.
My example here is a bit empty as I don’t use the wiki for this
repository, but here’s someone who does! This is the wiki for pg-
promise, a Postgres query tool I love:
That’s a TON of documentation, and it’s right there next to the code,
right in the repository.
GitHub Pages
If you have a project that needs a little pop, GitHub Pages might work
well for you. By “pop”, I mean clean design, easy to read, and its own
domain.
Like this:
THE IMPOSTER’S ROADMAP 681
This is the Guidebook theme from the Bootstrap CSS folks, and it
costs $49. I think that’s worth it because I’m not a CSS person. You
can buy this theme and then plug it into the Jekyll static site
generator, which is the application behind GitHub Pages.
You don’t need to use Jekyll, however, you can use whatever static
app you like — as long as it doesn’t require a server. GitHub Pages,
you see, runs inside your repo from a special source, or a special
branch.
That’s it! Just a simple markdown file with some placeholder text:
THE IMPOSTER’S ROADMAP 683
This is how Jekyll works with GitHub Pages. It looks for Markdown
files with names that correspond to URLs, and builds out a static site
for you.
This site doesn’t have any pop, however. We can change that by
adding a few directories with templating and a theme, like Just the
Docs, which is free.
Jekyll started out as a simple blog application, but you can do all kinds
of fun things with it, and I’ll leave it to you to read up on the
684 ROB CONERY
That’s what a Jekyll site looks like. I could pop this, for the most part,
into my /docs directory, and it would build just fine. I have also set it
up to be served from a custom domain, which is handled by
Cloudflare:
I love Cloudflare. I’m on the free plan, and they still offer free SSL
certificates through a proxy that you don’t need to install anywhere,
THE IMPOSTER’S ROADMAP 685
they just work. That means that my old blog, which is parked at https://
blog.bigmachine.io, will work just fine.
DISCUSSION: GENERATORS
As we saw with the Hex toolset above, you can generate
documentation from your code. Some of it is pretty nice looking, too,
but they all share the same issue: they don’t read very well.
I like this summation, which I read on Reddit just the other day:
686 ROB CONERY
Swagger-like Tools
Sometimes people want to understand your API and don’t need the
full backstory of how the application was written. This is end-user
documentation, to be sure, but if your API is going to extend
someone’s application, then something like Swagger can be extremely
helpful.
For internal projects, this could easily be all you need for new
developers. Clicking on one of the routes, you see a lot of information:
THE IMPOSTER’S ROADMAP 687
Setting this up means writing some additional code, but it’s worth it if
you ask me:
688 ROB CONERY
This is ASP.NET Minimal API, and as you can see, I’ve chained on a
method that documents the API using Swashbuckle, an open-source
project that builds out Swagger manifests. Swashbuckle is smart
enough to understand the request and response types too, so it builds
out examples and other documentation.
There are other choices out there, but Swagger (now OpenAPI) is the
most widely used.
Docusaurus
Using it is simple. You have to have Node installed, of course, and you
can get things setup using a single command:
If you don’t know, npx is Node’s “just in time” binary installer, which
means you can avoid installing global tools you might not want. This
is setting up a project called my-website using the classic template,
which they recommend.
Once you do this, you run npm start from within the directory, and
you’re off and running:
690 ROB CONERY
At the end of the day, this is simply generating a React site for you
that processes Extended Markdown (MDX), which allows you to do
fun React-y things with Markdown.
Your documentation lives in the /docs directory, and you can set up
navigation however you like. If you’re a React person, this could be
fun for you.
THE IMPOSTER’S ROADMAP 691
This site is also a React application, and it’s easy to use. I’m not a
React person, either, but the documentation for the template is
extremely thorough and simple to read. Same as Docusaurus, your
docs are in Markdown:
692 ROB CONERY
ReadTheDocs
The idea is simple: you create a /docs directory and hook up the
service, which will then cycle through your docs files and put together
a typical documentation site. You can extend it with themes, run rules,
and do all kinds of interesting things, which is great because if you’re
not doing an open-source project, the service costs $50/month.
Is this better than GitHub Pages? That depends on whether you want
to keep your docs on a separate service with a lot more control. I like
the simplicity of GitHub Pages, so I would probably go with that.
Gitbook
If you just want an internal knowledge base and need to keep things
private, Gitbook might interest you. It’s not free for businesses, but
the pricing is reasonable for what it does.
Ironically, years ago I used Gitbook as a starting point for The Imposter’s
Handbook. I loved the idea of writing a book in Markdown, using
GitHub for version control. The experience was… interesting.
The whole idea was that you wrote this book, and Gitbook would
generate a PDF and EPUB file for you. The problem was that it was
694 ROB CONERY
ugly. I think others agreed with me because the service pivoted years
back and are now concentrating on beautiful online documentation.
Gitbook’s main pitch is that you can integrate with other “knowledge
platforms” (Slack, Jira, Google Analytics, etc.) to build out a
knowledge base for your project. You can also focus on creating
documentation using their editor, which, I have to say, is fascinating.
In summary form: you create a “space” in Gitbook where you and your
team can collaborate and build out a set of documents, like this one:
THE IMPOSTER’S ROADMAP 695
The editor will look familiar to you if you have previously used a
service like…
Notion
It’s easy to add this to your space and then invite team members,
although that’s where Notion makes its money, and it’s worth every
penny if you ask me.
The best part is that you can publish your documentation to a static
website:
THE IMPOSTER’S ROADMAP 697
You can change the look and feel all you like, adding graphics and
video embeds and more. You can even set up your own domain, which
is wonderful.
Notion gives you a lot for free, but after that, you pay $8/mo/user for
smaller groups and $15/mo/user for larger businesses. You can do
internal knowledge management as well as external documentation
easily.
I know web apps, however, so this is easy for me. If I’m on a team, I
would delegate this to someone with web experience, making sure
that the entire team understands the importance of having something
that looks good because, well, mediocrity sucks, doesn’t it!
Part of every sprint would include documentation for the /docs that
we could discuss in the post. Personally, I wouldn’t focus too much on
the quality of the documentation as that will change as the project
takes shape. The last thing you want is for documentation quibbles to
hold up the sprint — but it’s a good idea to make sure your
documentation matures, and is versioned, along with your source.
Bloated docs are a good problem to have, too, and if you get to that
point, good for you! You should be able to hire a technical writer to
build out a Notion page for you — that’s what I would do. I like
Notion for docs, if you can’t tell!
T
here used to be a natural boundary between programmers
and IT people, which is as it should be. IT people make rigid
rules about what can happen where, and programmers do
their best to bend or break those rules because rules don’t apply to
them.
I have more than a few ops friends, and every time I tell them some
horror story about my app crashing in production, they look at me
quizzically: what was your monitoring stack?
I’m sure they’re going to give me a hard time for putting this section
at the back of the book, too, but why break form?
700 ROB CONERY
Things crash. It’s a truth of the universe that you can’t change. What
you can change is how fast you can get it back up and running. That’s
where a good monitoring plan comes in, ideally one that doesn’t
involve waking you up at 3am!
That’s my feeling, anyway. Let’s start from the outside and move our
way inward. We’ll take a look at monitoring solutions that you can use
for just about any platform, and then we’ll dig in to each of the
considerations from the list above.
They have a generous free tier, but as you might imagine, the cost
goes up as your team and application grows. I think it’s worth every
penny! When I ran my business on Rails (Tekpub.com) many years
ago, New Relic saved my butt quite a few times.
It’s an all-in-one service, which means it tracks all the metrics that I
702 ROB CONERY
These images are from New Relic’s blog, and highlight how you can
combine whatever information you need into your dashboard. I love
this… and it also scares me. This is the kind of thing I lose days on.
The numbers!
The difference between the two services comes down to “deep” vs.
“wide”. New Relic’s focus is your application, and how it’s running in
your infrastructure. Datadog is the opposite: its focus is your
infrastructure, and how well it can run your application.
There are plenty of other services out there (Scout, Skylight, and so
on) but my experience is with New Relic, and my focus for this
chapter isn’t the service itself, it’s what the service is telling you. That’s
the important part.
It’s also worth noting that you don’t need to go with an all-in-one.
There are individual open-source projects you can plug in to help you
understand what’s going on. That said, having a hosted service is
704 ROB CONERY
usually the smart choice, as the data it gathers can be used across all
the metrics you need.
APPLICATION PERFORMANCE
Application Performance Monitoring, also known as APM, is typically
my focus when thinking about monitoring. It’s one of the major
reasons I went with New Relic many years ago — I think about things
from my application’s perspective.
What does APM even mean, however? For us, it means 4 things:
Response time.
Requests/minute.
Error rates.
Query performance.
Our service should show us these things in a single dashboard, like so:
THE IMPOSTER’S ROADMAP 705
This is New Relic’s APM dashboard and tells you everything you need
to know at a glance. I’m running this Rails application locally (it’s the
Rails version of my bigmachine.io site) so the traffic is slight, but
hopefully, you get the idea here.
A term that you’re going to get to know during your career is “Service
Level Agreement”, or SLA. This can apply to end users, but mostly
applies to applications that are themselves services. You want to be
able to guarantee your customers a certain degree of uptime, which is
usually expressed by percentages, something like: “95% uptime
guaranty”.
But how do you know you’ve hit that number? That’s what a good
monitoring solution will tell you:
706 ROB CONERY
I love this report. We’re breaking down the weeks of the year and
showing what % of our application’s performance is satisfactory,
tolerable, and frustrating. Looks like my app is doing pretty well.
For this report to make any sense, however, we need to have our
Service Level Objectives (SLOs) defined somewhere. You can define
these yourself, or New Relic can take a swing at it for you with
“typical” industry standards of 95% and 99% uptime.
Bottlenecks
There are just some things that happen slower than others, and this
can cause a traffic jam inside your application. Slow queries, poorly
maintained open-source packages, or just crappy code can cause this
— but how do you know where it is?
Your monitoring service should be able to tell you. Given New Relic’s
deep integration into your code, we can run reports like this:
THE IMPOSTER’S ROADMAP 707
This is from my live site, taken just now, and shows the pages with
the slowest (or “most time-consuming”) response time.
You can click on each of these transactions (or “pages”) to see a more
complete breakdown of what took so long:
Here, I can see a rollup of the entire stack trace over time, and decide
where I might want to improve things. Looking at this, I already know
what the issue is — I’m showing the last 50 orders on the index page
(it’s an admin page) which takes a while to render. Probably better if I
show just the last 10.
We’ll get into profiling your application more in the scaling chapter.
Watching someone who knows what they’re doing is truly an art, and
when they resolve the problem, they become a god.
TRACKING ERRORS
The last thing you want is a potential customer emailing you or,
worse, tweeting out an error with your application:
THE IMPOSTER’S ROADMAP 709
It’s happened to all of us, especially me. Errors are going to happen,
and they usually happen because:
Each of these has happened to me, more than once. I had a customer
from Japan use Kanji for their name, and my database wasn’t set up
710 ROB CONERY
for UTF-8 (I was using SQL Server’s varchar when it should have
been nvarchar. Silly error on my part). Shopify changed their API
once without telling me, and all inbound orders began to fail.
I have had my disk fill up due to runaway log issues (from MySQL)
more times than I care to admit.
I should have known what was happening. Let’s take that one step
further: I should have known it was going to happen and prevented it.
Once again, a good monitoring service can spot these things and help
you out.
New Relic (and others) will monitor your infrastructure for you,
which could be your own server, a Docker container, a VM, or
Kubernetes. It examines CPU, RAM, disk activity and disk usage, and
will let you know if anything doesn’t “look right”:
Setting Up Alerts
It’s good to get to know these conditions because figuring out who
gets notified how and when is paramount. A good service will help
you with this, making sure that the right people get notified at the
right time.
The first thing to notice is that no one will be notified unless there are
more than 10 errors during a 5-minute period. I think that’s a bit
high, so let’s dial that down, shall we?
There’s an edit button just off-screen in the image above. I’ll click that
and tweak how this incident is triggered:
THE IMPOSTER’S ROADMAP 713
The nice thing about this screen is that the incident graph just above
will change as your values change, showing you what you would have
been notified about in the past.
Now let’s head back to the alert screen, and I’ll select “Notifications”
from the tab at the top of the screen:
This is where New Relic and services like it start paying for
themselves. I can see how many times this error has happened and if I
click on it, I get a full stack trace:
There’s even a place to discuss the issue and how best to solve it.
We’ll discuss triage in the chapter on Disaster Recovery, but that is the
next logical step: how do you address incidents when they come in?
You can’t just wing it, you have to have a process in place. Duplication
716 ROB CONERY
Consider the moving parts between your user and your application. As
I sit here and make a request to my main site, bigmachine.io, here’s
what’s happening:
The internet is a modern miracle and truly one of the wonders of the
world. If you think about the ridiculous number of services that need
to be running and healthy just to get my request through to my code — it’s
mind-boggling.
THE IMPOSTER’S ROADMAP 717
Two years ago, I set up monitoring for a hosted Docker service with
one of the major cloud providers. I turned on Health and Monitoring,
added my email to receive alerts, and promptly heard nothing when
my container failed to start. It turns out I was using the wrong
monitoring, which… of course I was. I’m still not sure what the
“right” monitoring would have been.
This is another service that New Relic provides, and why I love them:
718 ROB CONERY
Let’s say it’s late at night, and you’re about to go to bed, when your
phone chimes (you have a rule to let your monitoring service through
your Do Not Disturb if it’s a critical issue). You mutter “boundaries”
as you wander to your phone, and there it is: your monitoring service
is alerting you to an outage.
If it’s one of your servers, sleep is going to wait for a while. Unless, of
course, you have a monitoring service that can tell you exactly where
the problem is:
THE IMPOSTER’S ROADMAP 719
I think I mentioned above that I’ve had servers crash, and it was
extremely annoying. I was running my Rails app using Dokku, and the
MySQL logs filled up the disk — I still don’t know why. It took 6
months for this to happen, and thankfully I could up the size of the
VM to make the problem go away.
You know what would have been better? Having a monitoring service
that warned me ahead of time. This is actually when I started using
New Relic, and for this very reason. Just 3 months later, Redis was
about to tip over because I was using it for shopping cart data and a
few other things and I forgot to set an expiration for the data. Oops. I
720 ROB CONERY
got an alert from New Relic that told me my caching server (Redis)
was at 80% of its RAM, and I should probably fix that.
This will happen to you, at some point, and my hope with this chapter
is that you see the value in having a monitoring service without me
needing to convince you. Handling problems before they become
problems is going to make you look like a champion — and that’s a
good thing because you are a champion, right?
LOG ANALYSIS
Redis is one of those wonderful services that you fall in love with the
very first time you use it. It’s so simple and so fast, and I know many
people who use it as their application data store without a second
thought.
If you don’t know what it is: Redis is an in-memory data store that
uses various data structures to store its data. With a relational system,
you have tables with rows and columns, which is the only data
structure you’re given. Redis gives you simple key/value structures,
hashes, lists, sets, and more. It really is a fascinating system.
That said, most people use it for caching and session management,
which makes good sense. The trick, however, is making sure you
understand your traffic and site usage well enough to manage Redis as
you need. The metric you really care about is concurrent active users,
who are people actively using your application to do whatever they do.
Most caching and session libraries will have default expirations built
in. Sessions, for instance, are typically 20 minutes long. Caching is
something you tune yourself, and we’ll get to that in a later chapter.
THE IMPOSTER’S ROADMAP 721
So, you take your best guess, set things up and hope for the best. Or,
maybe, since you’ve read this book, you’ll do the next best thing
which is to run log analysis to ensure your measurements are correct.
We’ve discussed logging throughout this book, but this is where the
payoff happens. As I mentioned before: logs tell you the story of your
application. Or, more accurately, the story of how your users use your
application.
There’s a lot in there, and hopefully, you’ve set your logs up to record
the things that need recording. We covered that in a previous chapter,
but here we are, after we’ve deployed, realizing that we need our logs
to tell us more about our caching strategy.
That’s OK! Logging is an ongoing thing, and we can adjust what we’re
doing on the fly. We can also ensure that we’re using our monitoring
solution to its full extent:
These are the logs for my Rails application, and as you can see, they’re
pretty verbose and that’s fine — I would rather log too much than too
little. Well, sort of. It can be expensive if you log too much but what
we have here is fine.
722 ROB CONERY
At this point, your monitoring service should let you sift and query
your logs, even parse them according to some rules. If you don’t like
this query screen, you can export a subset of your logs to Excel or
some other spreadsheet, transforming the logs into something more
meaningful to your research.
The first thing we might want to know is our cache hit rate. How often
are we using the thing? The next is cache expiration rate (also called
cache eviction). We can know this exactly by analyzing our logs. We
might find that we’re over caching things, which is putting an undo
strain on Redis, so we might decrease our session time to 10 minutes,
and reduce the expiration time of our other caching efforts, or remove
them entirely.
So, how did I resolve my issue with Redis? I immediately bumped the
size of the VM and I reduced the session time from 20 minutes to 10.
I also realized, as I was discussing above, that I didn’t need to do the
model caching (I was using Rails) that I was doing. My web and
database server will be able to handle the load just fine.
Oh, and I added expirations to my cart data. That was extremely silly.
SECURITY
I hesitated adding this section to the “monitoring” chapter as security
is a world unto itself. That said, it is absolutely something you’re
going to need to think about, at some level.
If a user is messing with your site, there’s not much you can do aside
from hoping they don’t find something and, if they do, that they’ll let
you know. This, believe it or not, has become an industry, and an
annoying one at that.
There are scanning tools you can use (I’m purposely not going to link
to them) that will scan a website, DNS records, and a web server,
looking for vulnerabilities. Occasionally you find good ones, other
times you find ones that are, shall we say, “nice to haves”.
If you reply with a “Positive response”, you’ll likely get a request for
money so they can tell you how to fix a DNS record that isn’t filled out
“correctly” (usually an SPF record ending with ~all).
If you don’t pay, they won’t tell you what they find. Often, it’s
meaningless, but occasionally, it isn’t, which is a shame. I do find,
however, that the people who find an actual problem will simply tell
you and not ask for money.
If you knew, beyond a doubt, that the data in your database was going
to be stolen, what would you do differently? Keep that in mind as we
imagine this at a deeper level.
Hi, my name is Troy Hunt and I run a service called “Have I been
pwned?” That tracks data breaches and compromised passwords.
Unfortunately, you might be in for a very bad day.
Note: Troy sends emails in the context of each breach, and what I wrote above is
just a representation.
At this point, your emotions will follow a typical flow: denial, anger,
depression, acceptance. I think most people who receive emails from Troy
do, indeed, have very bad days.
You look at his service, decide this could be a legit email, and reply,
letting him know you’ll help as needed. If you asked him to get
stuffed, however, he would reply with a cordial email letting you know
he’s going to go public with it anyway, and you better do the right
thing.
This isn’t Troy being a jerk. Just about every country (and in the US,
all 50 states), has legal requirements for disclosing data breaches, and
you could be in big trouble for ignoring these laws. If you do have a
breach, you need to notify your customers in a timely manner, notify
law enforcement, figure out what was breached and then notify people
affected before Troy does. Oh, and you should probably speak to a
lawyer or two.
726 ROB CONERY
Let’s assume you did almost all of this, aside from emailing your
customers, whose data is now in the hands of some hacker.
What are you going to write? Your lawyer will help, to be sure, but
when it comes to the data that was stolen, what data protection
measures will you describe? What data did you need to store?
This is far more important than monitoring and, like so many things
in this book, I could spend countless pages detailing “how to store
data securely”. Instead, I’ll offer this summary:
The big thing here is how passwords are stored if you use them.
Encrypting all personal information and keeping the key safe (in your
cloud’s key vault, hopefully) will help, but if your entire database was
nabbed, stealing your key is likely a matter of echo $SECRET_KEY. If
you’re using a secure key vault, that’s great!
Denial of Service
People have agendas, and occasionally, you become part of their story
and find yourself awake at 0200, wondering why your application is
being picked on. Once again, however, we need to move on from why
and get straight to dealing with it.
THE IMPOSTER’S ROADMAP 727
I’ve been using them for many years and I love the service. I’m on the
free tier (I haven’t needed their full suite of services), and they host all
of my DNS for me, and also provide my web apps with a free SSL
certificate. So easy to use, and if I’m ever DDoS’d, I can toggle a
switch:
728 ROB CONERY
BUSINESS REVIEWS
Monitoring isn’t just for the engineering team. There is a lot of
business insight to be gained from careful log reviews and traffic
analysis. Google Analytics is usually where people go for this kind of
information, but it’s not totally complete given the rise of script
blockers and secure browsers, like Brave.
A monitoring system like New Relic can be set up to handle all kinds
of analysis, even for use with marketing:
I didn’t do any of this by hand, it’s a dashboard that New Relic offers
you with a single click:
730 ROB CONERY
This is where log reports and analysis start overlapping with business
analytics and, if I’m honest, the two don’t really mix. We’ll get into
reporting in a few chapters, but for now, I will say that monitoring
reports for checkout are still quite valuable. This is a sales report
that’s more for engineers than anything, focused on page load times,
transaction elapsed time, etc.
SUMMARY
There are so many great monitoring suites out there, including open-
source projects (like Grafana) that allow to you configure things as
you need. I love open-source solutions, but if I’m honest, I’d rather
pay someone to run monitoring for me. This is my opinion, of course,
and I suppose it’s also informed by having used services like New
Relic that I already know. If your servers are in your data center, then
Grafana (and tools like it) is a great choice.
In the next chapter, we’ll get into Disaster Recovery plans, and what
THE IMPOSTER’S ROADMAP 731
B
ack in the mid-2000s, “Web 2.0” was emerging from the ashes
of “Web 1.0”, otherwise known as the DotCom boom, where
I got my start in the tech industry. Wild times, back then, but
that’s for another book.
Web 2.0 was all about groovy scripted languages, like Ruby and
Python, and their equally groovy web frameworks, such as Rails,
Sinatra, Django and others. Building with these new frameworks was
fun because the development experience was dramatically better. You
could prop up a full commerce site (for example) in weeks instead of
months, and get paid that much sooner.
That, friends, is the dismissive nonsense that has plagued the Ruby
and Python communities for years, including JavaScript and Node in
more recent years: they’re cute, but they don’t scale very well.
Like so many things in the programming world, all context is lost due
to the abuse of the word itself. In short, scaling can mean increasing:
When you talk about scaling for capacity, what you’re hoping for is the
flattest response line you can get:
734 ROB CONERY
Those scaling measures kick in as the requests go up, which helps the
response times stay “flat”, which is what you want.
I’m going to bold this because if you take one thing away from this
chapter, I want it to be this: most of the time, applications aren’t
slow because of the CPU. They’re slow because of I/O.
fast, but if it’s waiting for a SQLite query executing on a small free-tier
cloud image, all that speed is meaningless.
Ryan Dahl, the creator of Node, understood the I/O problem very
well:
When more people come in, you get crappy scaling because our
server/cook/bartender gets busier and busier. They may have been
736 ROB CONERY
smart and prepared (cached) things beforehand and can keep service
limping along, but not as well as a restaurant with two people.
Fast-forward to today, and platforms like .NET and Java have async
facilities built right into the frameworks. Other languages (like Ruby
and Python), have done their best to build in optimizations where
they can as well.
That said, things have changed quite a lot when it comes to compute
power. If you don’t follow Kelly Sommers on Twitter, you should. She
can be a bit spicy at times, and quite challenging, but she definitely
has opinions:
THE IMPOSTER’S ROADMAP 737
There is one thing, however, that goes beyond diplomacy and tact.
There is only one way around this: numbers. You have to have them;
otherwise you have no idea what you’re talking about. By “numbers”,
I mean:
Unfortunately, that’s often not the case. I would offer that quite a few
problems exist between our ears, and not on the screen. We write
code “defensively”, and think about things that could happen — and
this is a great skill to have as a coder. This is figurative problem
assessment, not practical.
What happens, however, if you didn’t see that large bus barreling
toward you? You somehow managed to step off the curb, right into the
path of a bus that’s now screeching to a stop…
What do you do then? Did you have a plan for a getting out of the way
of a speeding vehicle, or just a plan to look both ways? This is
practical (jumping backwards) vs. figurative (looking both ways). In
the short time you have before possible impact, you might want to
answer some very pressing, very direct questions:
Your amazing brain might also snap a judgement on the forward speed
of the bus, realizing that it will stop many feet away from you, so no
action is necessary.
I just snapped a screenshot of my live Rails app that I’m using for my
production site at bigmachine.io:
A single row query like that should return in 1ms or less and, as a
740 ROB CONERY
Why yes, yes I did. Was this an actual problem for my users or my site?
Well… no, no it wasn’t. But it could turn into one!
When you think about scaling, you need to have a problem that’s
clearly a problem (error, low Apdex, slow throughput, etc.). You need
to have numbers to isolate and understand what service is causing the
problem, and then you must propose solutions that are, themselves,
measurable.
I can guarantee you that, if he were to read the graph above, I would
have an issue created for improving the response time of that
transaction. No crashes, no user complaints. Just a lead that doesn’t
like things being more than 10ms ever.
When this happens, it’s up to you to dig into the logs and make sure
what they’re seeing is real. If it is, and your boss agrees, then you have
a problem that you need to fix.
Since I’m the lead, the boss, and the programmer for bigmachine.io,
the meetings are short and the action straightforward when it comes
to > 100ms transactions: fix it with an index!
742 ROB CONERY
Our average page load has dropped now to 60ms or so, and this is
entirely without caching of any kind. I’m using Rails, so it’s possible
to do highly targeted caching, and who knows? I might… but… do I
really need it?
I don’t think so. There’s no bus rumbling down the street, and I need
to focus on the business itself, not how well my site is working. If the
transaction time creeps up above 100ms, I might look into caching, vs.
increasing the capacity of my server.
True scaling problems creep up on you, and when you’re not looking,
will assert themselves in ridiculous ways.
Did I address the problem by doing this? No! Scaling problems are
never resolved. They’re only put off for a while. By “scaling” I
mean both up and down. No use paying for expensive cloud resources
if you don’t have the traffic to justify it, right?
Your Code
It’s entirely possible to write code that accidentally taxes the CPU or
blows up your RAM. Consider this:
This is from my Rails app, specifically the courses page, where I show
all the exciting and wonderful courses I’ve made. Doesn’t look like a
problem on its own, does it? But what is that partial doing, and do I
need to care?
I use a Content Management gem called Spina, which I really like. I’m
using it to handle the Course and Lesson content, with a course
having 0 to n lessons, or “children”. This association is handled in the
gem itself, which is great as it saves me time and code. Unfortunately,
if I want to show summary information (number of videos, sum of
their length), I have to use the Rails associations. Is this acceptable?
Note: You might notice that I’m summing on the ID field, which is silly, but I’m
showing it here to represent what I was doing before I fixed a few things
The crazy thing is: you won’t know this is a problem until you ship
your application, and it comes under load. Even then, things like this
don’t crash, they just slow everything else down, like your database.
I couldn’t stand the idea, so I added fields for duration and video
count to the courses and filled them in. These things don’t change
much, if at all, so hard-coding is fine with me. It wasn’t a problem in
the real world, only in my head.
Increased load on your system (CPU and RAM) will also slow down
response times and, in some cases, cause timeouts altogether if your
web server (Nginx, Apache, IIS, etc.) decides it waited long enough
and here’s a 502 error instead.
Your Platform
If you install plugins, however, that’s when the fun starts. And who
uses WordPress without plugins? I used to use WooCommerce to sell
things but stopped because of what I’m about to show you:
Your Database
You can’t change the way WordPress does things because there are far
too many plugins that rely on the way WordPress does things. In other
748 ROB CONERY
words: they’re stuck with their weird database design, unless they
want to upend the entire plugin ecosystem.
Those last two are very useful, so of course you need to pay for them
on an annual subscription basis. I don’t mind this, most of the time,
THE IMPOSTER’S ROADMAP 749
My point here is simple: you will pay for crappy architecture when it
comes to scaling, especially if the database platform you use doesn’t fit
your needs or is difficult to optimize. This is a hard thing to discover,
especially early on because some database systems are just so simple
and easy to use, you’ll do anything to use them.
MongoDB, in the early days, was exactly like this. Super simple JSON
document storage, but after a year goes by, and you run sales reports,
when your boss asks “are you sure about these numbers?” it’s quite
nice to have relational guarantees behind you.
Don’t get me wrong! There are plenty of great use cases for document
storage. My claim, here, is that any data that will be used to make
decisions needs to be in a relational system. Those guarantees, while
of course not perfect, offer a lot of reassurance.
You can do a lot with constraints and foreign keys that keep you from
disabling future decision-making. Unique constraints help you avoid
overwriting existing records, foreign key constraints ensure that data
needs to exist in another table before a parent table write, and proper
750 ROB CONERY
There are, of course, rules and indexes you can put on systems like
Firestore and MongoDB that will help you replicate the niceties of
relational guarantees. The only problem is that you need to remember
to write these, and then hope that your custom solution is a good one.
If you’re hazy on this, pretend you have a blindfold on, and you have
to search for a given lego piece out of 100 different lego pieces. It’s
possible you could go through all 99 of them until you find what
you’re looking for (a rectangular brick with 12 studs, which is a term I
learned just now).
side leads to the direction you want to go based on the sorting rules,
you aim for the middle of the remaining blocks. You keep splitting
until you find what you’re looking for.
That’s excellent savings, and we’ll get more detail on this in the next
section. Before we get there, we need to discuss something essential.
To use binary search, the data you’re indexing needs to be sorted first.
That sorting is what is going to take up the resources.
If you have a high-write table, like our messages table here, the index
will be updating on a pretty constant basis, which adds load to your
database. You can spread that load out horizontally by sharding your
server, which I’ll get into in a minute, or you can up the specs on your
server so it can do things better, stronger, faster.
Slow indexing can result in another surprising side effect: dirty reads.
This is a term you often hear in data circles, and refers to old data
being returned in a query after good data has replaced it. If you’re a
data person, this might surprise you. Transactional systems (such as
ACID) guarantee that when you receive acknowledgment for a
transaction, it’s durable, which means it’s saved and ready to be used.
The transaction applies only to the table being written to, not its
corresponding indexes. If the transaction had to wait for the indexes
to update, that could end up taking quite a while, and even then, you
have a chicken-and-egg problem. What would happen if the table
754 ROB CONERY
write fails for some reason? The index might become corrupted, with
everyone becoming sad.
This is what’s known as a tradeoff, and every system has them. You
have a guarantee of an atomic, consistent, isolated, and durable
transaction, but you’ll have to wait a few microseconds for the
associated indexes to update.
Your Infrastructure
Let’s recap:
Your code is just text that is compiled into a binary at some point in
the execution chain. What that code runs on, and how it moves from
disk out to the wild beyond, is considered your infrastructure, and
includes:
I could add to this list, but hopefully you get the idea. When you go
through a scaling conversation, it’s a good idea to focus on the exact
problem, using measurements to come up with a scaling plan. That
plan, however, needs to be evaluated regarding the entire scheme —
your infrastructure.
I started out with a free tier offering and was quickly turned around.
WordPress, understandably, needs some RAM and CPU to run, and a
free tier is just not a feasible option.
My plan was to start simply by writing my own script to ping the site.
I figured that I could run requests in a loop to see how fast I could get
to 1000, which I know is not the best way of doing it, but it’s the
simple start I wanted to play with.
There are better tools for this, like Apache Benchmark, but my plan
was to wait until I got to the bigger SKUs (machine sizes) so I didn’t
break anything accidentally.
And then I remembered that Azure, like many cloud providers, has a
limit on virtual disk transactions, which are called IOPS (I/O per
second). If you have a small application, the I/O is also likely small, so
THE IMPOSTER’S ROADMAP 757
So: how do we scale this? We can’t simply bump the SKU, which would
also bump the I/O, we need to consider the entire infrastructure here.
What if we went with a hosted MySQL offering, that doesn’t have the
same I/O limit? Perhaps we could implement aggressive caching with
a WordPress plugin, and we could also go with a flavor of WordPress
(such as OpenLiteSpeed) that boasts some pretty impressive
numbers:
For instance: you can speed up your network throughput from your
hosted VM by adding another virtual network interface card (NIC),
which bumps you 3 SKUs. This will also up your IOPS, but if you go 4
SKUs you can also double your RAM and up your CPU cores, but
you’ll be paying another $400/mo.
758 ROB CONERY
This goes all the way back to your choice of application platform.
WordPress is a hard bit of tech to scale, given the raucous plugin
architecture and wild database design. Scala, C# and .NET are blazing
fast, and Elixir/Erlang are fascinating choices when it comes to uptime
and using in-memory solutions as opposed to disk-based ones (etc.d,
for instance).
It’s when you’re sitting there, staring at your cloud bill a few years
after launch that you start to ponder the Great Rewrite. I discussed
this many, many chapters ago and, at that time, I asserted that one of
the major reasons that companies rewrite their applications is for
financial reasons:
You’re also not going to get to market fast enough with .NET or Scala
simply because they don’t have the generators and convention that
Rails and Django do, and .NET and Java developers tend to be more
expensive.
THE IMPOSTER’S ROADMAP 759
PRACTICAL TIPS
Writing better code and learning how to tune whatever database
platform, web server, message broker, or DCOM server you’re running
is a product of experience. Every approach will be unique because it’s
the result of trial and error with your given system, or infrastructure.
What I’m trying to say here is I can’t go out and investigate “How Perf
Tune Stuff ” and come back here with a list of 10 things you can do to
speed up your app. What I can do, however, is to offer some general
tips that, like DNS, seem to always be in play when you’re trying to
squeeze out a few more RPS.
Faster Code
Writing “faster code” is almost always a myth. Eric Lippert, one of the
people who helped build C#, had the perfect answer to the question
Should LINQ be avoided because it’s slow?:
No. It should be avoided if it is not fast enough. Slow and not fast
enough are not at all the same thing!
Think About IO
CPUs are very fast and compilers are fantastic these days at
optimizing code. What you write is rarely what’s actually running
under the hood. The one thing you can control, which is the thing that
will likely slow your code down, is IO — input/output, or “hitting the
disk or network”.
Database Tuning
If you’re using SQL Server or Oracle, welcome to the land of 1000 perf
tools that aren’t free.
Most databases understand this, and will cache the data you query
most often. With Postgres, you can ask your database what it’s
caching by running a quick meta query:
762 ROB CONERY
Here, I ran my select statement 11 times and only the first query read
the data from the disk; the other 10 used the in-memory cache.
It’s for this very reason that you want to be certain your database
server has far more RAM than your actual data. This is a sneaky
bugger of a scaling problem!
Let’s say you’re running the next StackOverflow which is just like the
first StackOverflow, but people are actually nice and answer your
questions without making you feel like an absolute idiot (please make
this, someone). Your database server might start out with a solid
100G of RAM, which is great, and keeps things delightful and fast.
After the first year, your site becomes extremely popular because, as it
turns out, people don’t like being intellectually abused for simply
asking a question they need to know the answer to so they can feed
their children. Pretty soon, you’ve amassed 200G of data, mostly
because you’re allowing for versioning of questions and answers.
Your cache remains lean and mean, however, because it only retains
what people query the most, which is user data followed by a query
for a single question with its answers. The next biggest query is for
the home page, and then individual tag pages. The total size of the
cache is somewhere around 10G total.
Another year goes by, and your database is now into the terabytes.
People love your site! But you’ve noticed things are starting to slow
THE IMPOSTER’S ROADMAP 763
down, and you wonder what’s going on. Random timeouts happen,
and it feels like your database server is starting to buckle under the
weight of all that data.
What’s really happening is that your cache is now trying to hold over
100G of data and can’t do it because there’s not enough RAM (the
actual number would be less because the rest of the system needs
RAM but, for this example, let’s pretend you have 120G RAM or
something). That means it needs to hit the disk for some of the
queries that should be hitting the cache, which degrades performance
and makes everyone sad.
Have you ever bought a pair of shoes that just called to you? Like, you
had to have them or your day would be ruined! Comfortable, maybe
edgy, perhaps on the nicer side, fun, probably a bit too expensive as
well.
These are the Manganni Costa Leather Low Top Sneakers and cost
$375. I hate the name “Sneakers”, by the way, especially for a shoe
that costs this much money.
I don’t buy shoes that cost over $100. I wear Vans, or flip-flops, and I
might splurge on a pair of Hokas if they’re on sale, which is precisely
why I splurged and bought these shoes 5.5 years ago. I wanted
something impressive for when I visited clients, went to conferences,
or for a nice night out.
These shoes are 5.5 years old, and exceptionally clean. Do you know
why that is? I’ve worn them exactly once. This makes me sad, and I really
should do something about that, but it’s become a thing in my
mind now.
What does this have to do with database indexes? Here’s the deal: you
might analyze, research, and come up with the best reasons to create
an index for your database, only to miss the mark completely and
never actually use it.
To see what I mean: here’s the DDL (Data Definition Language) for a
users table in one of my applications:
THE IMPOSTER’S ROADMAP 765
It’s reasonable to assume that you’ll query this table using the id field
most often, which is why it’s the primary key and has an index. But
what about email? We really should have an index here, and we
should also ensure that it’s unique:
Great, that should solve our query problems! Or will it. It turns out
that one of the queries we’ve been struggling with is looking up users
with the same email domain as the current user. One of our
developers got lazy and thought this would be easier than doing joins,
and they did a fuzzy match:
766 ROB CONERY
Where’s our index? A query plan will show you if it uses an index
rather than a sequential scan, which means “loop every row in our
table”. A sequential scan is O(n), which isn’t good, as opposed to
O(log n), which is binary search as we discussed above, and that’s
what we want.
Indexes aren’t that demanding, honestly, but you have to keep in mind
that their power comes from their sorting. Our idx_users_email sorts
the email addresses and, using that sorting, can run a binary search. If
we do a fuzzy search, or a “contains”, if you will, that sorting doesn’t
matter because the value we seek is within the data, not at the start of
it, so the index is entirely ignored.
I like how Craig describes this, so I’m going to steal his words from
his blog:
THE IMPOSTER’S ROADMAP 767
This is good advice, but how do you know which queries are taking
the most time? This is where the pg_stat_statements extension
comes in! Installing it is easy, and it’s free:
This extension will profile your database, so you want to be certain it’s
installed on your production server so it can profile actual usage. After
a few days, you should be good to go, and you can query it thus
(again, thanks to Craig for this query):
768 ROB CONERY
I know that working in SQL is not fun for many people, but it
becomes fun, really fast, when you can dig into your data and come up
with something actionable!
If you don’t have any indexes, your top queries will jump out at you in
terms of total_minutes of execution. This usually falls inside the
80/20 distribution rule: 80% of your execution time will be from 20%
of your queries.
The great thing about this is that we can also see the SQL that’s being
run, which means we should be able to build a precise index for that
query.
In this example, I would follow Craig’s advice and only worry about
the average_time, making sure to index things that are taking more
than 5ms.
SUMMARY
Scaling your application is likely going to involve the following steps:
The only way you can do this properly is to measure as much as you
can using your monitoring solution, whatever tools your platform
gives you (like pg_stat_statements), and whatever profiler you’re
willing to pay for.
Scaling isn’t easy, and there’s no replacement for experience. You can’t
read this chapter and be prepared well enough to face a true challenge,
so please don’t get mad at me when you’re up at 2AM trying to figure
out why things are breaking.
It’s a good pain, and makes you stronger! Seriously, every scaling story
is a good story, as long as you don’t get fired. That’s my goal with this
chapter: preserving your job, and helping you get through a
challenging, yet extremely valuable, part of your career.
TWENTY-EIGHT
A LOUD BANG, THEN SILENCE
CREATING A DISASTER PLAN FOR WHEN
THINGS GO VERY BADLY
I
think the normal thing to do, with a chapter like this, is to start
off with horror stories. We’ve all had them; we’ve all heard
them. Yes, I’ve dropped the production database. Yes, I have
shut servers down with poorly written code. Yes, I have used the
wrong ENV variables and not known it, causing production data to get
corrupted.
If you haven’t had problems like these, you will. The point of this
chapter, however, is not to scare you; just prepare you.
Things will go upside down for you and your team. If you’re not prepared,
that’s a failure of leadership, which is either going to be yours, or the
person you’re working for. We should be extremely clear on this point:
you will be told to “deal with it later”, “yes, I’m sure it’s important,
but we have to get this feature out or there won’t be an application”,
and one of the classics: “you worry too much”.
The person who says these things to you will also forget they said
them, and you’ll be the one with a target on your head.
THE IMPOSTER’S ROADMAP 771
Tasks are great, but if they’re not assigned to anyone, they are
completely meaningless. It’s not difficult to think about your
application, what could go wrong, and, correspondingly, who gets
pulled out of bed.
Infrastructure
Application
Servers and Database
Networking
And then there’s you. Small issues (errors, bugs, etc.) can probably be
handled without you, but a full disaster that causes an outage? Your
job is to take point and coordinate the triage while simultaneously
keeping the rest of your company informed. If your team is big
enough, you could delegate this to a “disaster management team”, but
your neck will still be on the line, so it’s better if you’re a part of
whatever happens.
We could add more, but let’s start with this simple list. Now the
question becomes: how quickly do we want or expect things to come
back online in each case? It would seem that the obvious answer is
THE IMPOSTER’S ROADMAP 773
So: how long can an outage last? You’ll need to push on this one;
nobody wants to think they’re giving you an excuse to be lazy.
Managers and executives will look at this from a financial perspective,
every minute you’re down increases the support calls from your
customers, and the marketing team is going to run out of things to tell
people on social. This is called you Maximum Allowable Outage, or MAO
in ops circles.
It will be important that you learn to speak “ops” when doing this
assessment because acronyms mean you know what you’re talking
about (this is humor, for my Dutch friends out there).
To figure out your MAO, you need to know your Recovery Time Objective
(RTO) as well as your Work Recovery Time (WRT). RTO + WRT =
MAO. Put in simpler terms: “recovery time” means hardware and
system stuff — how long will it take for a backup to load up or for a
backup system to be promoted to primary. WRT is the people stuff —
how long will it take for humans to tell the machines what to do. This
is a very mechanical way of thinking about things, and every stage will
have an RTO and WRT element to it, so I’ll be moving forward with
the idea of stages.
If you walk in to your bosses’ office and say “our DRP has an MAO of
6 hours”, you might get some side eye. Just be ready to explain your
reasoning, and to shave an hour or two to make them feel better,
which means bringing this plan with you.
BACKUP STRATEGY
The first thing to worry about is your data. Code is the easy part, it’s
versioned and if you lose it, just pull the latest version, which should
be what’s deployed.
Your infrastructure can be replaced. Sure, it will take time, but it’s
certainly not business critical. The only thing that is, is your data. I think
I might have mentioned this once or 1000 times before?
You will have to be OK with losing some data, it’s the nature of things.
Even if you have a replication scheme going (which we’ll discuss in a
776 ROB CONERY
The question we first need to answer is: what is my tolerance for losing
data? For many businesses, like mine, a nightly backup is all I really
need. If something were to happen, and I needed to restore the
database, I might lose some customer and order data, but it’s nothing
I couldn’t manufacture from logs and processor records.
That’s me, however, and I run a simple commerce app. If you ran a
system like BaseCamp, which handles chat and project records for
thousands of customers and is, I assume, churning millions of records
an hour, you would probably want something like an hourly backup
strategy.
The bigger your database, the more often you’ll want to back it up.
That seems to be the rule, but it also presents a problem: where do you
put this data? I put mine on Amazon S3, which doesn’t fill up (I hope),
but I do have to pay for capacity. That’s OK because I also have a
pruning plan.
Here’s a script that does just that. Every data person has their favorite
backup script, so have a Google and look around, see what you see.
THE IMPOSTER’S ROADMAP 777
You can then load it to your database server and crack open cron:
Cloud services, like AWS, Azure, GCP, and Digital Ocean (what I use)
do this as well. I should also point out that Supabase is a service that
uses AWS under the hood, like so many other managed services out
there.
For a pretty decent price ($28/mo) you can get a premium SSD, 2G of
RAM and 40G of space. That’s usually all you need to get started, but
you can up that, of course, to suit what you need.
The nice thing about services like Digital Ocean is that they create a
cluster for you, which means databases with replication setup and
ready to go. If you don’t know what that is, you will in just a minute,
but in summary, it’s a Very Good Thing.
There are other services out there, including some startups like Neon
that are taking database hosting to a whole new level:
THE IMPOSTER’S ROADMAP 779
It’s like having your very own DBA! I love the autoscaling feature and
the fact that they separate the charges for storage and CPU. This
means you can have a big database with many historical records that
you query only once in a while.
The good thing about services like Neon is that you can tweak your
backup strategy with a slider:
780 ROB CONERY
This will cost you money, of course, but if your disaster plan calls for
it, it’s absolutely worth it.
If you have a DBA, make sure they’re the ones doing this. If you feel
brave, or know databases already, go for it. Otherwise: I would leave
this to a managed service, every time.
I’m not going to dig into replication for this book, but you can read
more about how to do it with Postgres right here.
You would rather not find out that your restore file won’t work when
you need it to work. This can happen if your backup script is
incomplete (omitting users and roles, only public schema, etc.), the
file is corrupted, or the file has the wrong encoding. In short: you want
to make sure your backup script does what it’s supposed to.
The next thing that testing will do for you is to find out how long it will
take to restore a full backup. This is a number you’ll need for your
RPO, the machine stuff, and how long it will take to get that file from
storage and load it up, which is part of your WRT.
These are things you want in your disaster plan, as well as a testing
schedule.
Recap
Pick a managed service that you like and is within your cost
range.
Make sure they have nightly, point-in-time (for at least 24
hours), and failover recovery options.
Test the recovery process.
For extra credit, figure out what it would take to move your
managed service entirely if your startup service goes out of
business.
782 ROB CONERY
Once you’ve done this, you can then detail who’s going to do what,
when. It will probably be you in the beginning, so write that down, as
well as the worst-case scenario of losing data in a 24-hour window if
someone deletes or corrupts critical data.
All of that goes in your plan, under the heading of “Data Recovery”.
The RPO will be the time it takes for the recovery itself, and in a
worst-case scenario, moving to a different service. The WRT will be
how long it takes you to make it all happen.
SERVER CRASHES
We discussed this in the Kubernetes chapter, so I won’t retread too
many of those topics here, aside from reassuring you that yes, your
server will crash at some point. By “server” I mean one, or more, of
the following:
Any one of these services can crash at any moment, and you will need
to detail how that can happen, the expected reboot period (RPO) and
what it will take to get them back into service (WRP).
In doing the research, we discovered that the way that the route
reflectors were configured was to set the control plane nodes as
the reflectors, and everything else to use them. Fairly
straightforward, and logical to do in an autoscaled cluster where
the control plane nodes are the only consistently available ones.
However, the way this was configured had an insidious flaw…
You knew Mike Tyson was going to make an appearance here, didn’t
you? He was paraphrasing a much older quote, but I like his version
better.
A DRP is just a plan for who does what, when, and how. It has time
estimates, contingencies (or “Plan Bs”, like moving your database),
but you will, at some point, be flying by the seat of your pants.
The Reddit team followed their plan until the 30-minute mark, when
it was time to make a choice:
This is the absolute worst possible case: when you just can’t find the
damned problem! Thankfully, Reddit had a competent team that knew
when it was time to abandon process and do whatever they needed to
do to figure out what was happening.
My point is simply this: the more complex your infrastructure is, the
more time you need to build in for your investigation phase. I’m a big
fan of simple, but I also don’t run Reddit, so there’s that. If I did, my
THE IMPOSTER’S ROADMAP 785
first order of business would be to hire people like Jayme who can fix
things when it all goes to hell, which it will.
It all comes down to the ops expertise on your team, and your chosen
infrastructure. I wish I could give a more detailed “do this, than that”
but there are just too many variables, aside from “keep it as simple as
possible”.
SECURITY
Can you hear it now? When you hand over your DRP and your boss
asks: what happens if we get hacked? You know it’s coming, so let’s add
that to our DRP too.
“Getting hacked” may or may not be a disaster. If they steal your data,
you probably won’t know for days or weeks (or longer) and you won’t
have an outage, so as far as you are concerned, it’s not really a
disaster. I mean it is for your company, but not a technical disaster.
786 ROB CONERY
If, however, they throw a DDoS attack at you, hijack your DNS, or
randomly change your data (always a fun one), you’ll want to have a
plan. That plan needs to start with steps for prevention.
This is my Rails app, the real one, and as you can see, I have some
packages that need upgrading. This is great, but what about my
server’s ports, software upgrades, and bare-metal things like that?
There are open-source tools you can use if you’re running Linux. Vuls
is one such tool:
THE IMPOSTER’S ROADMAP 787
It’s written in Go and can run standalone, without the need for an
agent or other installed services. You can even run it remotely and tell
it to ping you on Slack if there are issues:
788 ROB CONERY
Being open source, you, as the person running the scan, will need to
know a bit about Linux and how to fix/upgrade things when they
come up. You’ll probably also need to know how to RTFM if you have
any questions.
There are, of course, online services that will do this for you, and all
you need do is run a quick Google search to find one that works
for you.
When your project is small, and you’re just getting going, it’s likely
that security is going otherwise be an afterthought. I’m not saying
that’s a good thing, but let’s be real: your focus will be on getting your
MVP out the door and worrying about the details later.
It’s not difficult to do, and there are many firms out there that
specialize in this kind of thing. In fact, they can do it remotely. They
will look for things like:
THE IMPOSTER’S ROADMAP 789
Your data retention and encryption plan. Are you storing more
than you should, and how is that information protected?
Who in your company has access to your system?
What does that access look like (SSH, login/password, etc.)?
Who is the admin responsible for patching/managing the
servers?
Where are the server credentials stored?
Which ports are open on your servers and why?
I’m not a security expert by any stretch, and there will be many more
questions, which is wonderful for you because that means you get to
have a conversation and learn things. Take good notes! If this is your
first time through one of these, well, that’s valuable experience.
Above all: make sure the final decision of hiring someone is not yours
and, if it is, do it. It’s hard enough coming up with an idea that will
make money — to have it explode because of a data breach, or worse,
is simply cruel.
SUMMARY
A Disaster Recovery Plan causes conversation, which, I think, is more
valuable than the plan itself. It’s good to know who will do what when
things explode, which I’m sure is obvious, but you might be surprised
at how many companies making 7 figures a year don’t do this.
W
e’ve touched on reporting throughout this book, and it’s
fitting that we end on it, as I’m hoping this chapter will
stick with you as the last thing you read, aside from me
“saying thanks and good luck!” in the next chapter.
I wouldn’t be here, writing this book, or doing any of the things I’ve
done if it wasn’t for the strange quirk of circumstances that thrust me
into the world of data and data analysis. I think I mentioned already
that I was a Geologist when I started my tech career. That might seem
like an odd entry point, but it’s worth understanding what happened
to me because a variation of it will likely happen to you.
They did this for years, until the 1990s when the owner tried to sell
the land and an environmental assessment was done, which found a
problem.
The solvents that were dumped down the toilets made their way into
the main septic system, which was made of clay. It should have been
replaced in the 70s and 80s, but it wasn’t, so it was cracked
throughout, which let the solvents from the dry cleaner seep into the
ground, and then into the water table 50 feet (ca. 15 m) below the
shopping center.
1995 was the year that Windows 95 was released, along with Office
95, which made desktop computing a lot easier and more accessible.
Our laboratories started offering Excel spreadsheets for our results, in
addition to paper reports, which is when my boss popped into my
office and asked about me knowing computers.
792 ROB CONERY
You might be wondering why he didn’t run this himself? The short
answer is that computers and their software were expensive back
then, so they were only given to people that would actually use them,
and one of those people was me. My boss was not, and he wasn’t sad
about it.
I created the report he asked for, though I did have to call a friend to
get some help on a few of the formulas I needed. Averages and
Min/Max are pretty easy, but I had a few inspirations I wanted to try
out, so I dug into formulas.
I was tempted to say “of course, I didn’t create the data, the lab did”
but that wasn’t what he was asking. He didn’t know how I was
calculating these numbers, and he also didn’t trust Excel to calculate
the sums correctly. He wasn’t wrong to think these things — precision
errors are notorious with computers, but I didn’t know that at the
time.
He nodded his head and, like Adam always did, whipped out his own
calculator because he trusted me as much as he trusted Excel, which is
not at all. Thankfully everything was in order, and Adam looked up at
me, smiled, and said:
Hello Access
I still got to do Geologist things, but more and more I found myself
sitting behind a computer, pumping numbers into one system or
another. I didn’t want to sit behind the computer at all, but the
position I now held was a critical one, and I loved it.
I taught myself Microsoft Project and created the Gantt chart for the
entire investigation, which we had to print out on a massive plotter
and then tape to the wall behind me. My boss loved the thing,
everyone else hated it, but it was always fun to have people drop by
and look over my shoulder at what was going to happen next in the
project.
By that time, the lawsuit was joined by other businesses that were
upset because leaked solvents were making their way through the
groundwater and underneath their businesses, which put them at risk
for a big cleanup bill from the state. A gigantic mess, as you can
imagine, but having this report helped solve numerous issues and
provided immense value to our clients.
Data Is Life
Many programmers, mostly junior, don’t like this idea because they
like building applications and think that the applications themselves
are worth something. “Without my application, this data wouldn’t
exist!” That’s true. Unfortunately, that’s also a pretty good self own.
As time goes on, your application will change shape, be rebuilt, crash,
come back to life, become loved, hated, and everything in between.
Your data, however, will always be your data and if you lose it, you
might as well lock things up and go home.
Data Is Power
The data your application and monitoring systems collect will be used
to guide your company direction. As great as your code might be, I can
guarantee you it won’t be presented at a board meeting. Unless, of
course, it produces crappy data and your boss tries to deflect blame to
you, showing your code as the culprit (it happens, I’ve seen it).
THE IMPOSTER’S ROADMAP 795
I moved from a simple “Staff Geologist” role to “Data Guy”, one of the
pivotal people on our project. I’m not suggesting you drop what you’re
doing and become a DBA, but I am suggesting that you understand the
critical nature of handling data properly, and understand the power it
has for you and your company.
We’ll get to practical things in just a bit, but they won’t mean a thing
if you haven’t bought in to this truth.
Playing detective, we could theorize that someone just came back and
was preoccupied with a work task. They kicked off their shoes, made
some coffee, turned on some music and started their work — which
was probably writing given the Ulysses app is open on the screen with
the cursor blinking next to a few words. If you’re starting to wonder if
this person is me, coming home from the store with an itch to write
on a Saturday eventing, you would be correct.
Your database contains the same clues that people will sift through,
trying to read the story that they’re interested in. Marketing people
will want to see behavior and responses to their campaigns. Executive
types will want to see sales numbers and who is buying what, when,
where, and how.
796 ROB CONERY
But those are just first step analyses which lead to more questions,
which is where you come in. For instance: your boss might spot a
weird trend in sales based in Sweden. Every Tuesday night at 3AM
there’s a decent spike in sales, and they’re all from Sweden. More
information is needed here, including:
What pages did these people land on, and how long did they
stay?
What other pages did they visit?
How many bought something, and how much did they pay?
Who was the referrer?
It’s worth noting that all of these questions can be answered with
something like Google Analytics, or any other reporting service out
there. Your marketing department has decided, however, that financial
decisions can’t be made using these services due to script blockers,
that are prevalent with your users (programmers).
You run the report, hand over the data, and watch the boss smile as
they go to work trying to figure out why Swedes are digging your app
at 3AM.
The story is in your data, you just need to be certain you have the
clues you need.
Let’s take this to a more practical level, shall we? To illustrate what I
mean by “the data tells the story”, consider these tables:
THE IMPOSTER’S ROADMAP 797
The simplest of job trackers, with people, jobs, and assignments. Now
let’s add some data:
Looks like Darth Vader and Apple Dumpling are feeling pretty alpha,
but there’s more to this:
Let’s tweak our query and use a left outer join so that all the people
in the people table are shown:
THE IMPOSTER’S ROADMAP 799
Aha! Duke Leto is slacking off! Or is he? All we know, from running
this query, is that Duke Leto doesn’t have a job, which means he
either didn’t sign up for one, or wasn’t given one, or…?
Let’s dig in further and run a full outer join, which will show all job
data along with all the people data:
doing a job, but he’s not. Using our data detective skills (which means
we hate coincidence), is it possible that Leto should be ruling Arrakis,
but was removed from the job somehow?
The more you dig, the more you find. That’s the way it is with data
and while I will agree that the demo above was a bit contrived, it’s
also grounded in real experience trying to find a cause for a given
effect.
With the first report we ran, we had no idea there was someone
without a job. We then dug in a bit more and assumed Leto was being
a slacker, and then we dug up a galactic conspiracy thanks to being
able to write good SQL.
If this were a real investigation, we would want more data here, like
Leto’s journal entries, employment agreement, last login time and
more. This kind of thing is going to happen to you: someone at your
company is going to find a weird anomaly that could turn into money
or, worse, help stave off bankruptcy. They will turn to you for more
information, more data, something that will help them string together
the clues to figure out if their bold new plan is a good one, or if it’s
been tried already and failed. And everything in between.
goal in mind, and preparing reports. Scanning logs, for instance, to see
why a user couldn’t log in, builds your data sense.
Hi there, I’m trying to log in to your site and I can’t. Please let me
know when I can.
This is where our data senses kick in! What can the logs tell us? It
turns out, quite a lot:
We can see there are no 500 errors in the last 2 hours, which
covers an hour before the email was sent.
The email logs show success, aside from a few bounces that
don’t involve the user who sent the email.
Checking the database, our user doesn’t exist in the users
table, based on their email address.
This narrows things down quite a bit, the last thing we need to do is
query the logs for our user’s email, and the only reason I didn’t do
this first is because I wanted to rule out the simplest explanations.
Doing a quick query on the logs, there are no entries found. This tells
us something important:
Sorry for the trouble; I don’t see your email address in our system,
nor do I see a request for a login link. Is this the email you used?
802 ROB CONERY
If you can’t tell, I’ve had this email exchange before. I’m not sure what
it is about programmers, but wow are they bad at asking for help.
Anyway: now that we have this email, we can quickly check search for
our user in our logs and our users table.
It happens.
Sleuthing Is a Skill
What marketing is asking for here is a CSV dump of the sales data
and, before you read on, are there any alarms going off in your head or
weird tingling sensations happening in your body right now? If not,
here’s a simple truth for you: data that’s not in your database is not
protected by anything.
When you send CSVs out into the wild, consider them public domain.
The data will appear on laptop screens left open at Starbucks and
reports printed out and lost on the subway or airport lounge. Never
provide sensitive information unless you arrange for its safety ahead of time.
You’ll be the one who gets the blame, by the way, every time.
Daily sales don’t fall into this category, but demographic (“Demo”)
information might if you’re not careful. Knowing this, we can run a
query for the month of December, ensuring there are no email and IP
addresses included. We can add city, region, and country if we want
because it won’t be tied to any personal information.
But there’s another problem here. One that you need to get stung by a
few times before you start appreciating just how messed up it is.
I blame texting. People dig being terse and don’t realize that leaving
out critical information requires more typing in the form of protracted
Q&A. Our marketing person doesn’t like our data, for some reason,
and after a few emails back and forth we find out that the numbers
don’t align with their expectations:
804 ROB CONERY
Your initial reaction is a human one: I’m not deleting sales information if
that’s what you’re asking. That was my reaction when my client said
these exact words to me back in 2001, when they did a full sales
push for the holiday. They were short expectations if they used the
sales data from my report, and were insistent I did something
wrong.
I pushed back, told them the numbers were the numbers and no, we
didn’t lose any orders. That’s when my client asked me a question that
changed my life. Mark was a pretty technical guy and understood
databases well. With his perfectly nuanced Queen’s English, he asked:
In short: no. Skipping ahead, I was, indeed, storing the date as UTC
(Universal Time Coordinates) which corresponds to the GMT time
zone. My client’s office was in Oakland, and the sales time needed to
reflect that, and it’s something I never checked on the server.
Ironically, this exact problem would happen to me again in 2010, but this time
with my own business.
So, in summary:
Hard-won Experience
A date without a time stamp or a time zone. Thanks for that. Now I
get to guess how to handle orders from Australia vs. Hawaii… yay!
Being positive: the more you develop these skills, the better you will
be at anticipating what will be needed from your export information.
The better, and more complete, your export is, the better you look.
That said, you do have to let other people play with it occasionally —
but how do you do that without compromising things?
Thankfully, there are some tools that you can use to make life simpler.
These are referred to as “Business Intelligence Tools”, or “BI” for
short, and you should get to know them and have one as your go to
when you’re asked for your opinion.
808 ROB CONERY
Metabase
The setup wizard does the normal wizard things, adding you as an
administrator and setting up your credentials. Then comes this
important screen:
810 ROB CONERY
This is my development database for my Rails app that I’m using for
Big Machine. Metabase snooped around in there, and came up with a
several “explorations” that might interest me.
This is where we enter the deep end of the analytics pool. Metabase is
freaky good at making guesses as to what you want to see.
I can turn this into a quarterly chart, pie graph, and more.
812 ROB CONERY
I can also use ad-hoc SQL to build a dataset that I would like to dive
into. This is powerful, but it’s also scary because, yes, you can write
inserts, updates, and deletes, which is not a good idea.
I could write for days, showing you all the cool things you can do with
Metabase. I use it for my own business, and it sends me daily emails
with sales charts (seriously) and I can dig in to anything I can think of
with pivot tables.
I honestly can’t recommend this tool enough. It’s ridiculous how good
it is! I used to work at an analytics company back in 2003, and I
remember we paid $12,000 for a system called “Cognos” that, well,
let’s just say it was nowhere near as good as Metabase. A long time
ago, sure, but I’m still blown away every time I open this tool up.
but if you need more control or have teams of people, the starter plan
is about $100/mo and worth it. They even host the solution for you!
That’s obviously not the full file, you can get that from this gist.
There’s more information here as well if you run into any problems.
It’s likely your client/boss/whatever will be using Excel, and will ask
you for an “Excel file” that contains whatever data they want to have.
I’m sure you’ve used Excel — it’s ubiquitous in the business world,
and for good reason: it’s excellent at playing with data.
814 ROB CONERY
This means you need to be good at working with CSVs. I made a video
for Postgres fans that you can watch on YouTube if you like. A few
tricks here and there can always be useful for you when it comes to
CSVs.
Should you learn Excel? If it works for you. I use it occasionally, but I
usually find what I need much faster using SQL. There is one thing,
however, that you could learn about that might solve many problems
pretty easily.
The data for your Excel spreadsheets does not have to be in a sheet —
there are data sources of all kinds, including my favorite: the Web
Query.
If you don’t know about this: you can give Excel a URL, and it will
scan the web page it lands on, looking for tables. It will ask you to
THE IMPOSTER’S ROADMAP 815
verify the selection visually, and then you can transform the data if
you want using an old tool called Power Query.
Once you’re done, close and import and the next thing you see will be:
816 ROB CONERY
This is a sheet in Excel just like any other, and you can base equations,
charts, and rollups on this data as normal. You can even set options to
refresh on a given period so you don’t have to rerun this query
every day:
THE IMPOSTER’S ROADMAP 817
This lets the decision makers in your company do their thing without
worrying about bugging you. The best part? They’re using their
favorite tool!
You do not want to be the data fairy. Your job is to ship software
and ensure that your clients and bosses know the value of what you
do. Your role, when it comes to data and reporting, is to ensure that
you’re writing what people need to know about and omitting what is
not theirs to see.
SUMMARY
You know what I’m going to say, as I’ve been saying it throughout the
chapter and also throughout the book: data is the value of your
application. That data is worth good money, and you’re the one
producing it. Yes, the true value of your business is based on sales and
customer count, but all of that is determined by your data.
The best way to ensure you’re capturing the things you’ll need to
show your clients and bosses at the end of the month is to figure it
out, as best you can, from the beginning.
818 ROB CONERY
Use your discretion on the last one. It’s important to know, but there’s
a time and a place. That said, it is a question you should have in the
back of your mind. Your salary and incentives are based on the
company bottom line, but how is that figured?
It’s wild to think that your paycheck is based on the quality of data
you’re storing, isn’t it? That’s a good perspective to have as you
consider reporting capabilities.
THIRTY
AND HERE WE ARE
GO MAKE SOME MAGIC HAPPEN
I
started this book in September 2020, sitting in an apartment in
San Anselmo, CA, staring at an email from a person who had
just read one of my old posts. In summary, the note said:
I just finished your book and I loved it, but I wish it had more
information about the things you’re writing about here. A lot of
this goes right over my head, and I have no idea how I’ll be able to
ever lead a team. There’s just way too much to know.
The post was about mashing two design patterns together: Unit of
Work and Repository. In my opinion, it’s a ridiculous thing to do and
can result in transactions you don’t intend.
If you have 2–3 years experience under your belt, and you’ve read this
book hoping to shortcut your career, be careful. It’s great to know
what’s coming, but it’s not so great to avoid living it. There’s no
replacing solid experience, so use this book as a way to get yourself
out there, and get paid what you’re worth.
We’ve discussed this throughout the book, and I hope to leave off with
it as well: if the word “power” affects you, think about why. For many
people, they see visions of power-hungry freaks screwing the world
over so they can make another million.
I’m talking about using your place in life, your privilege, education,
drive, charisma, and empathy to do your best work, which is
delivering software. You can’t do this alone, you have to be able to
influence your team to do their best work, and your boss to let them
do so.
Don’t shy away from the word, own it and do good with it. If you
don’t, someone else will, which would be a shame.
Thanks so much for going on this journey with me! Best of luck
to you.