AFAIK, dynamically creating components was tricky and difficult to debug. This is why LWC's approach to disabling this feature seems to show that SF is shying away from usage of modals created by dynamically created components and removing other features like two way binding.
About your question, it depends on what you are trying to do. If you are trying to show/hide components based on minimal requirements you can use CSS, aura:if or you can use
$A.createComponent(). A particular use case for creating components would be when you need to show large amounts of data and only when it's necessary.
One of the use cases is if you have a backend metadata framework and you load the component to load on the screen from there in run-time.
Basically you wont know what component you need to load till run time. In such cases you would need dynamically created components. I had asked same question for LWC before
If you have like 5 stepped process and you know what components to render but just that based on certain information the step will get inferred in run-time then you would use aura:if to load corresponding step's component.