Why do we assign our outputs to signals first in VHDL?
It's because you couldn't read from ports of type OUT in VHDL.
If the value driving an OUT port was to be read within the design, a signal had to used to hold it, then that signal assigned to the OUT port.
The capability to do so was added in VHDL-2008. However, a huge amount of designs were created before 2008 and before take-up of VHDL-2008 became available in software tools. These designs would therefore use the signal-drives-OUT method.
As an aside, it depends upon your circumstances as an engineer but the option to use VHDL-2008 may well not be available to you. Some companies will require design revisions to be synthesised or simulated by a specific version of software (Quartus, Xilinx ISE, ModelSim etc.) with no changes to the design project settings, so you cannot use VHDL-2008. I have worked in a great many companies that do this, defence companies for example. Moving to a newer version of software introduces an unnecessary risk of unexpected changes that can discredit all the testing and experience gained with that firmware so far, with the time and expense that go with that. So there is a lot of value in writing 'middle of the road' VHDL that will be accepted by the widest range of software tools that you can, rather than using syntax specific to VHDL-2008 or VHDL-2002. The downsides of this are few or none - I'm not aware of anything that you can't do in the earlier versions that vast majority of designs require. As I said, it depends upon your circumstances and is something to consider. For me, I would definitely use signal-drives-OUT. Being completely portable between software tools and versions is valuable to me and one of my priorities.
If the signal from an output port also is read back you have to use the 'buffer' port type.
That by itself would not be a problem but if that 'output' port goes up a hierarchical chain of modules you have to change the output of each model to 'buffer'.
To avoid the hassle it is easiest to use a local variable and in one place assign that to the output.
I prefer to use that technique only for output ports that are also read back but I can image somebody preferring to use it all the time.
I will tell you a scenario. Suppose you are creating an entity with
2 input ports : A,B
2 output ports : C,D
Suppose the output C is generated from A and B using some logic. And Suppose D is found to be directly related with C. For example:
D = compliment of C
So it is compelling to write in the code: D = not C directly, instead of using a logic expression with and A and B. However VHDL semantics don't allow you to read the output port C and hence you cannot implement such an expression. So what you can do is turn that port into a buffer port. Some people also make use in/out port for this purpose. But that makes thing complex. So a simple solution is to use some local internal signal C_int, and "use" it like the output port inside your code. So that you can implement the logic for C into this internal signal, read it and manipulate with it. Finally assigning this internal signal to the output port, outside all the process blocks, completes the requirement. An example illustration of what is happening inside the circuit: