Stabilität in der Krise – business continuity & disaster recovery

Den Satz: lieber man hat als man hätte, hat sicher jeder einzelne von uns bereits am eigenen Leibe erfahren, ganz egal ob im beruflichen oder privaten Umfeld. Hätte man doch bloß nicht auf den schädlichen Link in der E-Mail geklickt oder so ähnlich, geht es einem dann durch den Kopf. Wenn das Kind aber erst einmal in den Brunnen gefallen ist, dann ist es auch schon zu spät für eine Vorsorge.

Was im Privaten meist nur ärgerlich ist, kann im Geschäftsumfeld aber rasch existenzbedrohend werden. Aus diesem Grunde ist es wichtig, sich rechtzeitig ein Sicherheitsnetz für den möglichen Schadensendfall aufzubauen. Leider wird in vielen Unternehmen das Thema Notfallwiederherstellung und Geschäftskontinuität nicht angemessen beachtet, was dann im Ernstfall zu hohen finanziellen Verlusten führt.

Die Menge an möglichen Bedrohungsszenarien ist lang. Das Eintreten mancher Szenarien ist wahrscheinlicher als andere. Deswegen gilt es, eine realistische Risikobewertung durchzuführen, die einzelne Optionen gewichtet. Das hilft, die entstehenden Kosten nicht ausufern zu lassen.

Die Corona-Pandemie war für viele Menschen ein einschneidendes Erlebnis. Besonders die staatlich auferlegten Hygieneregeln stellten viele Betriebe vor enorme Herausforderungen. Hier sei das Stichwort Homeoffice genannt. Um der Lage Herr zu werden, wurden Arbeitnehmer kurzerhand heimgeschickt, um von dort aus zu arbeiten. Da es speziell im deutschsprachigen Raum keine etablierte Kultur und noch viel weniger eine vorhandene Infrastruktur für Heimarbeit gab, musste diese unter sehr hohem Druck kurzerhand erschaffen werden. Das geschah natürlich nicht ohne Reibungspunkte.

Es muss aber nicht immer gleich ein drastisches Ereignis sein. Auch ein profaner Stromausfall oder eine Netzüberspannung können erheblichen Schaden verursachen. Es muss auch kein Gebäudebrand oder eine Überschwemmung sein, die zu sofortigem Stillstand führen. Auch ein Hackerangriff zählt in die Kategorie ernstzunehmender Bedrohungslagen. Damit soll es auch gut sein. Ich denke die Problematik ist mit diesen Beispielen ausführlich dargelegt. Kümmern wir uns daher zu Beginn um die Frage was man als gute Vorsorge bereits leisten kann.

Die am leichtesten umzusetzende und auch wirkungsvollste Maßnahme ist eine umfangreiche Datensicherung. Damit auch wirklich keine Daten verloren gehen, hilft es, die verschiedenen Daten aufzulisten und zu kategorisieren. In eine solche Tabelle gehören Informationen über die Speicherpfade, die zu sichern sind, ungefährer Speicherverbrauch, Priorisierung nach Vertraulichkeit und Kategorie der Daten. Diese Kategorien sind unter anderem Projektdaten, Austreibungen, E-Mail-Korrespondenz, Finanzbuchhaltung, Zulieferlisten, Lohnabrechnungen und so weiter. Es ist natürlich klar, dass im Rahmen des Datenschutzes nicht jeder im Unternehmen berechtigt ist, die Information zu lesen. Deswegen gilt es, verdauliche Daten durch Verschlüsselung zu schützen. Je nach Schutzklasse kann es sich um ein einfaches Passwort für komprimierte Daten handeln oder ein kryptografisch verschlüsseltes Verzeichnis oder eine verschlüsselte Festplatte. Die Frage, wie oft eine Datensicherung ausgeführt werden sollte, ergibt sich aus der Häufigkeit der Änderung der originalen Daten. Je häufiger die Daten verändert werden, umso kürzer sollten die Intervalle der Datensicherung sein. Ein anderer Punkt ist der Zielspeicher der Datensicherung. Ein komplett verschlüsseltes Archiv, das lokal im Unternehmen liegt, kann nach erfolgreichem BackUp durchaus auf einen Cloud-Speicher hochgeladen werden. Diese Lösung kann allerdings bei großen Datenmengen kostspielig werden und ist daher nicht unbedingt für kleine und mittelständische Unternehmen (KMU) geeignet. Ideal ist es natürlich, wenn es von einer Datensicherung mehrere Replikationen gibt, die an verschiedenen Orten aufbewahrt werden.

Es nützt natürlich wenig, umfangreiche Sicherungen zu erstellen, um dann im Ernstfall festzustellen, dass diese fehlerhaft sind. Deswegen ist eine Verifikation der Sicherung enorm wichtig. Professionelle Werkzeuge für Datensicherung enthalten einen Mechanismus, der die geschriebenen Daten mit dem Original vergleicht. Das Linux-Kommando rsync nutzt ebenfalls diesen Mechanismus. Ein einfaches copy & paste erfüllt die Anforderung nicht. Aber auch ein Blick auf die Dateigröße der Sicherung ist wichtig. Hier lässt sich schnell erkennen ob Informationen fehlen. Natürlich lässt sich noch viel mehr zum Thema Backup sagen, das würde aber an dieser Stelle zu weit führen. Wichtig ist das richtige Verständnis für die Thematik zu entwickeln.

Wenn wir einen Blick auf die IT-Infrastruktur von Unternehmen werfen, stellen wir sehr schnell fest, dass die Bereitstellung von Softwareinstallationen überwiegend ein manueller Prozess ist. Wenn wir uns überlegen, dass beispielsweise ein Rechensystem aufgrund eines Hardwarefehlers seinen, Dienst nicht mehr verrichten kann, gilt es auch hier eine geeignete Strategie zur Nothilfe in der Hand zu haben. Die zeitintensive Arbeit beim Auftreten von Hardwarefehlern ist das Aufspielen der Programme nach einem Gerätetausch. Nun macht es für viele Unternehmen aus Kostengründen wenig Sinn, eine redundante Infrastruktur bereitzuhalten. Eine bewährte Lösung kommt aus dem Bereich DevOps und nennt sich Infrastructure as a Code (IaaC). Hier geht es vor allem darum, Dienste wie E-Mail oder Datenbanken etc. via Script bereitzustellen. Für den Business Continuity & Desaster Recovery Ansatz genügt es wenn die automatisierte Installation beziehungsweise Aktualisierung manuell angestoßen wird. Dabei sollte man nicht auf proprietäre Lösungen von möglichen Cloud Anbietern setzen sondern frei verfügbare Werkzeuge nutzen. Denn ein mögliches Worst Case Szenario ist auch eine Preiserhöhung des Cloud Anbieters oder für Unternehmen nicht akzeptable Änderungen der Geschäftsbedingungen die einen schnellen Wechsel nötig machen können. Basiert die Automatisierungslösung auf einer speziellen Technologie die andere Anbieter nicht bereitstellen können, gestaltet sich ein schneller Wechsel äußerst schwierig.

Auch auf die Flexibilität der Angestellten sollte geachtet werden. Die Anschaffung von Notebooks anstatt Desktoprechner erlaubt eine hohe Mobilität. Das inkludiert natürlich auch die Erlaubnis, den Laptop mit heim nehmen zu dürfen und sich von dort in das Firmennetzwerk einzuwählen. Teams, die Anfang 2020 bereits mit Homeoffice vertraut waren, konnten nahezu nahtlos ihre Arbeit von zu Hause fortsetzen. Das hat den entsprechenden Unternehmen einen gewaltigen Wettbewerbsvorteil verschafft. Es ist auch davon auszugehen, dass im Rahmen der digitalen Transformation große repräsentative Firmenzentralen immer weniger Bedeutung haben. Die Teams organisieren sich dann flexibel mit modernen Kommunikationswerkzeugen remote. Aktuelle Untersuchungen zeigen, dass ein solches Setup in den meisten Fällen die Produktivität steigert. Ein verschnupfter Kollege, der sich dennoch in der Lage fühlt, sein Pensum zu leisten, kann so unbesorgt zur Arbeit erscheinen, ohne dass die Kollegen Gefahr laufen, auch angesteckt zu werden.

Wir sehen schon, wie weit sich dieses Thema denken lässt. Die Herausforderung besteht allerdings darin, eine schrittweise Transformation durchzuführen. Denn in aller Konsequenz entsteht als Ergebnis eine dezentrale Struktur, die mit Redundanzen arbeitet. Genau diese Redundanzen verschaffen bei einer Störung genügend Handlungsspielräume gegenüber einer zentralisierten Struktur. Redundanzen verursachen natürlich einen zusätzlichen Kostenfaktor. Die Ausstattung von Arbeitnehmern mit einem Laptop anstatt eines stationären Desktop-PCs ist in der Anschaffung etwas teurer. Mittlerweile ist die Preisdifferenz der beiden Lösungen nicht mehr so dramatisch wie noch zur Jahrtausendwende, und die Vorteile überwiegen allerdings. Die Transformation hin, die Geschäftsfähigkeit bei Störungen aufrechtzuerhalten, bedeutet nicht, dass man nun sofort loszieht und allen Arbeitnehmern neues Equipment kauft. Nachdem festgestellt wurde, was für das Unternehmen notwendig und sinnvoll ist, können Neuanschaffungen priorisiert werden. Kollegen, deren Geräte abgeschrieben und für einen Austausch vorgesehen sind, erhalten indessen Equipment der neuen Unternehmensrichtlinie nach. Nach diesem Vorbild folgt man nun auch in allen anderen Bereichen. Diese schrittweise Optimierung erlaubt einen guten Lernprozess und stellt sicher, dass jeder bereits abgeschlossene Schritt auch tatsächlich korrekt umgesetzt wurde.

Neue Talente braucht das Land

Wer als Freiberufler Akquise für neue Aufträge betreibt, erlebt seit einiger Zeit markante Veränderungen. Immer weniger Unternehmen haben kaum noch direkten Kontakt zu ihren Auftragnehmern bei der Beauftragung. Personalvermittlungsfirmen drängen sich immer mehr zwischen Unternehmen und selbstständigen Auftragnehmern.

Wenn im Projekt Spezialwissen benötigt wird, greifen Unternehmen gern auf externe Fachkräfte zurück. Dieses Vorgehen gibt den Firmen grösstmögliche Flexibilität bei der Kostenkontrolle. Aber auch die Freelancer haben ihren Vorteil mit dieser Praktik. Sie können sich ausschließlich um Themen kümmern, für die sie ein starkes Interesse haben. So vermeidet man für langweilige routinierte Standardaufgaben eingesetzt zu werden. Aufgrund der Erfahrung in unterschiedlichen Organisationsstrukturen und der Vielfalt der Projekte haben selbstständige Auftragnehmer ein breites Portfolio an unkonventionellen Lösungsstrategien. Diese Wissensbasis ist für Auftraggeber sehr attraktiv, auch wenn ein freiberuflicher externer Mitarbeiter im ersten Moment teurer ist als sein fest angestellter Kollege. Freiberufler können aufgrund ihrer vielfältigen Erfahrung positive Impulse in das Projekt tragen, die einen Stillstand überwinden.

