It's really hard to point at studies to evaluate these types of hyped development paradigms. Some thoughts, as someone who loves static typing and microservices:

My favorite thing about static typing is that it makes code more self-documenting. The reason I love Go specifically is because if you have 10 people write the same thing in Go, it's all going to come out relatively similar and use mostly built-in packages. Any API requests are going to be self-documenting, because you have to write a struct to decode them into. Any function has clear inputs and outputs; I can hover a parameter in my IDE and know exactly what's going on. You can't just throw errors away; you always are aware of them, and any functions you write should bubble them up.

Typescript addresses this somewhat, but basically offsets that complexity with more configuration files. I like Typescript in use, but I can't stand the fact that Javascript requires configuration files, transpilers, a million dependencies. Same for Python and mypy.

Yes, I could just look at class members in a dynamic language, but there's nothing that formally verifies the shape of data. It's much more annoying to piece apart. I don't use static analyzers, but my guess is that languages like Go and Rust are the most compatible with them. Go programs are the closest thing to a declarative solution to a software problem, of any modern language IMO. As we continue experimenting with GPT-generated programs, I think we're going to see much more success with opinionated languages that have fewer features and more consistency in how finished programs look.

Microservices are also great at making large applications more maintainable, but add additional devops complexity. It's harder to keep track of what's running where and requires some sort of centralized logging for requests and runtime.

You certainly can throw errors away in Go -- in various ways. It's one of the notable flaws in a largely cohesive, sensible language. (Which I use daily.)

    success, err := fail()
    do(success)

    success, _ := fail()

    fail()

The second one is pretty intentional - it'd be annoying it were downright impossible.

The first and third one fails on go vet. The first one also fails to compile if you never read from err in the entire function.

Vet accepts the third, and may (I forget) accept the first if err is redeclared or simply assigned.

My bad, I was thinking of errcheck, which is more thorough and integrated into most Go linting tools like Go CI linter.

https://github.com/kisielk/errcheck

In any case, it’s trivial to detect via static analysis.