Global monsters

I’m a hobbyist programmer who got started on a Commodore 64 back in the day. I’m also a teacher who writes program for classroom projects, etc. I tell you this so you’ll understand my lack of knowledge about modern programming.

Here’s my question: Why are globals evil? I told two young men yesterday my present project has about 100 global variables and they gasped. One of them told me, “Look up ‘singleton.’ That will help you.” I did that and, sad to say, I’m perhaps dumber now.

Here’s why I have so many global variables. My present project creates puzzles. The user – a teacher most likely – types in Questions, Answers, and a long Quotation from which the answers come. Each question is held in a global array, gQuestions(). The answers are in gAnswers(). And the quote is gQuotation. I used globals because I need to know the contents in various windows:
the editing window (in which the teacher types it in), the dictionary window (which helps crafts working answers), and the page layout window (which presents the finished puzzle). There are many other globals, most of them for the page layout (like width of blanks in the answers which the user can adjust, spacing between answers, etc.).

Why is this poor programming practice? I don’t know how else to do this that wouldn’t be clumsy. My two young friends told me the issue is you don’t know what’s going to mess with the globals but I just don’t get that. I control what utilizes them.

Sorry for the long post. I have tried understanding this and I know that some say spaghetti code is the monster that results from too many globals. But for me, the globals work fine. Is it worth it for me to learn other ways to control them?

Yes.

Each application is different, but from my 17 years of working in Xojo you’re doing it the old, non-class way of doing things. I’ve turned down (fixit) projects that use excessive global variables. The bigger the app the more likely it is to cause conflicts.

A possible better way to make it class based. (Off the top of my head) You have a class of Questions. The class has a property for Quotations and an array for Answers. That way you have a single array of questions rather than having to keep track of which question and which quotation and answers. You’d then have one current Question (the singleton) that would be used everywhere.

I have some experience with your type of app. I worked on a commercial application that was a test taking application that I took from an old-school style full of arrays to a class based approach. We also kept track of answers to see how students did over time which meant we had to keep track of the questions, and possible answers, at the time we saved the test because the questions and answers could morph a bit over time (to fix errors and/or include more information). Fun project.

Like you, I was a teacher before retiring and took up programming as a hobby. I am completely self-taught and will accept all of the disdain which might accompany that declaration. I have been coding since 1986 and selling software since 1994 and still love it to this day. I can’t add too much to what Bob has told you, but I would add to what your friend said: Get any good programming book and look up “encapsulation”. The idea is to keep processes and the code which supports them as self-contained as possible. The larger the project, the more important this is. Then I would just second Bob’s advice to learn to use classes to your advantage.
Finally, you may be interested in my flagship project QuizMaker Pro. It was the first app I sold in '94 and has been in continuous development since then. Grab it here Glad to answer any questions you may have about that app.

Thanks, Bob and Roger. Yeah, I guess I’m stuck in 1984. But that was a good year, right? There was a book written about it, if I recall.

And Bob, I’ll give some time to trying your Question class approach. And Roger, “encapulation” I will explore. I’ve got time, I just lack youthful brain cells.

To add another perspective and perhaps a bit of validation: There is nothing inherently wrong with your approach, given the circumstances of your project. The only problem is that this approach doesn’t scale well and there are other methods that have been developed over the years that work better. It’s not like your program is going to spontaneously burst into flames. We’re merely trying to gently nudge you into other ways of looking at it. I also want to acknowledge that this is a big cognitive challenge. Brighter minds than mine have wrestled with moving from 1984 to 2018. It’s a big step. Don’t beat yourself up if it doesn’t come easily. But I will encourage you that it is worth mastering.

Here’s one way to think about it. Consider a home’s electrical wiring. If everything were wired from a single (hopefully large) circuit breaker, then a light switch in the kitchen could turn off an outlet in an upstairs bedroom if a wiring mistake were made. That’s a risk with lots of global variables – unintended dependencies. However, a home wired with separate circuit breakers, usually one for each room of the house, prevents this. Each room is encapsulated so that you can shut off power to the kitchen without affecting a bedroom or even re-wire lights in one room knowing that it will not inadvertently affect anything in another room.

If you are starting to learn a new paradigm, please avoid singleton. It’s the same evil as global variables/methods.

Don’t do evil. Good advice. Now if Google would only follow it.

Good analogy. I do some wiring and plumbing and know the value of smaller units to work with. I even learned to write on the cable insultation what the wire services. Same too with plumbing. All Pex these days. Maybe Pex with a manifold distribution valve is another analogy.

@Tim Hare

I do believe I’ve advanced from …
10 INPUT “YOUR NAME”;A$
20 PRINT "HELLO, " A$

Like now I would use Name$. :slight_smile:

I get objects. I get properties. I get methods. And I’m starting to get classes. For some reason, classes has been hard for me. But I toil on, thanklessly …

[quote=375245:@Mark Jordan]
I do believe I’ve advanced from …
10 INPUT “YOUR NAME”;A$
20 PRINT "HELLO, " A$[/quote]
I used to teach computational physics and often translated old BASIC/FORTRAN source code into xojo.

+1

But:
This stuff has to exist somewhere.
If not singleton, then APP level
If not app level, then preferences object/s

