Limit-Operations

Ein Ding, das ich bei C# schon immer und wieder vermisst habe (zumindest Damals[TM]) ist ein LimitTo.

Wie oft kommt es vor, dass man Parameterwerte oder irgendwelche Eingaben auf eine gewisse Spanne eingrenzen will. Daher habe ich mir schon lange mal die Klasse LimitOperations geschrieben, welche solche LimitTo-Erweiterungsmethoden enthält.

Aufgebaut auf IComparable klappt das mit jedem Datentyp.

Die Benutzung ist erwartungsgemäß eine neue Zuweisung. Der originäre Wert wird nicht angerührt. Geht also bestens mit Werttypen.

lvalue = lvalue.LimitTo(1,60);

Hier mal die von mir empfohlene Klasse. Ganz klassisch ohne UnitTests (uups)

Code

using System;

namespace WpfBib.Extensions
{
	/// <summary>
	/// Klasse stellt Erweiterungsmethoden bereit um an ordinalen Typen
	/// Limits einzuhalten. Also "lass das nicht größer werden als..."
	/// </summary>
	/// <example>
	/// int i = 43, j=i.LimitTo(2,44);
	/// </example>
	public static class LimitOperations
	{
		public static T LimitTo<T>(this T inValue, T lowerLimit, T upperLimit) where T : IComparable
		{
			if (inValue.CompareTo(lowerLimit) < 0)
				return lowerLimit;
			if (inValue.CompareTo(upperLimit) > 0)
				return upperLimit;
			return inValue;
		}

		public static T LimitTo<T>(this T inValue, T upperLimit) where T : IComparable
		{
			if (inValue.CompareTo(upperLimit) > 0)
				return upperLimit;
			return inValue;
		}

		public static double LimitTo_NoNan(this double inValue, double upperLimit)
		{
			if (double.IsNaN(upperLimit))
				return inValue;
			if (inValue.CompareTo(upperLimit) > 0)
				return upperLimit;
			return inValue;
		}
	}
}

Amazon Pay ist auch Dreck

Wie ja generell Amazon Dreck ist und als normal gesinnter Mensch man diesem Laden aus dem Weg geht. Sowohl Ethisch (prekäre Arbeitsbedingungen, kein Steuerzahler), Machtpolitisch (Bezos ist zu reich und Geld ist Macht) als auch Kunden-technisch (kein Schwein redet mit einem). Schlicht: Man muss diesen Verein nicht unterstützen

Aufreger

Ich hab mal wieder einen Aufreger bekommen ohne danach gefragt zu haben. Dumm nur, dass ich mit dem Amazon-Konzern Geschäfte gemacht habe. Jetzt ärgere ich mich so sehr, dass ich mich hier auszukotzen muss.

Was ist passiert

Der Dreifachfail. Ich hatte was für einen Freund bestellt. Nicht bei Amazon, denn wer bei Trost ist, bestellt nicht bei Amazon. Also irgend ein Internethändler. Bezahlung ging umständlich, Klarna(türlichnicht) und Amazon Pay. Da ich dort seit Urzeiten noch meine IBAN drin hatte, dachte ich – der einfachste Weg. Lieferadresse eingegeben. Default Zahlungsmethode ausgewählt, klick, klick fertig.

Nö. Erstens ging das Paket dann doch an die Rechnungsadresse…. was zur Folge hatte, dass es nicht nur zu spät war, sondern auch noch 10€ mehr gekostet hat….. Dann kam mir aber noch Amazon Pay in die Quere. Die meinten dann irgendwie, ich solle doch Geld überweisen und dazu noch 3€ mehr wegen Rücklastschrift. Danke auch.
Rücklastschrift? Wieso das denn. In Amazon die Zahlungsmittel kontrolliert. Alles korrekte und gültige. Also WARUM? Unklar.
Ich erinnerte mich, dass die Standardauswahl nicht wirklich eine Bekannte Endziffer hatte (warum eigentlich immer nur Endziffern?). Aber ich dachte mir nichts weiter, denn ich hatte ja alle ungültigen Zahlungsmethoden längst rausgeworfen. Was also war passiert?

Natürlich war von Amazon Pay niemand zu sprechen. Ich bekam zwar mal Kontakt zu Amazon, aber nur um zu erfahren, dass Amazon Pay ja was komplett anderes ist als Amazon. Toll nur, dass ich in Amazon die Zahlungsmittel verwalte. Anscheinend mussten sie wegen irgendwelcher Steuervorteile ihre Bank nach Luxenburg auslagern – haha. Nur haben sie die Datenschnittstelle verpeilt. Der Default blieb, die Zahlungsmittel wurden aktualisiert.

Forderungen

Und jetzt, da sie…. die beiden Amazons da…. einen Fehler begangen hatten – ja mal eben von einer (in der Tat für alle Seiten) veralteten Zahlungsmethode abzubuchen. Da soll ich jetzt die Suppe auslöffeln, und ihre Rücklastschriftgebühr übernehmen.
Schlimmer noch: Ich habe jetzt UMSTÄNDE. Ich muss mich um SCHEIßE kümmern, derweil SIE der Zahlungsdienstleister sind, die sich darum kümmern sollte. Und ich soll noch mehr zahlen.
Dabei hatte ich alle Zahlungsmethoden gepflegt und korrekt,

Guten Tag!

Wir haben Sie bereits mehrfach bezüglich der fehlgeschlagenen Zahlung per Lastschrift für Ihre Bestellung kontaktiert. Dabei haben wir auch die umgehende Zahlung angefordert, haben aber bisher immer noch keine Zahlung erhalten.

