Finger weg von static in C#, Java & Co [Mit Beispiel] Clean Code Tipp #12



Im Clean Code Tipp der Woche beantworten wir dieses Mal die Frage: Ist static böse? : Clean Code beschreibt nicht nur die Struktur des Quellcodes in der Programmierung, sondern auch deren Struktur: hier kommt das Schlüsselwort static ins Spiel bzw macht dieses kaputt. Egal ob in C#, Java, Kotlin, Scala, TypeScript oder JavaScript – die nutzung von static bzw globalen Elementen verringert Eure Softwareuqalität und ist damit genua das Gegenteil von Clean Code. Wir schauen uns im Clean Code Tipp der Woche #12 an, warum genau das Schlüsselwort böse ist und wie Du es besser machen kannst.

▬ Über diesen Kanal ▬▬▬▬▬▬▬▬▬▬▬▬

Seit vielen Jahren arbeite ich als Consultant, Coach und Trainer für professionelle Softwareentwicklung mit den Schwerpunkten Softwarequalität, Softwarearchitektur sowie Prozessmanagement. Auf meinem Kanal möchte ich Euch mein Wissen und meine langjährige Erfahrung in diesen Bereichen vermitteln – natürlich kostenlos. Dabei versuche ich stets Euch das Wissen so zu vermitteln, dass Ihr damit direkt in der Praxis loslegen könnt und das ganze immer mit guten Portion Humor. Lernen soll ja schließlich Spaß machen 🙂

▬ Empfohlene Videos ▬▬▬▬▬▬▬▬▬▬▬▬

Wie viel Softwarequalität Ihr braucht – https://www.youtube.com/watch?v=yIzyz49A9q0&t=172s
Warum Software unwartbar wird – https://www.youtube.com/watch?v=y3Gsq4myMiY&t=177s
Architektur – Modularisierung – https://www.youtube.com/watch?v=9bBydhSBl3w&t=16s
Was ist Architektur – https://www.youtube.com/watch?v=CG6itx96wq8&t=597s
Warum Architektur – https://www.youtube.com/watch?v=nBbCV7B8aIQ&t=219s

▬ Wichtige Links ▬▬▬▬▬▬▬▬▬▬▬▬

Abonniere meinen Kanal: https://www.youtube.com/channel/UCQnJlfHdJ2OolZSa4h2H5Rg?sub_confirmation=1
Alle Videos: https://www.youtube.com/channel/UCQnJlfHdJ2OolZSa4h2H5Rg/videos

▬ Social Media ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
► Twitter: https://twitter.com/DavidTielke
► Xing: https://www.xing.com/profile/David_Tielke
► LinkedIn: https://www.linkedin.com/in/david-tielke-06140912b/

▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬

26 Comments

  1. Bin ich nicht mit einverstanden. Was ist mit statischen Methoden wie: User.getById(), User.findeOne(), Number.isFloat(), Number.isInt(), u.s.w. Ich denke du verstehst, welche Art von Methoden ich meine. Die müsste man dann alle in einer extra Funktionalität unterbringen, was meine Meinung nach den Code NICHT lesbarer macht. Gerade bei sowas wie Models bin ich eher weniger ein Fan von dem Repository weil sich gerade die getter und query methoden wunderbar generalisieren lassen und somit hervorragend in eine entsprechende Manager-Klasse passen.

    ps: Komme aus der JavaScript / TypeScript welt. Da ist ja im Grunde erst mal alles "static"

  2. (C++) Ich nutze statische Pointer, um zum einen den Heap nicht zu belasten und zum anderen den Zugriff auf die Klasse zu erleichtern. Das Objekt kann dadurch normal erstellt und gelöscht werden, einzig der Zugriff ist persistent, dies sorgt besonders in großen Projekten zu einer sehr großen Wiederverwendbarkeit, da ein anderes Team kein Objekt erstellen oder löschen muss, genauso muss dadurch keine Komplexe Einbindung stattfinden, es muss einzig der Header inkludiert werden. Die STL unteranderem nutzt eine ähnliche Implementierung an manchen Stellen.

  3. Auf Embedded Systemen mit kleinen Microcontroller (zB Cortex M) würde ich ohne statische Singletons jedes Mal den Flash Speicher sprengen.

    Allerdings lassen sich auch statische Singletons durch Dependency Injection und Statischen Interfaces prima entkoppeln, um eben die von dir genannten Attribute zu erreichen, wie Lesbarkeit, Testbarkeit, usw.

    Ich finde deine Videos Klasse und hab auch schon viel lernen/auffrischen können.

    Manchmal fehlt mir aber etwas der Bezug zum Zielsystem. Manche deiner Aussagen, sind eben manchmal nicht ganz so allgemein gültig. Nicht böse gemeint, aber evtl. könnte diese Information manchmal dem Lernenden Zuschauer weiter helfen.

    Oder hast du im Bezug auf Embedded Systemen eine andere Meinung?

    Gruß

  4. In meine in Java haben statische Klassen eine andere Bedeutung. Dort gibt es sie nur als innere Klassen und das static sorgt dafür, dass sie auch von außerhalb der Äußeren Klasse nutzbar sind. Oder nicht?

  5. ich brauchs in type script sehr selten wenn ich zb eine Unit klasse habe (mit unit ist eine Einheit in einem Spiel gemeint). und dann hab ich eine static methode auf der klasse generate welche mir ein neues Unit Objekt zurück gibt. damit ich halt nicht überall wo man eine unit generieren muss immer die 20 gleichen zeilen fürs generieren einer unit schreiben muss.
    aber bin mir nicht sicher ob in javascript die statische methode gleich ist wie das angesprochene beispiel in c# weil ich glaub in javascript ist es am ende einfach ein weiteres property auf dem objekt Unit

  6. Nachdem wir auf Quarkus setzen, verwenden wir DI und dann sind das einfach die Klassen mit der Annotation ApplicationScoped. Somit sind etwa 100% der Fälle weg, in denen man auf die Idee kommen könnte, das Schlüsselwort static zu verwenden. Das einzige was übrig bleibt sind Konstanten, die natürlich static sind.

  7. Ich nutze static für Hilfsklassen, die Statuslos sind und quasi alle Abhängigkeiten per Parameter erhalten. Hier finde ich static nach wie vor sinnvoll und nützlich.
    Ich bin allerdings auch ein Fan von Erweiterungsmethoden. 🙂
    Ein anderer Anwendungsfall wäre für rein statische Werte, quasi Konstanten die sich nicht ändern während der Laufzeit (HttpStatusCodes, CacheKeys usw.).

  8. Hallo David!

    Den Grundgedanken, das "static" böse ist, weil es Probleme beim Testen verursacht, teil ich.

    Ab und zu habe ich dennoch statische Methoden erstellt, pure Funktionen ohne Seiteneffekte, also optimal testbar. Keine statischen Klassen, mit Daten natürlich. Diese sollten für OOP Tests ebenfalls nicht relevant sein, weil ich sie nur Implementierungsdetails der zu testenden Methoden sind.
    Ich nutze sie meistens nur um in meinen Augen fehlende Funktionalitäten einer Sprache / einem Datentyp wegzumachen (da ich häufig von Sprache zu Sprache springe nerven mich teilweise fehlende Methoden in einigen Sprachen). Die Klassen sind dann so gestrickt, das sie jederzeit in jedes weitere Projekt kopiert und dort genutzt werden können, da sie keine Abhängigkeiten besitzen.
    Auch sonst kann man statische Methoden ganz gut nutzen um funktional zu programmieren. Damit lassen sich Stärken von OOP und FP kombinieren.

  9. Ich verwende in meinen Spiel eine Klasse Context mit dem Singleton Pattern Design. Darin sind wichtige Attribute wie Keyboard, Mouse, Höhe und Breite des Bildschirm und ganz viele andere Attribute. Sollte ich das Design nochmal überarbeiten?

  10. In der Methode Blubb bei Minute 1:23 besteht übrigens auch eine Kopplung an die nicht statische Klasse A, weil in der Methode new aufgerufen wird. Wenn man sich von A entkoppeln möchte ist ein Refactorin nötig, damit die benutzten A-Exemplare übergeben werden können. Den Aufruf der Methode Foo der statischen Klasse S kann man auch entkoppeln, indem man erlaubt eine Methodenreferenz zu übergeben.
    Falls verschiedene Methoden einer statischen Klasse aufgerufen werden, kann man sich beim Refactoring auch überlegen, diese in einem Interface zu definieren und in der Default-Implementierung weiterhin auf die statische Klasse zuzugreifen, während man in einem Test eine Testimplementierung übergibt.

  11. Hier ein Beispiel für Entkopplungs-Refactoring (falls es denn nötig sein sollte) bei Nutzung einer statischen Klasse (Java):

    class Foo {

    void bar() {
    System.out.println(Math.random());
    }

    }

    Refactoring (die Methoden der statischen Klasse können wohlgemerkt weiterhin verwendet werden, indem die Referenzen darauf an den Konstruktor übergeben werden):

    class Foo {

    private final java.util.function.DoubleConsumer doublePrinter;
    private final java.util.function.DoubleSupplier randomSupplier;

    public Foo(java.util.function.DoubleConsumer doublePrinter, java.util.function.DoubleSupplier randomSupplier) {
    this.doublePrinter = doublePrinter;
    this.randomSupplier = randomSupplier;
    }

    void bar() {
    doublePrinter.accept(randomSupplier.getAsDouble());
    }

    }

  12. Ich kenne jemanden der sehr gern auf private-static-Methoden setzt, wenn die Methode den Zustand nicht verändert.
    Performancetechnisch bringt das keinen messbaren Vorteil. Deswegen verwende ich es nie.
    Weil es aber in den Code-Richtlinien nicht geregelt ist und Programmierer gern kreativ sind, darf er das meiner Meinung auch gern machen. Toleranz ist hier gefragt.

  13. Du bist jetzt nur auf statische Klassen eingegangen aber was ist mit Methoden oder Feldern? Siehst du das da auch so negativ?
    Statische Felder verwende ich für Typen die ich als Konstante verwende wie z.B. ein fixes DateTime. Das lässt sich ja nicht per const deklarieren.
    Oder eben statische Eigenschaften wie z.B. DateTime.Now.
    Oder statische Methoden wie TimeSpan.FromSeconds().

    Also geht es dir in dem Video wirklich nur rein um statische Klassen oder wirklich um das Schlüsselwort static?

    Bei statischen Klassen gebe ich dir aber recht die vermeide ich auch. Wobei mich dein Argument mit dem Unit-Test irritiert hat.
    Mir fällt gerade kein gutes Beispiel für eine statische Klasse ein aber wenn ich so eine schreiben würde würde ich in dieser doch niemals Daten oder Zustände speichern. Entsprechend sollte es im Unit-Test egal sein wie oft und womit sie aufgerufen wird.

    Eine Frage die sich mir auch noch stellt wie verhalten sich nicht statische Klassen mit statischen Methoden im Speicher? Da die Klasse nicht statisch ist wird das Objekt dann nach jedem Aufruf wieder zerstört oder bleibt für alle zukünftigen statischen Aufrufe immer diese eine Instanz im Speicher wie bei einer reinen statischen Klasse?

  14. Moment… seit wann erzeugen static classes eine instanz? Dann würden sie ja einen this Pointer haben – aber is bestimm son c# ding ^^. Aber man sollte solche sachen aufjedenfall stateless halten, sonst gibt's irgendwann, irgendwo wirklich kopfzerbrechen was da eigentlich passiert 😀 – stichwort (JS-)Closure-Context, z.B. bei den würger.. äh wunderbaren React-Hooks ^^

  15. Da hab ich direkt mal ne Frage an dich (weil das in unserer Abteilung leider immer noch ein echtes Streitthema ist und zu dem Thema hier irgendwie passt):
    Ist für dich das Singleton-Pattern ein sogenanntes Anti-Pattern und folglich mit Vorsicht zu genießen, oder würdest du es woanders einordnen? LG

  16. Statisch und Zustand passt ja schonmal gar nicht zusammen. Das man sich in Unit Tests Zustand über statische Methoden o.ä. teilt… ich weiß jetzt nicht ob das so ein tolles Beispiel dafür ist. Die Standardantwort ist imho auch hier: Es kommt darauf an… Siehe Math.max – siehe Abschnitt Code Smells in "Clean Code". Aber im Video wurden darüber hinaus einige gute Punkte angesprochen, wo eben statics schlecht sind => alles wo man wirklich OO betreibt, also Polymorphie nutzt, da gehört sowas natürlich nicht hin.

  17. Wir haben einen einzigen Anwendungsfall für statische Klassen. Wir haben die Konvertierung unserer Entities in Datenmodelle in eine statische Klasse ausgelagert. Die statische Klasse ist auch nach außen hin nicht sichtbar und kann somit nur von der eigentlichen Mangerklasse verwerwendet werden.

  18. Statische Klassen (oder generell statische Dinge) versuchen wir grundsätzlich zu vermeiden.

    Ab und an werden mal Erweiterungsmethoden verwendet. Aber diese versuchen wir klein und ohne State zu halten. Sodass diese z.B. nur etwas umwandeln, umrechnen, … (was sich dann auch immer ganz gut testen lässt)

  19. Nutze ich statische Klassen: Ja eine Menge
    Welche negativen Konsequenzen hat das: Keine die ich bemerken würde.
    Ist das Testbar? Jup – nicht testbar ist veränderbarer Zustand in dieser statischen Klasse – einfach nicht machen und gut ist

    —-

    Im Endeffekt ist es ganz einfach: Wenn Du OO arbeiten möchtest (also inkl. Vererbung … nutzt das eigentlich noch jemand regelmäßig in eigenen Code nicht-lokal/inner?) dann ist statisch in der Tat nicht so geil.

    Wenn Du aber FP arbeiten möchtest dann macht es null Sinn überhaupt einzelne Instanzen von irgendwas zu erstellen – dann wirst Du mit statischen Klassen gerne arbeiten und viel Spaß damit haben.

    Die Diskussion ist also eher ob man mit C# funktional arbeiten darf / soll – das darf jeder gerne selber entscheiden – man kann es jedenfalls auch ohne die hier genannten Nachteil – jedenfalls meiner Meinung nach.

    Kleiner Hinweis zum Kontrakt: ja ein Kontrakt (Interface) auf die statische Klasse wird schwer – aber wenn Du eine Methode in dieser Klasse als ein Interface mit einer Funktion sieht ist es auf einmal wieder einfacher / möglich damit zu arbeiten.
    Zugegeben das ist in C# ziemlich lästig und Du hast recht: wenn Du die Funktionalität ersetzen können möchtest (ohne über irgendwelche Tricks mit statischen Klassen in verschiedenen Namespaces mit gleichen public members) dann ja Du brauchst was wo man Interfaces zurückgeben kann – in F# ist das kein Thema – geht auch aus nem Modul raus – in C# muss man halt ziemlich dämliche Fassaden-Klassen basteln … das macht keiner.

    Oder Du wartest bis Traits (statische Member in Interfaces) kommen 😉

    IMHO sind die Teile die Du mocken/ersetzen willst sowieso oft diejenigen wo FP / reine Funktionen etc. nicht wirklich nützlich sind – C# ist eine hybride Sprache – mach klassisches OO

    Ändert aber nichts daran, dass Sachen / Algorithmen / etc. die man rein funktional machen kann in statischen Klassen prima aufgehoben sind – Du testest dann sowieso nur die Funktionen einzeln (was sehr schön geht – FP-Funktionen lassen sich 1A per Unit-Tests testen) – da brauchst Du keine Mocks.

  20. Wie ich das so raus höre, scheint es ja grundsätzlich schlecht zu sein "static" einzusetzen. Die Argumente diesbezüglich kann ich auch verstehen. Wie stehst du dann zu ExtensionMethods die gern von Microsoft und anderen bereitgestellt werden und welche Alternativen siehst du da?

Leave a Reply

© 2023 53GB