RTL coding style and how you drive today's synthesis tools affect your results. Take advantage of global RTL optimizations by synthesizing big blocks in top-down fashion instead of attempting to optimize separately for speed, area, power, or testability. Try writing your RTL at a high level and trust your synthesis tool to take it from there. Using more abstract coding will enable the tool to take a more global view. For example, when coding a multiplexer, go with a case statement rather than instantiating a multiplexer gate or writing Boolean logic expressions.
The first step in the synthesis process, elaboration, tells the tool to read in the HDL code and create a control-flow/data-flow representation of the design. Elaboration creates a good intermediate stopping point before optimization to have the tool report all error and warning messages. Take advantage of this to check that there are no surprises.
Next, do a sanity check on your timing constraints (report timing-lint). If there are intentional combinational loops in the design, break them manually. Of course, if any such loops exist unintentionally, you have just found a coding problem.
Take The Middle Road
After elaboration and checking for warnings, start with a medium-effort optimization. If that run leaves you way off on timing, then you know your code has a micro-architecture problem. But if this process gets you close, then you know a subsequent high-effort run may finish the job. It's best to avoid running a high-effort optimization until you must, as they can cost a 2× runtime hit compared to a medium-effort run. Also, take advantage of your synthesis tool's early-feedback features. Some synthesis tools can give you early estimates of circuit performance well before even a medium-effort optimization can be completed.