Yeah, the mac system is sort of an oversimplified model in practice. Sure the executable and stuff that came with it is a nice "package" easy to move into applications, and later to the trash, but...
User data goes elsewhere. "~/Library/Application Support" is very comparable to Windows APPDATA (and more or less just as hidden from the common user). Even Linux programs have some equivalent to this, though how the typical program ends up using it might be a bit different between these platforms.
Then there's another problem of data that the program needs that isn't really part of the package. Updates, add-ons, documentation, optional components... where to put this is not consistent between mac programs. Some actually modify their own package and place new stuff inside there. Some put it in userdata. Here it is the "portable" version of the app that suffers most, as it is not straightforward to put files next to an executable package in a folder, like you can with other systems. (i.e. if the user were to copy it to Applications, it would be very inappropriate to start storing other information in that folder).
Ultimately many things just
need an installer and an uninstaller to cleanly come and go. Linux package managers
do run scripts for this. Many mac programs
do have installers. Windows is just a place where everybody has had to roll their own installer since the beginning (well, since DOS really). I think most people tend to use one of a few common install program generators, so at least the behaviour is somewhat consistent between programs... but people set up their installers wrong and you get stuff left over not infrequently.
Bad uninstall scripts is not a problem specific to Windows, but there have been a lot of bad ones written over the years. Mac's casual lack of installers does kind of cut out a source of error, but at the expense of making collateral data silently hang around... maybe this is a slight improvement on average? (Maybe hiding the problem from the user keeps them happier?
)
Program Files is semi-protected. There's too much practical stuff you need to use the registry for. Even setting up the uninstall hooks for add/remove programs necessitates an installer in the first place. There's a lot of reasons why most Windows programs
do need to use an installer. Not the least of which that a lot of users don't really understand how to use a portable style app and would have an easier time if you just gave them an installer. I release portable apps myself, but I do it knowing pretty well that I'm going to get reports from people who won't know what to do with it.
I do really despise the growing trend of abusing APPDATA as a place to store executables. Discord, SourceTree, and El Gato come immediately to mind. I hate it. I understand what they're working around, but I still hate it.
At least modifying the user's PATH is a thing that very few programs try to do these days, on Windows. I'm happy that's mostly died out. Aside from a few heavyweight things, most stuff doesn't mess with that anymore in an installer. (Even Visual Studio doesn't add to PATH these days... though I wish it still did... seems like part of a push away from CMD toward PowerShell, which is a whole other discussion, but long story short I don't like it.)
Android and iPhone and game consoles have more "package" oriented systems, but these have their own limitations... at least for the most part they have strict rules about where all of a program's data can go, and the OS is capable of keeping track of it and cleaning it up at uninstall. A lot of flexibility was traded away to get this though... and it feels like we're still figuring out what's a sensible model for this (how many different "permissions" does each have to ask you for now on Android?) ...but moving to a system like this does fix a lot of the install/uninstall problems. FWIW, Microsoft has been trying to go this route in Windows with their Windows Store that nobody uses, though maybe it will catch on eventually... not sure if that would be for the overall good. Feels more like a step toward locked systems where you don't have control over what you can run.