Archiv für den ‘Software-Design’ Kategorie

101 Regeln Software-Designs OOP, Objektkomposition als Basis für ein Log Beispiel mit C#

0

Ich hab in meinem letzten  Beitrag über Basis Regeln beim Software-Design berichtet. In diesem Beispiel versuche ich zu zeigen wie man mit einer Objektkomposition eine elegante Lösung baut. Das ganze kommt aus der Praxis und ist eine Debug/Log Lösung. Ich hab das ganze sehr vereinfacht um euch die Idee und den Grund Gedanken zu zeigen. Wie man so was lösen könnte.

Ausgangslage:

Die Softwarelösung war zu diesem Zeitpunkt sehr instabil. Ich wurde eingestellt die Softwarelösung zu Supporten und zu verbessern. Ein Hauptproblem war die Performance bei den wichtigen Prozessen vom Unternehmen (Bussiness Logik). Die Entwickler hatten begonnen überall im Code Prints Anweisungen einzubauen weil die Softwarelösung in der Prod Umgebung sich auch anders verhalten hatte. Es wurde sogar so extrem das die lieben Leute durch das ständige rein und raus kopieren von diesen Debug Prints auch ungewollt Fehler machten. Das ganze war eine Intranet Weblösung und die wurde aktiv 24h verwendet. Zudem Stand das ganze in einer Hight Secure Zone vom Unternehmen, man hatte keinen direkten Zugang zu dieser Zone.

Im Team Meeting hatte ich den Vorschlag gemacht eine Debug Lösung einzubauen. Wo man Ein- und Ausschalten kann über das Webinterface. Das ganze ist unabhängig und erweiterbar zudem wird das ganze nur in den kritischen Bereichen ergänzt.

Was brauchen wir?

  • Ein Interface in unserem Fall heisst es IDebug wo uns die Grund-Struktur für unsere Methode liefert.
  • Eine Klasse wo die Arbeit übernimmt und die Debug Informationen abarbeitet. Zudem ist der Aufbau dieser Klasse vom Interface IDebug abhängig.
  • Eine Methode in einer Bussiness Logik Klasse, in unserem Beispiel heisst die Klasse CurrencyBroker,
    wo uns zeigt wie wir unsere Debug Lösung einbauen können. Das Interface liefert uns wider die Grundstrucktur.

Ich fange mit dem Interface an IDebug. Wo ganz einfach aufgebaut ist mit der Methode Debug. Wo als Argument einen string erwartet.

/**
 * Interface Debug System
 * */
using System;

namespace ch.starwolf.SoftwareDesign {

 public interface IDebug {

 void Debug(string arg);

 }
}

Jetzt werden wir unsere Arbeiter Klasse definieren mit dem Klassennamen DebugLogger und der Implementation vom Interface IDebug. Ich habe weiter oben erwähnt das dass ganze erweiterbar ist. Wir sind genau an dieser Position jetzt,  in unserm Beispiel wird unsere Klasse nur einen Output in die Konsole schreiben. Aber hier könnten wir weitere Klassen definieren wo zum Beispiel die Debug Informationen in eine Datenbank oder in ein XML schreibt. Wir könnten auch Klassen zusätzlich definieren wo uns ein Email zustellt oder ein RSS Feed abfüllt. Die Möglichkeiten sind fast unbegrenzt.

/**
 * Debug job, write a log file
 * */
using System;

namespace ch.starwolf.SoftwareDesign {

	public class DebugLogger : IDebug{

		public DebugLogger() {}

		public void Debug(string Msg){
			Console.WriteLine("Write Msg into a log file, Msg is : "+ Msg +DateTime.Now.ToString());
		}
	}//end of class
}

Jetzt kommt die Implementation in unsere Business Logik. Wir müssen nur eine Debug Methode definieren und beim Initialisieren ein IDebug Instanz durch-reichen. Die im Konstruktor von der Klasse mitgegeben wird. Die Business Logik hat somit nur mit ihren eigenen Instanzen zu arbeiten und ist nicht verantwortlich für das erstellen eines Debugger Objekts. Das ganze wir auch als Lose-Kopplung bezeichnet. Die Trennung ist dadurch klarer was nur Vorteile bringt. Das ist der ganze Aufwand um einen Debugger einzubauen, zudem bleibt die Implementation immer gleich auch für andere Business Logik Klassen.  Das ganze sieht dann so aus.

/**
 * critical Business logic
 * */
using System;

namespace ch.starwolf.SoftwareDesign {

	public class CurrencyBroker {
		protected IDebug debugger;

		public CurrencyBroker(IDebug debugger) {
			this.debugger = debugger;
		}

		public void CurrencySale (string CC, int CCCount, int ID){
			//do something
			this.Debug("ID="+ID+" - CurrencySale - Done And Ready - ");
		}

