{"id":12532,"date":"2023-08-17T15:09:06","date_gmt":"2023-08-17T13:09:06","guid":{"rendered":"https:\/\/www.q-software-solutions.de\/blog\/?p=12532"},"modified":"2023-08-17T15:09:09","modified_gmt":"2023-08-17T13:09:09","slug":"meistens-geht-es-hier-um-politik","status":"publish","type":"post","link":"https:\/\/www.q-software-solutions.de\/blog\/2023\/08\/meistens-geht-es-hier-um-politik\/","title":{"rendered":"Meistens geht es hier um Politik"},"content":{"rendered":"\n<p>Speziell, wie wahnsinnig und menschenverachtend die inzwischen geworden ist.<\/p>\n\n\n\n<p>Es ist aber nicht mein einziges Steckenpferd ;-). Es klang sicher schon gelegentlich an, da\u00df ich Programmierer bin. Ich pflege seit mehr als 10 Jahren eine Branchenl\u00f6sung f\u00fcr Abfallbetriebe, Containerdienste. Das Ganze ist f\u00fcr kleine Betriebe mit weniger als sagen wir mal 5 AP f\u00fcr die EDV. Das sind nach meinem Wissen so ca maximal so um die 50 Leute die mit der Software bedient werden. Die meisten Dateneintr\u00e4ge d\u00fcrften Wiegungen sein. F\u00fcr jede komplette Wiegung braucht es, so gut wie immer zwei Wiegungen. Ich denke, die Software wurde schon zu DOS Zeiten entwickelt, vielleicht liege ich damit aber auch schief. Wie auch immer, die Programmiere haben m.E. a) relativ typisch in MS Access programmiert und b) wenig \u00fcber die Menge an Code nachgedacht. Im Zweifel lief es wohl so. Da l\u00e4uft was, wir kopieren es und passen es halt an. So gibt es Redundanzen noch und n\u00f6cher, aber nat\u00fcrlich nicht komplett, das w\u00e4re ja zu einfach. Wo man die Redundanzen sehr gut sehen kann, ist an folgendem Code:<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Private Sub DruckAngeboSum_Click()\nOn Error GoTo Err_DruckAngeboSum_Click\n\nDim objOut As CMediaOutput\n    \n    Set objOut = generateMediaOutputObjects(ActiveControl.Name)\n    objOut.doOutput\n\n'Dim intAntwort As Integer\n'Dim strNeueZeile As String\n'strNeueZeile = Chr$(10) &amp; Chr$(13)\n'\n'Dim intSchleife As Integer\n'Dim lngNr As Long\n'Dim lngDrucker As Long, strBericht As String\n'\n'Dim WSP1 As Workspace, DB1 As Database, Tabelle1 As Recordset\n'Set WSP1 = DBEngine.Workspaces(0)\n'Set DB1 = WSP1.OpenDatabase(strDatenbankGlo)\n'\n'Set Tabelle1 = DB1.OpenRecordset(\"HT_Nummernkreise\", DB_OPEN_TABLE)     ' Tabelle \u00f6ffnen.\n'\n'If Forms!HF_AuftrAnkErz!AngebotKz = True Then\n'    ' R\u00fcckfrage mit Speicherung der Antwort\n'    intAntwort = MsgBox(\"F\u00fcr diesen Auftrag wurde bereits ein Angebot gedruckt!\" &amp; strNeueZeile &amp; \"Wollen Sie diesen Ausdruck wiederholen?\", 33, \"Angebot drucken?\")\n'    If intAntwort = 2 Then\n'        GoTo Exit_DruckAngeboSum_Click\n'    End If\n'End If\n'\n'' Firma Beller\n'If strKundeNr = \"143\" Then\n'    strBericht = \"BR_DruckAngebotAnkErzoSum_Bel\"\n'Else\n'    strBericht = \"BR_DruckAngebotAnkErzoSum\"\n'End If\n'\n'ordneDruckerZu \"Angebot\", strBericht, HAUPT_DRUCKER\n'\n'' Pr\u00fcfen ob Kontrollk\u00e4stchen f\u00fcr Seitenansicht aktiviert\n'' wenn aktiviert dann Seitenansicht, ansonsten Ausdruck auf Drucker\n'If Me!Seitenansicht = True Then\n'    If strKundeNr = \"143\" Then\n'        strBericht = \"BR_DruckLiefschAuftrAnkErzNot_Bel\"\n'    Else\n'        strBericht = \"BR_DruckLiefschAuftrAnkErzNot\"\n'    End If\n'    DoCmd.OpenReport strBericht, acViewPreview\n'Else\n'    Tabelle1.MoveLast ' Letzten Datensatz suchen.\n'    setzeFelder Forms!HF_AuftrAnkErz, Tabelle1, DRUCK_BEREICH_ANGEBOT\n'    erhoeheNummer Tabelle1, \"AngebotNr\"\n'\n'\n'    druckeBericht \"Angebot\", strBericht, Me!AnzahlDrucke\n'\n'\n'    Forms!HF_AuftrAnkErz!AngebotKz = True   ' Setzen der Druckkennziffer\n'    Forms!HF_AuftrAnkErz.Refresh\n'\n'    ' Logbucheintrag\n'    If DLookup(\"&#91;Benutzerverwaltung]\", \"HT_SysParameter\") = True Then\n'        Call SetzeBenutzerLog(\"Drucke Angebot o. Summen Ankauf Erz.-Preis! Auftrag Nr: \" &amp; CStr(Forms!HF_AuftrAnkErz!AuftragNr) &amp; \", Angebot Nr: \" &amp; CStr(Forms!HF_AuftrAnkErz!AngebotNr))\n'    End If\n'End If\n  \nExit_DruckAngeboSum_Click:\n    On Error Resume Next\n'    Tabelle1.Close\n'    DB1.Close\n    Exit Sub\n\nErr_DruckAngeboSum_Click:\n    If err = 2501 Then\n        Me!Schlie\u00dfen.SetFocus\n    Else\n        MsgBox Error$\n    End If\n    Resume Exit_DruckAngeboSum_Click\n\nEnd Sub<\/code><\/pre>\n\n\n\n<p>Die drei Zeilen Code oder so sind das was nach dem \u00dcberarbeiten bleibt.<br>Ein paar Dinge d\u00fcrften Programmierer in neueren Sprachen durchaus verunsichern, das sind die Label zu denen man springt. Ja, das kann man inzwischen anders l\u00f6sen und nein, es ist recht typisch f\u00fcr VBA. Man sieht, nur f\u00fcr die Fehlerbehandlung kommen &#8222;locker&#8220; 5- 10 Zeilen Code zu jeder Funktion. Insgesamt sind es \u00fcber 500 000 Zeilen an Code und viele Methoden gehen \u00fcber mehrere Seiten.<br><br>Wie man sehen kann, gibt es keine Trennung der Bereiche. In einer Methode\/Funktion gibt es Zugriffe auf die Datenbank, Manipulation der UI und Interaktion mit dem Benutzer. Ich bef\u00fcrchte, da\u00df ist immer noch Stand der Dinge bei sehr vielen Access Programmen. Als wirklich ernsthaftes Problem sehe ich das Fehlen von brauchbaren Testm\u00f6glichkeiten an. AFAIK gibt es AccUnit zum Testen, das bekomme ich hier nicht installiert und ich bin derzeit immer noch zu faul um mich dahinterzuklemmen. <\/p>\n\n\n\n<p>Die Klasse, in der ich es auslagerte, sieht der Code nun so aus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Public Sub doOutput()\n    Dim bAdjustNumber As Boolean\n    Dim objControl As CControlNummernKreise\n    \n    \n\nOn Error GoTo HandleError\n    Dim iAuswahl As Integer\n    If outputMedia = outMediumPreview Then\n        outputPreview\n        GoTo HandleExit\n    End If\n    \n    \n    bAdjustNumber = True\n    If NZ(actForm(textFieldNumberName), \"\") &lt;> \"\" Then\n        iAuswahl = askToReprintIfPrintedBefore()\n        If iAuswahl = vbNo Then\n            GoTo HandleExit\n        Else\n            bAdjustNumber = False\n        End If\n    End If\n   \n    Set objControl = actualizeFormDataBeforePrint()\n         actualizeNumberCircle objControl, bAdjustNumber\n         Set objControl = Nothing\n        \n         actionBeforePrint\n             If outputMedia = outMediumPrinter Then\n                 outputPrinter\n             Else\n                 outputEmail\n             End If\n         actionAfterPrint\n    actualizeFormDataAfterPrint\n    writeLog\n\n    \n    \nHandleExit:\n    On Error Resume Next\n    Exit Sub\n\n\nHandleError:\n    If err.Number &lt;> 0 Then\n       MsgBox \"Error \" &amp; err.Number &amp; \" (\" &amp; err.Description &amp; \") in procedure doOutput.\"\n    End If\n    GoTo HandleExit\n\n\nEnd Sub<\/code><\/pre>\n\n\n\n<p>Sicher noch reichlich zu kritisieren, aber ich denke, eine Verbesserung ist zu erkennen.<br>Der Witz an dieser einen Methode ist: Die kann ich so an ungef\u00e4hr 8 Stellen so benutzen und mu\u00df da nichts mehr anfassen. Ich mu\u00df die Daten entsprechend vorbelegen<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Case FRM_AUFTRAG_ANKAUF_ERZ\nIf sKundeNr = \"143\" Then\nobjResult.reportName = \"BR_DruckAngebotAnkErz_Bel\"\nElse\nobjResult.reportName = \"BR_DruckAngebotAnkErz\"\nEnd If            \nobjResult.logEntry = \"Druck Angebot Ankauf Erz. m. Summen Auftrag Nr: \" &amp; NZ(objResult.orderNo, 0) &amp; _\n                                 \", Angebot Nr: \" &amp; NZ(objResult.actForm(objResult.textFieldNumberName), \"\")\n\n            objResult.lblFuerKLNr = \"Lieferant Nr:\"\n\n            Set objParameterAngebot = parDruckAngebot_WH()\n            objParameterAngebot.mainTableName = \"HT_AuftragAnkaufErz\"\n            objParameterAngebot.subTableName = \"UT_AuftragAnkaufErz_Positionen\"\n            objParameterAngebot.fieldNameKLNo = \"LieferantNr\"<\/code><\/pre>\n\n\n\n<p>gen, aber die Logik dieses Teils geht nicht verloren.  Ich denke, da\u00df ist einer meiner Lieblingstechniken, einen Algorithmus aust\u00fcfteln und dann m\u00f6glichst nicht mehr  anfassen zu m\u00fcssen. Sollte was schiefgehen, dann habe ich hier eine zentrale Anlaufstelle, um es zu korrigieren und mu\u00df nicht die Korrektur 8 mal wiederholen. <br>Leider macht es einem VBA unglaublich schwer Code wiederzuverwenden, denn obwohl das hier eine Klasse ist, kann ich nicht einfach davon ableiten und nur die Sachen umschreiben, die ich brauche.  Ja, es gibt Interfaces, aber die mu\u00df man dann von a-z in  allen Klassen implementieren, das ist einfach schlecht und d\u00fcrfte Leuten, die mit Java, Python, Ruby oder so gut wie jeder anderen OO-Sprache programmieren, die Tr\u00e4nen in die Augen treiben. Die Dinge sind aber nun mal, wie sie sind. Modularer bek\u00e4me man es nur hin, wenn man jede Methode in ein eigenes Interface auslagerte und  dann die Interfaces implementierte, die einzige zug\u00e4ngliche Methode w\u00e4re dann z.B. f\u00fcr<br> <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> If outputMedia = outMediumPreview Then\n        outputPreview\n        GoTo HandleExit\n    End If<\/code><\/pre>\n\n\n\n<p>outputTo aber man m\u00fcsste halt all notwendigen Daten in diesem Interface hinterlegen und br\u00e4uchte zumindest ein paar Parameter oder ein Parameter Objekt.<br><br>Dann k\u00f6nnte man ein Interface haben f\u00fcr eine Klasse mit dem Namen OutputPreview<br>und den Wert so setzen<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>objIf as OutputInterface\nif Test_If_Angebot then\n  set objIf = new OutputInterfaceAngebot \n...\n:..\n\nund riefe es so auf\nobjIf.outputTo\n<\/code><\/pre>\n\n\n\n<p>Es geht leider nicht anders und dann bekommt man eben auch so etwas:<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Case FRM_AUFTRAG_ANKAUF_ERZ\n            If sKundeNr = \"143\" Then\n                    objResult.reportName = \"BR_DruckAngebotAnkErz_Bel\"\n                Else\n                    objResult.reportName = \"BR_DruckAngebotAnkErz\"\n                End If\n               \n                objResult.logEntry = \"Druck Angebot Ankauf Erz. m. Summen Auftrag Nr: \" &amp; NZ(objResult.orderNo, 0) &amp; _\n                                     \", Angebot Nr: \" &amp; NZ(objResult.actForm(objResult.textFieldNumberName), \"\")\n                                     \n                objResult.lblFuerKLNr = \"Lieferant Nr:\"\n            \n                Set objParameterAngebot = parDruckAngebot_WH()\n                objParameterAngebot.mainTableName = \"HT_AuftragAnkaufErz\"\n                objParameterAngebot.subTableName = \"UT_AuftragAnkaufErz_Positionen\"\n                objParameterAngebot.fieldNameKLNo = \"LieferantNr\"<\/code><\/pre>\n\n\n\n<p>Hier mu\u00df ich einfach festhalten MS hat sich einiges bei VBA gedacht aber a) nicht zu Ende und b) mangelhaft an bestimmten Stellen.<br><br>Es gibt durchaus eine Menge Fans von Access. Vom Standpunkt von guter OO-Programmierung ist VBA ein Sanierungsfall. Dabei k\u00f6nnte es so einfach sein. VBA als Mitglied der .NET Sprachfamilie und gut w\u00e4r&#8217;s. Ich verstehe nicht, warum es MS nicht macht. Die Unterst\u00fctzung durch Werkzeuge ist so in den 80 er Jahren des letzten Jahrtausends h\u00e4ngen geblieben. Ja, man kann in VBA auch riesige Programme schreiben, es tut aber weh &#8230;.<br><br>Wo MS-Access (mit VBA) vollkommen mangelhaft ist<br>1) Keine integrierten Tests<br>2)  An Objekten orientiert, aber nicht OO-m\u00e4ssig zu programmieren<br>3) Grauenhafte Benutzung in einem RCS (hier benutze ich TortoiseGit) , Problem: Gro\u00df\/Kleinschreibung geht munter durcheinander, es gibt IDS, die sich einfach \u00e4ndern<br>4) Keine Unterst\u00fctzung f\u00fcr die Trennung von UI, Daten und dem Programm. Wie geschrieben, der Code ist heute noch typisch f\u00fcr Ms Access. Man bekommt  halt schnell was zusammen &#8230;<br>5) der SQL Editor ist eine Zumutung!<br><br>Wo  es gl\u00e4nzt<br>1) mal eben was zusammenstoppeln ist schnell erledigt<br>2) der Direktbereich, man kann w\u00e4hrend der Laufzeit anhalten und sich alles anschauen, kein rekompilieren n\u00f6tig<br>3) preisg\u00fcnstig<\/p>\n\n\n\n<p>Es ist klar MS will, da\u00df wir MS-SQL mit C# benutzen, es ist nicht \u00fcberzeugend, da\u00df dies f\u00fcr kleine Betriebe eine bessere L\u00f6sung als eine MS-Access basierte w\u00e4re. <br><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Speziell, wie wahnsinnig und menschenverachtend die inzwischen geworden ist. Es ist aber nicht mein einziges Steckenpferd ;-). Es klang sicher schon gelegentlich an, da\u00df ich Programmierer bin. Ich pflege seit mehr als 10 Jahren eine Branchenl\u00f6sung f\u00fcr Abfallbetriebe, Containerdienste. Das Ganze ist f\u00fcr kleine Betriebe mit weniger als sagen wir mal 5 AP f\u00fcr die [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7979],"tags":[],"class_list":["post-12532","post","type-post","status-publish","format-standard","hentry","category-programmierung"],"_links":{"self":[{"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/posts\/12532","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/comments?post=12532"}],"version-history":[{"count":0,"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/posts\/12532\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/media?parent=12532"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/categories?post=12532"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.q-software-solutions.de\/blog\/wp-json\/wp\/v2\/tags?post=12532"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}