Globale Variablen - besser vermeiden

    • Offizieller Beitrag

    Ich denke, die meisten deklarieren Variablen, wenn sie nicht innerhalb einer Funktion sind, als Global.
    Nun habe ich von Valik (EN-Forum) einen interessanten Beitrag zu diesem Thema gefunden, den ihr euch mal zu Gemüte führen solltet.
    Ich habe eine Übersetzung gemacht und hoffe, dass ich das Wesentliche getroffen habe. Falls ihr fehlerhafte Inhalte findet - bitte melden. (Besonders bei den umgangssprachlichen Einlagen hab ich mich etwas schwer getan). Einen Text 1:1 übersetzen ist, wie ihr von der Hilfe-Übersetzung wisst, nicht so easy und es ist besser, wenn nochmal wer querliest.
    Im Text ist ein Link enthalten, dessen Inhalt ich aber nicht extra übersetzt habe.

    [Valik] Why Global variables are bad

    Übersetzung

    Globale Variablen können zu unerwarteten Ergebnissen führen, s. hier. Ich war dabei ein Problem mit AutoIt und Aut2Exe zu fixen, welches beinhaltete, zwei getrennte (und fast identische) Listen von Funktionsnamen zu unterstützen. Habt ihr euch jemals gefragt, warum wir manchmal ein Release ausgeben würden (wie 3.3.5.0), welches nicht eine Funktion kompilieren konnte, aber es konnte laufen? Das ist, weil wir vergaßen, die Aut2Exe zu aktualisieren. Die von mir gezeigte Lösung, löste ein zusätzliches Problem. Es stellte sich heraus, dass in Reihenfolge der Benutzung der Array-Initialisierungs Syntax eine temporäre Lokale Variable erstellt und anschließend in eine 'heap-allocated' Variable kopiert wurde. Ein unangenehmer Leistungserfolg (fast 400 Element-Array mit 16 - 24 Bytes pro Element (32 Bit, 64-Bit-Größen)), der notwendig war, weil jede andere Weise, solch eine massive Struktur zu schaffen, geradezu grotesk sein würde. Ich schrieb den Code um, um statische Klassenmitglieder und die Tatsache auszunutzen, dass sie noch mit der Array-Initialisierungsprogramm-Syntax deklariert werden können. Die Klasse wurde entworfen, um beerbbar zu sein und erforderte nahezu Null Veränderungen zum vorhandenen Code um einfach magisch die vorherige Liste (geschützte Mitglieder mit identischen Namen) zu ersetzen. Alles sah gut aus (und es war gut), bis ich es ausführte. Das Problem war, es stürzte ab. Sehr seltsam. Es stellte sich heraus, dass die globale Klasse die von der neuen Klasse erbte, erstellt wurde und versuchte die Funktionsliste zu verwenden, bevor diese Liste initialisiert wurde. In einer Anwendung, die globale Variablen nicht missbraucht, würde das nie geschehen. Das statische Mitglied würde initialisiert, bevor main() jemals aufgerufen wird, und alles wäre gut. Statische und globale Variablen werden in der Reihenfolge initialisiert in der auf sie getroffen wird. Ich hatte also eine 50-50 Chance, um Glück zu haben, aber ich hatte es nicht. So musste ich die Klasse umschreiben und verwandelte sie in einen Pseudocontainer, um von lokalen statischen Variablen Gebrauch machen zu können. Ich verbrachte viel Zeit, diese Klasse umzuschreiben. Erwähnte ich, dass sie Templates und Makros (zusammen) verwendet? Ja, es ist ein Durcheinander. Der Compiler meckert und du bekommst keine genaue Idee, worin der Fehler besteht, weil er sich über ein hinter einem Makro verborgenes Template-Problem beklagt. Ich schweife ab...

    Diese Geschichte schließt auch Aut2Exe ein. Offensichtlich wurde meine Klasse entworfen, um in Aut2Exe ebenso verwendet zu werden, eine einzelne Liste statt zwei Listen zur Verfügung zu stellen. Ich nahm die passenden Änderungen mit Aut2Exe vor, baute sie ein und versuchte es auszuführen. Und es stürzte ab. Dieses Mal betraf es nicht nur meinen Code. Nein, es stellt sich heraus, dass Aut2Exe genau das gleiche Problem hatte, bevor ich jemals darauf stieß. Seit Jahren hat Aut2Exe nur durch eine reine Chance gearbeitet. Ich hatte erwähnt, dass die Chance bei 50-50 liegt? Gut, Aut2Exe hat damit seit Jahren gelebt. Ich habe keine Idee, warum es sich plötzlich dafür entschied zu crashen, als ich an Teilen ohne Beziehung zum Code arbeitete. Es verwirrt mich, warum es entschied, heute Abend war die Nacht, in der es in der Hölle speisen wollte. Aber lieber heute Nacht, wenn das Problem noch frisch ist, als später, wenn ich es wieder vergessen hab.

    Das war nicht das erste Mal, dass das beides geschehen ist. Ich habe ziemlich viele globale Variablen von den verschiedenen Tools im Laufe der Jahre entfernt. Ich brauchte ungefähr 25 Minuten, um den Crash nachzuvollziehen, als er heute Abend erstmalig geschah. Es brauchte nur 25 Sekunden bis zum nächsten mal. Ich habe viel Erfahrung mit dem Debugger, der Sprache und mit dem Bug insbesondere, so verschwendete ich nicht Tage mit dem Versuch, es ausfindig zu machen. Ihr könnt nicht dieses Glück haben, wie auch immer. Dies ist ein sehr übler und raffinierter Fehler. Er kann leicht verhindert werden, indem man so wenig wie möglich Globale Variablen verwendet. Klassen definieren, die andere abhängige Objekte richtig als Parameter akzeptieren und Referenzen/Pointer dazu speichern führt zu viel weniger Kopfschmerzen als den bequemen Weg zu nehmen und gemeinsam nutzbare Objekte als Globale Variable zu verwenden. Nehmt euch Zeit, es von Anfang an richtig zu tun, und ihr werdet nicht Stunden verbringen, um bei einem seltsamen Crash einen Fehler zu beseitigen, der aus dem Nirgendwo erscheint, wenn ihr Veränderungen vornehmt, die ohne Beziehung zum Code sind.


    Die Quintessenz ist also: Vermeidet/Minimiert Globale Variablen. Hier mal Beispiele, wie man es machen kann:

    Spoiler anzeigen
    [autoit]


    ;===============================================================================
    ; EDIT: Punkt 1 gestrichen, wie die Diskussion ergeben hat, war dies schlicht unsinnig.
    ;===============================================================================

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;============== 2. Vermeidung Globaler Variablen
    #cs
    Warum soll ich überhaupt Globale Variablen verwenden? Hier wird meist die Antwort kommen:
    'Damit ich den Inhalt in verschiedenen Funktionen nutzen/verändern kann.'
    Aber das läßt sich auch anders lösen:
    #ce

    [/autoit] [autoit][/autoit] [autoit]

    Local $myVar = 0

    [/autoit] [autoit][/autoit] [autoit]

    _PlusEins($myVar)
    ConsoleWrite('$myVar: ' & $myVar & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ; im Funktionskopf muß nicht der identische Variablenname stehen, erleichtert aber das Lesen
    ; die Variable wird der Funktion 'ByRef' übergeben ==> sie kann somit von der Funktion verändert werden
    ; ohne 'ByRef' erfolgt die Übergabe immer 'ByVar', d.h. eine Kopie der Quellvariable wird erzeugt
    Func _PlusEins(ByRef $myVar)
    $myVar += 1 ; kein Return erforderlich, da die Variable in ihrer Quelle geändert wird
    EndFunc

    [/autoit]


    Sicher kann man sagen: 'Ist mir noch nie passiert, solch Trouble.' Nun halte ich eine 50-50 Chance zum Crash durchaus für eine Größe, die man nicht unter den Tisch kehren sollte. Und es ist wirklich kein großes Problem, sein Programmierverhalten anzupassen und somit diesem Stolperstein von vornherein aus dem Weg zu gehen.


    Edit:
    Danke für die geführte Diskussion :thumbup: - hat mir auch einige Punkte etwas näher gebracht und auch die Erkenntnis, dass mein Gedanke, mittels Enumeration von Indexvariablen ein Array zu addressieren, hierfür schlicht blödsinnig ist. :huh:

    Allen Lesern dieses Posts möchte ich naheliegen, das Schlußwort von AspirinJunkie unbedingt zu lesen.

  • Von welcher Sprache redet der??
    bei der Erwähnung von "main()" dachte ich an C++, aber warum hat dann ein Beitrag über C++ hier im Forum was verloren??
    Außerdem, habe ich bei AutoIt nur (SEHR) selten festgestellt, dass Globals was bringen...

    mfG
    FLOSCHLO


    [autoit]


    Global $Var
    ;Das ist doch das selbe wie:
    $Var
    ;oder?????(solange das hier nicht in einer Funktion steht)

    [/autoit]
  • [autoit]

    Global $Var
    ;Das ist doch das selbe wie:
    $Var
    ;oder?????(solange das hier nicht in einer Funktion steht)

    [/autoit]


    Nicht ganz - es ist gleichbedeutend mit Dim $Var
    Und da wird kontextabhängig entschieden.
    Sobald man außerhalb einer Funktion Variablen deklariert ist es eigentlich Wurst als was sie deklariert werden - sie sind immer Global.
    Erst sobald sie innerhalb einer Funktion benutzt werden unterscheiden sie sich.
    Dabei ist nur bei Global und Local sicher was passiert - bei Dim entscheidet es sich ob es außerhalb eine globale Variable dieses Namens gibt:

    Spoiler anzeigen
    [autoit]

    Global $Test = 10

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Globale Variable $Test: " & $Test & @CRLF)
    TestLocal()
    ConsoleWrite("Globale Variable $Test nach Aufruf der Funktion Test(): " & $Test & @CRLF)
    TestDim()
    ConsoleWrite("Globale Variable $Test nach Aufruf der Funktion TestDim(): " & $Test & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Func TestLocal()
    Local $Test = 1
    ConsoleWrite("Lokale Variable $Test: " & $Test & @CRLF)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func TestDim()
    Dim $Test = 2
    ConsoleWrite("Lokale Variable $Test: " & $Test & @CRLF)
    EndFunc

    [/autoit]

    Daher ist der hier vorgestellte Workaround, freundlich ausgedrückt, Quatsch.
    Anstatt globale Variablen zu vermeiden kommt sogar noch eine weitere hinzu.
    Alle Variablen welche hier mit Enum deklariert werden (implizit: Dim Enum) bleiben global und man hat zusätzlich nun noch das Array.
    Warum das auch übersichtlicher sein soll ist mir dabei auch nicht klar da statt einfach den Variablennamen hinzuschreiben muss nun die gleiche Variable als Index eines Arrays eingesetzt werden.
    Also ich weiß nicht warum $aGui[$guiMain] übersichtlicher sein soll als $guiMain ?
    Auch die weiter unten vorgestellte Variable $myVar ist weiterhin global - da kann man noch so viel Local schreiben wie man will.
    Solange die Variable nicht in einer Funktion deklariert wird ist sie implizit global.

    Also zusammenfassend: Nimm Abstand von diesem "Workaround". Statt globale Variablen zu vermeiden kommen sogar zusätzliche dazu und die Übersicht leidet auch darunter.

  • In C++ , sollte man Globals aber vermeiden, darum beziehe ich den Beitrag einfach mal auf C++. . .


    FLOSCHLO

  • Globale Variablen bieten auf mehrere Arten potentielle Fehlerquellen welche mit ihrer Vermeidung auch vermieden werden: >>Klickmich<<

    Zitat von Wikipedia

    Globale Variablen sind scheinbar bequem, weil sie im ganzen Programm sichtbar sind. Es ist nicht notwendig, sie beim Aufruf einer Funktion als Parameter zu übergeben. Sie werden aber auch leicht zur Fehlerquelle, wenn man zum Beispiel eine globale Variable versehentlich oder sogar bewusst für verschiedene Zwecke benutzt.
    Auch kann es passieren, dass man eine lokale Variable mit dem Namen der globalen Variablen verwendet, von dem man annimmt, dass er im Programm bisher noch nicht benutzt wurde. Wenn es diesen Namen aber schon als Variable mit passendem Typ gibt (sofern dieser überhaupt vom Compiler und / oder vom Laufzeitsystem geprüft wird), dann wird deren Wert unkontrolliert überschrieben und umgekehrt. Ein schwer zu findender Fehler ist oft die Folge.
    Erfahrene Entwickler verwenden globale Variablen nur auf modularer Ebene und ausschließlich dann, wenn es sich nur durch unangemessen hohen Aufwand vermeiden ließe,


    Gerade in C++ bei welchem man seine Programme stark modularisiert und auch Bibliotheken von außen verwendet ohne diesen Code zu kennen kann es besonders schnell zu derartigen Problemen kommen. Desweiteren verletzen sie das Prinzip der Kapselung welches eine vernünftige Modularisierung erst ermöglicht.

    Einmal editiert, zuletzt von AspirinJunkie (3. Januar 2011 um 14:19)

  • Ich habe mich mittlerweile daran gewöhnt die nicht globalen Variablen in die Funktion mit reinzunehmen, beim Funktionsaufruf.

    [autoit]

    _neue_Funktion($Var_welche_nicht_bekannt_innerhalb_der_Funktion, $die_auch_nicht)
    ...
    ..
    ..

    [/autoit][autoit][/autoit][autoit]

    Func _neue_Funktion($var1,$var2)

    [/autoit][autoit][/autoit][autoit]

    .......

    [/autoit][autoit][/autoit][autoit]

    Endfunc

    [/autoit]

    Anfangs habe ich auch immer die Variable global bzw. mit Dim $Var1 ganz oben bekannt gemacht aber das sind mitunter tickende Zeitbomben....
    Lieber dynamisch bei der Funktion mitgeben an der Stelle wo man den Wert noch kennt. ;)

    Achtung Anfänger! :whistling:

    Betrachten des Quellcodes auf eigene Gefahr, bei Übelkeit,Erbrechen,Kopfschmerzen übernehme ich keine Haftung. 8o

    • Offizieller Beitrag

    Aber wie macht ihr das dann z.B. mit einer aufwendigen Main GUI?

    Ich deklariere dann eine Globale Variable (Array) und speichere darin alle erforderlichen Werte. Ist nur etwas mehr an Dokumentationsaufwand, damit man die Zuordnung auch vor Augen hat.

  • hi,

    Zitat von Wikipedia Globale Variablen....

    Sie werden aber auch leicht zur Fehlerquelle, wenn man zum Beispiel eine globale Variable versehentlich oder sogar bewusst für verschiedene Zwecke benutzt....

    Mumpitz!
    Solange ich weiss was ich tue, kann ich globale Variablen für ALLES verwenden. Punkt.
    NUR wenn man Scheiße baut, gehts in die Hose!
    Etwas anderes steht auch nicht in Valiks Post! Übrigens auch nicht in allen anderen Artikeln zu diesem Thema.
    Mit AutoIt hat das überhaupt nichts zu tun.
    Deshalb ist auch die Empfehlung auf globale Variablen zu verzichten ehrlich gesagt nur dann sinnvoll, wenn man NICHT weiss, was man tut...jedenfalls als Einzelprogrammierer.

    Anders siehts natürlich aus, wenn man im Team arbeitet.
    Da siehts aber idR so aus, dass Schnittstellen definiert sind und ergo auch die zu benutzenden (globalen) Variablen AUSSERHALB von Funktionen. Diese globalen Variablen sollte man dann natürlich tunlichst NICHT als interne Variablen innerhalb von Funktionen verwenden.
    Das kennt man von Assembler, da steht in der Funktionsbeschreibung, welche Register zerstört werden und welche NICHT beeinflusst werden. Stimmt diese Beschreibung allerdings nicht, ist man auch in den Hintern gekniffen :D . Daher retten vorsichtige Programmierer ALLE Register, bevor sie fremde Funktionen aufrufen ;) Sischäärr is sischäärr

    Und somit ist auch in HLL´s das Verfahren klar: in UDF´s möglichst auf globale Variablen (ausser natürlich Systemvariablen) verzichten. Sischäärr is sischäärr

  • Solange ich weiss was ich tue, kann ich globale Variablen für ALLES verwenden. Punkt.


    Solange du weißt was du tust kannst du auch statt normaler Variablennamen $1, $2, $3 usw. verwenden.
    Solange du weißt was du tust kannst du auch alles ohne Einrückung schreiben.
    Solange du weißt was du tust kannst du deinen Code auch komplett schreiben ohne ihn in Funktionen zu modularisieren.
    Kannst du alles machen - wenn du weißt was du tust.
    Ab einem gewissen Code-Umfang und wenn Teile des Codes woanders her kommen wirst du es dann aber nicht mehr wissen.
    Und nur darum geht es bei dieser Empfehlung.
    Es ist kein Gesetz das dich dazu zwingt - es ist ein Prinzip welches diesen möglichen Fehler von vornherein vermeidet anstatt sich darauf zu verlassen immer im Kopf zu haben was im gesamten Code passiert.
    Daher handelt es sich auch um eine Empfehlung mit welcher sich man das Leben leichter machen kann.
    Wenn du das nicht willst - mach es nicht.
    Aber dieses Prinzip hat durchaus seine Berechtigung und sollte nicht einfach als Mumpitz abgetan werden.
    Auch als Einzelprogrammierer mit etwas größeren Projekten (wenn man nach einem Jahr ein Skript erweitert weiß man nicht mehr aus dem Stehgreif was man alles für globale Variablen verwendet hat).

    Aber wie macht ihr das dann z.B. mit einer aufwendigen Main GUI?


    Ich persönlich würde da weiterhin globale Variablen nehmen - diese aber natürlich so eindeutig wie möglich benannt.
    Es sollen ja nicht um jeden Preis globale Variablen entfernt werden - nur wenn der damit verbundene Aufwand vertretbar ist.
    Und in diesem Fall, wenn ich das GUI öfter in vielen verschiedenen Funktionen brauchen sollte würde ich das als zu großen Aufwand für mich betrachten.
    BugFix Vorschlag mit dem Array halte ich auf der einen Seite für gut da man da an jede Funktion die es brauch direkt alle GUI-Daten direkt als Parameter übertragen kann.
    Andererseits denke ich für mich dass ich schnell den Überblick verlieren würde da ich mit den Indizes durcheinander kommen würde.
    Dann würde man sich eine neue potentielle Fehlerquelle schaffen nur um eine andere zu vermeiden.
    Also in dem Fall würde ich persönlich weiter die globalen Variablen nehmen - aber wenn jemand für sich eine andere bessere Möglichkeit zur Organisation findet (wie BugFix mit seinem Array) ist das natürlich auch ok.
    Aber nochmal: Nicht um wirklich jeden Preis globale Variablen vernichten!
    So kann man sich den Code schnell noch viel umständlicher und unübersichtlicher machen als einem lieb ist.
    Bei der Empfehlung hier geht es nur um globale Variablen welche mit VERTRETBAREN Aufwand vermieden werden könnten - nicht mehr.

    Einmal editiert, zuletzt von AspirinJunkie (4. Januar 2011 um 12:22)

  • Bei der Programmierung von SMF stolpere ich auch immer mal wieder über globale Variablen. Ich habe mir daher angewöhnt sämtliche Variablen schön lange und möglichst beschreibend zu benennen... und am Ende bügle ich einmal mit den Obfuscator Optionen "/sf /sv /om /cs=0 /cn=0" drüber :)...

  • Zitat

    Solange du weißt was du tust kannst du auch statt normaler Variablennamen $1, $2, $3 usw. verwenden.
    Solange du weißt was du tust kannst du auch alles ohne Einrückung schreiben.
    Solange du weißt was du tust kannst du deinen Code auch komplett schreiben ohne ihn in Funktionen zu modularisieren.
    Kannst du alles machen - wenn du weißt was du tust.
    Ab einem gewissen Code-Umfang und wenn Teile des Codes woanders her kommen wirst du es dann aber nicht mehr wissen.
    Und nur darum geht es bei dieser Empfehlung.

    Jedes, aber auch das noch so kleinste Windows-Programm verwendet reihenweise globale Variablen. Jede Funktion in der Windows-API benutzt globale Variablen. Globale Variablen schwirren reihenweise durch jedes Programm.
    Jetzt ist es in der Verantwortung des Programmierers, diese Variablen (für andere als die gedachten Zwecke) nicht zu verwenden!

    Wie will man einem AutoIt-Anfänger klar machen, dass man "keine globalen Variablen verwenden sollte", wenn allein im AutoIt-#Include-Verzeichnis tausende globale Variablen deklariert sind? Das hört sich für mich so an:
    Globale Variablen sind den "Pro´s" und UDF-Erstellern vorbehalten, alle anderen sollen gefälligst kein "Global" verwenden, um Fehlern vorzubeugen....Entschuldigung, dass ich lache....das impliziert, dass im Fehlerfall der "dumme User" schuld ist..

  • Jede Funktion in der Windows-API benutzt globale Variablen. Globale Variablen schwirren reihenweise durch jedes Programm.

    In erster Linie schwirren da keine Variablen sondern Konstanten rum.
    Und diese dienen nicht zum Datenaustausch sondern zur Definition der Schnittstellen der einzelnen Programmteile.
    Diese sollen natürlich im gesamten Programm bekannt sein.
    Hier geht es aber um Variablen welche nur aus Bequemlichkeit global sind und ihren Zweck nur für Codebereiche erfüllen wo sie genauso intern deklariert werden könnten.
    Die Grundaussage ist auch nicht "keine globalen Variablen verwenden" sondern "globale Variablen vermeiden wenn es mit vertretbaren Aufwand machbar ist".

  • Andy
    Da es bei AutoIt ja kein #define gibt, ist es zwingend notwendig Global Const zu verwenden.
    Lern strukturierte Programmierung(C++) und dann reden wir wieder. . .

  • Assembler wird in der Regel ebenfalls strukturiert programmiert.
    Ich denke Andy geht es darum dass hier dass Schlüsselwort implizit (aber nicht explizit...) als böse beschrieben wird.
    Was natürlich Quatsch ist (sonst gäbe es dieses Schlüsselwort ja gar nicht).
    Wer kleine Skripte schreibt die kleine Aufgaben übernehmen mit ein paar hundert Zeilen dem kann das natürlich Wurscht sein.
    Es ist eher eine Vorbereitung für größere Projekte wo man sich viel mehr an gewisse Programmierprinzipien halten sollte wenn man nicht vor sehr großen Problemen stehen will.
    Dieses hier gehört dazu.
    Auch muss man zwischen Konstanten und Variablen unterscheiden.
    Sie erfüllen 2 unterschiedliche Zwecke.
    Eine Strukturdefinition für einen DLL-Call welcher in verschiedenen Funktionen benutzt wird sollte natürlich global definiert werden (Redundanzminimierung).
    Allerdings als Konstante. Keine Funktion wird diesen Wert ändern oder überschreiben - geht ja auch gar nicht.
    Das kann aber durchaus bei globalen Variablen passieren - und das ist das hier beschriebene Problem.
    Damit, und ich denke darum ging es Andy, Einsteiger in die Programmierung nicht unnötig verwirrt werden nochmal zusammengefasst:

    Globale Variablen sollten, vor allem bei größeren Projekten wo die Übersicht abhanden kommen kann, nicht unnötig eingesetzt werden.
    Wenn man sie dennoch einsetzt sollte man sich schon Gedanken machen ob diese Verwendung im Skript gerade wirklich sinnvoll ist und vielleicht nicht vermieden werden könnte bzw. sollte.
    Wer nur kleine Skripte alleine schreibt dem kann das in der Regel fast egal sein da es dort sehr unwahrscheinlich zu den angesprochenen Problemen kommt.

    Kurzum als Faustregel:
    Wenn man die Wahl hat dann die lokale Deklaration von Variablen der globalen vorziehen - aber keine Kopfstände deswegen vollführen.

    Ich hoffe auf dieses Fazit können wir uns einvernehmlich einigen.

    • Offizieller Beitrag

    Ich hoffe auf dieses Fazit können wir uns einvernehmlich einigen.


    Das ist als Schlußwort absolut treffend. Ich habe meinen Startpost editiert und auch auf dieses Schlußwort verwiesen.
    Danke an alle Beteiligten für die aufschlußreiche Diskussion. :thumbup:
    Meine Großmutter hatte doch recht, wenn sie sagte: "Kannste alt werd'n, wie 'ne Kuh - lernste immer noch dazu."

  • Mal ganz ehrlich seit ich diesen Threat das erste mal las, versuche ich fast immer mit Enum-Globals zu Arbeiten! Dieses System ist einfach viel übersichtlicher als zig Tausend einzelne Globals!!
    Mit der Fehlertolleranz oder sonstiges hatte ich nie Probleme gehabt, mir geht es strickt darum auf den ersten Blick erkennen zu können für was diese Variable jetzt überhaupt steht...

    Grüsse!