I think Karl Bielefeldt's answer is the best one, but I would like to state it even more forcefully: you have a culture problem, and it has nothing to do with China. Your boss wants bugs in your software fixed? Awesome!!! There are countless times in my career when I wanted to prioritize bug fixing, but management wanted more feature delivery.
The real problem you have is your team's attitude towards code quality. Ultimately, this is a maturity problem. Most teams end up with buggy, broken code for a few common, recurring reasons:
- Not enough time/resources spent testing
- Not enough time spent documenting + reviewing code
- Too much focus on delivery
- Willingness to accrue unlimited technical debt
It is not your boss' job to fix these problems. These are not organizational or corporate problems. These are developer problems, and developers must acquire the proper attitude and strategy to deal with them.
Without knowing anything further about your company or team or business practices, I'm going to make a few predictions:
- Your codebase has few to no unit tests (code coverage < 20%)
- Your team engages in manual testing (few to no automated integration/functional/acceptance tests)
- Your team puts little effort into code review (either treats it as rubber-stamp, opportunity for gratuitous nitpicking, or skips entirely)
- Your team rarely documents code, or adds trivial comments (// next line prints a message to the log file)
- Your team does not engage in regular refactoring, or only has 1 or 2 engineers that believe refactoring is even a useful thing to do
- Your team loves to write new, green-field code, and tries to avoid maintaining existing code like the plague
- Your system lacks automated metrics of success (number of successful transactions/requests vs. attempts, number of errors per transaction, counts of timeouts, user-facing errors, etc.)
Climbing Out of the Hole
Even if I'm only right about half the predictions, that's enough to explain your predicament. The solution is not more overtime, nor trying to convince your boss to back down. Part of the problem is that you lack strong technical leadership on your team. Your team really needs a senior engineer or five that can promote mature software development practices that reduce defects as early in the pipeline as possible.
As you can imagine, the prescribed fixes will directly address the defects I predicted above, along with a short blurb on why you should invest in the activity:
- Unit Tests--I think 80% is the absolute bare minimum for a long-term maintainable codebase. I strive for 98%+, and that is almost always achievable. This isn't about checking off some box in a masochistic SDLC checklist. First, not all code is easy to unit test. Writing tests against such code forces the developer to rethink the design and organization of the code. Making code unit testable makes it better. I say this as an absolute truth, because I believe it is, and have never seen a counter-example. Furthermore, unit testing uncovers a lot of bugs that eventually manifest in production, and often in an insidious, hard-to-reproduce way. Finally, unit tests serve as a kind of documentation of developer intentions when the original coder has moved onto another project, and the maintainer is trying to infer what they were trying to accomplish. I claim that unit tests always save more time than they cost, which is why mature developers will invest the time to write them. Unfortunately, I would wager that less than 20% of developers worldwide count as "mature" by this metric. :/ You can't tell how well you are doing on unit testing until you implement a code coverage analyzer in your build process, and put the results on a "radiator panel" that the whole team can see 24/7.
- Acceptance Tests--your team has lots of bugs to fix because you have outsourced proper testing to your users, and this makes your boss quite understandably angry. Your developers are lazy, believe that someone else should do the testing (like, dedicated testers), and are clearly not maintaining a suite of automated tests. You need tests which run on every merge, on every production build, on every deployment to every test environment, and on every production deployment. You want broad coverage via randomized test generation and extensive data validation within your code. This is a whole topic by itself, but is also core to your problem. You don't need to write thousands of test cases to have a useful acceptance test suite. But you do need to find a good testing framework, get very comfortable with it, and make it your new best friend.
- Code Review--many developers don't get the value from code review which is readily available. First, code review should help maintain a consistent style and approach across the team. I don't think developers need to write code as if they were all clones, a la XP style. But it does help to enforce some common standards, without devolving into formatting wars. This extends to design patterns and coding idioms which occur frequently in your problem space. Second, code review is an opportunity for learning, for both the author and the reviewers. It's an especially good way for junior developers to learn good practices from more senior ones (assuming the seniors are actually good coders). Reviewers should ask lots of questions whenever code isn't clear, and the process should be collaborative rather than confrontational. Third, good reviewers can often spot bugs just by reading the code. This won't happen all the time, and is no replacement for testing. But it is a nice bonus, and one which you get "for free" just because you bothered to ask 2 other people to read your code. Every merge should have a code review.
- Writing good documentation is overlooked by about 95% of all developers, given my highly unscientific judgment. You don't need NASA-level documentation to improve your codebase, nor does all code require the same level of documentation. In general, the more code is re-used, the more documentation it should have. Therefore, any kind of shared libraries/classes/modules should get extra documentation, especially for things like thread safety, exception safety, intended usage, detailed function APIs, null handling, etc. Bespoke app code should tend more towards being clear and self-documenting. Again, you can't tell how good your documentation is until you generate it as part of the build process and publish it to a local web server. A lot of bugs occur because there are mismatched assumptions and expectations between engineers (about valid values for fields, where validation occurs, etc.). Documentation helps mitigate this failure mode.
- Refactoring--this is one of the most valuable things you can do for crufty codebases which have acquired a lot of technical debt. It is perhaps the second thing you should do (after writing unit tests, of course!). For a small company or a startup, there are times when moving fast and breaking things is the correct course of action. But that cannot be sustained indefinitely. If you do not push hard for refactoring pauses, then your team will eventually fall off a cliff of technical debt (sounds like it's holding on by a tiny little branch as we speak). Good engineers should push for refactoring anyway. The fact that you have not mentioned any developer-advocated remedies tells me that you lack such engineers. Code does not have to be perfect the first time you write it (and almost never will be). But you should be able to improve it every time you touch it. Refactoring should be second nature for your whole team, and everyone should feel empowered to do it, when the changes are clearly beneficial to the whole team. Obviously, you want to avoid gratuitous refactoring. But I doubt this is even a risk for your team.
- Ops/Metrics--Not only do you need tests at the code level and external to your product, you also need operational metrics to see how your product is performing. And these metrics should include quality parameters (transaction count, speed, error counts/rates, etc.). Your boss shouldn't be the one demanding that you fix bugs. You should have your own team-defined quality targets that force you to go into cleanup mode when you stray outside of them.
Curiously, the one thing you have not mentioned is your boss demanding that you deliver 20 new features by next week, in addition to fixing all the bugs. I assume there is some such pressure, but your failure to highlight it gives me hope. It suggests that you have space to ask for a feature delivery pause while your team pays down the massive technical debt it has accrued. If you put together a detailed plan for your boss on how you are going to systematically improve the quality of your product, and maintain a high quality level going forward, then perhaps you will find support for such a plan.
Of course, you need to work with your team on the plan, and get buy-in as to which steps will be most appropriate and effective. And surely there will be compromises that will need to be made on all sides. You may need to amortize refactoring across a few product cycles, while your boss may recognize the urgency of building out a decent test suite right away, even at the cost of feature freeze.
In summary, I think your situation is totally salvageable. However, I think it requires a big change in thinking and attitude for your whole team. Instead of seeing your boss as the enemy, you should start thinking of the boss as an ally in a new era of software quality. And be sure to use the focus on quality as your ammunition when you sell your remediation plan: "Well, you did tell us you want all the bugs fixed. We have a plan to do that, but it will require you to meet us halfway. Here is what we propose..."