Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Tutorials und Kurse (https://www.delphipraxis.net/36-tutorials-und-kurse/)
-   -   Guter Code ist lesbarer Code (https://www.delphipraxis.net/89903-guter-code-ist-lesbarer-code.html)

Luckie 8. Apr 2007 00:08


Guter Code ist lesbarer Code
 
Liste der Anhänge anzeigen (Anzahl: 1)
Dies ist kein Tutorial in dem Sinne, als dass ich konkret auf ein Problem oder ein Thema eingehe. Viel mehr geht es um etwas grundsätzliches was das Thema Code-Design betrifft: Die Lesbarkeit von Quellcode.

Ich programmiere schon länger und habe schon so manche Zeile an Code geschrieben und gelesen. Aber im Laufe seiner Laufbahn als Programmierer wird man immer wieder über ein Problem stolpern, welches einen dazu veranlasst wieder etwas dazu zu lernen, auch wenn es nur etwas Banales ist wie Enumerationen.

Ich hatte folgendes Problem: Es gab eine Variable oder Routine, die nur zwei Zustände annehmen können sollte, die Ausrichtung einer Seitenzahl auf einer Seite, entweder mittig auf der Seite zentriert oder am äusseren Rand der Seite. Man kann hiermit ganzen Zahlen arbeiten: 0 für mittig zentriert und 1 für am äusseren Rand. Das ist ist aber nicht ganz befriedigen, den nach einiger Zeit weiß man nicht mehr, welche Zahl für was steht. Und ein Aussenstehender weiß es schon gar nicht. Diese Lösung wäre so gut wie unlesbar, kaum wartbar und sehr fehleranfällig, denn was passiert, wenn jemand zwei oder drei oder minus vier übergibt? Wir haben also zwei Probleme: 1. Lesbarkeit des Codes und 2. Anfälligkeit für Fehler.

Betrachten wir Punkt eins und nehmen uns mal eine Windows Funktion vor: CreateEvent:

Code:
HANDLE WINAPI CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
  BOOL bManualReset,
  BOOL bInitialState,
  LPCTSTR lpName
);
Problematisch sind hier die zwei Boolean-Parameter. Es wird nicht deutlich, was ein Setzen auf Wahr oder Falsch bewirkt. Wird der erste auf Wahr gesetzt, habe ich dann ein manuelles Zurücksetzen oder nicht? Und was ist der Unterschied zwischen einem wahren und einem falschen Initialisierungstatus? Da hilft es nur in der Hilfe nachzugucken. Eine kleine Hilfe ist schon die Code-Vervollständigung der IDE, aber die hat man auch nicht immer zur Hand (in einem Forum, einer E-Mail, wenn man den Code in einem einfachen Editor betrachtet, als Ausdruck oder mit einem Overheadprojektor). Und oft Mals schreibt man den Code nicht selber, sondern liest ihn nur. Besser wären in diesem Fall Aufzählungstypen mit zum Beispiel den Werten: MANUEL_RESET und AUTO_RESET, dann wäre beim Lesen alles klar. Beim zweiten Boolean-Parameter könnte man sinngemäß verfahren.

Kommen wir zurück zu meinem konkreten Problem. Es hat etwas gedauert, aber ich bin dann doch auf eine gute Lösung gekommen. Ich habe mich nachher etwas geärgert, dass ich so lange dafür gebraucht habe, obwohl ich sie die ganze Zeit vor der Nase hatte: Die Lösung ist eine Aufzählung. Eine Aufzählung wie sie zum Beispiel von der VCL benutzt wird, um einen Absatz in einem TMemo auszurichten: taCenter, taLeftJustify, taRightJustify. Mit der Aufzählung hat man einen eigenen Datentypen mit einem vorgegebenen Bereich und benannten Konstanten, wenn man so will. Eine Lösung in Delphi sähe also so aus:

Delphi-Quellcode:
type
  TPageNumberAlignment = (paCenter, paLeft, paRight);

procedure SetPageNumberAlignment(Alignment: TPageNumberAlignment);
begin
  case Alignment of
    paCenter: ShowMessage('zentriert');
    paLeft: ShowMessage('links');
    paRight: ShowMessage('rechts');
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetPageNumberAlignment(paCenter);
end;
Damit haben wir mit einem Schlag unser beiden Probleme gelöst: Der Code ist lesbar und er ist nicht mehr fehleranfällig, da jetzt nur genau drei Werte eines bestimmten Datentyps übergeben werden können.

Man sieht also dass ein lesbarer Code in den meisten Fällen auch guten Code erzeugt. Deswegen der Grundsatz: "Design for readability". Oder in etwa auf deutsch: "Entwerfen für die Lesbarkeit". Wenn man sich an diesen Grundsatz orientiert beim Programmieren, ergibt sich ein zweiter Grundsatz von alleine: "So wenig Kommentare wie möglich, so viele wie nötig." Man sollte also nur das kommentieren, was nicht aus dem Code ersichtlich ist. Das Inkrementieren einer Variablen zu kommentieren ist überflüssig, wenn man den Code liest, sieht man ja, was passiert. Während hingegen das warum eventuell Sinn ergeben könnte.

Bleibt noch die Frage zu klären, wie man denn lesbaren, guten Code schreibt. Ich denke, das kann man nicht richtig lernen. da hilf wohl wirklich nur Erfahrung, die man sich über Jahre aneignet und das Lesen und Studieren von fremden Code. Obwohl, manchmal muss man gar nicht in die ferne schweifen. Oftmals reicht es schon aus, wenn man sich alten Code von sich selber nach ein, zwei Jahren wieder mal anguckt. Versteht man ihn ohne lange darüber nachzudenken, wie er funktioniert, was er macht und warum man das damals so und nicht anders gelöst hat, war es guter Code. Andernfalls könnte er etwas Überarbeitung gebrauchen. Eventuell hilft ja auch der Ratschlag von Donald Edwin Knuth:
Zitat:

Let us change our traditional attitude to the construction of programs. Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.
Oder um es mit den Worten des Pascal Erfinders, Niklaus Wirth, zu sagen:
Zitat:

Programs should be written and polished until they acquire publication quality.
Link zum Artikel auf meiner Homepage: Guter Code ist lesbarer Code
Und im Anhang das ganze noch mal zum Ausdrucken als PDF.

Ghostwalker 8. Apr 2007 06:53

Re: Guter Code ist lesbarer Code
 
Da kann ich nur voll und ganz zustimmen. :)

