Eine Entity ist ein zentrales Konzept im Bereich der Softwareentwicklung, insbesondere im Domain-Driven Design (DDD). Es beschreibt ein Objekt oder einen Datensatz, der eine eindeutige Identität besitzt und im Laufe der Zeit seinen Zustand ändern kann. Die Identität einer Entity bleibt dabei immer bestehen, unabhängig davon, wie sich die Eigenschaften der Entity verändern.
Eindeutige Identität: Jede Entity hat eine eindeutige Kennung (z.B. eine ID), die sie von anderen Entities unterscheidet. Diese Identität ist das primäre Unterscheidungsmerkmal und bleibt über den gesamten Lebenszyklus der Entity gleich.
Veränderlicher Zustand: Im Gegensatz zu einem Value Object kann sich der Zustand einer Entity ändern. Zum Beispiel können sich die Eigenschaften eines Kunden (Name, Adresse) ändern, aber der Kunde bleibt durch seine Identität immer derselbe.
Geschäftslogik: Entities enthalten oft Geschäftslogik, die mit ihrem Verhalten und Zustand in der Domäne zusammenhängt.
Stellen wir uns eine Kunden-Entity in einem E-Commerce-System vor. Diese Entity könnte folgende Eigenschaften haben:
Wenn sich die Adresse oder der Name des Kunden ändert, bleibt die Entity durch ihre ID immer derselbe Kunde. Das ist der wesentliche Unterschied zu einem Value Object, das keine dauerhafte Identität hat.
Entities werden oft in Datenbanken durch Tabellen abgebildet, wobei die eindeutige Identität in Form eines Primärschlüssels gespeichert wird. In einem Objektmodell einer Programmiersprache wird die Entity durch eine Klasse oder ein Objekt dargestellt, das die Logik und den Zustand dieser Entität verwaltet.
Conventional Commits sind ein einfacher Standard für Commit-Nachrichten in Git, der ein konsistentes Format für alle Commits vorschlägt. Dies erleichtert die Automatisierung von Aufgaben wie der Versionskontrolle (Versioning), der Changelog-Erstellung und der Rückverfolgung von Änderungen.
Das Format der Conventional Commits besteht aus einer speziellen Struktur der Commit-Nachricht, die typischerweise folgendermaßen aussieht:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Type (Pflichtfeld): Beschreibt die Art der Änderung im Commit. Es gibt standardisierte Typen:
Scope (optional): Beschreibt den betroffenen Teil des Codes oder der Anwendung, z. B. ein Modul oder eine Komponente.
fix(auth): corrected password hashing algorithm
Description (Pflichtfeld): Eine kurze, prägnante Beschreibung der Änderung. Diese sollte in der Gegenwartsform formuliert sein (z. B. „add feature“ statt „added feature“).
Body (optional): Eine ausführlichere Beschreibung der Änderung. Dies kann genutzt werden, um mehr Kontext oder technische Details anzugeben.
Footer (optional): Hier können Hinweise zu Breaking Changes oder Referenzen zu Issues oder Tickets stehen.
BREAKING CHANGE: remove deprecated authentication method
feat(parser): add ability to parse arrays
The parser now supports parsing arrays into lists.
This allows arrays to be passed as arguments to methods.
BREAKING CHANGE: Arrays are now parsed differently
Conventional Commits sind besonders in Projekten hilfreich, die SemVer (Semantic Versioning) verwenden, da sie es ermöglichen, automatisch neue Versionen basierend auf Commit-Typen zu erstellen.
"Toter Code" (engl. "dead code") bezeichnet Abschnitte in einem Computerprogramm, die zwar existieren, aber niemals ausgeführt oder verwendet werden. Das kann passieren, wenn der Code durch Änderungen oder Umstrukturierungen im Programm überflüssig wird, aber nicht entfernt wird. Obwohl er keine direkte Funktion hat, kann er den Code unnötig komplex machen, Wartung erschweren und in manchen Fällen die Performance leicht beeinträchtigen.
Typische Ursachen für toten Code sind:
Entwickler entfernen toten Code häufig, um die Effizienz und Lesbarkeit des Programms zu verbessern.
Eine Null Pointer Exception (NPE) ist ein Laufzeitfehler, der auftritt, wenn ein Programm versucht, auf eine Referenz zuzugreifen, die keinen gültigen Wert enthält, d.h., die auf "null" gesetzt ist. In Programmiersprachen wie Java, C#, oder C++ signalisiert "null", dass die Referenz auf kein tatsächliches Objekt zeigt.
Hier sind typische Szenarien, in denen eine Null Pointer Exception auftreten kann:
1. Aufruf einer Methode auf einem null-Referenzobjekt:
String s = null;
s.length(); // Dies führt zu einer Null Pointer Exception
2. Zugriff auf ein null-Objektfeld:
Person p = null;
p.name = "John"; // NPE, da p auf null gesetzt ist
3. Zugriff auf ein Array-Element, das null ist:
String[] arr = new String[5];
arr[0].length(); // arr[0] ist null, daher NPE
4. Manuelle Zuweisung des Werts null zu einem Objekt:
Object obj = null;
obj.toString(); // NPE, da obj null ist
Um eine Null Pointer Exception zu vermeiden, sollten Entwickler sicherstellen, dass eine Referenz nicht null ist, bevor sie darauf zugreifen. In modernen Programmiersprachen gibt es auch Mechanismen wie Optionals (z. B. in Java) oder Nullable-Typen (z. B. in C#), um mit solchen Szenarien sicherer umzugehen.
Syntaktischer Zucker bezieht sich auf Sprachmerkmale, die den Code einfacher und lesbarer machen, ohne die zugrunde liegende Funktionalität oder das Verhalten der Sprache zu verändern. Es bietet Entwicklern intuitivere Möglichkeiten, Operationen auszudrücken, die normalerweise durch komplexere oder längere Konstrukte erreicht werden könnten.
Mit anderen Worten, syntaktischer Zucker „versüßt“ den Code für den Programmierer, sodass dieser einfacher zu schreiben und zu verstehen ist, während die Maschine die gleichen Operationen wie vorher ausführt.
[x for x in list]
) syntaktischer Zucker für das Erstellen von Listen mittels Schleifen.()=>
) eine abgekürzte Schreibweise für Funktionsausdrücke (function() {}
).Syntaktischer Zucker hilft also dabei, den Code übersichtlicher und schneller zu schreiben, verändert aber nicht, wie der Code letztlich ausgeführt wird.
Redundanz in der Softwareentwicklung bezieht sich auf die bewusste Wiederholung oder Duplizierung von Komponenten, Daten oder Funktionen innerhalb eines Systems, um die Zuverlässigkeit, Verfügbarkeit und Fehlertoleranz zu erhöhen. Redundanz kann auf verschiedene Arten implementiert werden und dient oft dazu, den Ausfall eines Teils eines Systems zu kompensieren und so die Gesamtfunktionalität des Systems zu gewährleisten.
Code-Redundanz:
Daten-Redundanz:
System-Redundanz:
Netzwerk-Redundanz:
In einem Cloud-Service könnte ein Unternehmen mehrere Server-Cluster an verschiedenen geografischen Standorten betreiben. Diese Redundanz sorgt dafür, dass der Dienst auch dann verfügbar bleibt, wenn ein ganzer Cluster aufgrund eines Stromausfalls oder eines Netzwerkausfalls offline geht.
Redundanz ist eine Schlüsselkomponente in der Softwareentwicklung und -architektur, insbesondere in sicherheitskritischen oder hochverfügbaren Systemen. Es geht darum, ein Gleichgewicht zwischen Zuverlässigkeit und Effizienz zu finden, indem man die richtigen Redundanzmaßnahmen implementiert, um das Risiko von Ausfällen zu minimieren.
Ein Single Point of Failure (SPOF) ist eine einzelne Komponente oder ein Punkt in einem System, dessen Ausfall das gesamte System oder einen wesentlichen Teil davon unbrauchbar macht. Wenn ein SPOF in einem System vorhanden ist, bedeutet dies, dass die Zuverlässigkeit und Verfügbarkeit des gesamten Systems stark von der Funktion dieser einen Komponente abhängt. Fällt diese Komponente aus, kommt es zu einem vollständigen oder teilweisen Ausfall des Systems.
Hardware:
Software:
Menschliche Ressourcen:
Energieversorgung:
SPOFs sind gefährlich, weil sie die Zuverlässigkeit und Verfügbarkeit eines Systems stark beeinträchtigen können. Unternehmen, die von der kontinuierlichen Verfügbarkeit ihrer Systeme abhängig sind, müssen SPOFs identifizieren und Maßnahmen ergreifen, um diese zu eliminieren oder zu mitigieren.
Failover-Systeme:
Clustering:
Regelmäßige Backups und Notfallpläne:
Durch die Minimierung oder Beseitigung von SPOFs kann die Zuverlässigkeit und Verfügbarkeit eines Systems erheblich verbessert werden, was besonders in kritischen Umgebungen von großer Bedeutung ist.
In der Softwareentwicklung bezeichnet eine Pipeline eine automatisierte Abfolge von Schritten, die ausgeführt werden, um Code von der Entwicklungsphase bis zur Bereitstellung in einer Produktionsumgebung zu bringen. Diese Pipelines sind ein zentraler Bestandteil von Continuous Integration (CI) und Continuous Deployment (CD), zwei Praktiken, die darauf abzielen, Software schneller, zuverlässiger und konsistenter zu entwickeln und bereitzustellen.
Quellcode-Verwaltung (Source Control):
Build-Prozess:
Automatisierte Tests:
Bereitstellung (Deployment):
Monitoring und Feedback:
Diese Pipelines sind somit entscheidend für die moderne Softwareentwicklung, insbesondere in Umgebungen, die auf agile Methoden und DevOps-Praktiken setzen.
Magic Numbers sind Zahlen, die im Code ohne ausreichende Erklärung oder Kontext verwendet werden. Sie sind oft direkt in den Code geschrieben, ohne dass sie durch eine benannte Konstante oder Variable ersetzt werden, was es schwierig macht, ihre Bedeutung oder ihren Zweck zu verstehen. Die Verwendung von Magic Numbers kann die Lesbarkeit und Wartbarkeit des Codes erheblich beeinträchtigen.
Hier sind einige der Hauptmerkmale und Probleme von Magic Numbers:
Unklarheit: Die Bedeutung einer Magic Number ist oft nicht sofort ersichtlich. Ohne eine erklärende Konstante oder Variable weiß man nicht, warum diese Zahl gewählt wurde oder was sie repräsentiert.
Schwierige Wartung: Wenn dieselbe Magic Number an mehreren Stellen im Code verwendet wird, müssen alle Vorkommen aktualisiert werden, wenn sich der Wert ändert. Das kann fehleranfällig sein und führt leicht zu Inkonsistenzen.
Verletzung der DRY-Prinzipien (Don't Repeat Yourself): Das wiederholte Verwenden der gleichen Zahlen an verschiedenen Stellen im Code verstößt gegen das DRY-Prinzip, das empfiehlt, wiederverwendbaren Code zentral zu definieren.
Beispiel für Magic Numbers:
int calculateArea(int width, int height) {
return width * height * 3; // 3 ist eine Magic Number
}
Besseres Vorgehen: Statt die Zahl direkt im Code zu verwenden, sollte sie durch eine benannte Konstante ersetzt werden:
const int FACTOR = 3;
int calculateArea(int width, int height) {
return width * height * FACTOR;
}
In diesem verbesserten Beispiel ist FACTOR
eine benannte Konstante, die die Bedeutung der Zahl 3
klarer macht. Dies verbessert die Lesbarkeit des Codes und erleichtert die Wartung, da der Wert nur an einer Stelle geändert werden muss, falls erforderlich.
Zusammenfassung: Magic Numbers sind direkte numerische Werte im Code, die durch benannte Konstanten ersetzt werden sollten, um die Klarheit, Wartbarkeit und Verständlichkeit des Codes zu verbessern.
Spaghetti-Code bezeichnet einen Programmierstil, der durch eine unstrukturierte und chaotische Codebasis gekennzeichnet ist. Dieser Begriff wird verwendet, um Code zu beschreiben, der schwer lesbar, schwer verständlich und schwer wartbar ist, weil er keine klare Struktur oder Organisation aufweist. Hier sind einige Merkmale von Spaghetti-Code:
Mangelnde Modularität: Der Code besteht aus langen, zusammenhängenden Blöcken ohne klare Unterteilung in kleinere, wiederverwendbare Module oder Funktionen. Dies erschwert das Verständnis und die Wiederverwendbarkeit.
Verwirrende Kontrollflüsse: Komplexe und ineinander verschachtelte Kontrollstrukturen (wie verschachtelte Schleifen und bedingte Anweisungen) machen es schwierig, den Fluss der Programmausführung nachzuvollziehen.
Schlechte Namenskonventionen: Unklare oder nicht aussagekräftige Namen für Variablen, Funktionen oder Klassen, die keinen klaren Hinweis auf ihre Funktionalität oder ihren Zweck geben.
Fehlende Trennung von Verantwortlichkeiten: Funktionen oder Methoden, die mehrere Aufgaben gleichzeitig übernehmen, anstatt eine einzelne, klar definierte Aufgabe zu erfüllen.
Hohe Abhängigkeiten: Starke Kopplungen zwischen verschiedenen Teilen des Codes, die es schwierig machen, Änderungen vorzunehmen, ohne unbeabsichtigte Auswirkungen auf andere Teile des Programms zu haben.
Fehlende oder unzureichende Dokumentation: Mangelnde Kommentare und Erklärungen, die das Verständnis des Codes für andere Entwickler erschweren.
Ursachen für Spaghetti-Code können unzureichende Planung, Zeitdruck, mangelnde Erfahrung oder ungenügende Kenntnisse in Software-Design-Prinzipien sein.
Vermeidung und Verbesserung:
Durch diese Maßnahmen kann der Code lesbarer, wartbarer und weniger fehleranfällig gemacht werden.