monomon
This might be contrary to some, but i recommend diagramming! Can be anything from paper doodles to d2 to full blown uml diagrams. They help you stay focused, and aware of the program’s data dependencies.
Regarding code practices - read code. If you use a library for something, dive into its code. This can be beneficial in many ways - you observe the style they used, you understand better how the library works (documentation rarely contains enough detail), and you see how libraries are structured, which is often lacking in newbies.
Learn your language’s idioms. They can reduce complexity, and are usually more readable to people with experience in the given language.
Finally, don’t sweat it too much. The more you write, the better you’ll become, so just do it. New problems lead to new insights.
I started doing exactly this. Write a bunch of functions, that may end up in different systems, on different machines, even. This allows you to define the interfaces, figure out data dependencies, and so on.
The code may be runnable, just printing out some statements. Then I copy blocks of it to the place where it will belong.
It’s more of a thinking tool, than “actual code”.
I know you asked about VMs, but fwiw there are GPU-capable containers now: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
Used one of these and the setup is as easy as it sounds. It can run Houdini, Stable Diffusion.