Angepinnt Beispiele für guten und schlechten Code (Stil)

  • VB.NET

Es gibt 252 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Wer hat denn MS Richtlinien zum notwendigen Übel gemacht? MS, muss man auf MS hören, nur weil diese die Sprache gemacht haben? Nein, ansonsten wär C# immer noch in den Kinderschuhen. Nur weil MS einem etwas vorlegt ist es nicht gleich besser, aber ich halte mich ungern an Komplette Guidelines, da mir manches einfach nicht gefällt.
    Typen Bezeichnungen ist außerdem etwas anderes wie Variablen, da wird in dem zitierten Text anscheinend nicht unterschieden(und plötzlich von Variablen auf Typen gesprungen). Eine Sprache entwickelt sich durch ihre Verwendung, ich finde vorallem bei solchen Dingen sollte man eine größere Gruppe von programmierern damit spielen lassen und irwann entwickelt sich schon etwas wie ein Standard, denn man dann auch festlegen kann, aber nicht einfach plump vor die Nase setzen.

    Denn wenn wir uns an alles von MS halten würden hätten wir teilweise wohl Gurken Code(lasst @~blaze~: nur an die Implementierung des .Nets ran, der findet schon was)
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Ich persönlich halte mich da immer an die RT, so sieht der Code schön gleichmäßig aus. In C# UpperCamelCase und z.B. in C++ halt lower_case mit Unterstrichen. Theoretisch ist der verwendete Stil komplett egal, nur man sollte immer den Selben benutzen. Sofern man also das Framework benutzt, sollte man auch so programmieren. Andernfalls sieht's teilweise sehr unübersichtlich aus.
    Die beste Möglichkeit für das Vermeiden von schlechtem Stil ist imernoch

    VB.NET-Quellcode

    1. Option Strict On

    Am Besten in den Einstellungen auf "Standartmäßig aktivieren" stellen.
    Hallo,

    eigentlich ein interessantes und auch wichtiges Thema. Es ist nur immer wieder im Laufe der Diskussion über die letzten 13 Seiten ausgefranst. Ich habe in der Arbeit beim MS-Developer-Support tonnenweise fremden Code gesehen. Der war meistens schwierig zu lesen, manchmal wirklich eine Qual.
    Daraus ergeben sich für mich folgende wichtige Punkte für stabilen und lesbaren Code:

    1. Kommentare, das wurde hier auch schon erwähnt, ist aber untegegangen. Warum hat man etwas so und nicht anders gemacht? Klar, wenn man davor sitzt und sich das gerade ausgedacht hat, weiß man das natürlich. Aber nächstes Jahr auch noch, wenn aus dem alten Code bis zur CeBit eine neue Version gebastelt werden soll, die der Chef dort dann einem potentiellen Großkunden vorführen will? Wenn man da aus einem bestimmten Grund eine etwas andere Lösung gewählt hat, das aber nicht dazu schreibt, ist es ziemlich unwahrscheinlich, dass einem das Monate später nochmal einfällt. Ein anderer Kollege, der den Code irgendwann bearbeiten soll, kann den Hintergrund ja gar nicht kennen, wenn in den Kommentaren nichts drinsteht. Der ändert das also jetzt ab, was er seltsam findet und schon gehts an irgendeiner anderen Ecke nicht mehr. Aber warum...?

    2. Code als solcher muss lesbar sein. Oft habe ich bei Code von Kunden erstmal die fehlenden Einrückungen gemacht, um überhaupt sehen zu können, wo welche Strukturen anfangen oder enden.
    Zwei Operationen in einer Zeile sind auch schlecht zu debuggen:

    If Instr(String1, String2)=5 then DoSomeThingDifferentWith(String1)

    Noch schlimmer sind diese Konstrukte aus Abkürzungen, dutzenden Klammern, gern auch geschweifte dazwischen und natürlich alles in einer Zeile. Das hätte ich den Leuten immer gerne um die Ohren gehauen, aber durfte ich ja nicht, ich wurde ja dafür bezahlt, mir das anzugucken und irgendwann auch zu verstehen, warum es nicht das tut, was es soll.

    3. Sprechende Variablennamen:

    Statt

    if a <= 21 then
    cnba = True

    besser
    if Age <= 21 Then
    CanNotBuyAlcohol = True
    Jedem US-Amerikaner erzählt das eine Geschichte, die er auch kennt...
    Dazu vielleicht noch dies, um die Geschichte abzurunden:
    If Age >= 18 Then
    CanBeSoldier = True
    ...
    Guter Code sollte sich wie eine Geschichte lesen lassen.

    Ob man jetzt die ungarische oder sonst irgendeine Notation verwendet, ist erstmal zweitrangig. Wenn man für sich einen Standard gefunden hat, sollte man den aber auch einhalten.

    Lesbarer Code ist einfacher zu warten und gut gewarteter Code ist sicher auch stabiler, aber zur Stabilität kann man auch selbst natürlich viel beitragen.

    1. Die richtigen Variablentypen verwenden und sich vorher Gedanken machen, welche Typen das sein können. Will ich irgendwas berechnen, von dem ich nicht weiß, wie groß die Werte sein können, nehme ich Double. Weiß ich, dass meine Werte bestimmte Grenzen nicht überschreiten werden (z.B. die sicher noch immer endliche Geldmenge auf diesem Planeten) kann ich z.B. Decimal nehmen.
    Für VB-NET gibt es die Anweisung Option Strict On. Die erzwingt genaues Typcasting.

    2. Dateien öffnen und schließen, Resourcen allozieren und freigeben: Wenn ich eine Datei öffne oder Speicher alloziere, dann kommt danach die Anweisung zum Schließen der Datei oder zum Freigeben des Speichers. Esrt dann schreibe ich dazwischen rein, was mit dieser Resource zu passieren hat. Das Ganze nämlich zu Schließen oder Freizugeben wird leicht vergessen, wenn die Bearbeitung komplex ist und deren Programmierung einige Zeit erfordert. Dann muss man später irgendwo die entsprechenden Befehle einfügen und erwischt dabei vielleicht einen Codepfad, in dem sie unter Umständen niemals ausgeführt werden. Auch wenn man das selbst beim Testen nicht findet, die User da draußen in der Welt, die werden es schaffen, garantiert.
    Ein Beispiel für vermutlich schlampiges Allozieren von Ressourcen ist Ubisofts Anno1404: Da wussten sie sich nicht mehr anders zu helfen, als irgendwann während des Spiels eine Meldung auszugeben: "Ihr Speicher ist aufgebraucht!" Dann wird es Zeit, den Spielstand zu sichern (manchmal hängt es dabei schon) und alles neu zu starten.

    3. Konstanten verwenden so oft es geht. Beispiel: Ich habe eine Liste mit 10 Elementen. In der fuhwerke ich mit einer For .. Next Schleife herum, die will ich in eine Datei schreiben und in einer Listbox ausgeben. Immer muss ich dazu wissen, wie groß die Liste ist. Wer UBound nicht benutzen will, wird die 10 überall hartcodiert eintippen. Nur nächste Woche stellt sich heraus, dass die Liste besser 15 Elemente haben sollte. Jetzt muss man durch den Code gehen, überall, wo es passt, die 10 durch 15 ersetzen und hoffen, dass man keine Stelle vergessen hat. Oder es gibt in einer globalen Klasse oder einem globalen Modul einmal die Deklaration:
    Public Const LISTSIZE = 10
    Dann muss man das nur hier ändern und hat eher Feierabend ;) Kann aber auch sein, dass es dann gleich die nächste Aufgabe gibt...

    Gruß
    Carbonunit

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Carbonunit“ () aus folgendem Grund: Vertipperli

    Nochwas zum stabilen Code:
    Wenn ich eine Funktion aufrufe, die mir per Rückgabewert mitteilt, ob alles gut gegangen ist, dann sollte sich mein Code auch für diesen Rückgabewert interessieren. Oft genug lassen eilige Coder den unter den Tisch fallen und etwas später kracht es dann wegen irgendwas. Dabei hätte man vielleicht an diesem Rückgabewert sehen können, dass da was im Busch ist, weil ich vielleicht auf Grund eines Fehlers gar nicht die erwarteten Daten von der Funktion bekommen habe.
    Also nicht so:

    VB.NET-Quellcode

    1. Dim intDummy As Integer
    2. dim strImportantData As String
    3. intDummy = MyWonderfullFunctionGettingImportantData(strImportantData) ' Rückgabewert muss halt rein, weil der Compiler sonst meckert...
    4. MessageBox.Show(strImpotrtantData)


    sondern so:

    VB.NET-Quellcode

    1. Dim intError As Integer
    2. dim strImportantData As String
    3. intError = MyWonderfullFunctionGettingImportantData(strImportantData)
    4. if intError = 0 Then
    5. MessageBox.Show(strImpotrtantData)
    6. Else
    7. MessageBox.Show("Irgendwas ist schief gegangen, wir haben heute keine wichtigen Daten, Sorry!")
    8. End If


    Vermutlich sagt in diesem Beispiel die Fehlernummer sogar etwas darüber, was da schief gegangen ist, also muss der User nicht dumm vor dem Bildschirm sterben, sondern kann vielleicht etwas tun, um die Lage zu retten. Im ersten Fall sieht er im Fehlerfall irgendwelchen Mumpitz und kann sich keinen Reim darauf machen, wenn das Ganze nicht sowieso abstürzt.

    Stilvolle Grüße
    Carbonunit

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Carbonunit“ ()

    Aber waurm warten, bis mir das System eine Exception um die Ohren haut, wenn ich am Rückgabewert schon sehen könnte, dass da was in die Hose gegangen ist?
    Es löst ja auch nicht alles, was schief geht, gleich eine Exception aus.
    Inwiefern "warten"? Eine Exception ist der schnellere Weg, sowas zu lösen und genau dafür da. ^^ Dann kannst Du Deinen Wert nämlich anständig zurückgeben, wie man es von der Funktion erwartet und eine Exception kann man auch wunderbar abfangen. Dann muss man sich auch nicht mit irgendwelchen Errorcodes rumschlagen.
    Das ist C-Style (sieht man daher auch häufig bei WinAPI). Der einzige Anwendungsfall sind die Try-Methoden, bei denen man sich das zu Nutze macht, um zu determinieren, ob es geklappt hat oder nicht, ohne dass eine Exception fliegt, weil diese dann redundant ist. Integer.TryParse wäre da zu nennen.
    Aber bei mehreren Ausnahmemöglichkeiten machen Exceptions mehr Sinn.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Da sieht man mal wieder, dass es eben nicht genau einen guten Stil gibt. Wahrscheinlich ist das Thema auch genau deshalb so ausgefranst.
    Trotzdem nochmal: Wenn ich eine Funktion habe, die mir per Rückgabewert mitteilt, ob alles geklappt hat, warum ist es dann besser, den Rückgabewert zu ignorieren und sich auf eine Exception zu verlassen, die schon irgendwann geworfen wird, wenn was auf die Nase gefallen ist? Die Exception kommt in diesem Fall ja vielleicht später, weil in strImportantData nicht das Erwartete drinsteht. Und das steht deshalb nicht drin, weil meine Funktion irgendwas nicht gefunden hat und deshalb den Defaultwert eingetragen hat oder den Wert unverändert zurückgegeben hat. Also davon, das alles mit Exceptions zu regeln, bin ich nicht überzeugt, tut mir leid.
    Ich glaub, Du hast den Einsatz von Exceptions etwas missverstanden. Du sollst ja auch nicht warten, bis dann das Programm crasht, weil irgendwelche Werte falsch oder unpassend sind. Du sollst genau in dem Fall in Deiner Funktion eine Exception werfen.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    @Carbonunit:

    Statt

    VB.NET-Quellcode

    1. Private Function Test() As Integer
    2. Dim Result = ReadOutTheFollowingFile("Test.txt")
    3. Select Case Result
    4. Case 0: MessageBox.Show("Alles ok")
    5. Case 1: MessageBox.Show("Datei wurde nicht gefunden")
    6. Case 2: MessageBox.Show("Datei ist korrupt")
    7. End Select
    8. Return Result
    9. End Sub
    10. Private Function ReadOutTheFollowingFile(FileName As String) As Integer
    11. If Not FileExists(FileName) Then Return 1
    12. If FileIsCorrupt(FileName) Then Return 2
    13. Return 0
    14. End Function

    macht man heutzutage ungefähr sowas:

    VB.NET-Quellcode

    1. Private Sub Test()
    2. Try
    3. ReadOutTheFollowingFile("Test.txt")
    4. Catch FNFE As FileNotFoundException
    5. MessageBox.Show("Datei wurde gefunden")
    6. Catch FCE As FileIsCorruptException
    7. MessageBox.Show("Datei ist korrupt/nicht lesbar")
    8. End Try
    9. End Sub
    10. Private Sub ReadOutTheFollowingFile(FileName As String) 'ist keine Function mehr
    11. If Not FileExists(FileName) Then Throw New FileNotFoundException 'eigentlich auch redundant, da diese Exception bei einem Zugriff auf eine nicht existente Datei eh fliegt
    12. If FileIsCorrupt(FileName) Then Throw New FileIsCorruptException 'ein Beispiel, dass man auch eigene Exceptions einbauen kann
    13. End Sub

    Hat auch den Vorteil, dass man nicht den Rückgabe-Errorcode immer stufenweise weitergeben muss (ReadOutTheFollowingFile -> Test -> Prozedur, die "Test" auruft, sondern diejenige Prozedur fängt die Exception ab, die damit was anfangen kann bzw. wo man die Ex sinnvoll abarbeiten kann. Und wenn sich keiner drum kümmert, kümmert sich der Compiler mit nem Absturz drum.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    Gut, das kann man natürlich so machen. Das Beispiel mit dem Rückgabewert muss ja auch nicht jeder toll finden. ist mir nur eben oft aufgefallen, dass die Leute den gerne unter den Tisch fallen lassen. In dem Fall kommt vielleicht auch irgendwann eine Exception, die hat nur niemand vorher eingeplant, so wie ihr mit euren Beispielen hier und dann raucht was ab, dabei hätte man es vorhersehen können bei Nutzung des Rückabewerts.
    Ich habe auch hier oder in der VB-Doku gelesen, dass Exceptionhandling nicht empfohlen wird, wenn der Fehler im Code vorhersehbar ist (wie eben Datei nicht gefunden oder sowas) Der Grund war die Performance, die so ein Exceptionhandling kostet, die Quelle weiß ich nur gerade nicht.
    Rückgabewerte sind eine nützliche Sache, und braucht man oft - aber nicht zur Fehlerbehandlung - auch im weitesten Sinne nicht.

    Es ist kein Deut aufwändiger, eine (die passende) Exception zu werfen, als einen iwie gearteten FehlerCode zu returnen.

    Es ist aber sicherer, denn eine geworfene Exception kann nicht ignoriert werden - ein returnter FehlerCode allerdings schon.