Es kann bis zu 5 Geschäftstage dauern, bis die Bank die Zahlung verarbeitet hat und Ihr Kundenkonto aktualisiert wurde. Wenn Sie die Artikel bereits bezahlt oder zurückgesendet haben, können Sie diese Nachricht ignorieren.

Falls wir innerhalb der nächsten 5 Geschäftstage keine Zahlung von Ihnen erhalten, übergeben wir den Vorgang an unsere Inkassoagentur (Riverty Services), die die Zahlung dann in unserem Auftrag von Ihnen einfordern wird. Bezahlen Sie bitte unverzüglich 33.48 EUR auf das folgende Konto, um Maßnahmen zu vermeiden:
-- Empfänger: Amazon Payments Europe S.C.A.
-- Bank: HSBC Trinkaus und Burkhardt
-- IBAN: DE87300308801908262006
-- BIC: TUBDDEDDXXX
-- Verwendungszweck: 34769184262122

Angaben zum Betrag:
Bestellnummer            Betrag              Rücklastschriftsgrund                   
------------------------------------------------------------------------------------------
P02-7478620-0157327      EUR 30.48           Konto geschlossen                       
Rücklastschriftentgelt   EUR 3.00            
------------------------------------------------------------------------------------------
Gesamtbetrag             EUR 33.48           

Bestellte Artikel:
Bestellnummer            Bestelldatum        Webseite                                
------------------------------------------------------------------------------------------
P02-7478620-0157327      15.04.2024         Xxxxxxxxxxxyyyy

Nein Danke

OK, so eine Behandlung brauche ich nicht. Ich mache einen NOCH größeren Bogen um Amazon. Tut es mir gleich und straft den Verein ab…

Resumé: Ehe die mich noch in der Schufa anschwärzen und ich keine Ruhe rein bekomme. Überweise ich ihnen jetzt Geld…. ist ja nur 3€ mehr. Grollgroll. Und nutze sie nie mehr. Vielleicht überweise ich auch mehr, damit sie was zurück überweisen müssen

Meine Firefox-Addons

Die Addons, ohne die ich keinen Firefox betreibe.

Firefox

Achja, ich benutze für fast alles Firefox. Ungoogled Chrome liegt daneben, falls mal irgendwas nicht so will – passiert leider immer wieder mal. Aja und Edge in allen Varianten lasse ich hinter mir liegen. Schaue ich quasi gar nicht an.

So fein diese OSS und Firefox-Geschichte auch ist, aber das Internet ist halt einfach schlecht und böse und möchte mit einigen Plugins gezähmt werden. Folgende Addons empfehle ich jedem, sich zu installieren und drin zu behalten:

Absolute Enable Right Click & Copy

Mit diesem Addon kann ich überall, da wo Webentwickler auch anderer Meinung sind, Kopieren und Einfügen nutzen. Wieso auch sollte es gefährlich sein, ein Passwort einzufügen. Wer verdammt will denn heute noch ohne Passwortmanager auskommen?

AdBlocker for YouTube™

Naja klar, wer schaut sich schon Werbung bei Youtube an. Also weg damit. Schneller wirds damit ohnehin.

DuckDuckGo Privacy Essentials

Privatsphäre und Datenschutz hoch. Dieses Addon von den Machern von DuckDuckGo blockiert die meisten Trackingcookies und Hosts. Ob’s was bringt, weiß ich nicht. Vielleicht gebe ich damit ja nur die Daten von Google zu Duck?! Aber fühle mich besser.

Everything Metric – Auto Unit Converter

Diese Erweiterung schreibt mir hinter alle im Text erkannten Imperialen Angaben noch eine verständliche, metrische Einheit dazu. Beispiel: 10 feet【𝟯 𝗺】mpg -> L/100 km

I don’t care about cookies

Cookiebanner sind nervig, supernervig. Vor allem, wenn sie verzögert nachgeladen werden. Da ist der Gesetzgeber auch irgendwie in die Scheiße getreten. Am Ende machen die Webseiten ohnehin, was sie wollen oder funktionieren nicht, wenn man nicht in alles einwilligt. Dieses Addon klickt automatisch immer und schnellstens auf Zustimmung. Denn im zweiten Schritt werden die Cookies dieser Sorte wieder automatisch gelöscht. Also nix gekonnt, weniger Nerv.

IPvFoo

Das braucht zwar nicht jeder, aber auf diese Weise kann ich als Interessierter sehen, wie viele der angesurften Webseiten zusätzliche Hosts ansteuern und ob die IPv6 oder noch IPv4 nutzen. Also ne Nerdsache.

KeePassXC-Browser

Weil ich ja einen Passwortmanager wie Keepass nutze (und Passwörter lokal + synchronisiert mit meiner nextcloud halt), brauche ich natürlich das Plugin, damit die Zugangsdaten im Browser landen.

LocalCDN

Auch wieder eine Kombi aus Datenschutz und Geschwindigkeit. Das Internet hat CDNs. Viele Webseiten nutzen diese Content Delivery Networks, um relativ nahe die Datenintensiven Downloads bereitzustellen. Nur: Damit kann man sich auch wieder überwachen lassen. Hier geht es eher um häufig genutzte .js wie bootstrap oder vue.js oder Fonts wie GoogleFonts oder fontawesome, die dann lokal in diesem Addon liegen. Somit spare ich wieder Zeit und Daten. Optional für manche.

Remove German Gender Language

Ja, Verunstaltungen der deutschen Sprache behindert den Lesefluss und ändert nichts an der Gesellschaft – es spaltet eher. Da man die Leute, die das machen jedoch nicht umerziehen kann, kann man zumindest die unlesbaren Textpassagen zurechtkemmen und von den meisten Auswüchsen sogenannter Gendersprache (die eigentlich Sexussprache heißen müsste) befreit. Sehr zu empfehlen.

uBlock Origin

Das Addon schlecht hin – alternativ zu AddBlockPlus. Es blockiert die wichtigsten der schlechten URLs und verhindert damit Tracking, lange ladezeiten und nervende Werbung. Natürlich nicht ganz, aber doch ganz schön. Unbedingt zu empfehlen, die Welt wird besser dadurch.

User-Agent Switcher and Manager

Der ist auch eher nerdig, aber manchmal muss man der Webseite halt vorgaukeln, dass man mit dem IE 6.0 unterwegs ist oder mit einem Mobilgerät drauf zugreift. Dann hilft dieser user agent switcher. Also eher optional, aber für mich gut.

Es sind nur Daten im Format TT.MM.JJJJ erlaubt.

Die Eingabe in diesem Feld ist ungültig.

Die Frage ist: Warum?

Ja, klar, denn eine Angabe wie 5.6.1988 oder 05061988 oder 5.6.88 entsprechen nicht dem Regulären Ausdruck, der das Format TT.MM.JJJJ beschreibt. Daher ist es falsch. Und damit ist dieser Artikel auch schon zu Ende.

Aber nein, Spaß. Natürlich gibt es darüber jede Menge zu jammern, lästern und auch zu verbessern.

Denn es ist eigentlich eine Unsitte von diversen Programmierern oder Softwareentwicklern (sind es wirklich schon welche?), Datumsparser so zu implementieren, dass man als Endanwender mehr Kummer als Arbeit hat. Beides ist schlecht.

Die Frage ist also: Warum muss das entsprechende Programm so hart implementiert sein, dass nur exakt dieses ausladende Format erlaubt ist, und warum kann der Programmierer nicht einen Algorithmus implementieren, die ein heuristisch optimistisches Parsen erlaubt. Es wäre so einfach und so eindeutig. Die Parser existieren und man müsste einfach nur ein DateTime.Parse(string) auf das Ganze los lassen. Das, was da in der Regel herauskommt, ist eindeutig und das gewünschte. Zur Kontrolle kann man das geparste Datum ja dann wieder in dem GUI-Feld in der genormten Langschreibweise darstellen. Ein geneigter Anwender wird es im Zweifelsfalle dann korrigieren.

Insofern ergeht ein dringender Aufruf an alle Softwareentwickeler und diejenigen Programmierer, die welche werden wollen: Macht den Endanwendern das Eingeben von Datumsen so einfach wie möglich. Last den Server-Rechner schruppen, der ist dafür da – nicht der Anwender. Heuristik geht über möglichst stark und formal eingeschränkte Eingabefelder! Relaxiert die Anforderung – denn oft wisst ihr nicht genug über den Anwender und seine Kultur. Ein Beispiel ist Your name ist invalid.

Gewerbe an- abmelden bei Stadt München

Ich, Besitzer eines nPA, wollte dieser Tage mal eine Gewerbeabmeldung machen. Daher habe ich natürlich nach einem digitalen Verfahren gesucht (auf münchen.de), mit dem die Gewerbeabmeldung möglich ist. Sprich: Personalausweis und Kartenleser einsetzen, statt Formulare und Drucker zu bemühen.
Doch Pustekuchen. Bitte nur Analogditgal.
Pfui!

Das Verfahren, was angeboten wird wäre:

die Anträge können auch schriftlich (per Post oder per Mail) mit dem hierfür erforderlichen Formular sowie der Ausweiskopie des Gewerbetreibenden beim Kreisverwaltungsreferat eingereicht werden.

Benötigte Unterlagen

Wir bitten Sie, die Gewerbeabmeldung schriftlich per Post oder E-Mail mit den erforderlichen Unterlagen vorzunehmen:

  • Vollständig ausgefülltes Formular „Gewerbeabmeldung“
    (wichtig: geben Sie das Datum der Betriebsaufgabe an)
  • Personalausweis oder Reisepass in Kopie
  • Gewerbeschein oder Kopie des Gewerbescheins
  • bei Bevollmächtigung: eine schriftliche Vollmacht und Ausweis des Vollmachtgebers sowie des Bevollmächtigten in Kopie

Bearbeitungszeit

  • Sie erhalten die Abmeldebescheinigung umgehend per Post. EIne Zahlungsaufforderung geht Ihnen gesondert zu. Dies kann aktuell bis zu 3 Monate dauern.

Erstens ist es einer so großen Gemeinde nicht würdig, zweitens im Jahre 2022 ein Skandal und drittens hat es folgende Nachteile:

  • Meine Ausweiskopie könnte in falsche Hände geraten
  • Meine Unterschrift (hübsch eingescannt) könnte in falsche Hände geraten – denn offenbar vertraut Gott und die Welt in PDFs mit dem eingefügten Bild einer Unterschrift als authentisches Dokument.
  • Ich muss ein Formular ausfüllen und meine Daten, die eh schon bekannt sind und auf meinem Ausweis stehen. Überflüssige Arbeit ohne Unterstützung (Ausfüllhilfe bereits vorliegender Daten)
  • Die Authentifizierung ist nicht so sicher, wie eine Ausweisung mit dem nPA – siehe Unterschriftsproblematik
  • Sie haben mehr Arbeit in der Verwaltung
  • Formular soll unterschrieben werden – unnötig bei Ausweisung digital – wieder Unterschriftsproblematik (Bild gilt offenbar) Harrrrrr.
  • Formular muss ausgedruckt werden und eingescannt – völlig absurd und undigital.
  • Anmeldung soll mitgeschickt werden – die müsste ja vorhanden sein und könnte nur abgeglichen werden. Völlig absurde Mehrarbeit und Datenredundanz.