Vielleicht noch eine kleine Anmerkung zum Thema Kommentare. Aus meiner Erfahrung heraus kann ein zuviel an Kommentaren die Lesbarkeit eines Codes zerstören. Insbesondere wenn es sich, wie Luckie schon geschrieben hat, es sich um eher unwichtige Kommentare handelt.

hanselmansel 8. Apr 2007 08:15

Re: Guter Code ist lesbarer Code
 
Hi Luckie,

das soll jetzt keine Kritik an deinem Aufsatz werden, sondern eher eine weiterführende Frage. :) Ich finde es sehr gut, wenn du guten und lesbaren Code schreiben möchtest, unter anderem auch deshalb, damit fremde Programmierer deinen Code verstehen, wenn sie ihn lesen müssen. Die Lösung mit einem Aufzählungstyp finde ich auch sehr gelungen, da die Konstanten selbstredende Namen haben.

Wie würdest du es lösen, die anderen Konstanten dieses Aufzählungstyps dem fremden Programmierer mitzuteilen?
Ich meine, wenn du den Befehl SetPageNumberAlignment(paCenter); schreibst, kann sich jeder normal denkende Programmierer erschließen, dass es diese Einstellung auch für links und rechts gibt. Was würdest du allerdings tun, wenn es eine Funktion mit Parametern ist, die sich nicht auf Anhieb erschließen lassen?

