Batch pipeline barriers and use render passes to help properly batch barriers and allow the driver to defer and hoist barriers to render pass edges.
Avoid command buffers that include only barriers. If needed, put these barriers at the end of the command queue.
Use implicit render pass barriers when possible.
Limit the number of resource transitions by batching them and avoid interleaving with dispatches/render passes.
Generally, avoid barriers outside of render target changes and avoid states like D3D12_RESOURCE_STATE_COMMON unless necessary for presenting, context sharing, or CPU access.
When possible, supply resources for barriers; they allow more optimal GPU cache flushing, especially for aliasing buffers.
When possible, employ split barriers to allow for maximum predication of synchronizing events.
When transitioning resource states, do not over-set them when not in use; it can lead to excessive cache flushes.