Login
Newsletter
Mi, 11. Juni 2003, 16:26

The Good vs. The Bad

Wie versetzt man sich als Programmierer in die Lage, zu entscheiden, ob der eigene Programmentwurf gut oder eher schlechter ist?

Ganz einfach ist es nicht, dies in einen kurzen Tipp zu verpacken, aber folgende zwei Beobachtungen werden helfen, dieses Thema auf eine feste Grundlage zu stellen.

Stellen wir uns daher vor, eine Funktion zu haben, die etwas in eine Textdatei schreibt.

bool GibEtwasAus (const char* p_filename)
{ // <b>Precondition</b>:
 // <i>p_filename</i> verweist auf gültigen Namen!
 int fd;
 fd = open (p_filename, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
 if (fd == -1) return false;

 /* ... hier findet die Ausgabe statt ... */

 return close (fd) != -1;
}

Nun möchte wir sie erweitern um die Fähigkeit, nicht nur in eine Datei, sondern auch auf die Standardausgabe (normalerweise Shellfenster) zu schreiben. Daher die simple Entscheidung, den Parameter p_filename zu überladen, d.h. der eigentlich ungültige Wert NULL soll nunmehr auf die Standardausgabe verweisen.

Aus dieser Entscheidung könnte die folgende erweiterte Implementierung der Funktion resultieren:

bool GibEtwasAus (const char* p_filename)
{ // <b>Precondition</b>:
 // <i>p_filename</i> verweist auf gültigen Namen
 // <b>oder</b> p_filename ist NULL und meint damit Standardausgabe!!
 int fd;

 if (p_filename)
 {
  fd = open(p_filename, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
  if (fd == -1) return false;
 }
 else
 {
  fd = 1 /* Standardausgabe */;
 }

 /* ... hier findet die Ausgabe statt ... */

 return (p_filename? close (fd) != -1 : true);
}

An dieser erweiterten Implementierung können wir beobachten, daß sich unser Code an zwei Stellen aufgebläht hat. Nämlich beim Öffnen der Datei und beim Schließen muß nun die vormals gemachte Designentscheidung nachvollzogen werden. Daher folgender Schluss: Eine trennende Designentscheidung, in diesem Fall p_filename gültig oder gleich NULL, die weitere Trennungen erfordert, führt zu Komplexität (The Bad).

Das möchten wir als Programmierer nicht so einfach auf uns sitzen lassen und überlegen also etwas Neues. Um beim Beispiel zu bleiben, wollen wir eine neue trennende Entscheidung vollziehen. Diese ist mit dem Posix-API glücklicherweise schon für uns vollzogen worden. Nämlich die Trennung der Implementierung einer Datei (Dateiobjekt) im Linuxkernel und der sie nur referenzierende Dateideskriptor (File Descriptor). Diese schon existente Trennung und das Wissen um die Funktion dup erlaubt uns nun folgende Implementierung.

bool GibEtwasAus (const char* p_filename)
{ // <b>Precondition</b>:
 // <i>p_filename</i> verweist auf gültigen Namen
 // <b>oder</b> p_filename ist NULL und verweist auf Standardausgabe !!
 int fd;

 if (p_filename)
  fd = open (p_filename, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
 else
  fd = dup (1 /*Standardausgabe*/);
  if (fd == -1) return false;

 /* ... hier findet die Ausgabe statt ... */

 return close (fd) != -1;
}

Wie wir beobachten können, hat sich die Funktion vereinfacht an der Stelle der Funktion close. Den ersten Entscheidungspunkt beim open haben wir damit zwar noch, aber trotzdem kann aus der zweiten Beobachtung folgende Schlussfolgerung gezogen werden: Eine trennende Designentscheidung, in diesem Fall Dateideskriptor versus Dateiobjekt, die zu einer Vereinfachung, d.h. Vereinheitlichung führt, ist weise (The Good).

Nun schliesse ich mit den Worten: Sei die Macht der weisen Entscheidungen mit euch.

Kommentare (Insgesamt: 51 || Alle anzeigen )
Pro-Linux
Pro-Linux @Facebook
Neue Nachrichten