Technically there's no such thing as "UART over USB".
What does happen is sending comparable data, sometimes with a custom USB scheme (most USB-interfaced UART chips), sometimes with the more standard CDC/ACM meant as a serial-port replacement for things like mobile data modems, but also sometimes used by MCU's with an on-board USB engine.
From a host software perspective you shouldn't assume any difference, and you should leave device drivers to the operating system. You do need to keep the millisecond-scale USB latency in mind in how you use a serial channel, but today you need to do that anyway as most host system's don't have local-bus UARTS, but can only be accessorized with USB connected ones.
From a hardware perspective, it's going to be simpler to get software working and debug it if you use the UART peripheral with an external USB-UART adapter. You can find example code for implementing a CDC/ACM virtual serial device but it will make your program structure or environment more complicated, and you can expect the connection to break any time your MCU hits a breakpoint or the program otherwise stops. When the connection breaks, the serial port will dissapear from the host operating system and your software will have to re-open it. On a typical Linux, when it comes back it will come back as a different port number (eg,
/dev/ttyACM0 will become
/dev/ttyACM1). It's more likely to keep the same identify on OSX and Windows but will still need to be re-opened before it works again.
If you design an STM32 board, definitely give yourself connections to a hardware UART, even if you do not plan to use it. Also have connections to the SWD pins, the reset, and the boot mode pin.
You seem to be asking for a recommendation to a bit greater degree than stack exchange sites are really meant for, but if I were designing this, in addition to leaving the possibility of a UART in all cases, I'd probably consider options like this:
If the device is for personal use, or the serial interface will only be used occasionally, or where the device will see more time devoted to development than use, or where there need to be a lot of extremely cheap devices only occasionally connected to more expensive hosts, then UART with an external USB-UART converter module/cable.
If the device is a product intended for end users, but it's important that the interface have the semantics of a serial port, then USB CDC/ACM implementation, with due care to the degree to which these can be confused, eg the many cases of people mistaking an obscure feature of their Mac's bluetooth implementation for their Arduino.
If the device is a product which needs to just work, then a custom USB scheme unique to the product and its needs, and investing the effort in getting at least device-recognition level drivers signed for the needed platforms - hopefully libusb-based in at least the OSX and Linux cases.
Many years ago, I did design some products which incorporated a fixed-function USB-UART chip wrapping a UART-based MCU. But I'd probably not do that today, except in the case where the MCU is intended to host experimental end-user software, ie, where the product is a development board. The sorts of Arduino boards which have a USB-UART bridge distinct from the target processor, and the many ARM MCU demonstrations which have a second chip implementing an SWD adapter with a USB-UART mode for debug messages are good examples - but that's a development board architecture rather than a product one.