There has never been a worse time to be a software developer.

Practically all of the most popular tools encourage anti-patterns, add unnecessary complexity or solve superficial problems instead of focusing on critical problems that exist in today's software projects.

Some examples:

- TypeScript: Unfortunately, we cannot reduce a language's complexity by adding extra complexity on top. The complexity will keep rearing its ugly head no matter how much we try to hide it. The TypeScript project has had over 20K issues raised and 9K pull requests (that's not even mentioning the DefinitelyTyped repo)... To put it into perspective, the Linux project has only had about 380 PRs on GitHub. But how much value does TypeScript add? All evidence points to the fact that TypeScript does not have any positive effect on bug density. Its value is purely subjective and speculative. If humanity had invested a quarter of that time and energy towards coming up with and documenting proper JavaScript design patterns and architectures, TypeScript would have been completely redundant to begin with.

- NestJS: Makes heavy use of decorators; these aim to allow developers to handle cross-cutting concerns within their code. Unfortunately, cross-cutting concerns are an anti-pattern because they imply a violation of the principle of separation of concerns between components. It takes a bit of thinking and discipline to come up with components which have clear and distinct concerns/responsibilities, but this is not a problem that can simply be ignored by injecting decorators all over your code.

- InversifyJS: Dependency injection is a failed concept. It's been proven over and over. Angular 1 provided us with plenty of evidence for why we should avoid dependency injection (e.g. it's impossible to find stuff and you end up with a pseudo-global scope for everything which is as bad as simply using global variables). Again, dependency management is not a solution which can be automated away; it requires developers to make careful design decisions.

- Code coverage tools like Istanbul and others add very little value to projects. 100% coverage is not a useful goal to have, in fact it's counterproductive. When it comes to test coverage, quality of that coverage is WAY more important than quantity (this cannot be over-emphasized). Did you test all the right inputs? Do the tests focus on the most important code paths (and those which are more complex and therefore more likely to fail)? I'd rather have 10% quality coverage of the right parts of the code than 100% poor quality coverage. Also, you need to take into account that the more unit test coverage you have, the harder it is to make changes to your code.

- Linting tools such as ESLint/TSLint: These tools can be very nice if used correctly and not treated as a silver bullet for all programming problems. We should never forget that linters can only detect superficial problems. If your code passes all the most strict linting rules, it still says almost nothing about your project's code quality. I'd MUCH rather have code that fails ALL linting rules possible but has good architecture and good separation of concerns between components; at least the linting is easy to fix. Linting does not prevent architectural mistakes AT ALL; it only prevents superficial mistakes which are usually easy to identify anyway (if you have half-decent testing).

I hope that over the next decade, the masses of new developers will develop their critical thinking skills and that they will be able to see value beyond the hype which is always being shoved into their faces by various misguided organizations.

It's particularly difficult for me to see what has happened to software development because 10 years ago, I used to roll my eyes when I read comments like this from older and more experienced developers. New developers are often attracted to complexity like moths to a flame, but eventually we all learn that complexity is a silent killer - It's the ultimate enemy. Complexity is always trying to quietly sneak its way into your code (and I do mean ALWAYS; no matter how good your code is at any given point) and you must identify and stop every single attempt. It takes most developers at least a decade or two of coding to really appreciate this.

For me, starting a TypeScript project is like accepting unnecessary complexity from the beginning of the project. It's a bad start, a slippery slope.