Avoiding bugs at the point of design capture is one of the most effective practices to deliver high-quality designs that work. Of course, complexity is your enemy and design bugs are inevitable, but early validation of the design architecture, before RTL coding, is the best way to eliminate costly high-level design/architecture errors. Moving forwards with a badly architected design can mean power and performance requirements become difficult to achieve in the later implementation stages, and you may find yourself endlessly iterating the RTL code, introducing complexity and technical debt with the subsequent risk of introducing difficult and potentially critical bugs. Historically, many teams have done this architectural analysis statically, with spreadsheets. The modern and more effective way to do this today is dynamically by simulation of a virtual prototype running realistic software payloads and realistic I/O traffic profiles. At this abstraction level you want capabilities that enable you to explore architecture decisions and analyze both the functional performance and the power performance of your chosen solutions.
Further down the development lifecycle, as hardware designers start to develop the RTL code, there are good practices that they can apply to ensure RTL is “correct-by-design.” An assertion-based verification flow really helps to cross-check the intent of the coded behaviors, with the added benefits of facilitating both static (formal) verification, and dynamic (simulation or hardware acceleration) workflows downstream to catch more bugs and catch them faster and more efficiently.