Man kann ja eigentlich nicht davon ausgehen, dass dem fremden Programmierer deine Typdeklaration immer als Source vorliegt...

liebe Grüße,

hanselmansel

MathiasSimmack 8. Apr 2007 08:55

Re: Guter Code ist lesbarer Code
 
Meiner Meinung nach stellt sich die Frage nicht. Wenn der Quellcode nicht vorliegt, jemand aber Funktionen nutzen will, dann liegt in irgendeiner Form eine Art Dokumentation vor. Und wenn sich der Programmierer an einen Ansatz hält, so wie Luckie ihn vorstellt, dann begreift man auch anhand der Funktionsnamen und Parameterangaben welchen Sinn das hat.

Luckie 8. Apr 2007 09:35

Re: Guter Code ist lesbarer Code
 
Das zum einem und wenn man eine moderne IDE mit CodeInSight benutzt kann man ganz gut raten. In der VCL haben alle Enumerationstypen als Prefix die ersten beiden Buchstaben der Eigenschaft, siehe TMemo.TextAlignment -> ta... Man könnte es bei mir jetzt mit pa... probieren.

Billi Berserker 8. Apr 2007 10:11

Re: Guter Code ist lesbarer Code
 
Aufzählungstypen zu benutzen kann in den meisten fällen sehr hilfreich sein.
Nur habe ich dazu auch auch eine weiterführende Frage,
Wie speichert man diese am besten?

Nehmen wir das Beispiel von oben, ich habe eine variable vom Typ TPageNumberAlignment = (paCenter, paLeft, paRight);
Den Wert möchte ich nun in eine xml Datei speichern und auch wieder laden.
Gibt es eine möglichkeit den Aufzählungstyp automatisch in einen Integer Wert (basierende auf dem Index in der List?) umzuwandeln?
So das praktisch paCenter in 0, paLeft in 1 und paRight in 2 umgewandelt wird und ich das ganze auch rückwärts machen kann.
Oder gibt es sogar eine möglichkeit das ganze in einen String mit dem Namen umzuwandeln? so das man den TPageNumberAlignment Wert in 'paCenter', 'paLeft', 'paRight' umwandelt und das ganze gut lesbar in der xml Datei speichern kann.
Das ginge natürlich wenn man sich selbst eine case anweisung schreibt... aber bei vielen und großen Aufzählungstypen wird das irgendwann ziemlich ätzend :)
Gibt es irgendwie eine effektive möglichkeit die case anweisung zu umgehen?

St.Pauli 8. Apr 2007 10:18

Re: Guter Code ist lesbarer Code
 
Ich denke, dass bei deinem WinAPI-Beispiel mehr der Benutzer als Microsoft gefragt ist. Das Problem liegt hier weniger bei der Funktionsdeklaration, als bei der Parameterübergabe im Programm. Der Programmier muss den Funktionsaufruf so schreiben, dass er auch in 10 Jahren noch ungefähr weiß, was er damit bezwecken wollte. Mit einem simplen

Code:
hGlobalWriteEvent = CreateEvent(NULL, TRUE, TRUE, "WriteEvent");
würde er dies mit Sicherheit nicht. Am einfachsten wäre es, für jeden Parameter eine Variable zu verwenden.

Code:
LPSECURITY_ATTRIBUTES SecurityAttributes = NULL;
BOOL ResetManual = TRUE;
BOOL SignaledInitState = TRUE;
LPCTSTR EventObjectName = "WriteEvent";

hGlobalWriteEvent = CreateEvent(SecurityAttributes, ResetManual, SignaledInitState, EventObjectName);
Noch etwas umfangreicher, aber wahrscheinlich auch noch besser wäre, eine eigene Schnittstelle für die WinAPI zu schreiben, wo man die Funktionen direkt in Klassen packen könnte. Man verwendet in seinem Programm dann nur noch die gut leserlichen Schnittstellenfunktionen.