But no matter how you slice it, there are variables that are needed in lots of places and stored once.
Things get messy when you try to parameterise things to the nth degree, and a function that needs 8 variables then needs 12, 15 as your app grows
The parameter list is long and ugly. Or you use globals of some kind

You can wrap up ‘types’ of variables into global single-instance classes
One prefs object for printing
One for screen
etc
Then you can pass the class as a single parameter instead of values

[quote=375257:@Jeff Tullin]+1

But:
This stuff has to exist somewhere.
If not singleton, then APP level
If not app level, then preferences object/s

But no matter how you slice it, there are variables that are needed in lots of places and stored once.
Things get messy when you try to parameterise things to the nth degree, and a function that needs 8 variables then needs 12, 15 as your app grows
The parameter list is long and ugly. Or you use globals of some kind

You can wrap up ‘types’ of variables into global single-instance classes
One prefs object for printing
One for screen
etc
Then you can pass the class as a single parameter instead of values[/quote]
I use MVVM architecture in all of my xojo projects. On the first level, there is front controller which usually hold database connection and main windows VM. Database connection than will be passed into the next level, but only for objects that required the connection. Every level will hold their own dependencies object. However, the dependencies, often, are injected by the previous level.

For the illustration, when program start, Xojo application object will open database configuration file, fetch the values, create db config object and then create front controller by passing db config object. Xojo application object will only hold front controller instance. Front controller than make some startup tasks (initialization), create database connection and hold the instance, and then create main window VM to show the main window.

For sure, it’s more complex but we can avoid dependencies hell. In addition, we can reuse these objects on different projects.

Note: I hope I can convert my dependency injection library to Xojo.

@Asis Patisahusiwa : I would be really interested in seeing your approach.

[quote=375186:@Mark Jordan]Here’s why I have so many global variables. My present project creates puzzles. The user – a teacher most likely – types in Questions, Answers, and a long Quotation from which the answers come. Each question is held in a global array, gQuestions(). The answers are in gAnswers(). And the quote is gQuotation. I used globals because I need to know the contents in various windows: the editing window (in which the teacher types it in), the dictionary window (which helps crafts working answers), and the page layout window (which presents the finished puzzle). There are many other globals, most of them for the page layout (like width of blanks in the answers which the user can adjust, spacing between answers, etc.).
[/quote]

Why is this bad?

Imagine you have the idea of letting a teacher edit two quizzes at once. This is a common thing for people to do (open and old document in one window, and start editing a new document in another window.

Using your solution, you’d probably have to add new global variables:

    gQuestions2
    gQuotations2
    gAnswers2
    etc.

And then each window would have to know which array to reference, gQuestion1 or gQuestions2.

Imagine allowing 5 quizzes to be edited at once. You’d quickly end up with spaghetti code.

Instead you should have a Class called “Quiz” which inside it holds the variables for Questions, Answers, Quotations etc.

Each window then holds a variable (a “pointer” in other language) that points to your single Quiz object.

The short answer is that there is absolutely nothing wrong with Global Variables as long as they are something that logically needs to be global. Chances are that some to most of the things you’re putting into the global namespace would be better grouped into the objects to which they apply.

If they are important to a specific object or part of a specific command path or something then they can be encapsulated into the objects that use them to make more sense. If they truly need to be accessed from anywhere, everywhere then they can be global and thats not wrong. But it’s likely that many of them actually do not need to be accessed from everywhere but are specific. If you find that they aren’t specific then your design for the objects and modules level of the app probably needs some refactoring.

Sometimes there needs to be a single, globally accessible instance of a class. That’s what singleton addresses. It binds the storage to the class that uses it, and hides that storage from the world. Hiding it makes it read only to the world, avoids dependency, and makes it so that callers don’t actually know if the instance is one or one of many. Because that might change later (design time) or even under certain conditions (runtime), and is not their concern.

For two reasons. One, data is not protected and hidden, and any piece of code can modify the global state. Two, behavior is implemented repeatedly across the code base instead of being implemented alongside the data it uses and modifies.

As a result:

  • It’s easy to introduce bugs, even with only one dev, and it makes some bugs very difficult to trace since any piece of code might have corrupted the global state.
  • It doesn’t scale at all. (Michael Diehr’s example.)
  • It encourages code duplication and discourages code reuse.
  • There’s no good way to make sure that X occurs every time Y is accessed or changed. Say, a sanity check every time a full question is added to the arrays tracking the pieces of a question.
  • Modifying data representation affects the entire code base instead of only the code related to that data.
  • It’s not thread friendly at all.
  • It often requires extra code to maintain state. In your case you no doubt have to do work to link every gAnswer and gQuotation to gQuestion. If you had a single array of Question instances, and Question was a class with three properties (Question, Answers, Quotation), then the binding between those pieces would be automatic.

I could go on, but those are some of the major problems.

I would recommend the first edition of Code Complete by Steve McConnell. You read and understand that book, and the principles he’s trying to drive home, and you will be ahead of most college graduates when it comes to software architecture and design patterns. And alternatives to your current globals design will be intuitive to you.

Thanks for the tip. I’ll check that book out ASAP.