Code-Review in C#: Was man prüfen sollte und wie man praktisch Feedback gibt
\n\nCode-Review ist nicht nur eine formale Prozedur vor dem Mergen eines Pull-Requests. Es ist ein mächtiges Werkzeug zur Verbesserung der Codequalität, zur Wissensverbreitung im Team und zur Vermeidung von Fehlern. Besonders relevant ist dies für C# und das .NET-Ökosystem, wo es viele Nuancen gibt: von der Speicherverwaltung und Asynchronität bis hin zur strengen Typisierung und LINQ.
\n\nIn diesem Artikel analysieren wir, worauf Sie bei der Überprüfung von C#-Code konkret achten sollten und wie Sie Feedback geben, sodass man Ihnen zuhört und Sie nicht hasst.
\n\n1. Architektur und Logik: "Warum machen wir das?"
\n\nBevor Sie auf Formatierung und Variablennamen achten, stellen Sie sicher, dass die zu lösende Aufgabe überhaupt sinnvoll ist. Dies ist der wichtigste, aber oft übersprungene Schritt.
\n\n- \n
- Übereinstimmung mit den Anforderungen: Löst der Code genau die Geschäftsaufgabe, die im Ticket beschrieben ist? Gibt es unnötige Funktionalität (YAGNI)? \n
- Verletzung der SOLID-Prinzipien: Ist die Klasse zu einem "göttlichen Objekt" geworden? Gibt es eine klare Trennung der Verantwortlichkeiten? Zum Beispiel: Wird Geschäftslogik mit Datenzugriffslogik vermischt? \n
- Übermäßige Komplexität: Kann die Aufgabe einfacher gelöst werden? Manchmal schreiben Entwickler komplexe Muster, wo ein einfaches
if-elseoder eine einfache Schleife ausreichen würde. \n
// ❌ Schlecht: Die Klasse macht zu viel\npublic class UserService\n{\n public void RegisterUser(string email, string password)\n {\n // Validierung\n if (!email.Contains("@"))\n throw new Exception("Ungültige E-Mail");\n\n // Passwort-Hashing\n var hash = BCrypt.HashPassword(password);\n\n // Speichern in der DB\n using var db = new AppDbContext();\n db.Users.Add(new User { Email = email, PasswordHash = hash });\n db.SaveChanges();\n\n // E-Mail senden\n SmtpClient.Send("welcome@site.com", email, "Willkommen!");\n }\n}\n\n// ✅ Gut: Aufteilung in Schichten (SRP)\npublic class UserRegistrationService\n{\n private readonly IUserRepository _repository;\n private readonly IEmailService _emailService;\n\n public UserRegistrationService(IUserRepository repository, IEmailService emailService)\n {\n _repository = repository;\n _emailService = emailService;\n }\n\n public async Task<Result> RegisterAsync(string email, string password)\n {\n if (!EmailValidator.IsValid(email))\n return Result.Failure("Ungültige E-Mail");\n\n var user = User.Create(email, password);\n await _repository.AddAsync(user);\n await _emailService.SendWelcomeAsync(email);\n\n return Result.Success();\n }\n}\n\n2. Leistung und Sicherheit: "Wird das den Server töten?"
\n\n.NET ist ein leistungsstarkes Framework, aber es kann leicht falsch verwendet werden. Hier ist, was Sie in jedem Review prüfen sollten.
\n\n- \n
- Asynchronität (async/await): Gibt es blockierende Aufrufe (
.Result,.Wait()) in asynchronem Code? Das tötet die Leistung. Verwenden SieConfigureAwait(false)in Bibliotheken. \n - Speicherlecks: Wurde vergessen,
IDisposable-Ressourcen freizugeben? WirdusingfürStream,SqlConnectionusw. verwendet? \n - SQL-Injection: Werden Abfragen durch String-Verkettung erstellt? In modernem C# mit Entity Framework oder Dapper ist das selten, aber die Überprüfung ist obligatorisch. \n
- LINQ und Sammlungen: Gibt es mehrere Durchläufe durch dieselbe Sammlung? Wird
Any()anstelle vonCount() > 0verwendet, um das Vorhandensein von Elementen zu prüfen? \n
// ❌ Schlecht: Blockierender Aufruf und mehrfacher Durchlauf\nvar task = GetDataAsync();\nvar data = task.Result; // Thread-Blockierung!\n\nif (data.Count() > 0) // Erster Durch