Some of it is just about finding a way that you're comfortable with, there's no one right way or wrong way.
For instance, I do most of my development on a Windows machine, but there are so many things that I'd like to also do in Linux, so a VM is super-useful. However, since I'm usually in the same physical location where I can have other machines, I decided to get some cheap machines (I have two or three
Intel NUCs, they are tiny, fairly quiet, and cost very little nowadays in used condition, maybe $100 or so, i.e. cheaper than some Raspberry Pi's + enclosure + SSD), and then I've got Linux on a couple of them, and VMWare
ESXI (it is free, bit of a learning curve though, and not an essential thing to start off with) on another so that I can quickly swap between VMs (i.e. I only run one VM on that box usually, but could run a couple simultaneously if really required). None of the NUCs are connected to a monitor or keyboard, they are just connected via WiFi or Ethernet to the network.
VS Code on Windows has really nice remote Linux coding capability (it is an extension from Microsoft called "
Remote - SSH"), it is pretty exceptional. Well worth a try in case it suits the way you want to work. This saves me from needing to run a remote desktop. Then, I can use an SSH terminal (I like
SecureCRT on Windows, it is equivalent to free
PuTTY, but nicer but not free; there are other good free options but I don't know them) to get to a Linux shell and perform builds there if desired. Also, totally agree with the above comment that if you're developing for Linux, then build it on Linux, i.e. don't cross-compile unless you can justify it to yourself, because it is easy to end up with things breaking due to slightly different libraries being used. Cross-compiling is necessary for microcontrollers, but for desktop and server apps it's unnecessary usually (unless you're developing for a career, in which case there could be very good reasons for it, e.g. build-server support by the IT team, higher performance machines, and so on).
I developed a C++ application running on a server for about five years, and it takes daily work with C++ to try to be reasonably competent, so it is for sure a high barrier. I'm still only familiar with a subset of C++ and a subset of the Standard Template Libraries (STL), since I no longer code frequently in C++. I didn't like it initially, but now I prefer Python unless there's a good reason not to. It's just very productive, you can do a lot with very few lines of code, and it is excellent for data manipulation type of programs. Plus there are many libraries for helping with almost anything. Example: I needed to write code the other day to make backups of file folders, timestamped and delete the oldest, and search-and-replace content within each one, based on text menu input from the user; it was all done in a couple of dozen lines of code.
Python is a good complement to more 'normal' languages like C/C++; for instance, for writing tests, Python can save a lot of time, because you can use it interactively. In other words, your microcontroller app could be in say C or C++, but you could then test it with Python from your PC (or from microcontrollers running MicroPython). As an example, you could write a function to send I2C data, and then interactively (from a Python shell) issue commands one at a time, allowing you to (say) capture other signals with a 'scope easily since you're in control of the I2C stream. This is just a contrived example. Plus, MicroPython on boards like Pi Pico is very close to normal Python, so you've got control of hardware interfaces (GPIO, and peripheral interfaces like SPI or I2C, or UART or RS-232) very easily, under direct interactive control.
As an example, when I wanted to test a servo motor, the interactivity looked something like this, all done one command at a time, so I could (say) quickly stop the motor if I was unhappy with something, or go back and try a different speed if it vibrated and so on:
import my_motor_controller as m
m.reset()
m.op_mode(m.SPEED)
m.set_velocity(20)
m.set_velocity(400)
Some systems allow for combining great speed with that Python ease-of-use. An obvious example is that Pi Pico's high-speed 'PIO' code can be executed from MicroPython and data from the PIO can be processed by MicroPython too. You can also technically write some function in C to accelerate them, and execute from within MicroPython, although there are some limitations (it suits algorithms more than GPIO control from C).
On a PC, you could write some parts of code architected as C command-line apps, and then execute them from within Python, but I've not often needed to do that, since Python is speedy enough for whatever I've worked on.
Regarding GUIs, unfortunately (or fortunately) I've never had much need for developing them, and so I use what tools I'm familiar with, which can be config files, or command-line parameters, or (if none are supplied) just get the C/C++ or Python program to display a menu and prompt the user for input. But as mentioned by others, there are Python GUI libraries; I've not used a single library frequently enough to get good with it, but pyQt was fairly straightforward to use the few times I've tried it.
If I just need graphical output with no GUI interaction, then again there are lots of options, ranging from (say) matplotlib for nice charts, to writing out SVG format, or generating data files for importing and charting with Excel or MATLAB or whatever.
I also quite like (hate to mention the language!) to just use JavaScript for a simple web app; I don't like JavaScript itself, but it sure is convenient for a way to make an app that needs no compiling and will run on any platform with a browser. It's also super-easy to then convert that to what looks like an app on your mobile phone. I'm just a beginner, but there are enough examples online to make progress with JavaScript to do quite a lot. JavaScript can interact with hardware through various ways; one way is to implement your own web server (this is where Node.js is quite a useful option (it runs JavaScript on your server too, so you can program exclusively in JavaScript on both server and client [browser page], but you can also use Python, if you wish to minimize JavaScript usage to the web page only.
A nice mechanism (well, it's the only one I know - I'm no expert in this) is to use socket.io; it allows you to asynchronously send and receive data between the server and the web page in the browser. This means you don't really need a GUI library at all, if all you want is things like boxes and buttons on a browser page, interacting with your app.
I'm OK with not knowing everything, and not starting from first principles when it comes to writing code; I can generally fill in the blanks later for the areas I didn't initially understand. This doesn't suit everyone of course. I spend a fair bit on books (and books get outdated quickly, but I still find it's worth the investment provided I make use of the book quickly!). Provided it is a good book of course (some are pretty bad) to learn some best practices etc. Watching programmers code over their shoulder, to see what tools they use, how they name things, what notes they take and so on, and ask them questions, is super-interesting, but it's not feasible for many, especially if you're working in isolation.
I'm a member of a Linux User Group or LUG (I simply joined an arbitrary one, not actually anywhere near me) and if I get stuck, then I can email and someone might know the answer, or I can wait and ask questions on the next Webex/Zoom group meeting and so on. A nearby one would have the benefit of in-person meetings of course. Many members do programming for a career, so generally someone is around to give some help if it comes to it; I don't necessarily ask Linux-specific questions, I just ask general programming questions and I try not to annoy the members by focusing on Windows. There are LUGs worldwide.
This comment was a longer than it was intended to be; I don't know if any is useful or relevant, but I thought it worth adding in case you spot anything useful.