Leider bemühen sich Unternehmen seit einiger Zeit nicht mehr eigenständig darum, die benötigten Fachkräfte zu gewinnen. Der Aufgabenbereich der Personalbeschaffung ist mittlerweile nahezu überall an externe Vermittlungsfirmen ausgelagert. Diese sogenannten Recruitment-Firmen werben nun damit, für offene Positionen die optimal geeigneten Kandidaten zu finden und für eine Besetzung vorzuschlagen. Schließlich können diese Personalvermittler auf einen großen Pool an Bewerberprofilen zugreifen. Unternehmen, die eine freie Stelle besetzen wollen, wissen oft nicht, wie Spezialisten zu finden sind und wie diese direkt kontaktiert werden können. Deswegen ist das Angebot der Vermittlungsfirmen auch für mittelständische Unternehmen attraktiv. Nach ausreichend persönlicher Erfahrung habe ich über die Jahre ein völlig anderes Bild gewonnen. Von dem, was ich erlebt habe, ist das, was Recruitment-Firmen versprechen, weit von dem entfernt, was sie tatsächlich leisten.

Eigentlich finde ich die Idee, einen eigenen Vermittler für mich zu haben, der meine Auftragsakquise übernimmt, sehr reizvoll. Es ist wie in der Film- und Musikbranche. Man hat einen Agenten, der einem den Rücken frei hält und regelmäßig Feedback gibt. So bekommt man ein Bild über gefragte Technologien, in denen man sich etwa weiterbilden kann. Dadurch lasst sich die eigene Marktrelevanz verbessern und sichert eine regelmäßige Beauftragung. Das wäre eigentlich eine ideale Win-Win Situation für alle Beteiligten. Leider ist das was tatsächlich in der Realität passiert, etwas völlig anderes.

Anstatt das Personalvermittler eine gute Beziehung zu ihren Fachkräften aufbauen und deren Entwicklung fördern, agieren diese Recruiter wie schädliche Parasiten. Sie schädigen sowohl die Freiberufler als auch die Unternehmen, die offene Stellen besetzen wollen. Denn im Business geht es nicht darum, für eine Firma wirklich den am besten geeigneten Kandidaten zu finden. Es geht ausschließlich darum, Kandidaten anzubieten, die mit einem möglichst niedrigen Stundenlohn halbwegs auf das gesuchte Profil passen. Ob diese Kandidaten dann wirklich die Dinge können, die sie vorgeben zu können, ist oft fragwürdig.

Das Vorgehen der Personalvermittler ist sehr identisch. Sie versuchen eine großen Pool an aktuellen Bewerberprofilen zu generieren. Diese Profile werden dann mittels automatischer K. I. Texterkennungssysteme auf Schlüsselwörter durchsucht. Dann werden aus den vorgeschlagenen Kandidaten die mit dem geringsten Stundensatz für ein Vorgespräch kontaktiert. Wer in diesem Vorgespräch keine groben Auffälligkeiten zeigt wird dann den unternehmen für einen Interviewtermin vorgeschlagen. Der Gewinn der Vermittlungsfirma ist enorm. Denn sie streichen die Differenz des Stundensatz den der Auftraggeber bezahlt zum Stundensatz den der Selbstständige bekommt ein. Das können in manchen Fällen bis zu 40% ausmachen.

Das ist aber bislang nicht alles, was diese parasitären Vermittler zu bieten haben. Oft verzögern sie noch den Auszahlungstermin für die gestellte Rechnung. Zudem versucht man, das gesamte unternehmerische Risiko auf den Freiberufler abzuwälzen. Das geschieht, indem man sinnlose Haftpflichtversicherungen verlangt, die für die ausgeschriebene Position nicht relevant sind. Als Resultat erhalten Firmen auf freie Stellen dann vermeidliche Fachkräfte, die eher als Hilfsarbeiter zu deklarieren sind.

Nun könnte man sich fragen, wieso die Firmen dennoch weiterhin mit den Vermittlern zusammenarbeiten. Ein Grund ist auch die aktuelle politische Situation. So gibt es seit ca. 2010 beispielsweise in Deutschland Gesetze, die eine Scheinselbstständigkeit verhindern sollen. Unternehmen, die direkt mit Freelancern zusammenarbeiten, werden oft durch Rentenversicherungen bedrängt. Das sorgt für sehr viele Unsicherheiten und dient nicht dem Schutz der Freiberufler. Es sichert ausschließlich das Geschäftsmodell der Vermittlerfirmen.

Ich habe mir mittlerweile angewöhnt kommentarlos und unverzüglich aufzulegen wenn ich verschiedene Grundmuster bemerke. Solche Telefonate sind Zeitverschwendung und führen zu nichts außer das man sich über die Dreistigkeit der Personalvermittler ärgert. Wichtigstes Indiz für unseriöse Recruiter ist das am Telefon auf einmal eine völlig andere Person ist als die die eine zu erst kontaktiert hat. Hat diese Person dann noch einen sehr starken indischen Akzent kann man sich zu 100% sicher sein mit einem Callcenter verbunden zu sein. Auch wenn die Nummer als Vorwahl England anzeigt sitzen die Leuten tatsächlich irgendwo in Indien oder Pakistan. Nichts das die Seriosität unterstreichen würde.

Ich habe mich im Laufe der vielen Jahre meiner Karriere auf diversen Jobportalen registriert. Mein Fazit is das man sich die Zeit dafür sparen kann. 95% aller Kontakte die darüber zustande kamen sind Recruiter wie zuvor beschrieben. Diese Leute haben dann die Masche das du sie als Kontakt speicherst. Es ist aber naiv zu glauben das es bei diesen sogenannten Netzwerkanfragen wirklich um den direkten Kontakt geht. Sinn und Zweck dieser Aktion ist es an die Kontaktliste zu kommen. Denn viele Portale wie XING und LinkedIn haben die Einstellung das Kontakte die Kontakte aus der eigenen Liste sehen oder auch über die Netzwerkfunktion angeboten bekommen. Diese Kontaktlisten können bares Geld wert sein. So finden sich dort Abteilungsleiter oder andere Professionals die es sicher lohnt einmal anzuschreiben. Daher habe ich in allen sozialen Netzwerken auch den Zugriff der Freundesliste auch für Freunde deaktiviert. Zudem lehne ich pauschal alle Verbindungsanfragen von Personen mit dem Titel Recruitment ausnahmslos ab. Meine Präsenz in sozialen Netzwerken dient mittlerweile nur noch dazu den Profilnahmen gegen Identitätsdiebstahl zu sichern. Die meisten Anfragen auf das Zusenden eines Lebenslaufs beantworte ich nicht mehr. Aber auch meine persönlichen Informationen zu Aufträgen, Studium und Arbeitgebern trage ich nicht in diese Netzwerkprofile ein. Wer mich erreichen möchte dem gelingt dies über meine Homepage.

Eine andere Angewohnheit, die ich mir über die Jahre zugelegt habe, ist niemals als Erstes über meine Gehaltsvorstellung zu sprechen. Wenn mein Gegenüber keine konkrete Zahl nennen kann, die sie bereit sind, für meine Dienste zu zahlen, wollen sie nur Daten abgreifen. Also ein weiterer Grund, das Gespräch abrupt zu beenden. Es geht auch keine dieser Leute an, was ich bereits in früheren Projekten an Stundensatz hatte. Sie nutzen diese Information ausschließlich, um den Preis zu drücken. Wer etwas sensibel ist und keine unhöfliche Antwort geben möchte, nennt einfach einen sehr hohen Stundensatz beziehungsweise Tagessatz.

Wir sehen, es ist gar nicht so schwer, die wirklichen schwarzen Schafe sehr schnell an ihrem Verhalten zu erkennen. Mein Rat ist, sobald eines der zuvor beschriebenen Muster vorkommt, Zeit und vor allem Nerven zu sparen und einfach das Gespräch zu beenden. Aus Erfahrung kann ich sagen, dass, wenn sich die Vermittler wie beschrieben verhalten werden, definitiv keine Vermittlung zustande kommen. Es ist dann besser, seine Energie auf realistische Kontakte zu konzentrieren. Denn es gibt auch wirklich gute Vermittlungsfirmen. Diese sind an einer langen Zusammenarbeit interessiert und verhalten sich völlig anders. Sie unterstützen und geben Hinweise zur Verbesserung des Lebenslaufes und beraten Unternehmen bei der Formulierung realistischer Stellenangebote.

Leider befürchte ich, dass sich die Situation weiterhin von Jahr zu Jahr verschlechtern wird. Auch der Einfluss der wirtschaftlichen Entwicklung und die breite Verfügbarkeit neuer Technologien werden den Druck auf den Arbeitsmarkt weiter erhöhen. Weder Unternehmen noch Auftragnehmer werden in der Zukunft weiter Chancen haben, wenn sie sich nicht an die neue Zeit anpassen und andere Wege gehen.


Podcast

Flaschenhals Pull Requests

Der sichere Umgang mit Source Control Management (SCM) Systemen wie Git ist für Programmierer (Development) und auch Systemadministratoren (Operations) essenziell. Diese Gruppe von Werkzeugen hat eine lange Tradition in der Softwareentwicklung und versetzt Entwicklungsteams in die Lage, gemeinsam an einer Codebasis zu arbeiten. Dabei werden vier Fragen beantwortet: Wann wurde die Änderung gemacht? Wer hat die Änderung vorgenommen? Was wurde geändert? Warum wurde etwas geändert? Es ist also ein reines Kollaborationswerkzeug.

Mit dem Aufkommen der Open Source Code Hosting Plattform GitHub wurden sogenannte Pull Requests eingeführt. Pull Requests ist in GitHub ein Workflow, der es Entwicklern erlaubt, Codeänderungen für Repositories bereitzustellen, auf die sie nur lesenden Zugriff haben. Erst nachdem der Besitzer des originalen Repositories die vorgeschlagenen Änderungen überprüft und für gut befunden hat, werden diese Änderungen von ihm übernommen. So setzt sich auch die Bezeichnung zusammen. Ein Entwickler kopiert sozusagen das originale Repository in seinen GitHub Arbeitsbereich, nimmt Änderungen vor und stellt an den Inhaber des originalen Repositories eine Anfrage, die Änderung zu übernehmen. Dieser kann dann die Änderungen übernehmen und gegebenenfalls noch selbst anpassen oder mit einer Begründung zurückweisen.

Wer nun glaubt, dass GitHub besonders innovativ war, der irrt. Denn dieser Prozess ist in der Open Source Community ein ‚sehr‘ alter Hut. Ursprünglich nennt man dieses Vorgehen Dictatorship Workflow. Das 1990 zum ersten Mal veröffentlichte kommerzielle SCM Rational Synergy von IBM basiert genau auf dem Dictarorship Workflow. Mit der Klasse der verteilten Versionsverwaltungswerkzeuge, zu denen auch Git gehört, lässt sich der Dictatorship Worflow recht einfach umsetzen. Also lag es auf der Hand das GitHub diesen Prozess seinen Nutzern auch zur Verfügung stellt. Lediglich die Namensgebung ist von GitHub weitaus ansprechender gewählt. Wer beispielsweise mit der freien DevOps Lösung GitLab arbeitet, kennt Pull Requests unter der Bezeichnung Merge Requests. Mittlerweile enthalten die gängigsten Git-Server den Prozess der Pull Requests. Ohne zu sehr auf die technischen Details zur Umsetzung der Pull Request einzugehen, richten wir unsere Aufmerksamkeit auf die üblichen Probleme mit denen Open Source Projekte konfrontiert sind.