Dabei könnte das Verfahren so schön modern und einfach sein:

  • Anmeldung mit nPA bei der Webseite
  • Navigation zu Gewerbeabmeldung
  • Es werden meine angemeldeten Gewerbe aufgeführt
  • Ich wähle dasjenige aus
  • Gebe die entsprechenden Zusatzinfos ein (Datum der Ambledung etc.)
  • Bestätige eine dabei eventuell auftretende Adressänderung (Gewerbe wurde halt mal woanders angemeldet)
  • Bestätige alles
  • Bin fertig und erhalte ein digital unterschriebenes PDF (welches ich auch immer wieder holen könnte)
  • Stadt ist auch fertig.

Aber nein, man ist immer noch nicht im heute angekommen. Daher mache ich jetzt mit Estland weiter – da gehen solche Dinge. „GmbH“ mit 2,5k€ und das „Gewerbe“ ist gleich mit angemeldet. Servus Gewerbesteuer München!

Aja und ein Aufruf von https://münchen.de/ landet im Datennirwna. Kann denn hier nach 30 J immer noch keiner einen Webserver + DNS korrekt konfigurieren? Krass!

China ist kaputt

Ich verfolge ja schon eine Weile Nachrichten aus China. Ist ja auch interessant etc. Die letzten Jahre konnte man ja irgendwie glauben, das Land kocht nicht nur mit Wasser, sondern mit Spiritus und läuft dem Westen in allen Belangen davon…. aber das ist wohl 1. nur Schein und 2. alles auf Pump (Mensch, Geld, Natur) und 3. Sondereffekte. Das Land hat enorme Probleme und wird uns absehbar nicht überholen. Zunächst mal ein paar Fakten, wie uns das Land scheinbar abhängt. Danach die Probleme.

  • Mit die höchsten Hochhäuser
  • Ganze Städte werden im Akkord hingestellt
  • Täglich werden 100 Hochhäuser fertig
  • Enormes Wirtschaftswachstum
  • Das längste Autobahnnetz der Welt in kürzester Zeit
  • mit den abenteuerlichsten Brücken und Tunneln
  • Das längste und am schnellsten wachsende Schnellbahnnetz
  • Die schnellsten Supercomputer
  • Hypermoderne Städte wie Shenzen mit gigantsichen Elektronikfabriken
  • Krasse Fortschritte bei KI und kompromissloser Einsatz
  • Schnellster Ausbau von Erneuerbaren Energien
  • Mehr Millionäre jeden Tag
  • Umschlagplatz der Welt für Seltene Erden
  • Viele E-Auto-Firmen (viel mehr)
  • Große Investments in Kriegsmaterial inkl. eigener Flugzeugträger und Überschallbomber.
  • Raumnation China

Das Ganze ist aber nicht nur auf Fleiß und Können aufgebaut. In dem Land staut sich eine Latte gigantischer Probleme. Hier mal eine kleine Liste der Probleme die das Land hat.

  • Gigantische Umweltprobleme durch Industrie und Gewinnstreben
  • inklusive Artensterben (Spatzen, Bienen), die bei der Schädlingsbekämpfung und Bestäubung geholfen hätten. Jetzt tut es der Mensch
  • Schlechte und teils belastete Lebensmittel. Durch Industrieabwässer und Gewinnstreben (soll Fälle gegeben haben mit Plastikreis, Kühe mit Blei füttern für mehr Gewicht, Melanin im Milchpulver). Also sogar vergiftet für Profit
  • TOFU-Gebäude. Gebäude werden aus minderwertigem Stahl und bröselndem Beton sowie viel zu dünnen Wänden gebaut und fallen vor den Augen der Bewohner auseinander. Im schlimmsten Fall (passiert wohl wöchentlich) stürzen Gebäude ein und begraben Bewohner. Billig, billig, gefährlich
  • Mindere Qualität bei Gebäuden. Neu hingepflasterte Geisterstädte verfallen nach nur 5 J wieder. Nichts hat Substanz.
  • Miese Qualität auf Kosten der Sicherheit bei Elektronik. Bei Geräten wird der Tod durch el. Schlag der Anwender bewusst in kauf genommen, um Gewinne zu maximieren. (Leider kommt das Zeug bis zu uns)
  • Miese Qualität von Infrastruktur. Brücken stürzen ein oder müssen nach kurzer Zeit erneuert werden (= teurer als gedacht). Scheint bei der Schnellbahn und dem Weltallprogramm besser zu sein.
  • Ein Überalterungsproblem. Noch sind die meisten Leute tüchtig (Aufbaugeneration). Aber durch die 1-Kind-Politik kommt wenig nach und zudem viele Männer und es wird immer mehr alte (Rentner) geben.
  • Das führt mittelfristig zu einem Pflegeproblem
  • Eine Ausgelaugte Jugend. Die Jugend musste bisher sehr stoisch Dinge lernen (10-14h am Tag). Sie hat keine Lust mehr und es formiert sich Widerstand.
  • Genau diese Jugend will sich auch nicht mehr in 996-Arbeit zwängen lassen. von 9-21h arbeiten an 6 Tagen die Woche. Die Mittelschicht wird anhand dieser Arbeitmodalitäten zerschlissen. Auch hier regt sich Widerstand
  • Ineffizientes Arbeitsleben. Mit 996 kann mir keiner erzählen, dass man dabei produktiver ist als mit 9-17 Uhr an 4 Tagen im Westen. Zudem besteht keine Fehlerkultur und zu viel „Auswendiglernen“, nicht reflektieren und mal was hinterfragen.
  • Die Schnellbahn ist zu schnell und auf Pump gebaut worden. Aktuell häuft sie 100 Mio Schulden pro Tag an, weil sie aufgrund der Ticketpreise mal Passagierkilometer/km nicht kostendeckend zu betreiben ist.
  • Zwar wurde die Infrastruktur (Bahn, Autobahn) sehr schnell und günstig hin gebaut (so lange die Gehälter noch so günstig sind), dafür aber die im Nordwesten lebende Bevölkerung wie Sklaven ausgebeutet und damit auch Gesellschaftlicher Schaden angerichtet (Gesundheit).
  • Stromprobleme. Man verhaut es sich sehr schnell mit anderen Ländern (z.B. Australien) wegen Lappalien und hat dann nicht mehr genug Kohle, um 7/24 Strom zu haben. So sind aktuell 11/2021 massive und großflächige Stromausfälle in Provinzen des Nordostens. Betrifft Städte und Industrie. Das ist super schädlich für den Fortschritt und bringt Menschen in ziemliche Notlagen. Da Strom sehr günstig und staatlich reguliert verkauft wird, können Kraftwerkbetreiber nicht mehr kostendeckend arbeiten und schalten ab.
  • Ein Überwachungsproblem
  • Das Betreiben von KZs für Uiguren. Man beraubt sich aus Xenophobie eines Teils der arbeitenden Gesellschaft.
  • Ein Luftverschmutzungsproblem und einhergehend Gesundheitliche Probleme. Noch nie gab es so viele Hautkrankheiten und Autoimmunkrankheiten.