Hawkeye219 8. Apr 2007 10:23

Re: Guter Code ist lesbarer Code
 
Hallo,

Zitat:

Zitat von Billi Berserker
Gibt es irgendwie eine effektive möglichkeit die case anweisung zu umgehen?

das geht unter Verwendung der Unit TypInfo:

Delphi-Quellcode:
// uses TypInfo

type
  TPageNumberAlignment = (paCenter, paLeft, paRight);

procedure TDemoForm.Button1Click (Sender: TObject);
var
  pna : TPageNumberAlignment;
  s  : string;
begin

  pna := paLeft;
  s := GetEnumName(TypeInfo(TPageNumberAlignment), Ord(pna));
  ShowMessage (s);

  s := 'paRight';
  pna := TPageNumberAlignment(GetEnumValue(TypeInfo(TPageNumberAlignment), s));
  ShowMessage (IntToStr(Ord(pna)));

end;
Gruß Hawkeye

thkerkmann 8. Apr 2007 10:24

Re: Guter Code ist lesbarer Code
 
Hi,

sicher gibt es solche Möglichkeiten.

Zunächst mal kann man mit ord(paCenter) den Ordinalwert des Aufzählungstypen bekommen, und mit einem Typecast wieder in den entsprechenden Aufzählungstypen zurückwandeln.

Mit Hilfe der Delphi Runtime Type Information kann man auch die Namen bekommen - allerdings weiss ich jetzt nicht genau wie das geht. Stichwort RTTI und siehe auch ObjectInspector.

Aber Achtung:
XML ist nicht gedacht als menschenlesbare Schreibeweise. Es ist nicht wirklich erforderlich hier aufschlussreiche Textformen zu verwenden. Das geht glaub ich ein bisschenn zu weit. XML dient dem Datenaustausch zwischen Programmen, und kann daher ruhig mit den ordinalen Werten arbeiten.

Gruss

Reinhard Kern 8. Apr 2007 15:38

Re: Guter Code ist lesbarer Code
 
Zitat:

Zitat von Luckie
...
Kommen wir zurück zu meinem konkreten Problem. Es hat etwas gedauert, aber ich bin dann doch auf eine gute Lösung gekommen. Ich habe mich nachher etwas geärgert, dass ich so lange dafür gebraucht habe, obwohl ich sie die ganze Zeit vor der Nase hatte: Die Lösung ist eine Aufzählung. .

Hallo Luckie,

etwa 25 - 40 Jahre, das ist durchaus rekordverdächtig. Das stand schon in meinem Compilerhandbuch von 1981, aber ich vermute stark, dass Aufzählungstypen schon im Jensen-Wirth von 1970 definiert waren - den müsste ich aber erst wieder finden. Die ersten Pascalprogramme hatte ich auf der UCSD-Pascal-Engine geschrieben, so etwa 1978.

Willkommen in der neuen Welt von Pascal.

Gruss Reinhard

Hansa 9. Apr 2007 02:44

Re: Guter Code ist lesbarer Code
 
Zitat:

Zitat von Reinhard Kern
Zitat:

Zitat von Luckie
...Die Lösung ist eine Aufzählung. .

etwa 25 - 40 Jahre, das ist durchaus rekordverdächtig...aber ich vermute stark, dass Aufzählungstypen schon im Jensen-Wirth von 1970 definiert waren...Willkommen in der neuen Welt von Pascal..

In der Tat sind sie seit 1970 verfügbar. Verwunderlich ist lediglich, dass diese Frage tatsächlich im Jahr 2007 auftaucht. :shock: Luckie, es kann doch wohl nicht Dein Ernst sein, bei 3 statisch feststehenden Möglichkeiten zu überlegen mit Aufzählungstypen jetzt erst anzufangen ? *entsetzt* :shock:

Nebenantwort 1 : Vorsicht, die ist gefährlich für Anfänger ! Aber wer mehr Kommentare braucht, als Source-Zeilen vorhanden sind, der macht was verkehrt.

Nebenantwort 2 : Falls nötig kann die Größe der Kommentare die des Source-Codes bei weitem überschreiten. Und das sind dann die Programmstellen, die echt diffizil werden können, besonders auch nach Jahren. An denen sollte man sich schon Zeit lassen und richtig kommentieren.

Nebenantwort 3 : die Auswahl der richtigen Typen war schon immer das richtige Mittel. Siehe Wirth.

marabu 9. Apr 2007 07:31

Re: Guter Code ist lesbarer Code
 
Guten Morgen,

wenn ich Luckies Beitrag richtig verstehe, dann behauptet er ja gar nicht er habe den Aufzählungstyp kürzlich erfunden. Vielmehr möchte er ihn als Entwurfsmittel etwas in den Fokus rücken, weil er wohl von vielen Mitgliedern auch dann erfolgreich verdrängt wird, wenn sein Einsatz naheliegend wäre.

Frohe Ostern

Reinhard Kern 9. Apr 2007 13:08

Re: Guter Code ist lesbarer Code
 
Zitat:

Zitat von marabu
Guten Morgen,

wenn ich Luckies Beitrag richtig verstehe, dann behauptet er ja gar nicht er habe den Aufzählungstyp kürzlich erfunden. Vielmehr möchte er ihn als Entwurfsmittel etwas in den Fokus rücken, weil er wohl von vielen Mitgliedern auch dann erfolgreich verdrängt wird, wenn sein Einsatz naheliegend wäre.

Frohe Ostern

Hallo,

es geht ja auch keineswegs um Luckie bashing, im Gegenteil. Es ist auffallend, dass die Konstrukte der ursprünglichen Sprache Pascal so wenig verwendet werden, ja dass sie von einigen Teilnehmern sogar angefeindet werden wegen nicht OO und unmodern. Dabei hätte es Delphi nie gegeben, wenn Pascal nicht eine so hervorragende Sprache wäre. Jeder Delphi-Anhänger sollte wenigstens mal das Urpascal nach Jensen und Wirth beherrschen - das Win32-API ist sowieso immer das Gleiche und die VCL ist auch nur eine Bibliothek wie andere auch, dafür müsste man nicht Delphi lernen.

Gruss Reinhard

marabu 9. Apr 2007 13:33

Re: Guter Code ist lesbarer Code
 
Hallo Reinhard,

mein Beitrag bezog sich auf einen Satz aus Beitrag #11, den ich zu zitieren vergaß:

Zitat:

Zitat von Hansa
Luckie, es kann doch wohl nicht Dein Ernst sein, bei 3 statisch feststehenden Möglichkeiten zu überlegen mit Aufzählungstypen jetzt erst anzufangen ? *entsetzt*

Aber wer weiß - vielleicht war das nur eine weitere Kostprobe von Hansas Humor, welcher mir auch nach zwei Jahren DP noch nicht so richtig eingängig ist.

Der zweckmäßige Einsatz von Sprachmitteln ist sicherlich das Ergebnis von Erfahrung. Wenn also heute oder morgen wieder unversöhnliche Standpunkte (z.B. zum Thema Record vs. Object) verfochten werden, so wirst du vielleicht feststellen, dass da Mitglieder um den Weg zum Licht ringen. Manche Erfahrungen müssen "am eigenen Leib" gemacht werden, damit sie nachhaltig sind.

Freundliche Grüße

Christian Seehase 9. Apr 2007 13:39

Re: Guter Code ist lesbarer Code
 
Moin Hanselmansel,

Zitat:

Zitat von hanselmansel
Wie würdest du es lösen, die anderen Konstanten dieses Aufzählungstyps dem fremden Programmierer mitzuteilen?
Ich meine, wenn du den Befehl SetPageNumberAlignment(paCenter); schreibst, kann sich jeder normal denkende Programmierer erschließen, dass es diese Einstellung auch für links und rechts gibt. Was würdest du allerdings tun, wenn es eine Funktion mit Parametern ist, die sich nicht auf Anhieb erschließen lassen?

also ich würde da D2006 (ff) empfehlen. ;-)
Wenn Du dort eine Case-Anweisung mit einem Aufzählungstypen deklarierst, initialisiert Dir die Code-Vervollständigung die Anweisung mit den möglichen Werten.

Luckie 9. Apr 2007 16:19

Re: Guter Code ist lesbarer Code
 
Zitat:

Zitat von marabu
Guten Morgen,

wenn ich Luckies Beitrag richtig verstehe, dann behauptet er ja gar nicht er habe den Aufzählungstyp kürzlich erfunden. Vielmehr möchte er ihn als Entwurfsmittel etwas in den Fokus rücken, weil er wohl von vielen Mitgliedern auch dann erfolgreich verdrängt wird, wenn sein Einsatz naheliegend wäre.

Genau so war es.

Und speichrn, denke ich mir, könnte man es einfach als Integer, aber das werde ich am Dienstag selber ausprobieren können. ;)

Luckie 9. Apr 2007 20:36

Re: Guter Code ist lesbarer Code
 
So, heute Nachmittag hatte ich nicht viel Zeit, deswegen neoch mal etwas ausführlicher:

@Hansa: Ist ja schön, das Delphi/Pascal dieses Sprachfeature schon sein 40 Jahren beherrscht und dies im Handbuch seit 40 Jahren steht. Das heißt aber noch lange nicht, dass auch jeder Programmierer alle Sprachfeatures auch kennt. Und das ist bestimmt nicht das letzte Sprachfeature, was ich nicht kenne. Was ich zum Ausdruck bringen wollte, war, dass man nie auslernt, dass man sich auch als "alter Hase" nicht schämen braucht, wenn man wieder was gelernt hat und ich wollte es etwas in den Focus rücken, da es mir so vorkam, als wenn es ein Sprachfeature ist, was nicht umbedingt so geläufig ist. Der zweite Teil des Artikels, hat sich dann ganz von alleine aus dem ersten Teil ergeben, so dass sich beide Teile schön ergänzen, wie ich finde.

Inzwischen hat ein Leser aus dem Delphi-Forum, Heiko, einen schönen, ergänzenden Kommentar noch zu dem Artikel abgegeben:
http://www.michael-puff.de/Developer..._GuterCode.php

Hansa 9. Apr 2007 20:50

Re: Guter Code ist lesbarer Code
 
Zitat:

Zitat von Luckie
...dass man sich auch als "alter Hase" nicht schämen braucht, wenn man wieder was gelernt hat und ich wollte es etwas in den Focus rücken, da es mir so vorkam, als wenn es ein Sprachfeature ist, was nicht umbedingt so geläufig ist...

Du bist eben als Hase nicht alt genug. :mrgreen: Schaden tut so ein Artikel natürlich nichts.

mkinzler 9. Apr 2007 21:01

Re: Guter Code ist lesbarer Code
 
Zitat:

Du bist eben als Hase nicht alt genug. Mr. Green
Alter schützt vor Torheit nicht

Ghostwalker 9. Apr 2007 21:19

Re: Guter Code ist lesbarer Code
 
Und weil es so schön ist, noch eine Anmerkung von mir :)

Man kann solche Aufzählungen auch wunderbar in ein Set packen.


Beispiel:

Delphi-Quellcode:
    TFontstyletype = (fsBold,fsItalic,fsUnderline);

    TFontstyle = set of TFontstyletype;

Damit kann man sehr sprechend und bequem mehrere Elemente einer Aufzählung zulassen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:54 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz