📚
Lerndokumentationen
Prozesse
Prozesse
  • Willkommen
  • Agile Entwicklung
    • Was ist agile Enwicklung?
    • Agiles Manifest
    • Agile Prinzipien
    • Agile Werte
  • Scrum
    • Was ist Scrum?
    • Prinzipien
    • Werte
    • Rollen
    • Sprint
    • Meetings
    • Artefakte
    • Vision
    • Epics und User Stories
    • Priorisierung
    • Schätzung
    • Sprintplanung
    • Kanban
    • Release Planning
  • Extreme Programming
    • Was ist Extreme Programming?
    • Pair Programming
    • Test Driven Development
  • Clean Code
    • Was ist Clean Code?
    • Code Smells und Refactoring
      • Naming
      • Lange Parameterlisten
      • Magic Numbers
      • Verschachtelte Verzweigungen
      • Switch Statements
Bereitgestellt von GitBook
Auf dieser Seite
  • Prinzipien
  • SOLID
  1. Clean Code

Was ist Clean Code?

Clean Code bezeichnet eine Art der Softwareentwicklung, die sich durch gut lesbaren, wartbaren und verständlichen Code auszeichnet. Ziel ist es, Code zu schreiben, der nicht nur für Maschinen, sondern vor allem für Menschen leicht zu verstehen ist. Dies wird durch verschiedene Prinzipien, Methoden und Praktiken erreicht.

Prinzipien

Don't Repeat Yourself

Das DRY-Prinzip zielt darauf ab, die Wiederholung von Logik innerhalb eines Codes zu vermeiden. Es fördert die Wiederverwendbarkeit und Wartbarkeit, indem es sicherstellt, dass jede Wissenseinheit in einem System eine einzige, eindeutige und autoritative Darstellung hat.

Beispiel

public class Smartphone
{
    ..

    public decimal ApplyDiscount(decimal discountPercentage)
    {
        return Price - (Price * discountPercentage / 100);
    }
}

public class Laptop
{
    ..

    public decimal ApplyDiscount(decimal discountPercentage)
    {
        return Price - (Price * discountPercentage / 100);
    }
}

public static class DiscountCalculator
{
    public static decimal CalculateDiscount(decimal price, decimal discountPercentage)
    {
        return price - (price * discountPercentage / 100);
    }
}

public class Smartphone
{
    ..

    public decimal ApplyDiscount(decimal discountPercentage)
    {
        return DiscountCalculator.CalculateDiscount(Price, discountPercentage);
    }
}

public class Laptop
{
    ..

    public decimal ApplyDiscount(decimal discountPercentage)
    {
        return DiscountCalculator.CalculateDiscount(Price, discountPercentage);
    }
}

Keep It Simple, Stupid

Das KISS-Prinzip steht für "Keep It Simple, Stupid" und betont, dass Systeme einfach gehalten werden sollten, um die Wartbarkeit und Verständlichkeit zu verbessern. Indem man unnötige Komplexität vermeidet, können Fehler leichter identifiziert und behoben werden.

Beispiel

Im folgenden Beispiel zeigt eine einfache Methode, wie das KISS-Prinzip angewendet werden kann.

public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

In diesem Fall wird eine einfache Addition implementiert, ohne überflüssige Logik oder unnötige Features hinzuzufügen.

You Ain't Gonna Need It

YAGNI steht für "You Aren't Gonna Need It" und ist ein Prinzip der Softwareentwicklung. Es besagt, dass Entwickler nur die Funktionen implementieren sollten, die aktuell benötigt werden, und nicht die, von denen sie glauben, dass sie in der Zukunft nützlich sein könnten. Das Ziel ist es, die Projektkomplexität zu verringern und unnötige Arbeiten zu vermeiden.

Beispiel

Angenommen, ein Entwickler arbeitet an einer kleinen Anwendung und überlegt, ein Logging-System zu implementieren, weil es in Zukunft vielleicht nützlich sein könnte. Nach dem YAGNI-Prinzip sollte er das vermeiden und nur implementieren, was gerade gebraucht wird:

public class Greeter
{
    public void Greet()
    {
        Console.WriteLine("Hello, User!");
    }
}

In diesem Beispiel wurde das benötigte Feature erstellt, ohne zusätzlichen ungenutzten Code hinzuzufügen.

Tell, Don't Ask

Das TDA-Prinzip, oder Prinzip der "Tell, Don't Ask"-Methode, ermutigt dazu, Objekte ihre Zustände selbst verwalten zu lassen, anstatt von aussen nach ihren Zuständen zu fragen und darauf basierend Aktionen durchzuführen. Dies fördert die Kapselung und reduziert die Abhängigkeiten zwischen Objekten.

Beispiel

public class BankAccount
{
    private decimal balance;

    public void Deposit(decimal amount)
    {
        if (amount > 0)
        {
            balance += amount;
        }
    }

    public void Withdraw(decimal amount)
    {
        if (amount > 0 && amount <= balance)
        {
            balance -= amount;
        }
    }
}

BankAccount account = new BankAccount();
account.Deposit(100);
account.Withdraw(50);

In diesem Beispiel wird der Kontostand (balance) nicht von aussen abgefragt, sondern durch Methoden verändert, die die erlaubten Operationen direkt kapseln.

Law Of Demeter

Die Law of Demeter (auch bekannt als das Prinzip des geringsten Wissens) ist ein Entwurfsmuster, das darauf abzielt, die Kopplung zwischen Modulen in einem Softwaredesign zu minimieren. Es besagt, dass ein Objekt nur mit unmittelbaren "Freunden" kommunizieren sollte und nicht mit Fremden. Im Wesentlichen sollte jede Methode nur auf folgende Informationen zugreifen:

  • Ihre eigenen Felder und Methoden.

  • Felder und Methoden von Objekten, die als direkte Parameter ĂĽbergeben werden.

  • Felder und Methoden von Objekten, die sie selbst erstellt.

Beispiel

public class Engine
{
    public void Start()
    {
        Console.WriteLine("Engine started");
    }
}

public class Car
{
    private Engine engine = new Engine();

    public void Start()
    {
        engine.Start();
    }
}

Car myCar = new Car();
myCar.Start();

In dem obigen Beispiel vermeidet die Car-Klasse unnötige Exposition ihres Engine-Objekts und interagiert nur mit ihm durch die eigene Methode StartCar, was das Prinzip der Law of Demeter demonstriert.

Separation Of Concern

Separation of Concern

Separation of Concern (SoC) ist ein Prinzip in der Softwareentwicklung, das besagt, dass ein Softwareprogramm in verschiedene, voneinander unabhängige Teile oder Module aufgeteilt werden sollte, von denen jedes eine spezifische Funktion innerhalb der Gesamtstruktur erfüllt. Dies erleichtert die Wartung, die Anpassung und das Testen von Software, da jedes Modul isoliert behandelt werden kann.

Beispiel

In diesem Beispiel wird das SoC-Prinzip angewendet, indem die Logik fĂĽr Datenzugriff und Business-Logik getrennt wird:

public class ProductRepository
{
    public List<Product> GetAllProducts()
    {
        ..
    }
}

public class ProductService
{
    private readonly ProductRepository _repository;

    public ProductService(ProductRepository repository)
    {
        _repository = repository;
    }

    public void DisplayAllProducts()
    {
        var products = _repository.GetAllProducts();
        ..
    }
}

Hier übernimmt ProductRepository die Aufgabe, sich nur mit dem Datenzugriff zu beschäftigen, während ProductService die Business-Logik enthält.

SOLID

Single Responsibility

Das Single Responsibility Prinzip besagt, dass eine Klasse nur einen Grund für eine Änderung haben sollte, d.h. sie sollte nur für einen Teil der Softwarefunktionalität verantwortlich sein.

public class User
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class UserManager
{
    public void CreateUser(string name, string email)
    {
        User user = new User { Name = name, Email = email };
        Console.WriteLine($"User {name} created.");
    }
}

public class EmailService
{
    public void SendEmail(string email, string message)
    {
        Console.WriteLine($"Email sent to {email}: {message}");
    }
}

UserManager userManager = new UserManager();
EmailService emailService = new EmailService();

userManager.CreateUser("Levin", "levin@example.com");
emailService.SendEmail("levin@example.com", "Welcome to our system!");

Open-Closed

Das Open-Closed-Prinzip besagt, dass Software-Module offen für Erweiterungen, aber geschlossen für Veränderungen sein sollten. Dies bedeutet, dass das Verhalten eines Moduls durch das Hinzufügen von neuem Code erweitert werden kann, ohne den bestehenden Code zu ändern.

Beispiel

public abstract class Shape
{
    public abstract double GetArea();
}

public class Circle : Shape
{
    private double _radius;
    
    public Circle(double radius)
    {
        _radius = radius;
    }

    public override double GetArea()
    {
        return Math.PI * _radius * _radius;
    }
}

public class Rectangle : Shape
{
    private double _width;
    private double _height;

    public Rectangle(double width, double height)
    {
        _width = width;
        _height = height;
    }

    public override double GetArea()
    {
        return _width * _height;
    }
}

Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 6);
Console.WriteLine("Circle Area: " + circle.GetArea());
Console.WriteLine("Rectangle Area: " + rectangle.GetArea());

In diesem Beispiel kann die Klasse Shape durch neue Formen erweitert werden, ohne den bestehenden Code zu ändern, indem einfach neue Unterklassen hinzugefügt werden. Dies zeigt, wie das Open-Closed-Prinzip angewendet werden kann.

Liskov Substition

Das Liskov Substitution Principle (LSP) besagt, dass Objekte einer abgeleiteten Klasse überall dort verwendet werden können, wo Objekte der Basisklasse erwartet werden, ohne das Verhalten des Programms zu ändern.

Mit anderen Worten: Eine Unterklasse darf die Funktionalität der Basisklasse nicht brechen oder unerwartetes Verhalten einführen.

Beispiel

public abstract class Shape
{
    public abstract int GetArea();
}

public class Rectangle : Shape
{
    public int Width { get; set; }
    public int Height { get; set; }

    public override int GetArea() => Width * Height;
}

public class Square : Shape
{
    public int SideLength { get; set; }

    public override int GetArea() => SideLength * SideLength;
}

Shape rect = new Rectangle { Width = 5, Height = 10 };
Shape square = new Square { SideLength = 5 };

Console.WriteLine($"Rechteck-Fläche: {rect.GetArea()}");
Console.WriteLine($"Quadrat-Fläche: {square.GetArea()}");
Interface Segregation

Das Interface Segregation Principle (ISP) besagt, dass ein Client niemals gezwungen sein sollte, Methoden zu implementieren, die er nicht benötigt.

Mit anderen Worten:

  • Grosse, allgemeine Interfaces sollten in kleinere, spezifische Interfaces aufgeteilt werden.

  • Dadurch mĂĽssen Klassen nur die Methoden implementieren, die fĂĽr sie relevant sind.

Beispiel

public interface IWorkable
{
    void Work();
}

public interface IEatable
{
    void Eat();
}

public class HumanWorker : IWorkable, IEatable
{
    public void Work() => Console.WriteLine("Mensch arbeitet.");
    public void Eat() => Console.WriteLine("Mensch isst.");
}

public class RobotWorker : IWorkable
{
    public void Work() => Console.WriteLine("Roboter arbeitet.");
}


IWorkable robot = new RobotWorker();
robot.Work();

IEatable human = new HumanWorker();
human.Eat();
Dependency Inversion

Das Dependency Inversion Principle (DIP) besagt:

  1. Höhere Module sollten nicht von niedrigeren Modulen abhängen. Beide sollten von Abstraktionen (Interfaces oder abstrakten Klassen) abhängen.

  1. Abstraktionen sollten nicht von konkreten Implementierungen abhängen. Konkrete Klassen sollten von Abstraktionen abhängen.

Ziel: Vermeidung direkter Abhängigkeiten zwischen Modulen, um Flexibilität und Testbarkeit zu erhöhen.

Beispiel

public interface ILogger
{
    void Log(string message);
}

public class FileLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine($"Logging to file: {message}");
    }
}

public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine($"Logging to console: {message}");
    }
}

public class UserService
{
    private readonly ILogger _logger;

    public UserService(ILogger logger)
    {
        _logger = logger;
    }

    public void RegisterUser(string username)
    {
        Console.WriteLine($"User {username} registered.");
        _logger.Log("User registered.");
    }
}

ILogger logger = new ConsoleLogger();
UserService service = new UserService(logger);
service.RegisterUser("Levin");

VorherigeTest Driven DevelopmentNächsteCode Smells und Refactoring

Zuletzt aktualisiert vor 1 Monat