Hannah B. und die geheime Chemnitzer U-Bahn

Es klingt wie aus einem schlechten amerikanischen, immer wieder aufgewärmten, Märchen und fand doch vor der eigenen Haustür statt: die zehnjähriger Hannah B. Fiel auf dem Heimweg von der Schule zu den berühmten Kletterfelsen einem Eichhörnchen folgend in das plötzlich, zur Grabung des einer zweiten Bazillenröhre, ausgehobene Loch zwischen dem Hauptbahnhof und dem Chemnitzer Stadtteil Sonnenberg.

Und damit ließ sich nicht mehr unter Verschluss halten, was doch bei genauer Beobachtung längst offensichtlich war: In Chemnitz gibt es eine geheime U-Bahn. Träumten wir doch schon immer von einer schnellen Verbindung zwischen Lokomov und Haamit ohne an der Zenti 4000 Rentnern zu begegnen, so ist dieser Traum wahr. Nur irgendwie anders.

Diese stammt aus den finsteren Zeiten des vergangenen Jahrhunderts und obwohl es bis dato keinerlei Beweise gibt, keine Baupläne, keine offiziellen Beschlüsse und keine Fotos, deuten doch es ein paar Indizien auf das versteckte Verkehrsnetz hin. Noch heute ist im CVAG Plan von einem „speziellen Transportsystem“ namens AliTa die Rede, das nicht näher erklärt wird. Auch auf Stadtratsanfragen hin wird bis heute verschwiegen, wo die Linie 2 im ÖPNV System dieser Stadt den fährt. Die geheime U-Bahn war nicht dauerhaft in Betrieb: Sie wurde zuvorderst für den Transport von Waffen zum Bahnhof und ferner für Notfälle und Krisen gebaut. Eine wichtige Rolle spielte sie während des Zweiten Weltkrieges: Die Schächte und Stationen dienten als größter Luftschutzbunker

Ein eingleisiges System sollte die wichtigsten Macht-und Industriezentren der Stadt verbinden und eben hohe Regierungsbeamte jederzeit schnellstmöglich und heimlich aus der Stadt evakuiert werden. Die menschenscheue BabaLu erwog daher schon zu Beginn ihrer ewigen Amtszeit den Ausbau des Systems bis nach Kleinolbersdorf-Altenhain.

Ein Grund, warum die Stadt Chemnitz sich so lange weigerte , die Bazillenröhre bis zum Sonnenberg fortzusetzen und eine zweite Parallelröhre anzulegen, ist die äußerst wahrscheinliche Kreuzung mit der U-Bahn. Diese selbst stammt eben aus einer Zeit, der gewisse und nicht besonders leise Chemnitzer jetzt noch frönen und das passt nun gar nicht zur Wisch-und Weg-Imagekampagne „Chemnitz ist weder grau noch braun“. Dabei ist es an einem Markttag mit Obst-und Gärtnerstäden von oben betrachtet doch einfach nur bunt und grau.

Dieselbe Begründung dürfte für die ewige Unbebauung des Contilochs gelten. Da war man sich ewig unsicher, wie beim Bau die U-Bahn umgangen werden könnte. Erst ein Umbau des Dresdner Platzes samt einer Rest-Wildfläche machte die Bebauung mit dem Technischen Rathaus möglich. Während normaler jeder kleine Spatenstich, auch der in den Sandkästen eines Kindergartens im benachbarten Lutherviertels publiziert wird, wurde den bedeutenden Grabungen der zweiten Fuswegstammstrecke zum jegliche öffentliche Nachricht verweigert. Denn oberstes Gebot: die Existenz der U-Bahn muss unter Verschluss bleiben.

Derweil die eingangs erwähnte Hannah B. glücklicherweise den sichtbaren Notausgang auf der Sonnenstraße fand und ihrer alleinerziehenden Mutter in der immer einspurigen Schlange im Ghetto-Netto-Einkauf aufgeregt davon erzählte, lauschten wir auf und begannen die Grabungen in unseren Erinnerungen.