		/* Debug Implementation */
		protected void Debug(string Msg){

			// if null no need for debug
			if (this.debugger != null) {
				this.debugger.Debug(Msg);
			}
		}
	}//end of class
}

Der Aufruf und die Übergabe sieht so aus in unserem kleinen Beispiel.

/**
 * Demo API
 * */
using System;
using ch.starwolf.SoftwareDesign;

namespace ch.starwolf.SoftwareDesign {
	class MainClass {

		public static void Main(string[] args) {

			Console.WriteLine("Run CurrencyBroker Job");
			DebugLogger Debug = new DebugLogger();

			CurrencyBroker job01 = new CurrencyBroker(Debug);
			job01.CurrencySale("CHF",100,1);

		}
	}//end of class
}

Ausgabe der Konsole:

Run CurrencyBroker Job
Write Msg into a log file, Msg is : ID=1 - CurrencySale - Done And Ready - 23.03.2010 19:34:30

Dazu noch ein UML Diagramm. Die roten Felder könnten zusätzliche Klassen sein.

101-scharp-001-UML

UML Diagramm

Ich hab das Beispiel mit MonoDevelop und das Diagramm mit Dia unter Linux erstellt. Das kleine Projekt könnt Ihr hier runter laden.

Das war der ganze Zauber zu diesem Thema. Viel Spass beim Ausprobieren @all.

Hier noch ein paar Links zum Thema : Design Pattern, UML


101 Regel des Software-Designs, OOP

0

Kapselung der Daten

Oft hat man Variablen die in einer Konfigurationsdatei abgelegt werden oder globale Variablen die in der Anwendung gebraucht werden. Wenn jetzt die Anforderung ändert oder die Anzahl der Variablen in der Konfigurationsdatei steigt. Kann man das ganze in einer Methode Kapseln, somit kann man bei einer Veränderung das ganze überschreiben. z.B Die Berechnung einer Börsen Transaktion ist anders von Mitarbeitern der Bank und den normalen Kunden.

Erweiterbar

Die Schnittstellen sollten so Programmiert werden, dass diese auch später erweitert werden könnten.

Wiederverwendbarkeit

Duplizierung von Code sollte vermieden werden. Weil der Aufwand grösser ist bei einer Anpassung und das Risiko eines Fehlers steigt.

Diese drei Definitionen sind die klassischen Regeln die man als Software Entwickler lernt, wenn man mit einer OOP Sprache arbeitet. Es gibt noch andere wichtige Regeln die ich bei der täglichen Arbeit gelernt habe. Die komplette Liste werde ich weiter unten auflisten. Die oben genannten Regeln werden auch wider dabei sein.

Wichtige Punkte für gutes Software-Design

  • Wiederverwendbarkeit von Logik und Code. Duplizieren von Logik und Code sollten vermieden werden.
  • Wiederverwendbarkeit von Strukturen und Aufbau im Code. Dadurch wird die Wiedererkennbarkeit gefördert.
  • Kapseln vom Zugriff auf die Daten in einer Klasse. der Zugriff sollte über get und set Methoden oder Properties gewährleistet werden.
  • Kapseln von Algorithmen über Methoden Innerhalb der Klasse. Wichtige Algorithmen sollten an einer zentraler Stelle implementiert werden.
  • Konkrete Implementierung vermeiden, programmieren gegen eine Schnittstelle ist ein gutes Mittel.
  • Die Schnittstellen sollten Erweiterbar sein.
  • Klare und wenn möglich kurze Namen verwenden für alle Bausteine der Klassen und Objekten.
  • Durch die Vererbung  entstehen oft starre Strukturen. Objektkomposition ist ein gutes Mittel um verschiedene Methoden miteinander kombinieren zu können.
  • Lose Kopplungen von Klassen helfen feste Abhängigkeiten zwischen den Klassen in der Anwendung zu vermeiden.
  • Kleine Bausteine die unabhängig implementiert sind verhindern monolithische Strukturen. Grosse und Tiefe Strukturen die z.B mit IF, ELSE, ELSE IF oder Switch, Case gemacht werden, sollten durch kleine Methoden oder Klassen ausgetauscht werden wenn es Sinn macht. Restrukturierung von Code ist oft eine Sinnvolle Aufgabe die man im Team machen sollte. (Refactoring)
  • Fluent Interfaces fördern die Lesbarkeit und Wartung von Code.
  • Einheitliche Notation im Code verwenden.
  • Jeder Code der ein Check IN erfährt sollte durch ein Review laufen. Fördert die Qualität und hat einen guten Lerneffekt.

Der letzte Punkt hat nicht direkt mit dem Software-Design zu tun, ist aber ein sehr wichtiger Punkt wo ein gutes Software-Design auch fördert. Das ganze ist aber abhängig von der Software-schmiede. Meine Erfahrungen zeigten auch, dass oft dann die Person wo die Qualität der Implementierung beurteilen soll überfordert ist. Ein guter Senior Developer kann sowas.


Artikelnavigation