Inspired by Ben Horowitz’s Good Product Manager/Bad Product Manager, I ended up coming up with my own version for software engineers—Good Engineer, Bad Engineer. Keeping the following ideas and principles in mind has helped me become a better software engineer; hopefully they’ll be useful to you as well!


Good engineers write quality code. Quality code is clear, readable, and easy to understand. Good engineers strive to write code that is defensive, resilient, and maintainable.

Good engineers understand that others will have to read, update, and maintain their code in the future. Good engineers understand that taking the time to write quality code in the present saves much more time in the future. Bad engineers aim to write code that merely satisfies requirements in specs or mocks.

Good engineers are proficient at reading and understanding existing code, as well as navigating the code base. Good engineers quickly understand not only what a piece of code does, but also how it fits into the existing system. Bad engineers understand a piece of code only on the surface; they lose sight of the overall picture and don’t understand the concerns that code needs to fulfill.

Good engineers learn from their mistakes so they can avoid them in the future. Good engineers monitor their code both before and after deployment to ensure that it behaves correctly and properly. Good engineers strive to identify potential problems or pain points as early as possible, preferably before any code is implemented.

Bad engineers fail to apply what they’ve learned to future work, leading to problems, bugs, or wasted time. Bad engineers are consistently surprised when a pattern, library, or some other component doesn’t work as intended.

Good engineers spend time to understand the tools that they use. Good engineers understand that mistakes are inevitable but still aim to minimize the amount of mistakes they make.

Good engineers know how to balance conflicting objectives while still managing their time well. These conflicting objectives can include solving technical problems or understanding complex systems. Bad engineers waste their time by over-engineering a solution and they waste others’ time by under-engineering a solution that others need to fix. Bad engineers waste their time by spending too long being lost or stuck and they waste others’ time by asking for help too frequently. Good engineers strive for perfection but understand when they must compromise or ask for help in order to complete their work in a timely matter.

Good engineers understand that they don’t work in isolation. Good engineers communicate and coordinate with their team for a variety of reasons, such as to parallelize tasks, to reduce blocking others from doing their work, and to avoid duplicate or unnecessary work. Bad engineers are unaware of what their teammates are doing, which can cause inefficiency. Good engineers keep their team informed of problems and complications that arise.

Good engineers communicate effectively with their team, other engineers, product, and other stakeholders. Good engineers communicate effectively to other engineers in order to properly articulate what they need. Good engineers notify product of important problems, changes, or concerns in a timely manner. Good engineers can discuss and answer questions about what their code should do, even with a non-technical audience. Bad engineers communicate poorly because they are unclear or imprecise about what they want or need, or because what they are saying is mismatched to their audience’s technical level.