„Auch du wirst entdecken, dass viele Wahrheiten, an die wir uns klammern, von unserem persönlichen Standpunkt abhängig sind.“ (Obi wan Kenobi, Star Wars).

Ein sehr betagter Herr berichtete uns eins von den geheimen Plänen und seinem Plattenbau über dem Notausgang. Er wusste auch von den Stationen, die wir nun zu rekonstruieren versuchen.

Gemutmaßte Streckenführung:
Sonnenstraßenkarree, mysteriöse Treppe von alten Mann gehört
Contiloch
Hauptbahnhof, die seltsame Zwischengeschossführung des Liftes zum WC und zu Gleis 14 weist ja irgendwie drauf hin.
Limbacher Str/Hartmannwerk-eingestürztes Haus“ Risse in der Wand, Loch in der Grundmauer: (Anwohner der Brückenbaustelle Hartmannstraße in Sicherheit gebracht, März 2010, Die Ursache, die zu den Gebäudeschäden führte, ist nach wie vor unklar.)
Kaßberggewölbe
Geheimer Tresor im Gunzenhauser, falls ihr es zur nächsten Museumsnacht mal hineinschafft, schaut euch genau um.
Endstation Industriemuseum
Mögliche Abzweigungen zum Bahnhof-Mitte oder in Richtung Tietz/Heutige Tiefgarage der Sparkasse denkbar

Wie wird es nun weitergehen. Auch unter Ausschluss der Öffentlichkeit sind Millioneninvestitionen angekündigt. Nicht von dem Dauergünstling und Hoffreund aus Regensburg. Sondern von einem, und das ist so überraschend wie unglaublich clever, jüdisch-iranischen Konsortium. Deren Bedingung ist nun eine bessere Anbindung der Restaurants Shalom und Safran. Darauf wären selbst die größten Aluhüte nicht gekommen.

Mit EF N:M-Beziehungen pflegen

Letztens wieder in einem Projekt mit Entity Framework. Da habe ich wieder eine Erkenntnis erlangt, die ich hier zu teilen versuche.

Situation

Man stelle sich vor, die Software soll eine Tabelle mit einer Detailtabelle (n:m) bearbeiten. Als Beispiel nehmen wir Produkt und Laden. Zur Einnordung: Ein Produkt kann in vielen Läden geführt werden und ein Laden führt viele Produkte. Also klassisch n:m. Das Ganze soll mit Entity Framework umgesetzt werden. Als besondere Schwierigkeit hat Produkt keine Navigationseigenschaft für die Läden. Das mag EF nicht so sehr. Passieren kann das, wenn Produkt z.B. extern zugeliefert wird. Man also keinen Einfluss auf den Code hat.

Umsetzung:

Entitäten

public class Produkt 
{
    public Produkt(Guid id, string name, decimal preis)
    {
        Id = id;
        Name = name;
        Preis = preis;
    }

    public virtual Guid Id { get; set; }

    public virtual string Name { get; set; }

    public virtual decimal Preis { get; set; }
}

public class Laden
{
    public Laden(Guid id, string name)
    {
        Id = id;
        Name = name;
        Produkte = new HashSet<Produkt>();
    }

    public Guid Id { get; }

    public virtual string Name { get; set; }

    public virtual string Inhaber { get; set; }

    public virtual ICollection<Produkt> Produkte { get; set; }
}

Laden verweist auf n Produkte, Produkte aber nicht auf Laden. Klassischerweise würde EF hier eine 1:n-Beziehung per Konvention machen. Daher ist Arbeit im Modelbuilder nötig. Hier also unser Datenkontext:

public class ErpDbContext : DbContext
{

    public DbSet<Produkt> Produkts { get; set; }

    public DbSet<Laden> Ladens { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<Produkt>(b =>
        {
            b.ToTable("Produkts"); 
            b.ConfigureByConvention();
            b.HasKey(x => x.Id);
            b.Property(x => x.Name).HasColumnName(nameof(Produkt.Name)).IsRequired();
            b.Property(x => x.Preis).HasColumnName(nameof(Produkt.Preis)).IsRequired();
        });

        builder.Entity<Laden>(b =>
        {
            b.ToTable("Ladens"); 
            b.ConfigureByConvention();
            b.HasKey(x => x.Id);
            b.Property(x => x.Name).HasColumnName(nameof(Laden.Name)).IsRequired();
            b.Property(x => x.Preis).HasColumnName(nameof(Laden.Inhaber));
            b.HasMany<Produkt>(p => p.Produkte).WithMany("Laden").UsingEntity(j => j.ToTable("Produkt2Laden"));
        });

    }
}

Hier werden die beiden Entitäten eingerichtet und auch die einseitige N:M-Beziehung von Laden auf Produkte. Entity Framework erzeugt nun im Hintergrund die nötige Zwischentabelle, die hier „Produkt2Laden“ genannt wird. Im optimalen Fall hätte man die Navigationsproperties auf beiden Seiten gesetzt, aber hier geht es ja genau darum, es nur einseitig zu haben.

Der Trick ist hier die Anweisung .HasMany(p => p.Produkte).WithMany("Ladens"). Hier wird es als n:m-Beziehung definiert. Normalerweise wäre Ladens eine Eigenschaft von Produkt. Aber die haben wir ja nicht. Bei WithMany() wird daher kein Lambda, sondern eine Zeichenkette verwendet. Mit Stringliteralen kann man wenigstens etwas faken. Es könnte also irgendwas dort stehen. Aus diesem Grund funktioniert auch nicht Alles komplett. Die Verwendung von .Include(), um die Detailtabelle mitzuladen, wird zum Problem. Es geht nicht unter allen Umständen. So z.B. bei diesem Versuch eines Delete:

public async Task DeleteProduktFromLadenAsync(Guid ladenId, Guid produktId)
{
    Laden entitywithdteails = await this.Where(d => d.Id == ladenId).Include(i=>i.Produkte).FirstOrDefaultAsync();
    Produkt detail = entitywithdteails.Teams.FirstOrDefault(z=>z.Id == orgId);
    if( detail!=null )
    {
        entitywithdteails.Teams.Remove(detail);
    }
}

Dieser Versuch funktioniert nicht. Entity Framework gibt einem eine relativ nichtssagende Fehlermeldung. Auch wenn es nicht nötig ist, möchte EF da scheinbar einmal durch alle drei Relationen durch und wieder zurück. Da die „Rückreferenz“ also die ICollection<Produkt> Läden in Produkt fehlt, geht es per default nicht.
Nebenbei (wenn man also weiß, dass eine N:M-Beziehung über eine Zwischentabelle realisiert wird) ist es auch gar nicht nötig, zunächst auch nur eine der beiden Entitäten ([Laden,Produkt]) zu laden, um an den Beziehungen der beiden zu arbeiten. Umso mehr muss man sich um eine effiziente und zuverlässige Bearbeitung der Detailtabellendaten kümmern.

Coden

Ich bin dabei auf folgende beiden Implementierungen der Add/Remove-Operationen gekommen:

public async Task AddProdukteToLaden(Guid ladenId, Guid produktId)
{
    ErpDbContext context = await GetDbContextAsync();
    // fake element attachen und dann in die Collection rein.
    var prod = new Produkt(produktId, null, null);
    var laden = new Laden (ladenId, null, null);
    context.Attach(laden);
    // zeige EF, was passieren soll
    laden.Produkte.Add(prod);
}
public async Task DeleteProduktFromLadenAsync(Guid ladenId, Guid produktId)
{
    var laden = new Laden(ladenId, string.Empty);
    var produkt = new Produkt(produktId, string.Empty, 0);
    // simuliere Zustand davor
    laden.Produkte.Add(produkt);

    var context = await GetDbContextAsync();
    context.Attach(laden);
    // zeige EF, was du willst
    laden.Produkte.Remove(produkt);
}

Der Trick besteht dabei darin, dass Entity Framework die Hauptentitäten gar nicht unbedingt holen muss. Es ist auch nicht wichtig, was in den Feldern steht. Einzig wichtig ist die Id des Datensatzes. Wenn man so eine Enität an den DB-Kontext per .Attach() anfügt, beginnt das Tracking von Entity Framework ab diesem Zeitpunkt. Werden keine anderen Eigenschaften/Felder verändert, hat es auch keine Updates zur Folge. Ergeo wird in diesem Fall nur das Add/Remove von der Detailkollektion mitgeschnitten und somit in die DB persisitiert.

Wir lernen also: Man braucht nicht die ganzen Entitäten zu laden um an Detailkollektionen Änderungen zu machen. Und: context.SaveChanges() nicht vergessen. In meinem Fall gab es ein Framework drumherum, welches alles in eine UnitOfWork einpackt und somit erfolgreiche Operationen automatisch persisitiert sind. Daher fehlt es bei meinen Beispielen.

Erfolgreiche Softwareentwicklung

In diesem Beitrag versuche ich eine lose Auflistung von Punkten zu bieten, die eine Softwareentwicklung erfolgreich machen. Klar ist: Alles kann nichts muss. Also ist es weder so, dass man alles einsetzen muss, noch ist der Erfolg bei Einsatz garantiert.

