How (Not) to Learn TypeScript

Brooks Lybrand

TypeScript is a superset of JavaScript, meaning it is built on top of JavaScript. Per the documentation, “TypeScript is JavaScript with syntax for types”. This allows you to tell your program and other programmers exactly what type of arguments your functions and classes can accept and return, such as strings, numbers, arrays, objects, etc. This is powerful because it helps avoid a ton of low-hanging bugs (such as trying to access an object’s property that doesn’t exist), as well as document your code as you write it.

That being said, this article is not meant to convince you or motivate you to learn TypeScript. If you are reading this I’m going to assume you’ve at least thought about learning TypeScript, and most likely have made an attempt or two yourself. The purpose of this article is to get you past mere motivation, and instead help you form a plan to learn TypeScript. At the least, I hope you can read my story and have a good chuckle at my bumbling around in TypeScript land.

It took me three tries and nearly one year to learn TypeScript. I started and stopped multiple times, got caught in tutorial hell, and enlisted others to learn and struggle with me. This is my story about How (Not) to Learn TypeScript. And while it may not resonate for everyone, I’m sure there are some people out there who have had the same experiences, or are in the middle of making the same mistakes. This article is for those people.

If you want to skip this tale of trials and tribulations, you can go straight to my take-aways at the end and read How to Learn TypeScript.

Chapter 1: Tutorial Hell

It was November 19th, 2019 (insert obligatory pre-pandemic, sweet summer child joke). I was feeling very confident in my JavaScripting, React-building self, and even had a couple of junior developers whom I was mentoring. I decided it was time to take on a new challenge, the challenge that many web developers before me had already faced: TypeScript. 

Little did I know how unprepared I was for this endeavour. The only thing I did have in abundance was motivation.

This was good enough for me: a win-win. Whether I ended up liking it, hating it, or was totally indifferent to it, I knew I would find it worth my time to learn TypeScript.

Jump forward 3 months: February 19th, 2020. By now, I’ve admitted to the outside world that I have attempted to learn TypeScript once or twice already, with no success. I tried to blame these failures on not wanting to take up any more of my colleagues' time learning TS. However, I knew perfectly well that this all began as a solo adventure, driven by my own goals and motivations, and thus only I was to blame.

Kristofer’s blog post is a useful one, especially if you feel you lack motivation. Many people try to rely too much on motivation or having the right goal when learning something new. But motivation on its own really isn’t enough. You need a plan, you need a system. I lacked a plan, I thought my motivation to learn was enough, and so I became stuck in tutorial hell, blaming other things for the lack of types in my life. 

That is, until one day, I finally did come up with a plan. A bad one, but a plan nonetheless.

Chapter 2: How (Not) to Learn TypeScript

In this chapter, I describe how I made a significant dent in my TypeScript learning - through a series of mistakes.

Mistake 1: Trying to convert an existing project to TypeScript

I told you I had a plan. On April 28th, 2020, I decided to convert one of my projects to TypeScript.

As a learning method, converting an existing JS project to TypeScript was a bad idea. This conversion is incredibly deceptive. It seems like it should be easier; you don’t have to think about what you’re coding and can just focus on the typing part, right? 

Wrong! Unless your project is split up into a single function per file (which I don’t recommend), you’re going to end up dealing with a ton of errors all coming in at once when you change the extension from .js/.jsx to .ts/.tsx.

I also found that many of my functions weren’t written in a way that was easy to convert to TypeScript. I had arguments that could be multiple types because I was so used to the dynamic nature of JavaScript. I didn’t realize how much code I would end up wanting to rewrite when converting to TypeScript. 

What’s more, during the conversion, I was also trying to practice Tailwind CSS and XState.  Since I was more familiar with Tailwind and XState, I ended up implementing those two libraries and then stalling on TypeScript.  I was doing too many things at once and not focusing on what I really wanted to learn.

My takeaway from all this? If you’re trying to learn TypeScript, focus on TypeScript. Start a fresh TS project, and don’t try too many things all at once.

Mistake 2: Resource overload

After two weeks of struggling with the TypeScript portion of my application revamp, I asked a friend for some resources. He was kind enough to send me a “tweet storm” of material he recommended, as well as a few tips and tricks.

Here is a list of all the resources he provided:

These are all fantastic resources, some I’ve relied on more than others. John also provided some helpful tips and code samples in his replies. 

However, having these resources did not get me over the learning hump with TypeScript. Not because of the resources, this came 100% down to me. I just didn’t know how to think about the resources in relation to my learning. I didn’t know when to use which resource. 

The problem with learning is pretty much never due to a lack of resources, especially when it comes to web development. There are so many amazing and free resources available. To me, effectively learning TypeScript is largely, if not entirely, about the process, and my process for using my resources sucked. I’d go through all the content at a resource’s site before writing any TypeScript. Then I’d get bored and my motivation to learn would start to fade.

(If you’re interested, under How to Learn TypeScript at the end, I’ve included a breakdown of the resources that I wish I’d had while I was learning TypesScript,)

Mistake 3: Starting from the bottom

Maybe starting from the bottom works well for Drake, but personally, I wouldn’t recommend it.  

That is, if you’re converting a JS project to TS and you start at the “root” of your application versus the “leaves”, this will likely not work out well.

In my case, I started by rewriting App.js to App.tsx, which is the core of my application, or in other words, the “root”. This was a mistake. Lower levels of the application/codebase depend on other components and functions, all of which aren’t typed yet. This means you’re not getting much feedback about your TypeScripting because everything you’re calling doesn’t care what you pass into it. 

Additionally, I find that my application “leaves” are usually less complex than core components and functions. This isn’t true for every “leaf” element, but the majority of these functions are simple utilities that do things like convert strings to dates, perform simple mathematical calculations, or generate some straightforward JSX. 

The nature of the “leaves” compared to the more core elements makes them much easier to type, and it would have been best to start practicing TypeScript there.

Chapter 3: A Breakthrough!

Finally, after three failed attempts to learn TypeScript, I had a breakthrough! 

In fact, several breakthroughs, all of which finally allowed me to learn how to use TypeScript. 

On August 12th, 2020, I got back to my demo project and finished the conversion.

So what changed? There were a few things.

Breakthrough 1: Learning how to use my resources

I mentioned in Mistake 2 that I suffered from resource overload. I think this can often be the root of tutorial hell. I often feel like I have to go through all the materials before I’m ready to start doing any real work. So I get caught up churning through tutorials, yet never cementing the concepts in real life experience.

There are way too many resources you could read or watch which can perpetually stop you from starting. As you finish one resource, a new one is probably being created. 

I needed a way to think about my resources. I discovered that it helps to split resources into three categories: survey level, reference level, and deep dive.

Survey level resources are good resources to get a high level grasp of what you’re studying. I found Understanding TypeScript’s type notation by Dr. Axel Rauschmayer to be perfect for this. Additionally, the TypeScript Handbook is also a really great tool. The key for me when reading survey level resources is to stop when I start getting bored. Usually when I start getting bored with a resource, it’s because I don’t have a good way to associate what I’m learning with a problem I’ve faced in the real world.

Reference level resources are pretty self explanatory. I often make the mistake of trying to consume these resources cover to cover like a novel. This generally is not very helpful, and I suffer from the same problem mentioned above: I don’t have a good way to ground what I’m learning in some real life experience. Reference level resources like the React TypeScript Cheatsheets are best used to get you unstuck, or to look at after you’ve solved a problem, to see how someone with more experience approaches things.

Deep dive resources are what you want to use after you have a good foundation. Most of the time I don’t even get into these resources, or at least not until I’ve been using the tool for a while. Certain tools/libraries you’ll use so rarely, or are so simple they don’t need deep dives. In the case of TypeScript, you will likely want to do more deep dive learning as you get better with the language. Everyone learns differently, but for me I find these to be most beneficial after I’ve spent a good amount of time with the language, which can be anywhere from 6 months to 2 years.

Breakthrough 2: Understanding when and when not to use the “any” type

This breakthrough is very specific, yet incredibly important when learning TypeScript. Over and over again I heard people give advice to TypeScript beginners and veterans alike, to not be afraid to “slap an any” type on something. The any type is essentially a TS escape hatch. It bails you out of all typechecking errors and helps you avoid having to deal with writing difficult and complex types.

So, when I heard the advice to not be afraid to use any, I thought it would make my life easier to just skip over hard to type functions so they wouldn’t interfere with my progress and learning.

What made things even worse: I seemed to be getting conflicting advice from different engineers:

It sounded like I was supposed to both use any and not use any at the same time. This just left me more frustrated and confused, and made it really hard to figure out what to put in my tsconfig file.

Fortunately, there were a few kind souls on the internet who pointed out that I simply didn’t understand what I’d read.

Implicit (or implied as Iain referred to it) any means that if you don’t provide a type to something like an argument to a function, the TypeScript compiler assumes that its type is any. 

I 100% agree that you should avoid this, especially if you’re a beginner learning about TS, since when you add any as the type, you will be consciously opting out of TypeScript. Set noImplicitAny to true in your tsconfig file and let TypeScript start nudging you in the right direction.

I also now better understand the advice from seasoned TS developers about adding any types when writing something complicated. As you gain more skill, this can be a really good workflow when developing your applications. Once I learned how to use TypeScript, I’ve certainly done this myself, but typically I come back and swap out the any type within the same commit or maybe a commit later.

But when you are just starting out with TS, using any can be a very bad idea. There is just too much nuance to when you should add it versus when you should keep trudging along. Plus, most of your learning comes from struggling with the more complex types, even though you’ll be tempted to reach for escape hatches. I encourage you to not use the any type, at least not until you’ve started enjoying the language just a little bit.

Breakthrough 3: Starting from the top

On October 7th, 2020, I think I can definitively say that I sort of kind of knew TypeScript.

I have no interest in being a gatekeeper, if you get to this point in any language, library, skill, or hobby, you’re part of the club. If this tweet marks my TypeScript birthday, that means it took roughly 11 months for me to go from motivation to actual learning.

Recognizing the mistakes I’d made, and applying lessons learned from my previous breakthroughs were key to my learning progress. 

Another change also made a big difference. Very simply, I just inverted what I was doing in Mistake #3. Instead of working on the ‘’core’’ of the application, I started with the “leaves”. It’s best to start with features that don’t have their own dependencies when you’re converting a project. Even if you’re starting on a new project, it can be best to add the simple things first if possible. Go after the easy wins. It’s okay if you’re not writing the most complicated, interesting types, you’ll get there soon enough. Start making progress and don’t let yourself get overwhelmed trying to think about the whole application.

Breakthrough 4: Learn with others!

My final breakthrough: learn with others if you can! While you can learn on your own, learning with others absolutely can make the process more fun and rewarding.

Obviously your ability to learn with others depends on whether you’re working with a community of engineers that includes people who also know or want to learn TypeScript. Even for the solo developers, it’s usually still possible to find some sort of community through sites like twitter or discord.

In my case, at first I didn’t learn with my colleagues because I wanted to make sure we would stick with TypeScript long term. Then it was really helpful and even fun learning alongside other people.

How to Learn TypeScript

I hope you found my foibles and fumblings in the land of typed TypeScript interesting and helpful. I certainly learned a lot through the process, and I am now very happy to know TypeScript.

To summarize everything I learned, if you came to me today and said you wanted to learn TypeScript, I would tell you to:

  • Start with just TypeScript, don’t focus on React immediately
  • Build a simple application or tool
  • Don’t convert a project as your first means of learning
  • If you do decide to convert an app, convert from the top down, not the bottom up
  • Categorize learning materials, and use them appropriately:
    Don’t try to read these all at once, start reading and come back periodically, intermixing reading and learning
  • Survey level:
  • Reference level:
  • Deep dive:
  • My only strong opinion is to set noImplicitAny to true
  • It’s okay to not understand everything in a config file when you’re starting out. From what I can tell, most people just muck around with their tsconfig until they get something they like. As you get better you’ll form stronger opinions—something you don’t need when you’re getting started.
  • Try to avoid using the any type when you’re first learning. Some types will be difficult to think about, but that’s part of the learning process! If something is really complicated, try writing it in a different way.

How to optimize your debugging workflow with BugReplay

BugReplay HQ

We created BugReplay to save you time. Indeed, some of our customers have reduced the amount of time they spend on bug resolution by over 75%– that includes the amount of time it takes to report a bug, diagnose a bug, fix a bug, and test the fix.


The “bug report” has made great strides over the last few years. Gone are the days when you would wake up to this: “That thing on the site is broken. Please fix it ASAP.”


Today’s post examine's the elements of a good bug report, and how BugReplay can help you at every step. Dare I say- bug reporting can be fun for everyone! Here’s a sample BugReplay bug report so you can see what we're talking about.


The elements of a proper bug report include:


1.    Title and description. It seems self-evident, but providing your bug report with a suitable title makes your entire team happy. You can keep track of the bugs better, your developers know exactly what they’re getting into without having to open the report, and your project managers can manage the tickets more efficiently. A good title and description help prevent the ticket from getting lost in the shuffle. What’s the problem? And where is it? Keep it short and simple. With BugReplay, you can add a title and description at several points in the process, and edit them later- when you first create the report in the browser extension or later from your dashboard.


2.    Steps to Reproduce. What’s the expected behavior? What’s the actual behavior? Start from there. It’s always best to include a note on how to reproduce the bug in question. Include all the relevant URLs! (I don’t want to spoil the fun, butBugReplay captures the URLs– and a LOT of other data– automatically, so you don’t have to. You also don’t have to write out all the steps to reproduce. WithBugReplay, the screen recording captures exactly what happened, and when it happened, allowing the developers to see the bug for themselves.


3.    Add some environmental details. Where did you encounter this bug? What operating system? What browser? Was the browser version up to date? Were cookies enabled? Okay, enough questions. None of that matters. Why? Because BugReplay captures all that information automatically.


4.    Add the logs.  Developers often want to see your console logs so that they can see what happened. Sometimes they ask for something that you don’t even understand. That often creates friction among technical and non-technical members of the team, or between QA and development generally.BugReplay automatically collects all the frontend data like JavaScript logs, network traffic, and resource timing information, as well as the backend data such as server logs and exceptions. Basically, all the data that you could ever want! And what’s more, all this data is automatically synched with the video, so you can pinpoint what’s happening at a precise moment. You can read more about our full-stack feature set on our Zendesk page. The technical documentation is also on GitHub.

5.    Provide evidence of the bug. If you can capture a screenshot or a video of the bug, then it’ll make it much easier for everyone to get on the same page. Well, the cat’s out of the bag on this one. That’s our core product: all you have to do with BugReplay is open the site, click record, and you’re done. You can also take unlimited screenshots. Here’s the sample bug report again, so you can see exactly what you’d be getting!


6.    Send the bug report to the right place. This one is important too. Don’t just send a bug report to the back of the queue. Instead, add the right tags (indicating severity of the bug report) and statuses (frontend or backend, web or mobile, is it design or development, is it in Project X or Project Y, etc.). BugReplay makes all that easy- you can assign the ticket, add tags and status, you can even write some comments in the ticket, or attach additional documents. You can keep the report private or share the report outside your team with a publicURL.


7.    Integrate with your existing workflow. To make your life as easy as possible, we’ve also built some integrations, so that you can always make sure the bug report is easy-to-find and given its proper due. We have integrations with Jira, Slack,Trello, Zendesk, GitHub, GitLab, Asana, Basecamp, and Zapier. To sync the server-side data with your BugReplay video bug reports, we have all the documentation you need to set up with our APIs. We also have integrations withSentry and Papertrail, making it easy to incorporate data from third-party vendors. Our Bugsnag integration is in progress.

Speaking of integrations, there’s one more feature we’re excited to write about: automated testing. BugReplay began as a manual, interactive debugging tool. But we’ve now integrated with popular end-to-end automation frameworks to automate the entire BugReplay reporting process. If you’re an automation QA engineer or test engineer or other such position, we have integrations with, Nightwatch.js, Cypress, and TestCafe. Check out more on our GitHub page. Or watch some tutorials on our YouTube page.

Happy (bug) hunting!

New Add-On: Server Logs and Exception Tracking

BugReplay HQ

Today we’re announcing the release of our Full Stack add-on product, which synchronizes your server logs and exceptions with your BugReplay video bug reports and all the frontend data you’re already collecting.

With the full stack add-on, you can track exceptions whenever you record a bug on your own web application. All network calls towards your backend will automatically receive a special key in the header that your developers can intercept and send back to our API to log whatever is most useful for analyzing bugs.

While you can use our APIs to sync your server-side data, you can also integrate with your existing vendor. We currently offer integrations with Sentry and Papertrail.

You can learn more on our help desk. The technical documentation is also available on our GitHub page. Video tutorials are coming soon!

Converting Create React Apps to esbuild

Brooks Lybrand

As a product developer and not a JavaScript tools expert, I rely heavily on frameworks and packaged tools such as Create React App (CRA) and Next.js to handle the “build” side of my applications. When I leverage these tools to more quickly and efficiently compile and bundle my applications, I rely on someone else having already done the heavy lifting of configuring Babel and webpack.

However, sometimes I want a little more control and speed in my bundling process. That is why I decided to test a new and exciting bundler called esbuild. To do this, I convert a project I’d built with CRA to a custom version that uses esbuild. As an introduction to esbuild, CRA users may find this particularly useful.

What is esbuild?

Esbuild advertises itself as “an extremely fast JavaScript bundler”, which succinctly highlights what this simple, yet powerful tool is all about.

JavaScript bundler

We’ve had JavaScript bundlers for years, long before I became a web developer. You use bundlers to break up your project into multiple files for an easier development experience, while still bundling all of your code together for browsers to run.


Esbuild’s claim to fame is that it’s fast. This is the driving force behind using it, though there are lots of other cool things it can do (see the “major features” on the first page of the docs).

Why is esbuild so fast? It’s fast because it’s built in Go instead of JavaScript, which is a much faster language. Go also handles concurrent processes really well, making for a speedy bundling experience.

Why use esbuild?

So you can build faster! There are roughly two sides to building an app, development and production.

During development, esbuild uses incremental builds, which make it very easy to change your code, save, and see your updated app. This means you don’t have to rebuild your entire application every time you make a change during development.

Second, there is the production side to building a website. Bundling for production is often different from bundling for development, because you’ll usually want to do things like minify your source code, tree shake your app, and create source maps. You don’t really need to do these things during development, as these features add more time to building your bundle. For small projects that aren’t rebuilt often, the time it takes to build the bundle isn’t that big of a deal. 

However, for larger projects you typically require CI/CD pipelines to catch errors before pushing to production, as well as preview deployments created on every commit. Because of features like these, your production build is generated more often than you’d expect. 

To speed up this process, developers need to get feedback on whether their build passes the test suite, so they can share preview deployments with reviewers more quickly. With it’s incredible speed, esbuild tightens the feedback loop for developers, leading to faster insights and thus new features getting shipped more quickly.

Converting a CRA app to esbuild

To learn how esbuild works, we will convert a simple app which implements John Conway’s Game of Life in React. You can check out a live version of the app, or look at the source code. Note, the application runs pretty smoothly for me on every browser I’ve tried except for Chrome.

Currently this application uses Create React App. We are going to replace CRA with esbuild.

Installing esbuild

We begin the process by installing esbuild and uninstalling react-scripts.

Next we need to update our public/index.html file to fix how CRA handled some images. Since esbuild does not bundle css the same way as CRA, we also need to import all our styles generated by Tailwind CSS in this file. If you’re not familiar with Tailwind, don’t worry about it, just know that it’s been set up to automatically generate build/index.css which has all of the styles we use.

Bundling an application with esbuild

Now we’re ready to bundle our application with esbuild. If we run the following command in the terminal, it will create the production build almost instantly:

npx esbuild src/index.tsx --bundle --minify --outdir=public/build

While we could add this as a script in our package.json file, it is better in the long run to create a JavaScript file to handle the build script. To do this, we create the file scripts/build.js.

We use an IIFE (Immediately Invoked Function Expression) to call esbuild directly, passing in many of the same commands as we passed to the CLI. There is much more you can do with esbuild, but this is a nice start.

Let’s go ahead and update the scripts section in package.json.

Now we run npm run build to make Tailwind create the production stylesheet and esbuild generate the production bundle. If we run npx serve -s public, we can start hosting a local version of the application.

Comparing esbuild and CRA build speeds

If you ran the CRA build before, you’ll notice that esbuild is significantly faster.

I compared running the two side by side and the build time was reduced by 70% using esbuild. The majority of the esbuild version’s runtime is running Tailwind CSS/PostCSS, so the actual work esbuildis doing takes almost no time. This is a really small app, so your mileage will vary, but as your application gets larger, esbuild will scale really well.

Implementing live reloading

We’ve gained some speed, but we’ve lost a big feature, the development version of our application. As a modern web developer, I want to see the changes I make in my code reflect nearly instantly in the browser, which is something CRA gave us for free.\

To get live-reloading setup in esbuild, we’re going to need to do a little bit of work. First, let’s start by installing 2 helpful tools, chokidar and live-server:

Next, we’ll add a start.js file in the scripts directory we created earlier:

There’s a little more going on here, but hopefully the code is pretty easy to follow. Basically we’re using chokidar to watch if we make any changes inside of the src directory, and if we do it will rebuild the application. For more details, take a look at the more fleshed out example from which I derived my script. Now we can run npm start and have our application automatically reload when we make changes to our codebase. Take a look at the code changes we made. It really didn’t take a whole lot to replace CRA with esbuild (especially if you ignore the package-lock.json changes 😉).

What we gained


I can’t stress speed enough, this is esbuild’s biggest draw. It’s freaking fast!

We also gained a lot of control. Don’t get me wrong, abstracting things away and using pre-existing frameworks and tools to get your apps up and running can be incredibly valuable. But sometimes it’s nice, and even necessary, to look under the hood and be able to hook things up for yourself.

What we lost

We did unfortunately lose a few things. Currently esbuild doesn’t support hot module replacement, so it’s up to you to set up some sort of live reload as we did above. Given esbuild’s incremental builds, this is still very fast.  But we lost some nice developer experience benefits.

Additionally, esbuild does not have a 1.0 version yet. People can and certainly have used esbuild in production settings, however it is still under very active development, so approach with caution when deciding if it’s the right tool for your next project.

Other resources

There are a number of community plugins available which handle things like converting markdown, implementing various css flavors, compiling Svelte or Vue components, and much more. You can create your own plugins if you need, but it’s definitely worth checking out the community plugins first.

Besides the esbuild docs, I found the blog “What is esbuild?” to be a very helpful survey.

If this blog has made you excited about the potential that esbuild unlocks for frontend development, definitely check out Snowpack (a frontend build tool) or Remix (a React framework) which are both amazing and use esbuild. For further inspiration, checkout the thousands of open source projects using esbuild.

Communicating with Developers

Brooks Lybrand

A unique communication challenge

While communication can be difficult in any work arena, communication between developers has unique challenges.

These challenges often center around the nature of the work we’re doing, resulting in asynchronous communication, and issues around how "it works on my machine".

Asynchronous communication

Communication between members of partially or completely remote development teams tends to be asynchronous. Developers communicate with each other across the globe, using a variety of platforms like slack, discord, and email. Frustrations can arise, for example, as developers try to communicate across time zones and potentially even language barriers to resolve development issues with colleagues who aren’t even awake.

“It works on my machine”

Then there is the pesky "it works on my machine" issue. When a developer creates a new feature, it doesn’t always work on a colleague’s - or worse, a customer's - device. This often occurs due to missing or incorrect environment variables such as databases credentials, or differing operating systems and/or browsers.

Trying to discover why someone else's code is not working on your machine can be tough, because you don't know how they got it to work, and what information they need about your machine to debug. Finding a solution in these scenarios requires ongoing back-and-forth communication that potentially becomes very frustrating.

The communication formula

No tool magically fixes communication challenges. Good results come when we cultivate empathy and develop processes to reduce friction. For good developer communication, here’s a simple formula:

  • Assume the best about the other person
  • First understand, then be understood
  • Show your work

Assume the best about the other person

Most people are just trying to do their best and developers really want their code to work for others. Yet it can be easy to become angry when you assume, for example, that another developer is being intentionally vague when your attempt to communicate with them to fix a problem isn’t working.

When communication is difficult, it’s best to take a step back and give the other person the benefit of the doubt. Ask yourself if it is possible that you’re the one not communicating clearly? Perhaps you can fix something too. In any event, choose to believe that others are doing their best to communicate effectively with you.

First understand, then be understood

When reviewing another developer’s work or trying to run their program, ask yourself these questions:

Did you read their instructions carefully? Did you follow each step? Did they leave any comments in their code, or anywhere else that might be useful?

In the best case scenario, you can solve the communication on your own by making sure you've understood and tried the other developer’s instructions. Alternatively, you may still have issues, but your next conversation with the developer builds on what you discovered on your own. When you do everything you can to understand, you show the other developer that you're not being lazy or difficult, but are working towards clear communication.

Show your work

If you are sharing your development work, have you written your steps out? Do you have an updated README? Have you added comments to your code/PR?

If you're reviewing someone’s code, have a question, or have spotted a bug, have you explained the steps it took to produce the issues you see? Can you share a screenshot or recording?

There are tools and processes you can use to show your work, and make it easier to communicate with other developers. As a best practice to enhance communication efforts between developers, your team or company should acquire the appropriate tool and write down a process to help developers show their work. For example, if your company uses BugReplay, you can capture screenshots coupled with console and network logs to show your outcomes to another developer.

Apply the communication formula

Let’s walk through a couple of “It works on my machine” communication scenarios, where two developers learn to use the formula above to communicate clearly and effectively with each other.

Example 1: Testing Authentication Workflow

In this scenario, Sally is a developer working on the authentication workflow for a new website, where users are authenticated via their Google accounts. She’s asked Bill to review her work. Feel free to check out the source code, or take a look at the live demo.

Sally just completed programming the ability to authenticate users with their Google accounts. She asks Bill to pull her code base and test whether he can log in. She sends him a link to the repository, provides the environment variables he needs to put in his .env file, and tells him the instructions are in the file.

Bill clones Sally’s repo, installs all the packages, and sets up the variables correctly, but once he clicks the "Continue with Google" button, something goes wrong! He's not sure why things aren't working – he checks his .env file to make sure the setup is correct, then runs through the installation steps again.

He still gets the same error. Bill figures the best way to share what seems like a bug is to send Sally a screencast of the issue. You can see for yourself his recording in BugReplay, which captures helpful network logs and other information about the environment in which the failure occurred.

When she reviews the logs, Sally sees that Bill ran the code on the port https://localhost:8000. However, the Google authentication is set up so that it redirects to https://localhost:3000. When she contacts Bill to ask why he ran the code on port 8000, he tells her he was told to do so in a previous project, and assumed he should do so again.

Sally explains that Google requires allowed domains to be explicitly set up, and the developer domain they are using is https://localhost:3000. Bill reruns the installation, this time without overriding the default port 3000, and it works like a charm! Sally updates the README to make the domain requirement more explicit so others won’t experience Bill’s issue.

Now let’s review how Sally and Bill applied the communication formula to their situation:

  • Assume the best about the other person
    We don't know what went on in Bill or Sally's minds during this whole exchange, but they both acted respectfully in giving and receiving feedback, even when things weren't working.
  • First understand, then be understood
    Bill probably could have done a better job here. He did attempt to run through the setup several times, but when it came to starting the server, he added the --port 8000 command in order to run it on a different port than the default, which was an extra step Sally didn’t ask him to do. People often get used to doing something one way, and don’t realize that their actions might break things in a different project.
  • Show your work
    As soon as Bill realized he had an issue he didn't know how to resolve, he documented exactly what was happening. BugReplay made it exceptionally easy to hit record, get all the relevant information, and send it to Sally. From there, Sally quickly figured out what was going on and was able to take the feedback to improve the documentation.

In the end, this was a communication win for everyone!

Example 2:  Previewing a Deployment

In this scenario, Sally implements a new passwordless authentication method using 🪄magic🪄 links. Unlike Google authentication, magic links can be used for preview deployments.

As a result, when Sally asks Bill to test her new authentication method, he won’t have to pull all of Sally's code, install the dependencies, and run everything locally on his machine. Sally uses the platform vercel so that each pull request automatically deploys its own unique URL for every commit which anyone can view.

Sally sends Bill a link to her pull request, which directs him to this preview deployment.

Bill is happy to review Sally's work, but again runs into trouble. As before, he documents his attempt to test Sally’s authentication method and sends the recording to Sally.

In the recording, as shown in the video below, Bill repeatedly clicks the Continue with Email button, but nothing happens:

From the network logs Bill sends her, Sally sees that Bill gets a 500 HTTP response code, which indicates a problem on the server. She tests the preview link herself and gets exactly the same result.

After some additional investigation, Sally realizes that she forgot to add the necessary environment variables to production 🤦. She adds the variables and sends Bill the deployment preview again. This time Bill reviews and approves!

Sally and Bill have certainly become better at applying the communication formula, as you see here:

  • Assume the best about the other person
    Bill and Sally were both respectful towards each other. The preview deployment provides an ‘’objective source of truth”, because nothing has to be set up locally to view the new feature, and both of them can view the same site through the same link. This made it easy to verify that Bill tested the deployment correctly.  
  • First understand, then be understood
    Bill clearly understood what he was testing and correctly followed the instructions Sally provided. Sally made sure to figure out what bug Bill discovered. Sally could have done a better job verifying her own work before sending it to Bill. While she did test the magic links locally, she never checked if they worked in the preview link.
  • Show your work
    Bill was able to leverage some useful software to share a screencast and the network logs with Sally. He wasn't able to show what happened on the server, but he gave Sally enough information to direct her to the solution.


Just as we have to learn how to code, we also need to grow our communication skills.

Acquiring communication skills isn’t hard when we follow the communication formula to become more empathetic, aware, and diligent.

In the end, while understanding linked-lists can help you get a job, effective communication allows you to excel on the job.