It's not hard once you know the rules. shellcheck helps, but it's usually whiny about escaping variable substitution that are intended for outside of the current script such as for editing other files.
Its biggest flawed design decision is word splitting by default and Bash's lack of a standard library helper functions for arrays and associative arrays. These could also be implemented as bash native extensions without build-time modification with a user-provided programmatic builtin. I could be wrong, but zsh may be able to add compiled functionality at runtime dynamically as well.
It’s a scripting language, not a general purpose one and as such had different design decisions. Next, you’d want a type system and a package manager.