Kommen wir also zu meinen Empfehlungen. Vermutlich ist kollidieren sogar einige meiner Empfehlungen. Daher gilt: Nehmt Euch raus, was Euch gefällt und setzt es für Euch richtig um. Denn wie so oft im Leben gibt es mehr als nur schwarz und weiß. Viel Spaß.

  • Einsatz eines Versionskontrollsystems (z.B. GIT)
  • Einsatz von Entwicklungszweigen im VCS (Versionskontrollsystems). Branches.
  • UnitTests: Für einzelne Klassen (Basisbausteine) bis hin zu Komponenten (Fertigbauteile) sollten UnitTests eingesetzt werden und bei CI/CD ausgeführt werden. UnitTests von Anfang an schreiben.
  • Für Komponentenübergreifende Teile sollten Modultests gemacht werden. Testszenarien. GUI-Tests, Replay-Tests und bei Testreleases und sowieso bei Releases ausgeführt werden.
  • Für die Gesamtanwendung sollte eine QA-Abteilung mit Menschen sich dran setzen. Die ganze Zeit und speziell zu Releases.
  • Einrichtung einer CI/CD-Pipeline . UnitTests sollten dort ausgeführt werden, besser: Statische Analysen + Code-Style. Als Ergebnis wird ein Installer/Paket oder ein Deployter Container o.ä. erwartet. Ein Tester kann also gleich ran an den Speck!
  • Release-Versionierung. Es kann für Regressionen wichtig sein, auf einen laufenden früheren Stand zurückzugehen. Also: „War das früher auch schon kaputt, oder ist das neu?“. Daher: Setups reproduzierbar machen (Installer, VMs, Container deployments etc.)
  • Release-Management. Es braucht einen Plan, wie man von Release zu Release kommt und wie ältere gepflegt werden und welche Merkmale „gemerged“ werden.
  • Ticketsystem einsetzen. Es ist unmöglich in einem Wust von Code und Information den Überblick zu behalten. Aufgaben müssen verwaltet werden. Tickets immer mit Commits im Versionskontrollsystem verknüpfen (wo sinnvoll).
  • Logging einsetzen. Erfindet das Rad nicht neu! Nutzt Logging-Frameworks. So kann auch auf externe Server geloggt werden etc.
  • Audit-Log. Je nach Anwendung frühzeitig einführen, denn später anflanschen ist doof. Es gibt immer wieder sicherheitsrelevante Dinge zu loggen -> Audit-Log
  • Baut die Anwendung in Schichten auf. Es hat sich bewährt.
  • ORM ist Pflicht. Die Datenschicht ist oft eine Relationale Datenbank. Vermeidet SQL-Zeug. Überbrückt die OO-ER-Lücke mit einem Object Relational Mapper (ORM) wie z.B. Entity Framework!
  • Scheut Euch nicht, auch mal andere Konzepte auszuprobieren. Sie könnten für das zu lösende Problem eine einfachere, zuverlässigere Lösung parat haben. Genannt sei das Aktor-Modell oder Reactive oder Prolog-artige Horn-Klauseln.
  • Baut Internationalisierung (i18n) von Anfang an ein. Das schärft gleich den Sinn, wann etwas lokalisiert dargestellt wird, und wann eine Darstellung kulturinvariant sein soll (bei Persistenz). Außerdem: Später hinzufügen ist wieder mal schlecht und teuer.
  • Baut Barrierefreiheit (accessiblity, a11y) von Beginn an ein. Es ist inzwischen in manchen Ländern oder Bereichen (öffentliche Hand) Pflicht. Aber: Großes Thema, nicht einfach. Screenreader sollten aber an den Text kommen können.
  • Setzt immer Unicode ein. Geht davon aus, dass die Anwender alle gültigen Zeichen der Welt einsetzen wollen und werden. Kodiert Dateien mit UTF-8-BOM.
  • Lernt bei Developer Falsehoods und dem gigantischen Git-Repo über Falsehoods, was so die typischen Fehlannahmen sind und vermeidet sie. Schon gewusst: Vor+ Nachname sind eine Besonderheit, die es hier gibt.
  • Bedenkt Sicherheit im Sinne von Security und setzt Verschlüsselung ein. Nutzt aber immer Bibliotheken und erfindet nichts selbst.
  • Paarprogrammierung. Setzt das XP-Merkmal der Paar-Programmierung ein. Ein Junior kann von einem Senior so viel lernen und Umgekehrt. Oder Wissen aus verschiedenen Programmbereichen verteilen. Vorteil: Es gibt nicht mehr einzelne Koryphäen, da sich Wissen dupliziert. Man lernt Programmiertechniken und Prozesse und die Entwickler sind konzentrierter dabei und machen weniger Fehler, was den „doppelten Aufwand“ mehr als Wett macht.
  • Nutze TDD – Test driven develoment. Nicht überall aber bei Kernkomponenten/Klassen empfohlen. Die dabei entstehenden UnitTests können gleich bleiben und in der CI-Pipeline verwendet werden.
  • Coding-Standard. Entwickelt einen Formatierungsstandard und forciert ihn mit Programmen wie StyleCop.
  • Code-Reviews. Macht z.b. alle 14 Tage ein öffentliches Review. Das ist ein unglaublich gutes Werkzeug, um Fehler zu finden und einander Einblick und Tricks zu vermitteln.
  • Check-In mit Pull-Requets und 4-Augen-Prinzip. Nutzt die Mechanismen, die moderne Entwicklungsplattformen bieten. Bei Git gibt es einen zweistufigen Commit mit Code-Review. Nutzt das und lasst einen Check-In immer von einer anderen Person reviewen. Es hilft immens, Fehler von Beginn an zu vermeiden.
  • Refaktorisieren. Mut zur Refaktorisierung. In der Regel kommt was besseres dabei raus. Schiefe Balken müssen gerade gerichtet werden. Nutzt Tools dazu.
  • Kommentiert, aber auch nicht zu viel. Dokumentation veraltet schnell, Kommentare veralten auch. Daher Pflegt zumindest diese. Keine Kommentare ist auch falsch. Mittelweg! Bewährt hat sich, öffentliche Methoden zu kommentieren mit (ohoh) XML-Doc und die Klasse an sich. Dies gefällt mir insbesondere bei fremdem Code, wenn wieder „die nächste Klasse“ auftaucht, und man wieder sich fragt : „warum ist diese Klasse jetzt nötig, was verdammt soll ihre Aufgabe jetzt genau sein?“. Wer mir diese Frage gleich oben beantwortet (und die sollte recht konstant bleiben), der hat bei mir einen Stein im Brett! Sparam im Quellcode zu kommentieren ist auch keine gute Idee. Ich vergesse recht schnell, welche kranken und doch genialen Ideen ich da hatte.
  • Nutzt schlaue Tools. Tools, die Euch das Leben einfacher machen und z.B. Code überprüfen, generieren oder automatisch umstrukturieren. Genannt sei hier z.B. Re-Sharper. Viele haben Angst vor der Automatik, aber sie ist deterministisch und wenn man es einmal gelernt hat, ist sie ein Segen. Denn sie denkt meist sogar an mehr, als man selbst. Dazu gehören auch Analysetools, wie z.B. der Nachfolger von FxCop oder LINTer. Sie analysieren Code auf typische Fehler und weisen Entwickler darauf hin.
  • Automatisiert, wo es geht. Das ist DevOps. Alle dummen, manuellen Schritte sollten wenn möglich automatisch getriggert und ausgeführt werden.