Entwickler, die sich an einem Open Source Projekt beteiligen möchten, werden Maintainer genannt. Nahezu jedes Projekt hat eine kleine Anleitung, wie man das entsprechende Projekt unterstützen kann und welche Regeln gelten. Für Personen, die das Programmieren erlernen, eignen sich Open Source Projekte hervorragend, um die eigenen Fähigkeiten schnell signifikant zu verbessern. Das bedeutet für das Open Source Projekt, dass man Maintainer mit den unterschiedlichsten Fähigkeiten und Erfahrungsschatz hat. Wenn man also keinen Kontrollmechanismus etabliert, erodiert die Codebasis in sehr kurzer Zeit. Wenn das Projekt nun recht groß ist und sehr viele Mainatainer auf der Codebasis agieren, ist es für den Inhaber des Repositories kaum noch möglich, alle Pull Requests zeitnahe zu bearbeiten. Um diesem Bottelneck entgegenzuwirken, wurde der Dictatorship Workflow zum Dictatorship – Lieutenant Workflow erweitert. Es wurde also eine Zwischeninstanz eingeführt, mit der die Überprüfung der Pull Requests auf mehrere Schultern verteilt wird. Diese Zwischenschicht, die sogenannten Lieutenants sind besonders aktive Maintainer mit einer bereits etablierten Reputation. Somit braucht der Dictator nur noch die Pull Requests der Lieutenants zu reviewen. Eine ungemeine Arbeitsentlastung, die sicherstellt, dass es zu keinem Feature Stau durch nicht abgearbeitete Pull Requests kommt. Schließlich sollen die Verbesserungen beziehungsweise die Erweiterungen so schnell wie möglich in die Codebasis aufgenommen werden, um dann im nächsten Release den Nutzern zur Verfügung zu stehen.

Dieses Vorgehen ist bis heute der Standard in Open Source Projekten, um Qualität gewährleisten zu können. Man kann ja nie sagen, wer sich alles am Projekt beteiligt. Möglicherweise mag es ja auch den ein oder anderen Saboteur geben. Diese Überlegung ist nicht so abwegig. Unternehmen, die für ihr kommerzielles Produkt eine starke Konkurrenz aus dem feien Open Source Bereich haben, könnten hier auf unfaire Gedanken kommen, wenn es keine Reglementierungen geben würde. Außerdem lassen sich Maintainer nicht disziplinieren, wie es beispielsweise für Teammitglieder in Unternehmen gilt. Einem beratungsresistenten Maintainer, der sich trotz mehrfachen Bitten nicht an die Vorgaben des Projektes hält, kann man schwer mit Gehaltskürzungen drohen. Einzige Handhabe ist diese Person vom Projekt auszuschließen.

Auch wenn das gerade beschriebene Problem der Disziplinierung von Mitarbeitern in kommerziellen Teams kein Problem darstellt, gibt es in diesen Umgebungen ebenfalls Schwierigkeiten, die es zu meistern gilt. Diese Probleme rühren noch aus den Anfängen von Visualisierungswerkzeugen. Denn die ersten Vertreter dieser Spezies waren keine verteilten Lösungen, sondern zentralisiert. CVS und Subversion (SVN) halten auf dem lokalen Entwicklungsrechner immer nur die letzte Revision der Codebasis. Ohne Verbindung zum Server kann man faktisch nicht arbeiten. Bei Git ist dies anders. Hier hat man eine Kopie des Repositories auf dem eigenen Rechner, sodass man seine Arbeiten lokal in einem separaten Branch durchführt und wenn man fertig ist, bringt man diese Änderungen in den Hauptentwicklungszweig und überträgt diese dann auf den Server. Die Möglichkeit, offline Branches zu erstellen und diese lokal zu mergen hat einen entscheidenden Einfluss auf die Stabilität der eigenen Arbeit, wenn das Reopsitory in einen inkonsistenten Zustand gerät. Denn im Gegensatz zu zentralisierten SCM Systemen kann man nun weiter arbeiten, ohne darauf warten zu müssen, dass der Hauptentwicklungszweig repariert wurde.

Diese Inkonsistenten entstehen sehr leicht. Es genügt nur eine Datei beim Commit zu vergessen und schon können die Teamkollegen das Projekt nicht mehr lokal kompilieren und sind in der Arbeit behindert. Um diesem Problem Herr zu werden, wurde das Konzept Continuous Integration (CI) etabliert. Es handelt sich dabei nicht, wie oft fälschlicherweise angenommen, um die Integration verschiedener Komponenten zu einer Anwendung. Die Zielstellung bei CI ist die Commit Satge – das Code Repository – in einem konsistenten Zustand zu halten. Dazu wurden Build Server etabliert, die in regelmäßigen Abständen das Repository auf Änderungen überprüfen, um dann den aus dem Quelltext das Artefakt bauen. Ein sehr beliebter und seit vielen Jahren etablierter Build-Server ist Jenkins. Jenkins ging ursprünglich aus dem Projekt Hudson als Abspaltung hervor und übernahm mittlerweile viele weitere Aufgaben. Deswegen ist es sehr sinnvoll, diese Klasse von Tools als Automatisierungsserver zu bezeichnen.

Mit diesem kleinen Abriss in die Geschichte der Softwareentwicklung verstehen wir nun die Probleme von Open Source Projekten und kommerzieller Softwareentwicklung. Dazu haben wir die Entstehungsgeschichte der Pull Request besprochen. Indessen kommt es in kommerziellen Projekten sehr oft vor, dass Teams durch das Projektmanagement gezwungen werden mit Pull Requests zu arbeiten. Für einen Projektleiter ohne technisches Hintergrundwissen klingt es nun sehr sinnvoll, in seinem Projekt ebenfalls Pull Requests zu etablieren. Schließlich hat er die Idee, dass er somit die Codequalität verbessert. Leider ist das aber nicht der Fall. Das Einzige was passiert ist ein Feature Stau zu provozieren und eine erhöhte Auslastung des Teams zu erzwingen, ohne die Produktivität zu verbessern. Denn der Pull Request muss ja von einer kompetenten Person inhaltlich bewertet werden. Das verursacht bei großen Projekten unangenehme Verzögerungen.

Nun erlebe ich es oft, dass argumentiert wird, man könne die Pull Requests ja automatisieren. Das heißt, der Build Server nimmt den Branch, mit dem Pull Request versucht diesen zu bauen und im Fall dass das Kompilieren und die automatisierten Tests erfolgreich sind, versucht der Server die Änderungen in den Hauptentwicklungszweig zu übernehmen. Möglicherweise sehe ich da etwas falsch, aber wo ist die Qualitätskontrolle? Es handelt sich um einen einfachen Continuous Integration Prozess, der die Konsistenz des Repositories aufrechterhält. Da Pull Requests vornehmlich im Git Umfeld zu finden sind, bedeutet ein kurzzeitig inkonsistentes Repository kein kompletten Entwicklungstop für das gesamte Team, wie es bei Subversion der Fall ist.

Interessant ist auch die Frage wie man bei einem automatischen Merge mit semantischen Mergekonflikten umgeht. Die per se kein gravierendes Problem sind. Sicher führt das zur Ablehnung des Pull Requests mit entsprechender Nachricht an den Entwickler, um das Problem mit einem neuen Pull Request zu lösen. Ungünstige Branchstrategien können hier allerdings zu unverhältnismäßigen Mehraufwand führen.

Für die Verwendung von Pull Requests in kommerziellen Softwareprojekten sehe ich keinen Mehrwert, weswegen ich davon abrate, in diesem Kontext Pull Request zu verwenden. Außer einer Verkomplizierung der CI / CD Pipeline und einem erhöhten Ressourcenverbrauch des Automatisierungsservers, der nun die Arbeit doppelt macht, ist nichts passiert. Die Qualität eines Softwareprojektes verbessert man durch das Einführen von automatisierten Unit-Tests und einem testgetriebenen Vorgehen bei der Umsetzung von Features. Hier ist es notwendig, die Testabdeckung des Projekts kontinuierlich im Auge zu behalten und zu verbessern. Statische Codeanalyse und das Aktivieren von Compilerwarnings bringen mit erheblich weniger Aufwand bessere Ergebnisse.

Ich persönlich vertrete die Auffassung, dass Unternehmen, die auf Pull Requests setzen, diese entweder für ein verkompliziertes CI nutzen oder ihren Entwicklern komplett misstrauen und ihnen in Abrede stellen, gute Arbeit abzuliefern. Natürlich bin ich offen für eine Diskussion zum Thema, möglicherweise lässt sich dann eine noch bessere Lösung finden. Von daher freue ich mich über reichliche Kommentare mit euren Ansichten und Erfahrungen im Umgang mit Pull Requests.

Konfigurationsdateien in Softwareanwendungen

Wieso benötigen wir überhaupt die Möglichkeit, Konfigurationen einer Anwendung in Textdateien zu speichern? Genügt nicht einfach eine Datenbank für diesen Zweck? Die Antwort auf diese Frage ist recht trivial. Denn die Information, wie sich eine Anwendung mit einer Datenbank verbinden kann, lässt sich ja schlecht in der Datenbank selbst speichern.

Jetzt könnte man sicher argumentieren, dass man solche Dinge mit einer integrierten Datenbank (embedded) wie beispielsweise SQLite hinbekommt. Das mag auch grundsätzlich korrekt sein. Leider ist diese Lösung für hoch skalierbare Anwendungen nicht wirklich praktikabel. Zudem muss man nicht immer gleich mit Kanonen auf Spatzen schießen. Das Speichern wichtiger Konfigurationsparameter in Textdateien hat bereits eine lange Tradition in der Softwareentwicklung. Mittlerweile haben sich aber auch verschiedene Textformate wie INI, XML, JSON und YAML für diesen Anwendungsfall etabliert. Angesichts dessen stellt sich die Frage, auf welches Format man am besten für das eigene Projekt zurückgreifen sollte.

INI Dateien

Eines der ältesten Formate sind die bekannten INI Dateien. Sie speichern Informationen nach dem Schlüssel = Wert Prinzip. Wenn ein Schlüssel in solch einer INI-Datei mehrfach vorkommt, wird der finale Wert immer durch den zuletzt in der Datei vorkommenden Wert überschrieben.

; Example of an INI File
[Section-name]
key=value ; inline 

text="text configuration with spaces and \' quotas"
string='can be also like this'
char=passwort

# numbers & digets
number=123
hexa=0x123
octa=0123
binary=0b1111
float=123.12

# boolean values
value-1=true
value-0=false

Wie wir in dem kleinen Beispiel sehen können, ist die Syntax in INI-Dateien sehr einfach gehalten. Der Sektionsname [section] dient vor allem der Gruppierung einzelner Parameter und verbessert die Lesbarkeit. Kommentare können entweder durch ; oder # gekennzeichnet werden. Ansonsten gibt es die Möglichkeit, verschiedene Text- und Zahlen-Formate, sowie Boolean-Wert zu definieren.

Web-Entwickler kennen INI Files vor allem von der PHP-Konfiguration, der php.ini in der wichtige Eigenschaften wie die Größe des Datei-Uploads festgelegt werden können. Auch unter Windows sind INI-Dateien noch immer verbreitet, obwohl seit Windows 95 für diesen Zweck die Registry eingeführt wurde.

Properties

Eine andere sehr bewährte Lösung sind sogenannte property Files. Besonders verbreitet ist diese Lösung in Java-Programmen, da Java bereits eine einfache Klasse mitbringt, die mit Properties umgehen kann. Das Format key=value ist den INI-Dateien entlehnt. Kommentare werden ebenfalls mit # eingeleitet.

# PostgreSQL
hibernate.dialect.database = org.hibernate.dialect.PostgreSQLDialect
jdbc.driverClassName = org.postgresql.Driver 
jdbc.url = jdbc:postgresql://127.0.0.1:5432/together-test

Um in Java-Programmen beim Einlesen der .propreties auch die Typsicherheit zu gewährleisten, hat die Bibliothek TP-CORE eine erweiterte Implementierung. Trotz dass die Properties als Strings eingelesen werden, kann auf die Werte mittels Typisierung zugegriffen werden. Eine ausführliche Beschreibung, wie die Klasse PropertyReader verwendet werden kann, findet sich in der Dokumentation.

Auch im Maven Build Prozess können .property Dateien als Filter für Substitutionen genutzt werden. Selbstredend sind Properties nicht nur auf Maven und Java beschränkt. Auch in Sprachen wie Dart, nodeJS, Python und Ruby ist dieses Konzept nutzbar. Um eine größtmögliche Kompatibilität der Dateien zwischen den verschiedenen Sprachen zu gewährleisten, sollten exotische Optionen zur Notation vermieden werden.

XML

XML ist seit vielen Jahren auch eine weitverbreitete Option, Konfigurationen in einer Anwendung veränderlich zu speichern. Gegenüber INI und Property Dateien bietet XML mehr Flexibilität in der Definition der Daten. Ein sehr wichtiger Aspekt ist die Möglichkeit, fixe Strukturen durch eine Grammatik zu definieren. Dies erlaubt eine Validierung auch für sehr komplexe Daten. Dank der beiden Prüfmechanismen Wohlgeformtheit und Datenvalidierung gegen eine Grammatik lassen sich mögliche Konfigurationsfehler erheblich reduzieren.

Bekannte Einsatzszenarien für XML finden sich beispielsweise in Java Enterprise Projekten (J EE) mit der web.xml oder der Spring Framework und Hibernate Konfiguration. Die Mächtigkeit von XML gestattet sogar die Nutzung als Domain Specific Language (DSL), wie es bei dem Build-Werkzeug Apache Maven zum Einsatz kommt.

Dank vieler frei verfügbarer Bibliotheken existiert für nahezu jede Programmiersprache eine Implementierung, um XML-Dateien einzulesen und gezielt auf Daten zuzugreifen. Die bei Web-Entwicklern beliebte Sprache PHP hat zum Beispiel mit der Simple XML Erweiterung eine sehr einfache und intuitive Lösung, um mit XML umzugehen.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/assembly/ApplicationContext.xml</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>${jsf.project.stage}</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
</web-app>

JavaScript Object Notation oder kurz JSON ist eine vergleichsweise neue Technik, obwohl diese mittlerweile auch schon einige Jahre existiert. Auch JSON hat für nahezu jede Programmiersprache eine entsprechende Implementierung. Das häufigste Einsatzszenario für JSON ist der Datentausch in Microservices. Der Grund liegt in der Kompaktheit von JSON. Gegenüber XML ist der zu übertragene Datenstrom in Webservices wie XML RPC oder SOAP mit JSON aufgrund der Notation wesentlich geringer.

Ein signifikanter Unterschied zwischen JSON und XML besteht aber auch im Bereich der Validierung. Grundsätzlich findet sich auf der offiziellen Homepage [1] zu JSON keine Möglichkeit, eine Grammatik wie in XML mit DTD oder Schema zu definieren. Auf GitHub existiert zwar ein Proposal zu einer JSON-Grammatik [2] hierzu fehlen aber entsprechende Implementierungen, um diese Technologie auch in Projekten einsetzen zu können.

Eine Weiterentwicklung zu JSON ist JSON5 [3], das bereits 2012 begonnen wurde und als Spezifikation in der Version 1.0.0 [4] seit dem Jahr 2018 offiziell veröffentlicht ist. Zweck dieser Entwicklung war es, die Lesbarkeit von JSON für Menschen erheblich zu verbessern. Hier wurden wichtige Funktionen, wie beispielsweise die Möglichkeit, Kommentare zu schreiben, hinzugefügt. JSON5 ist als Erweiterung vollständig zu JSON kompatibel. Um einen kurzen Eindruck zu JSON5 zu gewinnen, hier ein kleines Beispiel:

{
  // comments
  unquoted: 'and you can quote me on that', 
  singleQuotes: 'I can use "double quotes" here',
  lineBreaks: "Look, Mom! \
No \\n's!",
  hexadecimal: 0xdecaf,
  leadingDecimalPoint: .8675309, andTrailing: 8675309.,
  positiveSign: +1,
  trailingComma: 'in objects', andIn: ['arrays',],
  "backwardsCompatible": "with JSON",
}

YAML

Viele moderne Anwendungen, wie zum Beispiel YAML, zur Konfiguration. Die sehr kompakte Notation erinnert stark an die Programmiersprache Python. Aktuell ist YAML in der Version 1.2 veröffentlicht.

Der Vorteil von YAML gegenüber anderen Spezifikationen ist die extreme Kompaktheit. Gleichzeitig besitzt die Version 1.2 eine Grammatik zu Validierung. Trotz der Kompaktheit liegt der Fokus von YAML 1.2 in einer guten Lesbarkeit für Maschinen als auch Menschen. Ob YAML dieses Ziel erreicht hat, überlasse ich jedem selbst zu entscheiden. Auf der offiziellen Homepage findet man alle Ressourcen, die für eine Verwendung im eigenen Projekt benötigt werden. Dazu zählt auch eine Übersicht zu den vorhandenen Implementierungen. Das Design der YAML Homepage gibt auch schon einen guten Vorgeschmack auf die Übersichtlichkeit von YAML Dateien. Anbei noch ein sehr kompaktes Beispiel einer Prometheus Konfiguration in YAML:

global:
  scrape_interval:     15s
  evaluation_interval: 15s

rule_files:
  # - "first.rules" 
  # - "second.rules"

#IP: 127.0.0.1
scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ['127.0.0.1:8080']

  # SPRING BOOT WEB APP
  - job_name: spring-boot-sample 
    scrape_interval: 60s
    scrape_timeout: 50s
    scheme: "http"
    metrics_path: '/actuator/prometheus' 
    static_configs:
     - targets: ['127.0.0.1:8888']
    tls_config:
     insecure_skip_verify: true

Resümee

Alle hier vorgestellten Techniken sind im praktischen Einsatz in vielen Projekten erprobt. Sicher mag es für spezielle Anwendungen wie REST Services einige Präferenzen geben. Für meinen persönlichen Geschmack bevorzuge ich für Konfigurationsdateien das XML Format. Dies ist leicht im Programm zu verarbeiten, extrem flexibel und bei geschickter Modellierung auch kompakt und hervorragend für Menschen lesbar.

Referenzen

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.


Modern Times

Die meisten DevOps-Teams sind überzeugt, dass die Automatisierung selbst und die Automatisierung selbst eine große Herausforderung darstellt. Es scheint dringend notwendig zu sein, alles zu automatisieren – sogar die Automatisierung selbst. Dies ist für die meisten DevOps-Teams ein allgemeines Verständnis und somit Motivation. Werfen wir einen Blick auf typische, kontinuierliche Dummheiten bei der Transformation vom reinen Konfigurationsmanagement zum DevOps-Engineer.

Die meisten DevOps-Teams sind davon überzeugt, dass die Automatisierung selbst und die Automatisierung selbst eine große Herausforderung darstellt. Es scheint dringend notwendig zu sein, alles zu automatisieren – sogar die Automatisierung selbst. Dies ist für die meisten DevOps-Teams ein allgemeines Verständnis und somit Motivation. Werfen wir einen Blick auf typische, kontinuierliche Dummheiten bei der Transformation vom reinen Konfigurationsmanagement zum DevOps-Engineer.

  1. Build-Logik kann eine fehlerhafte Architektur nicht reparieren. Zahlreiche SCM-Zusammenführungskonflikte entstehen durch die fehlende Kapselung der Geschäftslogik. Bei Funktionen, die über viele Module oder Dienste verteilt sind, ist die Wahrscheinlichkeit hoch, dass eine Datei von mehreren Entwicklern bearbeitet wird.
  2. Die Notwendigkeit orchestrierter Builds deutet auf Architekturprobleme hin. Transitive Abhängigkeiten, fehlende Kapselung und eine umfangreiche Abhängigkeitskette sind typische Gründe für das Henne-Ei-Problem. Entwerfen Sie Ihre Artefakte so unabhängig wie möglich.
  3. Build-Logik wird von Entwicklern und nicht von Administratoren entwickelt. Personen mit Fokus auf den Betrieb haben andere Konzepte zur Pflege von Artefakt-Builds als Softwareentwickler. Ein gutes Beispiel für eine Anti-Pattern-Build-Struktur sind webMethods der Software AG. webMethods bietet keinen Repository-Server wie Sonatype Nexus zum Teilen von Abhängigkeiten. Der Build verweist immer auf die Abhängigkeiten innerhalb einer webMethods-Installation. Diese Vorgehensweise verstößt gegen die Grundidee der Build-Automatisierung, die im Buch „Praktiken eines agilen Entwicklers“ von 2006 beschrieben wird.
  4. Nicht alles auf einmal. Teilen Sie die Build-Jobs in konkrete Ziele auf, wie z. B. Artefakt erstellen, Abnahmetests durchführen, API-Dokumentation erstellen und Berichte generieren. Wenn einer der letzten Schritte fehlschlägt, müssen Sie nicht alles wiederholen. Die Ausführungszeit des Builds wird drastisch reduziert, und die Build-Infrastruktur lässt sich leichter warten.
  5. Geben Sie Ihrer Build-Infrastruktur nicht zu viel Flexibilität. Dieser Punkt hängt eng mit dem ersten Thema zusammen, das ich erläutert habe. Ein undisziplinierter Build-Manager erstellt extrem komplexe Skripte, die niemand versteht. Der JavaScript-Task-Runner Grunt ist ein Beispiel dafür, wie eine Build-Logik unübersichtlich und unleserlich werden kann. Dies ist einer der Gründe, warum ich mich für Maven als Build-Tool für Java-Projekte entscheide, da es die Steuerung verständlicher Builds ermöglicht.
  6. Es besteht keine Notwendigkeit, die Automatisierung zu automatisieren. Komplexe Automatisierungsstufen verursachen per Definition höhere Kosten als einfache Aufgaben. Überlegen Sie sich immer vorher, welchen Nutzen Ihre Automatisierungsaktivitäten bringen, um zu prüfen, ob es sich lohnt, Zeit und Geld dafür aufzuwenden.
  7. Wir tun, was wir können, aber können wir auch, was wir tun? Oder mit den Worten von Gardy Bloch: „A fool with a tool is still a fool.“ Verstehen Sie die Anforderungen Ihres Projekts und entscheiden Sie auf dieser Grundlage, welches Tool Sie wählen. Wenn Ihnen die Ressourcen fehlen, kann Sie selbst die professionellste Lösung nicht unterstützen. Wenn Sie Ihr Problem verstanden haben, können Sie neue, professionelle und fortgeschrittene Prozesse erlernen.
  8. Die Build-Logik wurde zunächst in der lokalen Entwicklungsumgebung ausgeführt. Wenn Ihr Build nicht auf Ihrem lokalen Entwicklungsrechner läuft, nennen Sie es nicht Build-Logik. Es ist nur ein Hack. Die Build-Logik muss plattform- und IDE-unabhängig sein.
  9. Vermischen Sie Quellcode-Repositories nicht. mit anderen Dateien Die Organisation der Quellen in mehreren Ordnern innerhalb eines riesigen Verzeichnisses führt zu einem komplexen Build ohne jegliche Flexibilität. Quellen sollten nach Technologie oder separaten, unabhängigen Modulen strukturiert sein.

Viele der genannten Punkte lassen sich anhand der aktuellen Situation in fast jedem Projekt nachvollziehen. Die Lösung für eine erfolgreiche Problembehebung ist meist nicht allzu kompliziert. Sie erfordert lediglich ein wenig Aufmerksamkeit und gute Planung. Mein wichtigster Ratschlag ist das KISS-Prinzip (Keep it simple, stupid). Das bedeutet, den Standardprozess so weit wie möglich unverändert zu übernehmen. Man muss das Rad nicht neu erfinden. Es gibt Gründe, warum ein Standard zum Standard wird. Hier ist ein kurzer Plan, dem Sie folgen können:

  • Erstens: Verstehen Sie das Problem.
  • Zweitens: Suchen Sie nach einer Standardlösung für den Prozess.
  • Drittens: Entwickeln Sie einen Plan zur Integration der Lösung in die bestehende Prozesslandschaft. Dies bedeutet, Tools zu entfernen, die Standardprozesse nicht unterstützen.

Wenn Sie Ihren eigenen Weg Schritt für Schritt gehen, ohne zu weit zu springen, können Sie schnell positive Ergebnisse erzielen.

Übrigens: Wenn Sie Unterstützung für einen erfolgreichen DevOps-Prozess benötigen, kontaktieren Sie mich gerne. Ich biete praktische Beratung und Schulungen zum Aufbau eines leistungsstarken DevOps-Teams an.

Arbeiten mit Textdateien auf der Linux-Shell

Linux entwickelt sich mehr und mehr zu einem beliebten Betriebssystem für IT-Profis. Einer der Gründe für diese Entwicklung sind die Serverlösungen. Stabilität und geringer Ressourcenverbrauch sind einige der wichtigsten Eigenschaften für diese Wahl. Wer schon einmal mit einem Microsoft Server herumgespielt hat, wird den grafischen Desktop bei einem Linux Server vermissen. Nach dem Einloggen in einen Linux Server siht man nur die Kommandozeile, die auf Eingaben wartet.

In diesem kurzen Artikel stelle ich einige hilfreiche Linux-Programme zur Umgang mit Text Dateien auf der Kommandozeile vor. Auf diese Weise lassen sich leicht Informationen sammeln, zum Beispiel aus Protokolldateien (Logfiles). Bevor ich beginne, möchte ich noch einen einfachen und leistungsfähigen Editor namens joe empfehlen.

Strg + C – Abbrechen der aktuellen Bearbeitung einer Datei ohne Speichern der Änderungen
Strg + KX – Beenden der aktuellen Bearbeitung und Speichern der Datei
Strg + KF – Text in der aktuellen Datei suchen
Strg + V – Einfügen der Zwischenablage in das Dokument (CMD + V für Mac)
Strg + Y – Aktuelle Zeile an der Cursorposition löschen

Um joe auf einer Debian-basierten Linux-Distribution zu installieren, müssen Sie nur folgendes eingeben:

1. Wenn Sie Inhalte in einer großen Textdatei finden müssen, ist GREP Ihr bester Freund. Mit GREP können Sie nach Textmustern (Pattern) in Dateien suchen.

gerp <pattern> file.log 
    -n : number of lines that matches
    -i : case insensitive
    -v : invert matches
    -E : extended regex
    -c : count number of matches
    -l : find filenames that matches the pattern
Bash

2. Wenn Sie Netzpakete analysieren müssen, ist NGREP das Werkzeug Ihrer Wahl.

ngrep -I file.pcap
    -d : specify the network interface 
    -i : case insensitive
    -x : print in alternate hexdump
    -t : print timestamp
    -I : read a pcap file
Bash

3. Wenn Sie die Änderungen zwischen zwei Versionen einer Datei sehen wollen, ist DIFF genau das Richtige für Sie.

diff version1.txt version2.txt
    -a : add 
    -c : change
    -d : delete
     # : line numbers
     < : file 1
     > : file 2
Bash

4. Manchmal ist es notwendig, die Einträge in einer Datei in eine bestimmte Reihenfolge zu bringen. SORT wird Ihnen bei dieser Aufgabe helfen.

sort file.log 
     -o : write the result to a file 
     -r : reverse order
     -n : numerical sort
     -k : sort by column
     -c : check if orderd
     -u : sort and remove
     -f : ignore case
     -h : human sort
Bash

5. Wenn Sie Strings innerhalb eines großen Textes ersetzen müssen, z. B. durch Suchen und Ersetzen, können Sie dies mit SED, dem Stream-Editor, tun.

sed s/regex/replace/g
     -s : search 
     -g : replace
     -d : delete
     -w : append to file
     -e : execute command
     -n : suppress output
Bash

6. Das Parsen von Feldern mit Begrenzungszeichen in Textdateien kann mit CUT durchgeführt werden.

cut -d ":" -f 2 file.log 
     -d : use the field delimiter
     -f : field numbers
     -c : specific characters position
Bash

7. Die Extraktion von Teilstrings, die nur einmal in einer Textdatei vorkommen, erreichen Sie mit UNIQ.

uniq file.txt
     -c : count the numbers of duplicates 
     -d : print duplicates
     -i : case insesitive
Bash

8.  AWK ist eine Programmiersprache, mit der Daten manipuliert werden können.

awk {print $2} file.log 
Bash

Test First?

java Aktuell 2024.03

Als ich vor über 10 Jahren begonnen habe testgetrieben zu programmieren, waren mir sehr viele verschiedene Konzepte theoretisch bekannt. Aber diese Sichtweise erst Testfälle zu schrieben und dann die Implementierung umzusetzen war irgendwie nicht der Weg mit dem ich gut zurecht gekommen bin. Wenn ich ehrlich bin ist das bis heute der Fall. So das ich eine für mich funktionierende Adaption des TDD Paradigma von Kent Beck gefunden habe. Aber langsam der Reihe nach. Vielleicht ist mein Ansatz ja für den einen oder anderen ebenfalls recht hilfreich.

Ich komme ursprünglich aus einem Umfeld für hoch skalierbarer Webanwendungen auf die sich all die tollen Theorien aus dem universitären Umfeld in der Praxis nicht ohne weiteres umsetzen lassen. Der Grund liegt vor allem in der hohen Komplexität solcher Anwendungen. Zum einen sind verschiedene Zusatzsysteme wie In Memory Cache, Datenbank und Identität und Zugriffs Management (IAM) ein Teil des Gesamtsystems. Zum Anderen verstecken viele moderne Frameworks wie OR Mapper Komplexität hinter verschiedene Zugriffsschichten. All diese Dinge müssen wir als Entwickler heutzutage beherrschen. Deshalb gibt es robuste, praxiserprobte Lösungen die gut bekannt sind aber wenig Verwendung finden. Kent Beck mit ist eine der wichtigsten Stimmen für den praktischen Einsatz automatisierter Softwaretest.

Wenn wir uns auf das Konzept TDD einlassen wollen ist es wichtig nicht jedes Wort zu sehr auf die Goldwaage zu legen. Es ist nicht alles in Stein gemeißelt. Wichtig ist das Ergebnis am Ende des Tages. Aus diesem Grund ist es unabdinglich sich die Zielvorgabe aller Bemühungen vor Augen zu führen um dann einen persönlichen Mehrwert zu erzielen. Also schauen wir uns zu erst einmal an was wir überhaupt bezwecken wollen.

Der Erfolg gibt uns Recht

Als ich meine ersten Gehversuche als Entwickler unternommen hatte benötigte ich stetiges Feedback ob das was ich da gerade zusammen bauen auch wirklich funktioniert. Diese Feedback habe ich meist dadurch erzeugt, in dem ich meine Implementierung einerseits mit unzähligen Konsolenausgaben gespickt habe und andererseits habe ich immer versucht alles in eine Benutzeroberfläche einzubinden um mich dann ‚manuell durchzuklicken‘. Im Grunde ein sehr umständliches Test Setup, das dann auch am Schuß wieder zu entfernen ist. Wenn dann noch spätere Bugfixes vorgenommen werden mussten ging das ganze Prozedere wieder von Neuem los. Alles irgendwie unbefriedigend und weit entfernt von einer produktiven Arbeitsweise. Irgendwie musste das verbessert werden ohne das man sich jedes Mal neu erfindet.

Schließlich hat mein ursprünglicher Ansatz genau zwei markante Schwachstellen. Die offensichtlichste ist das ein und auskommentieren von Debug Informationen über die Konsole.

Viel schwerwiegender ist aber der zweite Punkt. Denn all das erworbene Wissen zu dieser speziellen Implementierung ist nicht konserviert. Es droht also über die Zeit zu verblassen und schlußendlich auch verloren zu gehen. Ein solches Spezialwissen ist für viele nachfolgende Prozessschritte in der Softwareentwicklung aber äußerst wertvoll. Damit meine ich explizit das Thema Qualität. Refactoring, Code Reviews, BugFixes und Change Requests sind nur einige der möglichen Beispiele wo tiefgreifendes Detailwissen gefragt ist.

Für mich persönlich kommt auch hinzu, das mich monoton wiederholbare Arbeiten schnell ermüden und ich diese dann sehr gern vermeiden möchte. Sich immer wieder aufs neue mit der selben Testprozedur durch eine Anwendung zu klicken ist weit davon entfernt was für mich einen erfüllten Arbeitstag ausmacht. Ich möchte neue Dinge entdecken. Das kann ich aber nur wenn ich nicht in der Vergangenheit gefangen gehalten werde.

Die trauen sich aber was

Bevor ich aber darauf eingehe wie ich meinen Entwicklungsalltag durch TDD aufgepeppt habe muss ich noch ein paar Worte über Verantwortung und Mut loswerden. Immer wieder wird mir in Gesprächen erklärt das ich ja recht habe aber man können das alles ja nicht selber umsetzen, weil der Projektleiter oder irgend ein anderer Vorgesetzter kein grünes Licht gibt.

Eine solche Einstellung ist in meinen Augen äußerst unprofessionell. Ich frage doch auch nicht den Marketingleiter welcher Algorithmus am besten terminiert. Er hat schlichtweg keine Ahnung, denn es ist auch nicht sein Aufgabengebiet. Ein Projektleiter der sich gegen das testgetriebene Arbeiten im Entwicklungsteam ausspricht hat aber auch seinen Beruf verfehlt. In der heutigen Zeit sind Testframeworks so gut in die Build Umgebung integriert, das die Vorbereitung für TDD sich selbst für unerfahrene Personen in wenigen Augenblicken umsetzen lässt. Es ist also nicht notwendig das Vorhaben an die große Glocke zu hängen. Denn ich kann versprechen das selbst bei den ersten Gehversuchen nicht mehr Zeit benötigt wird als mit der ursprünglichen Vorgehensweise. Ganz im Gegenteil sehr schnell wird sich eine merkliche Erhöhung der Produktivität einstellen.

Die erste Stufe der Evolution

Wie bereits erwähnt ist Logging für mich ein zentrale Teil der testgetriebene Entwicklung. Wann immer es sinnvoll erscheint versuche ich den Zustand von Objekten oder Variablen auf der Konsole auszugeben. Wenn wir hierfür die aus der verwendeten Programmiersprache zur Verfügung gestellten Mittel nutzen, bedeute dies das wir diese Systemausgaben nach getaner Arbeit mindestens auskommentieren müssen und bei späterer Fehlersuche wieder einkommentieren. Ein redundantes und fehleranfälliges Vorgehen.

Nutzen wir hingegen von beginn an ein Logging Framework so können wir die Debug Informationen getrost im Code stehen lassen und deaktivieren diese später im Produktivbetrieb über den eingestellten Log Level.

Ich nutze Logging aber auch als Tracer. Das heißt jeder Konstruktor einer Klasse schreibt während er aufgerufen wird einen entsprechenden Log Eintrag im Log Level Info. Damit kann man sehen in welcher Reihenfolge Objekte instanziiert werden. Hin und wieder bin ich so auch auf die übermäßig oft vorkommende Instanziierung eines einzelnen Objektes aufmerksam geworden. Dies ist hilfreich für Maßnahmen zur Performance und Speicheroptimierung.

Fehler die bei der Ausnahmebehandlung geworfen werden logge ich je nach Kontext als Error oder Warning. Das ist später im Betrieb ein sehr hilfreiches Mittel um Fehlern auf die Spur zu kommen.

Wenn ich also eine Datenbankzugriff habe, schreibe ich also eine Logausgabe im Log Level Debug wie das zugehörige SQL zusammen gebaut wurde. Führt dieses SQL zu einer Exception, weil ein Fehler enthalten ist so wird diese Exception mit dem Log Level Error geschrieben. Findet wiederum eine einfache Suchanfrage mit korrekter SQL Syntax statt und die Ergebnismenge ist leer wird dieses Ereignis je nach Bedarf entweder als Debug oder Warning klassifiziert. Handelt es sich beispielsweise um eine Loginanfrage mit falschem Benutzernamen oder Passwort neige ich dazu mich für den Log Level Warning zu entscheiden, da dies im Betrieb eventuell sicherheitstechnische Aspekte enthält.

Im gesamten Kontext konfiguriere ich das Logging für die Testfallausführung eher sehr geschwätzig und beschränke mich auf eine reine Konsolenausgabe. Im Betrieb wiederum werden die Logging Informationen in eine Logfile geschrieben.

Die Henne oder das Ei

Wenn wir mit dem Logging die Voraussetzung für eine zusätzliche Feedbackschleife gelegt haben stellt sich im nächsten Schritt die Frage wie geht es weiter. Wie bereits erwähnt tue ich mich sehr schwer erst einen Testfall zu schreiben um dann eine entsprechende Implementierung dafür zu finden. Vor diesem Problem stehen auch viele andere Entwickler die mit TDD beginnen.

Eine Sache die ich bereits voraus nehmen kann ist das Problem, das man bei einer Implementierung darauf achten muss diese auch testbar zu halten. Habe ich erst den Testfall so merke ich umgehend ob das was ich gerade erstelle auch wirklich testbar ist. Erfahrene TDD Entwickler haben recht schnell in Fleisch und Blut übernommen wie testbarer Code auszusehen hat. Der wichtigste Punkt hierbei ist das Methoden stets einen Rückgabewert haben sollten, der möglichst nicht null ist. So etwas erreicht man beispielsweise wenn man anstatt null eine leere Liste zurück gibt.

Die Vorgabe einen Rückgabewert zu haben liegt an der Art und Weise wie Unit Test Frameworks arbeiten. Ein Testfall vergleicht den Rückgabewert einer Methode mit einem Erwartungswert. Die Testzusicherung (engl. Assertation) kennt verschiedene Ausprägungen und kann entsprechend: gleich, ungleich, wahr oder falsch sein. Natürlich gibt es hier auch verschieden Variationen. So kann es unter Verwendung von Exceptions möglich sein Methoden die keinen Rückgabewert haben zu testen. Alle diese Details erschließen sich bei der Anwendung in sehr kurzer Zeit. So das jeder ohne langwierige Vorbereitungen umgehend loslegen kann.

Bei der Lektüre des Buches Test Driven Development by Example von Kent Beck finden wir auch schnell eine Erklärung warum die Testfälle zu erst geschrieben werden sollten. Es handelt sich um einen psychologischen Faktor. Es soll uns dabei helfen den üblichen Stress der im Projekt entsteht besser zu bewältigen. Es erzeugt in uns einen mentalen Zustand über den Zustand und Fortschritt der aktuellen Arbeit. Es leitet uns in eine iterativen Prozess die vorhandene Lösung schrittweise über die verschiedenen Testfälle weiter auszubauen und zu verbessern.

Für alle die wie ich aber zu beginn einer Implementierung noch keine konkrete Vorstellung über das fertige Ergebnis haben ist dieser Ansatz schwer umzusetzen. Der bezweckte Effekt der Entspannung kehrt sich ins negative um. Da wir Menschen alle unterschiedlich sind müssen wir also herausfinden wie wir ticken um das bestmögliche Ergebnis zu erzielen. Ganz so wie es mit Lernstrategien ist. Manche Menschen verarbeiten Informationen besser visuell andere eher haptisch und wieder andere extrahieren alles wichtige aus gesprochenem. Versuchen wir uns also nicht wider unserer Natur zu verbiegen um mittelmäßige oder schlechte Ergebnis zu produzieren.

Den ersten Strich zeichnen

Mir erschließt sich ein Thema eben erst während ich damit arbeite. Also Versuche ich mich solange an einer Implementierung bis ich ein erstes Feedback benötige. Genau dann schreibe ich den ersten Test. Es ergebenen sich bei diesem Vorgehen automatisch Fragen bei der jede einzelne einen eigenen Testfall wert ist. Finde ich alle vorhanden Ergebnisse? Was passiert wenn die Ergebnismenge leer ist. Wie lässt sich die Ergebnismenge eingrenzen? Alles Punkte die sich auf einem Zettel notieren und Schritt für Schritt abhaken lassen. Die Idee eine Aufgabenliste auf einem Zettel zu notieren hatte ich schon sehr lange bevor ich das bereits erwähnte Buch von Kent Beck gelesen habe. Es hilft mir schnelle Gedanke zu konservieren ohne mich von meinem aktuellen Tun ablenken zu lassen. Außerdem vermittelt es am Ende des Tages ein Gefühl etwas geschafft zu haben.

Da ich nicht warte bis ich alles Umgesetzt habe, um den ersten Test zu schreiben ergibt sich auch bei diesem Vorgehen ein iterativer Ansatz. Ich merke auch sehr schnell wenn mein Entwurf nur unzureichend testbar ist, da ich sofort eine Rückmeldung erhalte. Daraus ergibt sich meine eigene Interpretation für TDD die sich durch den permanenten Wechsel zwischen Implementieren und Test schreiben auszeichnet.

Als Ergebnis meiner frühen TDD Versuche habe ich bereits in der ersten Woche eine Beschleunigung meiner Arbeitsweise bemerkt. Ich bin auch sicherer geworden. Aber auch die Art und Weise wie ich Programmiere hat sich schon sehr zeitig zu verändern begonnen. Mir ist aufgefallen das mein Code kompakter und robuster geworden ist. Dinge die sich erst mit der Zeit aufgezeigt hatten ergaben sich bei Tätigkeiten wie Refactoring und Erweiterungen. Fehlgeschlagene Testfälle haben mich vor bösen Überraschungen bewahrt.

Ohne Übereifer beginnen

Wenn wir uns in einem bestehenden Projekt dazu entschließen TDD einzusetzen ist es eine schlechte Idee loszulegen und für bestehende Funktionalität Testfälle zu schreiben. Abgesehen von der Zeit die hierfür eingeplant werden muss wird das Ergebnis die hohen Erwartungen nicht erfüllen.

Eines der Probleme ist das man sich nun in jede Funktionalität neu einarbeiten muss und das ist sehr Zeitaufwendig. Die Qualität der so entstandene Testfälle ist auch unzureichend. Das Problem ergibt sich auch aus der Erfahrung. Wird die Erfahrung erst aufgebaut so ist die Qualität der Testfälle auch noch nicht ganz optimal und möglicherweise muss auch Code umgeschrieben werden, damit dieser Testbar wird. Es entstehen also eine Menge Risiken die für das tägliche Projektgeschäft problematisch sind.

Ein bewährtes Vorgehen TDD einzuführen ist es einfach für die aktuelle Implementierung an der man gerade arbeitet einzusetzen. Es wird also der ist Zustand des aktuellen Problems durch automatisierte Tests dokumentiert. Da man sich bereits auf vertrautem Terrain befindet muss man sich nicht erst in eine neue Thematik einarbeiten, so das man sich voll auf das formulieren von aussagekräftigen Tests konzentrieren kann. Abgesehen davon, das man ungefragt Verantwortung über fremde Arbeiten übernimmt wenn man für diese Testfälle umgesetzt.

Bestehende Funktionalität wird nur bei Fehlerkorrekturen entsprechend um Testfälle ergänzt. Für die Korrektur muss man sich eh mit den Implementierungsdetails auseinander setzen, so das hier genügend Wissen vorhanden ist wie eine Funktionalität sich verhalten sollte. Die so entstandene Tests dokumentieren zusätzlich auch die Korrektur und stellen für die Zukunft sicher das sich das Verhalten bei Optimierungsarbeiten nicht verändert.

Folgt man dieser Vorgehensweise diszipliniert verliert man sich nicht in sogenannter hektischer Betriebsamkeit, die wiederum das Gegenteil von Produktivität ist. Zudem erwirbt man so recht schnell fundiertes Wissen wie effektive und aussagekräftige Tests umgesetzt werden können. Erst wenn ausreichend Erfahrung gesammelt wurde und möglicherweise umfangreiche Refactorings geplant werden, dann kann man überlegen wie für das gesamte Projekt die Testabdeckung schrittweise verbessert werden kann.

Qualitätsstufe

Nur weil Testfälle vorhanden sind bedeutet dies nicht das diese auch eine Aussagekraft haben. Genausowenig beweist eine hohe Testabdeckung das ein Programm fehlerfrei ist. Eine hohe Testabdeckung stellt nur sicher das sich ein Programm im Rahmen der Tests verhält.

Wir kann man also sicherstellen das die vorhandene Tests auch wirklich eine Bereicherung sind und eine gute Aussagekraft haben? Der erste und meines Erachtens wichtigste Punkt ist Testfälle möglichst kurz zu halten. Das heißt im Konkreten, das ein Test nur eine explizite Fragestellung beantwortet, z. B. Was passiert wenn die Ergebnismenge leer ist? Entsprechend der Fragestellung ergibt sich dann auch die Benennung der Testmethode. Den Mehrwert dieser Vorgehensweise ergibt sich in dem Moment wenn der Testfall fehlschlägt. Ist der Test sehr kurzgefasst lässt sich oft schon an der Testmethode ablesen worin das Problem besteht, ohne sich erst langwierig in einen Testfall einzuarbeiten zu müssen.

Ein anderer wichtiger Punkt im TDD Vorgehen ist für meine umgesetzte Funktionalität sowohl die Testabdeckung für Codezeilen als auch für Verzweigungen zu überprüfen. Kann ich zum Beispiel in einer IF-Abfrage das Eintreten einer einzelnen Bedingung nicht simulieren, so kann diese Bedingung bedenkenlos gestrichen werden.

Natürlich hat man im eigenen Projekt auch genügend Abhängigkeiten zu fremden Bibliotheken. Nun kann es vorkommen das eine Methode aus dieser Bibliothek eine Ausnahme wirft, die durch keinen Testfall simuliert werden kann. Das ist genau der Grund wieso man zwar eine hohe Testabdeckung anstreben sollte aber nicht verzweifeln muss wenn 100% nicht erreicht werden können. Gerade bei der Einführung von TDD ist ein gutes Maß für die Testabdeckung größer als 85% üblich. Mit wachsender Erfahrung des Entwicklungsteams kann dieser Wert bis zu 95% angehoben werden.

Abschließend ist aber noch anzumerken, das man sich nicht zu sehr in den Eifer begibt. Denn es kann auch schnell übertrieben werden und dann sind die ganzen gewonnene Vorteile schnell wieder dahin. Und zwar geht es um den Punkt das man keine Tests schreibt die wiederum Tests testen. Hier beißt sich die Katze in den Schwanz. Das gilt auch für Bibliotheken von Fremdanbietern. Für diese werden ebenfalls keine Test geschrieben. Kent Beck äußert sich hierzu sehr klar: Selbst wenn es gute Gründe gibt dem Code anderer zu misstrauen, teste ihn nicht. Externer Code erfordert mehr eigene Implementierungslogik.

