For desktop application that is. This is just a general question that maybe only need general answers.
That entirely depends upon the problem you are trying to solve. This key bit of information was left out by you. If you're looking for an over-arching solution, there isn't one. There are merely patterns which we apply when applicable.
Answer depends on the language. I recently met a guy whose company develops the USB stack that runs on many popular cell phones (e.g., so your phone can talk to your computer). They have a rule in their shop that all C procedures must be reentrant. In practice what this means is that instead of global variables, they use an extra parameter to each routine; the parameter points to the state that should persist between routines.
I use this technique all the time for abstractions with state. Example: reader abstraction for photographic images: reader provides access to one pixel at a time; it must know open file descriptor, what is the current position in the image, so on and so forth. All that information goes into a private C struct or the private members of a C++ class. No global variables. The outside world sees:
typedef struct Pnmrdr_T *Pnmrdr_T;
struct Pnmrdr_T *Pnmrdr_new(FILE *);
pixel Pnmrdr_get(Pnmrdr_T);
void Pnmrdr_close(Pnmrdr_T);
void Pnmrdr_free(Pnmrdr_T *rp); // frees memory and sets *rp = NULL
This style of programming is very similar to OO methods.
Why better than global variables? There are no surprises. If something goes wrong or you want to add a feature, you know that everything is explicit in values passed in. Moreover, you know you can plug lots of modules together and they won't interfere unless you explicitly pass state between them. My contact in the cellphone biz says this property has been huge for his company---they're an OEM software outfit and they can easily plug different pieces together for different clients.
I really like programming this way because I get to see everything that's going on, and my private data structures are protected from prying eyes :-)
A common solution to this is to use single-instance classes instead of singleton/global variables.
Your application will be responsible for making sure you have only one instance.
This solution kinda sucks 'cause you can't prevent people from instanciating your class (is not a singleton) so it must be an internal class.
I wouldn't care too much about all the religious wars about the singleton pattern though - If I think it suits my needs i generally use it.
First, there's no point in pretending that singletions are somehow better or more acceptable than globals. A singleton is just a global dressed up to look like OOP. With a bunch of other problems thrown in.
And the alternative is, of course to not have global data. Instead of your class accessing some static (global) variable somewhere, pass the data to its constructor. Yes, it means you have to add a few arguments to the constructor, but is that a bad thing? It makes the dependencies for the class explicit. I can test the class simply by providing different objects to it in the constructor, whereas if it relies on global data, those globals have to exist in my test, which is messy.
Similarly, I can refactor easily, because there are no magic dependencies on classes other than what's passed directly to the object.
Thread safety gets easier to manage because you no longer have all your objects communicating with the same global instance. Instead, they can be passed separate instances of the class.
global variables a re fine in small programs, but when they get bigger you start getting weird side effects when someone makes a change or fixes a bug by going "oh, i'll just set this global and the problem goes away"
The most common concern I've seen with both globals and singletons is that you risk bad behaviour when using threads. In this case, you should always use execution scope as your base unit. This is one of the strengths of OO programming - you can use object members to hold all relevant data with very little fear of accidental thread mayhem. This stands in contrast to a non-OO-capable programming language, where you'd have to hand data down via parameters.
The other common concern tends to be organizational - it's hard to understand exactly where data comes from in a large system when it can be read/written to at any time. This is, in my experience, more a problem with the developer rather than the code per se. Unless you're working on one of those hundred-million-line megasystems that seem to crop up mainly in programming books as examples of difficult problems, you're going to be able to search your entire codebase for a particular item in a reasonably short period of time. The necessary next step is to regularly audit the codebase to ensure that globals/static variables aren't being assigned to at random. This is anathema to a lot of development approaches, but for systems under a certain size and complexity it's a perfectly workable solution.