Lessons Learned

Gerade die Erkenntnisse die sich bei dem Versuch eine möglichst hohe Testabdeckung zu erzielen sind die, welche sich beim künftigen Programmieren auswirken. Der Code wird kompakter und robuster.

Die Produktivität steigt einfach durch die Tatsache, das fehleranfällige und monotone Arbeiten durch Automatisierung vermieden werden. Es entstehen keine zusätzlichen Arbeitsschritte denn alte Gewohnheiten werden durch neue, bessere ersetzt.

Ein Effekt den ich immer wieder beobachten konnten, wenn sich einzelne Personen aus dem Team für TDD entschieden haben, wurden deren Erfolge schnell beachtet. Innerhalb weniger Wochen hat dann das gesamte Team TDD entwickelt. Jeder einzelne nach seinen eigene Fähigkeiten. Manche mit Test First andere wiederum so wie ich es gerade beschrieben habe. Zum Schluß zählt das Ergebnis und das war einheitlich hervorragend. Wenn die Arbeit leichter fällt und am Ende des Tages jeder einzelne auch noch das Gefühl hat auch etwas geleistet zu haben bewirkt dies im Team einen enormen Motivationsschub, der dem Projekt und dem Arbeitsklima eine gewaltigen Auftrieb verschafft. Also worauf warten Śie noch? Probieren Sie es am besten gleich selber aus.

Tschüß Privatsphäre, Tschüß Freiheit

Die im Oktober 2023 veröffentlichten neuen AGB für Microsoft-Dienste lösten in der IT-Welt einen Aufschrei aus. Der Grund war ein Absatz, in dem es hieß, dass mittlerweile alle Microsoft-Dienste auf künstlicher Intelligenz basieren. Diese K.I. soll dazu dienen, Urheberrechtsverletzungen zu erkennen. Dazu gehören Dinge wie Musik, Filme, Grafiken, E-Books und natürlich auch Software. Falls diese K. I. Urheberrechtsverletzungen auf dem System erkennt, sollten diese Dateien automatisch vom „System“ gelöscht werden. Derzeit ist nicht klar, ob diese Regel für die eigene lokale Festplatte oder nur für die Dateien in der Microsoft Cloud gilt. Microsoft hat außerdem erklärt, dass Benutzer, die gegen die Urheberrechtsbestimmungen verstoßen, künftig von allen Microsoft-Diensten ausgeschlossen werden sollen.

Dieser Ausschluss hat verschiedene ‘Geschmäckle’. Die ersten Fragen, die mir in den Sinn kommen, sind: Was passiert mit kostenpflichtigen Abonnements wie Skype? Werde ich gesperrt und anschließend wird mein ungenutztes Guthaben zurückerstattet? Ein noch schlimmeres Szenario wäre, dass ich möglicherweise auch all mein Guthaben und digitale Käufe wie den Zugang zu Spielen und anderen Dingen verliere. Oder sind kostenpflichtige Abonnements davon nicht betroffen? Bisher ist dieser Teil nicht klar.

Wer ein Apple Nutzer ist und denkt, dass dies keine Auswirkungen auf Applegeräte hat, sollte sicherstellen, dass keine Microsoft-Dienste verwendet werden. Möglicherweise wissen sie nicht, dass dieser zu Microsoft gehört. Nicht jedes Produkt enthält den Firmennamen. Denken Sie darüber nach, denn wer weiß, ob diese Produkte Ihr System ausspionieren. Einige Anwendungen wie Skype, Teams, Edge Browser und Visual Studio Code sind auch für andere Plattformen wie Apple und Linux verfügbar.

Microsoft besitzt außerdem die Quellcode-Hosting-Plattform GitHub und ein soziales Netzwerk für Spezialisten namens LinkedIn. Mit Office 360 können Sie die gesamte Microsoft Office Suite per Webbrowser als Cloud-Lösung nutzen und alle Ihre Dokumente werden in der Microsoft Cloud gespeichert. Dieselbe Cloud, in der US-Regierungsinstitutionen wie die CIA, die NSA und viele andere ihre Dateien aufbewahren. Nun, es scheint wohl ein sicherer Ort für alle Ihre Gedanken zu sein, die in ein Office Dokument niedergeschrieben wurden.

Dieses kleine Detail zu Office-Dokumenten führt uns zu einer weiteren Randbemerkung in den neuen Geschäftsbedingungen von Microsoft. Der Kampf gegen Hassrede. Was auch immer das heißt. Öffentliche Beleidigungen und Verleumdungen werden seit jeher vom Gesetzgeber strikt als Straftat behandelt. Es ist kein Kavaliersdelikt, der mit einem kleinen Bußgeld geahndet wird. Daher ist mir nicht klar, was dieses ganze Gerede über Hassreden bedeutet. Vielleicht ist es ein Versuch, eine öffentliche Zensur der Meinungsfreiheit einzuführen.

Aber zurück zum Randhinweis der Microsoft-Nutzungsbedingungen zu Hassreden. Microsoft hat so etwas geschrieben wie: Wenn Hassreden festgestellt werden, wird der Benutzer verwarnt und wenn die Verstöße mehrmals auftreten, wird das Microsoft-Konto des Benutzers deaktiviert.

Wenn Sie vielleicht denken, dass dies nur etwas ist, was jetzt bei Microsoft passiert, seine sie sich im klaren, dass viele andere Unternehmen ebenfalls daran arbeiten, solche Bestimmungen für ihre Produkte einzuführen. Die Kommunikationsplattform Zoom beispielsweise beinhaltete auch K. I. Techniken, um die Benutzerkommunikation zu ‘Trainingszwecken’ zu beobachten.

Bei all diesen Neuigkeiten stellt sich eine große Frage, die beantwortet werden muss: Was kann ich selbst tun? Die Lösung ist einfach. Verlassen Sie das digitale Universum und gehen Sie zurück in die reale Welt. Schalten Sie das Gehirn wieder ein. Benutzen Sie Stift und Papier, zahlen Sie bar, lassen Sie Ihr Smartphone zu Hause und dort niemals auf dem Nachttisch. Wenn Sie es nicht verwenden, schalten Sie es aus! Treffen Sie Ihre Freunde, wann immer es möglich ist physisch und bringen Sie dazu nicht Ihr Smartphone mit. Es wird keine Regierung, keinen Präsidenten und keinen Messias geben, die eine Veränderung herbeiführen wird. Es ist an uns, dies zu tun.

Zu argumentieren, dass Privatsphäre für dich nicht wichtig ist, weil du nicht zu verbergen hast, ist das Gleiche wie zu sagen, das Meinungsfreiheit unwichtig ist, weil man nicht zu sagen hat.

Die dunkle Seite der künstlichen Intelligenz

Als Techniker bin ich recht schnell von allen möglichen Dingen zu begeistern, die irgendwie blinken und piepsen, ganz gleich, wie unnütz diese auch sein mögen. Elektronikspielereien ziehen mich an, wie das Licht Motten. Seit einer Weile ist eine neue Generation Spielwaren für die breite Masse verfügbar: Anwendungen der Künstlichen Intelligenz, genauer gesagt künstliche neuronale Netze. Die frei verfügbaren Anwendungen leisten bereits Beachtliches und es ist erst der Anfang dessen, was noch möglich sein wird. Vielen Menschen ist die Tragweite KI-basierter Anwendungen noch gar nicht bewusst geworden. Das ist auch nicht verwunderlich, denn das, was gerade im Sektor KI geschieht, wird unser Leben nachhaltig verändern. Wir können also zu Recht sagen, dass wir in einer Zeit leben, die gerade Geschichte schreibt. Ob die kommenden Veränderungen etwas Gutes werden, oder sie sich als eine Dystopie entpuppen, wird an uns liegen.

Als ich im Studium vor sehr vielen Jahren als Vertiefungsrichtung Künstliche Intelligenz gewählt hatte, war die Zeit noch von sogenannten „Expertensystemen“ geprägt. Diese regelbasierten Systeme waren für ihre Domäne hoch spezialisiert und wurden für entsprechende Experten ausgelegt. Das System sollte die Experten bei der Entscheidungsfindung unterstützen. Mittlerweile haben wir auch die notwendige Hardware, um viel allgemeinere Systeme zu schaffen. Wenn wir Anwendungen wie ChatGPT betrachten, basieren diese auf neuronalen Netzen, was eine sehr hohe Flexibilität in der Verwendung erlaubt. Der Nachteil ist allerdings, dass wir als Entwickler kaum noch nachvollziehen können, welche Ausgabe ein neuronales Netz für eine beliebige Eingabe erzeugt. Ein Umstand, der die meisten Programmierer, die ich kenne, eher eine ablehnende Haltung einnehmen lässt, da diese so nicht mehr Herr über den Algorithmus sind, sondern nur noch nach dem Prinzip Versuch und Irrtum agieren können.

Dennoch ist die Leistungsfähigkeit neuronaler Netze verblüffend. Vorbei scheint nun die Zeit, in der man sich über unbeholfene, automatisierte, softwaregestützte Übersetzungen lustig machen kann. Aus eigener Erfahrung weiß ich noch, wie mühselig es war, den Google Translator aus dem Deutschen einen vernünftigen Satz ins Spanische übersetzen zu lassen. Damit das Ergebnis brauchbar war, konnte man sich über die Option Englisch – Spanisch behelfen. Alternativ, wenn man nur ein rudimentäres Englisch für den Urlaubsgebrauch spricht, konnte man noch sehr einfache deutsche Sätze formulieren, die dann wenigstens inhaltlich korrekt waren. Die Zeitersparnis für automatisiert übersetzte Texte ist erheblich, obwohl man diese Korrektur lesen muss und gegebenenfalls ein paar Formulierungen angepasst werden müssen.

Sosehr ich es schätze, mit solchen starken Werkzeugen arbeiten zu können, müssen wir uns aber auch im Klaren sein, dass es auch eine Schattenseite gibt. Denn je mehr wir unsere täglichen Aufgaben über KI-gestützte Tools erledigen, umso mehr verlieren wir die Fähigkeit, diese Aufgaben künftig weiterhin manuell bearbeiten zu können. Für Programmierer bedeutet dies, dass sie im Laufe der Zeit über KI-gestützte IDEs ihre Ausdrucksfähigkeit im Quellcode verlieren. Das ist natürlich kein Prozess, der über Nacht stattfindet, sondern sich schleichend einstellt. Aber sobald diese Abhängigkeit einmal geschaffen ist, stellt sich die Frage, ob die verfügbaren, liebgewonnenen Werkzeuge weiterhin kostenfrei bleiben oder ob für bestehende Abonnements möglicherweise drastische Preiserhöhungen stattfinden. Denn es sollte uns schon klar sein, das kommerziell genutzte Werkzeuge, die unsere Produktivität erheblich verbessern, üblicherweise nicht zum Schnäppchenpreis verfügbar sind.

Ich denke auch, dass das Internet, wie wir es bisher gewohnt sind, sich in Zukunft sehr stark verändern wird. Viele der kostenlosen Angebote, die bisher durch Werbung finanziert sind, werden mittelfristig verschwinden. Schauen wir uns dazu einmal als Beispiel den Dienst „Stack Overflow“ an – in Entwicklerkreisen eine sehr beliebte Wissensplattform. Wenn wir nun künftig für die Recherche zu Fragestellungen der Programmierung ChatGPT oder andere neuronale Netze nutzen, sinken für Stack Overflow die Besucherzahlen kontinuierlich. Die Wissensbasis wiederum, die ChatGPT nutzt, basiert auf Daten von öffentlichen Foren wie Stack Overflow. Somit wird auf absehbare Zeit Stack Overflow versuchen, seine Dienste für KIs unzugänglich zu machen. Es könnte sicher auch eine Einigung mit Ausgleichszahlungen zustande kommen, sodass die wegfallenden Werbeeinnahmen kompensiert werden. Denn als Techniker muss uns nicht ausschweifend dargelegt werden, dass für ein Angebot wie Stack Overflow erhebliche Kosten für den Betrieb und die Entwicklung anfallen. Es bleibt dann abzuwarten, wie die Nutzer das Angebot künftig annehmen werden. Denn wenn auf Stack Overflow keine neuen Daten zu Problemstellungen hinzukommen, wird die Wissensbasis für KI-Systeme auch uninteressant. Daher vermute ich, dass bis circa 2030 vor allem hochwertige Inhalte im Internet kostenpflichtig werden.

Wenn wir die Prognose des mittelfristigen Trends über den Bedarf von Programmierern betrachten, kommen wir zu der Frage, ob es künftig eine gute Empfehlung sein wird, Informatik zu studieren oder eine Ausbildung als Programmierer anzutreten. Ich sehe hier tatsächlich eine positive Zukunft und würde jedem, der eine Ausbildung als Berufung versteht und nicht als Notwendigkeit ansieht, seinen Lebensunterhalt zu bestreiten, in seinem Vorhaben bekräftigen. Meiner Ansicht nach werden wir weiterhin viele innovative Köpfe benötigen. Lediglich jene, die sich anstatt sich mit Grundlagen und Konzepten zu beschäftigen, lieber mal schnell ein aktuelles Framework erlernen wollen, um aufkommende Hypes des Marktes mitzunehmen, werden sicher nur noch geringen Erfolg in Zukunft erzielen. Diese Beobachtungen habe ich aber auch bereits vor der breiten Verfügbarkeit von KI-Systemen machen können. Deshalb bin ich der festen Überzeugung, dass sich langfristig Qualität immer durchsetzen wird.

Dass man sich stets Themen möglichst kritisch und aufmerksam nähern sollte, betrachte ich als eine Tugend. Dennoch muss ich sagen, dass so manche Ängste im Umgang mit KI recht unbegründet sind. Sie haben ja schon einige meiner möglichen Zukunftsvisionen in diesem Artikel kennengelernt. Aussagen wiederum, dass die KI einmal unsere Welt übernehmen wird, indem sie unbedarfte Nutzer subtil beeinflusst, um diese zu Handlungen zu motivieren, halte ich für einen Zeitraum bis 2030 eher für reine Fantasie und mit dem aktuellen Erkenntnisstand unbegründet. Viel realistischer sehe ich das Problem, dass findige Marketingleute das Internet mit minderwertigen, ungeprüften, nicht redigierten, KI-generierten Artikeln übersähen, um ihr SEO-Ranking aufzupeppen und diese wiederum als neue Wissensbasis der neuronalen Netze die Qualität künftiger KI-generierter Texte erheblich reduziert.

Die bisher frei zugänglichen KI-Systeme haben gegenüber dem Menschen einen entscheidenden Unterschied. Ihnen fehlt die Motivation, etwas aus eigenem Antrieb zu tun. Erst durch eine extrinsische Anfrage durch den Nutzer beginnt die KI, eine Fragestellung zu bearbeiten. Interessant wird es dann, wenn eine KI sich aus eigenem Antrieb heraus selbstgewählten Fragestellungen widmet und diese auch eigenständig recherchiert. In diesem Fall ist die Wahrscheinlichkeit sehr hoch, dass die KI sehr schnell ein Bewusstsein entwickeln wird. Läuft eine solche KI dann noch auf einem Hochleistungsquantencomputer, haben wir nicht genügend Reaktionszeit, um gefährliche Entwicklungen zu erkennen und einzugreifen. Daher sollten wir uns durchaus das von Dürrenmatt geschaffene Drama „Die Physiker“ in unserem Bewusstsein halten. Denn die Geister, die ich einmal rief, werde ich möglicherweise nicht so schnell wieder los.

Grundsätzlich muss ich zugeben, dass mich das Thema KI weiterhin fasziniert und ich auf die künftige Entwicklung sehr gespannt bin. Dennoch finde ich es wichtig, auch vor der dunklen Seite der Künstlichen Intelligenz den Blick nicht zu versperren und dazu einen sachlichen Diskurs zu beginnen, um möglichst schadenfrei das vorhandene Potenzial dieser Technologie auszuschöpfen.

Das Neueste wird nicht immer das Beste sein

Microsoft hat beispielsweise seit der Einführung von Windows 10 seinen Nutzern ein Update-Zwang auferlegt. Grundsätzlich war die Idee durchaus begründet. Denn ungepatchte Betriebssysteme ermöglichen Hackern leichten Zugriff. Also hat sich vor sehr langer Zeit der Gedanke: ‚Latest is greatest‘ durchgesetzt.

Windows-Nutzer habe hier wenig Freiräume. Aber auch auf mobilen Geräten wie Smartphones und Tabletts sind in der Werkseinstellung die automatischen Updates aktiviert. Wer auf GitHub ein Open Source Projekt hostet, bekommt regelmäßige E-Mails, um für verwendete Bibliotheken neue Versionen einzusetzen. Also auf den ersten Blick durchaus eine gute Sache. Wenn man sich mit der Thematik etwas tiefer auseinandersetzt, kommt man rasch zu dem Schluss, dass latest nicht wirklich immer das Beste ist.

Das bekannteste Beispiel hierfür ist Windows 10 und die durch Microsoft erzwungenen Update Zyklen. Dass Systeme regelmäßig auf Sicherheitsprobleme untersucht und verfügbare Aktualisierungen eingespielt werden müssen, ist unumstritten. Dass die Pflege von Rechnersysteme auch Zeit in Anspruch nimmt, ist ebenfalls einsichtig. Problematisch ist es, aber wenn durch den Hersteller eingespielte Aktualisierungen einerseits das gesamte System lahmlegen und so eine Neuinstallation notwendig wird, weil das Update nicht ausreichend getestet wurde. Aber auch im Rahmen von Sicherheitsaktualisierungen ungefragt Funktionsänderungen beim Nutzer einzubringen, halte ich für unzumutbar. Speziell bei Windows kommt noch hinzu, dass hier einiges an Zusatzprogrammen installiert ist, die durch mangelnde Weiterentwicklung schnell zu einem Sicherheitsrisiko werden können. Das bedeutet bei aller Konsequenz erzwungene Windowsupdates machen ein Computer nicht sicher, da hier die zusätzlich installierte Software nicht auf Schwachstellen untersucht wird.

Wenn wir einen Blick auf Android-Systeme werfen, gestaltet sich die Situation weitaus besser. Aber auch hier gibt es genügend Kritikpunkte. Zwar werden die Applikationen regelmäßig aktualisiert, so dass tatsächlich die Sicherheit markant verbessert wird. Aber auch bei Android bedeutet jedes Update in aller Regel auch funktionale Veränderungen. Ein einfaches Beispiel ist der sehr beliebte Dienst Google StreetMaps. Mit jedem Update wird die Kartennutzung für mich gefühlt unübersichtlicher, da eine Menge für mich unerwünschter Zusatzinformationen eingeblendet werden, die den bereits begrenzten Bildschirm erheblich verkleinern.

Als Nutzer ist es mir glücklicherweise bisher nicht passiert, dass Applikationsupdates unter Android das gesamte Telefon lahmgelegt haben. Was also auch beweist, dass es durchaus möglich ist, Aktualisierungen ausgiebig zu testen, bevor diese an die Nutzer ausgerollt werden. Was aber nicht heißt, dass jedes Update unproblematisch war. Probleme, die hier regelmäßig beobachtet werden können, sind Dinge wie ein übermäßig erhöhter Batterieverbrauch.

Reine Android Systemupdates wiederum sorgen regelmäßig dafür, dass die Hardware nach knapp zwei Jahren so langsam wird, dass man sich oft dazu entscheidet, ein neues Smartphone zu kaufen. Obwohl das alte Telefon noch in gutem Zustand ist und durchaus viel länger genutzt werden könnte. So ist mir bei vielen erfahrenen Nutzern aufgefallen, dass diese nach circa einem Jahr ihre Android-Updates ausschalten, bevor das Telefon durch den Hersteller in die Obsoleszenz geschickt wird.

Wie bekommt man ein Update-Muffel nun dazu, seine Systeme trotzdem aktuell und damit auch sicher zu halten? Mein Ansatz als Entwickler und Konfigurationsmanager ist hier recht einfach. Ich unterscheide zwischen Feature Update und Security Patch. Wenn man im Release Prozess dem Semantic Versioning folgt und für SCM Systeme wie Git ein Branch by Release Modell nutzt, lässt sich eine solche Unterscheidung durchaus leicht umsetzen.

Aber auch der Fragestellung einer versionierbaren Konfigurationseinstellung für Softwareanwendungen habe ich mich gewidmet. Hierzu gibt es im Projekt TP-CORE auf GitHub eine Referenzimplementierung, die in dem zweiteiligen Artikel ‘Treasue Chest’ ausführlich beschrieben wird. Denn es muss uns schon klar sein, dass wenn wir bei einem Update die gesamte vom Nutzer vorgenommene Konfiguration auf Werkseinstellung zurücksetzen, wie es recht oft bei Windows 10 der Fall ist, können ganz eigene Sicherheitslücken entstehen.

Das bringt uns auch zu dem Punkt Programmierung und wie GitHub Entwickler durch E-Mails dazu motiviert, neue Versionen der verwendeten Bibliotheken in ihre Applikationen einzubinden. Denn, wenn es sich bei einem solchen Update um eine umfangreiche API-Änderung handelt, ist das Problem der hohe Migrationsaufwand für die Entwickler. Hier hat sich für mich eine ebenfalls recht einfache Strategie bewährt. Anstatt mich von den Benachrichtigungen über Aktualisierungen von GitHub beeindrucken zu lassen, prüfe ich regelmäßig über OWASP, ob meine Bibliotheken bekannte Risiken enthalten. Denn wird durch OWASP ein Problem erkannt, spielt es keine Rolle, wie aufwendig eine Aktualisierung werden kann. Das Update und eine damit verbundene Migration muss zeitnahe umgesetzt werden. Dies gilt dann auch für alle noch in Produktion befindlichen Releases.

Um von Beginn an der Update Hölle zu entrinnen, gilt allerdings eine Faustegel: Installiere beziehungsweise nutze nur das, was du wirklich benötigst. Je weniger Programme unter Windows installiert sind und je weniger Apps auf dem Smartphone vorhanden sind, umso weniger Sicherheitsrisiken entstehen. Das gilt auch für Programmbibliotheken. Weniger ist aus Sicht der Security mehr. Abgesehen davon bekommen wir durch den Verzicht unnötiger Programme noch eine Performance Verbesserung frei Haus.

Sicher ist für viele private Anwender die Frage der Systemaktualisierung kaum relevant. Lediglich neue unerwünschte Funktionen in vorhandenen Programme, Leistungsverschlechterungen oder hin und wieder zerschossene Betriebssysteme verursache mehr oder weniger starken Unmut. Im kommerziellen Umfeld können recht schnell erhebliche Kosten entstehen, die sich auch auf die gerade umzusetzenden Projekte negativ auswirken können. Unternehmen und Personen, die Software entwickeln können die Nutzerzufriedenheit erheblich verbessern, wenn sie bei Ihren Release Veröffentlichungen zwischen Security Patches und Feature Updates unterscheiden. Und ein Feature Update sollte dann entsprechend auch allen bekannten Security Aktualisierungen enthalten.