Ich begrüße Sie zum neuen Kapitel der Lehrveranstaltungssoftware Re-Engineering und wir beschäftigen uns jetzt mit Maßnahmen,
die Wartbarkeit zu verbessern, Re-Engineering tatsächlich durchzuführen.
Bis jetzt ging es vor allen Dingen darum,
was ist dabei wichtig, das war das Kapitel 1,
worauf kommt es an, wie gehen wir vor,
was ist das Besondere bei solchen vorhandenen Systemen, existierenden Systemen,
wie bewerten wir sie und wie finden wir die Dinge,
die stellen, an denen man Re-Engineering durchführen muss,
das war vor allen Dingen Gegenstand von Analyse und Assessment.
Wir haben uns soweit vorgearbeitet, dass wir wissen,
welche Maßnahmen wir wo durchführen müssen. Und jetzt geht es
eins, das wirkliche Durchführen. Ich habe dieses wirkliche Durchführen,
die Re-Engineering-Maßnahmen hier aufgeteilt auf zwei Kapitel. Und zwar deswegen,
weil ein Teil, nämlich das, was wir auf Code-Ebene durchführen,
tatsächlich in der Praxis durchgeführt wird,
in der Industrie erfolgreich angewendet wird und auch für Legacy-Systeme sich ein Basisstand von Buddy of Knowledge,
wenn man so möchte, herausgeprägt hat.
Während die Maßnahmen auf oberhalb von Quellcode tatsächlich erst in Entwicklung sind.
Da gibt es bis jetzt noch nicht so viele Erfahrungen.
Da sind mehr Forschungsergebnisse und manche Sachen sind noch sehr vage.
Ich möchte sie aber unbedingt damit vertraut machen, dass wir dann das Kapitel 5 sein.
Doch zunächst starten wir mit Reengineering-Maßnahmen auf Kot-Ebene. Dieser Maßnahmen auf Kot-Ebene ist Kapitel 4,
gliedern wir so, dass wir zunächst erst mal zu dem,
sagen wir mal, so ein bisschen traditionellen Old-Fashioned,
bevor der Objektorientierung, das ist das Kapitel 4,
1, wo es darum geht, wie modularisieren wir,
strukturieren wir das, wie verbessern wir die Struktur,
während Kapitel 4, 2 eine Besonderheit betrachtet,
nämlich die Abhängigkeit von Daten.
Auch Daten müssen gepflegt werden, müssen reingeniert werden,
damit wir Weiterentwicklung zulassen können
Kapitel 4, 3 beschäftigt sich mit dem Refactoring,
wie es das traditionelle nach Martin Fohler definierte Refactoring im Objektorientierten Vorgehen ist.
Aber das passt nicht so richtig für tatsächlich Legacy-Systeme, also Systeme mit eingeschränkter Wortbarkeit,
mit eingeschränkter Pflegbarkeit, da ist man schnell im Teufelskreis.
Deswegen gibt es dieses Kapitel, oh,
das wollten wir hier, wollten wir nicht drauf malen,
sondern nur eigentlich nur was zeigen. Das Kapitel 4,
4, dabei wird er sich dann darum gehen,
wie gehen wir denn vor, wenn wir nur eingeschränkte Testbarkeit haben,
wenn wir tatsächlich schon irgendwie auf diesen Staged Model,
ich hoffe, sie erinnern sich noch,
schon ein bisschen abgerutscht sind und nur noch Service-Patches haben.
Wie kommen wir da, können wir das wieder verbessern und
trotzdem Refactoring machen? Obwohl die klassischen Voraussetzungen,
die Martin Foul erfordert für das Refactoring,
was wir in Kapitel 4, 3 hier bezeichnen,
ich hätte vielleicht schreiben sollen, klassisches Refactoring, wie unterscheidet sich das?
Wir starten mit 4-1, Modularisierung und dazu
sind Fragen, die Fragen 1 und 2 gedacht.
Und zwar werden wir kurz darüber sprechen,
was ist automatische Restrukturierung des Steuerflusses und Modularisierung,
was ist das eigentlich
Lassen Sie uns damit starten, dass wir kurz,
dass ich Ihnen kurz das Problem erkläre.
Jeder von uns hat vielleicht schon mal Quellcode gesehen,
der in irgendeiner Form, ja, schlecht strukturiert ist,
wie auch immer.
Und da gibt es den netten Namen Spaghetti-Code dafür.
Sie können sich alle vorstellen, dass es auf so einem
Tellosch-Paket die schönen Kreuzung quer geht.
Und das verhindert, das behindert die Verständlichkeit sehr stark.
Dieses schöne Kreuz und Quer muss kein auf den ersten Blick durchaus ordentlich aussehen,
wie hier in dieser Software, da sieht es doch sehr ordentlich aus.
Ja,
also wir haben hier
klare Bezeichner
Ja, also hier gibt es irgendwie solche Gets,
dann ist das hier strukturiert. Dann gibt es hier etwas,
wo man ganz klar mit Eindrückungen arbeitet.
Das sind Labels, also Sprungmarken in dieser Programmiersparte,
sieht so ein bisschen Pascal oder Vortrang mäßig aus.
Und if than, also das mit GoTo macht man Sprünge,
diese Sprünge sind eine Zeit lang sehr verrufen gewesen,
also in vor der Objektorientierung war das ein großes Thema.
Wie gehe ich mit Spaghetti-Code um? Und dieses Thema haben
wir tatsächlich heute auch noch, auch wenn wir heute in
den objektorientierten Sprachen eigentlich GoTo kaum verwenden oder solche ähnlichen Sprünge.
Man kann aber auch objektorientiert,
darf ich gleich mal vorgreifen,
wunderbar ganz schlechten Code schreiben
Das ist also Code, der irgendwie nur mittelschlecht aussieht,
weil das sieht doch sehr gut aus.
Alles hier gibt es, ist klar strukturiert.
Es gibt ordentliche Bezeichnungen. Hier steht nicht nur Tele 135,
so und man kann hier tatsächlich vermuten,
dass man hier sich aus dieser, aus dieser Sache etwas darstellt,
dass man das verstehen könnte.
Wenn man jetzt versuchen will, dieses zu verstehen,
dann wird sich ganz schnell zeigen, dass es irgendwie schwierig ist.
Ja, und zwar liegt das daran,
dass wir hier mit diesen ganz vielen Go-Tos arbeiten.
Lassen Sie uns das ein bisschen verfolgen. Ja,
also hier gibt es, gibt es irgendwie dieses Go-To oft.
Das geht also hierhin, so,
das Go-To-On geht hierhin
Wir zeichnen einfach nur mal an, was hier drin.
Go to loop, ich mache das mal rechts rum,
damit es ein bisschen, da geht es wieder hoch zum Start dann.
Ja, so. Und hier haben wir auch Go to Loop.
So, und das ist hier go to on.
Go to off. Dann haben wir hier ein Go to
start.
Nochmal Go to start
Und, dann gibt's hier was mit Go-to-Switch,
der Switch ist eigentlich nur die übernächste Zeile.
So. Und, ähm, ja, so sieht das doch
schon irgendwie, ist das noch klar? Ja,
es sieht doch nicht so, nicht so unklar aus,
es geht nicht so völlig durcheinander, aber die Struktur ist nicht da.
Es ist ganz schwer, das zu verstehen, was dieses Programm macht.
Wir können, ich kann Ihnen so weit verraten,
es geht hier um eine Heizung, ja,
ich schreibe es mal noch mit dran,
damit Sie das als kleine Aufgabe
mal sehen
Und diese Heizung, diese Heizung hat mehrere Modi,
zeitgesteuert, temperaturgesteuert und manuell.
Oh, das ist schlecht zu lesen, das machen wir
ein bisschen besser.
Das ging schon mal besser,
Ein... Aber das kann man auch noch machen. So,
und jetzt versuchen sie mal, das Programm zu verstehen.
Am besten, wir machen hier,
sie machen hier einen kleinen, kleinen Pause,
schauen sich das Programm an und mit meinen Hilfen und den Erläuterungen.
Vielleicht kriegen sie es ja raus. Während sie Pause machen
, sage ich mal schon mal, oder...
Ja, genau, jetzt soll hier Pause beendet sein,
jetzt sollten sie schon wissen, wie es weitergeht.
Sie haben das verstanden und haben da wahrscheinlich eine ganze Menge
Kraft investiert, um das zu verstehen,
was hier wirklich passiert und dass wir irgendwie hier Zustände haben.
Die Zustände sind durch Blöcke gekennzeichnet
Ist irgendwie schwierig. Nun gibt es aber,
und das haben die Leute schon relativ zeitig gemerkt,
es gibt hier so ein ganz berühmtes Paper,
go to considered harmfool, dass man sagt, ja,
das Go-To ist eigentlich die Quelle, alles bösen.
Und tatsächlich gibt es ein Theorien, was sagt,
und es gibt auch einen Beweis dafür,
dass sich Go-To durch Schleifen ersetzen kann und zwar komplett ersetzen kann.
Und dafür gibt es automatische Verfahren. Hier wäre das Ganze
wieder, wäre das umgeformt ohne Go-To.
Also wir sehen hier im ganzen Programm kein einziges Go-To.
Stattdessen gibt es Schleifen. Es gibt immerhin hier
eine Switch-Anweisung
Das ist hier dieser Bereich, dieses Switch hat hier drei Alternativen.
Und dann haben wir, genau. So, und ja,
hier unten ist, hier sehen wir also schon mal die Modi viel deutlicher.
Also wenn das im Zustand eines manuell eingeschaltet,
wenn es im Zustand aus ist, manuell ausgeschaltet,
wenn es im Zustand mit der Regelung ist,
dann gibt es hier die Zeitregelung und wie ist denn das mit der Temperatur,
ist wert und soll wert.
Das können wir hier doch relativ gut ablesen.
Und damit ist es sehr viel besser verständlich.
Das ist letztlich der Kleid, die gleiche Funktion wie eben
nur klarer verständlich
Nachdem ich Ihnen an diesem Beispiel nur gezeigt habe,
worum es bei Restrukturierung geht,
möchte ich kurz etwas zu diesen Zielen und zum Vorgehen sagen.
Ich beziehe mich auf Restrukturierung und Modularisierung.
Nein, wir wollen schreiben. Worin bestehen die Ziele?
Am Ende wollen wir erreichen,
dass wir
die Wartbarkeit verbessern
Verständlichkeit erhöhen ist das eine Ziel und das können wir dadurch mal erreichen,
dass wir zum Beispiel das Programm neu organisieren.
Indem wir eine klarere Struktur geben. Diese klare Struktur ist einerseits
dadurch gekennzeichnet, dass wir Dinge zusammenfassen, Die zusammen gehören.
Nein, da wollen wir noch nicht hin.
Dann wäre das Nächste, dass wir Abstraktionen einführen.
Vielleicht nehmen wir hier Abstraktionen einführen, die Obstraktionen der
realen Welt entsprechen
Das wäre in unserem Beispiel, dass wir hier so was haben,
wie die Zustände des Programms oder des Systems abgebildet und diese
Zustände der Regelung abgebildet durch bestimmte Programmabschnitte, nämlich hier,
das wäre dieser gesteuerte Bereich der Dauereindauer aus.
Das ist doch sehr viel deutlicher als hier,
wo es hier irgendwie hier,
da ist eigentlich nur so eine Schleife und was passiert denn da,
das ist nicht wirklich klar.
So, also das meine ich mit Abstraktionen einführen,
dass man Sachen erkennt und das ist natürlich leichter,
die Verständlichkeit dann,
da ist die Verständlichkeit
besser gegeben
Dann könnte man die Verständlichkeit erhöhen dadurch,
dass man Bezeichner ändert. Das ist kein großes Ding,
man muss einfach der Bezeichnung austauschen, überall, woher ist es,
da braucht man gar nicht ganz viel methodisches Vorgehen,
sondern eher Richtlinien, wie man die Bezeichner einführt.
Ein weiteres Ziel, was für Wartbarkeit beiträgt,
ist den Änderungsaufwand senken
Das wäre, ja, auch keine Punkte man mehr,
auch keine. Das wäre zum Beispiel durch... Kapselum,
die wir einführen, dass bestimmte Einheiten nur für einen
bestimmten Bereich zugreifbar sind, dass wir Modularisierung bilden.
Das wäre der nächste Punkt, dass wir Redundanzen entfernen.
Und Abhängigkeiten reduzieren
Über Redudanzen hätten wir schon bei Code Clones gesprochen.
Das ist einfach mehrfacher Aufwand. Ich muss es mehrfach verstehen.
Es könnte eine Quelle subtiler Fehler sein. Sowas haben wir in
unserem Beispiel auch irgendwo, dass wir Sachen einfach mehrfach haben.
Das sieht irgendwie so ein bisschen schematisch aus.
Wir haben immer dieses Switch go to on, so ähnlich.
Das haben wir hier unten dann auch nochmal mit dem Oin und Off.
Das ist alles nicht so richtig klar, was wir damit gemeint haben.
Und es ist vor allen Dingen nicht entkoppelt.
Hier haben wir so globale Variablen
Die wir im ganzen Programm haben, das sind die Steuerwerte,
das werden wir nicht ganz loswerden. Es ist ja
nicht wirklich modularisiert, aber hier ist es schon so,
dass wir die Haupteinheit, nämlich das, was passieren soll,
tatsächlich konzentriert haben in diesem einen Block.
Er hat nicht wirklich Parameter, die Parameter sind weiter hier
in globalen Variablen gehalten, global für dieses Stückchen Steuerungsprogramm.
Aber es ist wenigstens hier in einem Block kompakt zusammengeteilt.
Also das wären die Ziele, die wir mir verfolgen.
Und natürlich würden wir auch noch versuchen, die Interaktion zu optimieren.
Das führt auch dazu, dass wir leichter mal was ändern
Das schreiben. Damit ist gemeint,
die Interaktion mit anderen Systemen, die Interaktion mit den Menschen,
wenn das besser strukturiert ist, dann ist zu erwarten,
dass der Änderung, dass weniger Änderungen kommen,
weil die Leute da nochmal dran bauen wollen,
mir das sehr klar und gut strukturiert ist und elementar ist,
dann ist das sozusagen atomare Bedienoperationen haben,
dann ist das sehr viel weniger Änderungswahrscheinlich.
Ja, also das wären Punkte,
wo wir modularisierung brauchen
Wer ist vielleicht auch noch wertvoll zu sagen, was für Modularten gibt es denn?
Um es gleich zu sagen, okay, nach denen,
jedes dieser Modularten brauchen wir ein anderes Vorgehen oder andere Richtlinien für gut.
Und zwar, das hat ja was damit zu tun,
mit Arten von Abstraktionen die dadurch abgebildet werden durch so ein Modul.
Das Modul steht ja für etwas anderes, für ein bestimmtes Konzept,
was verallgemeinert wird, was zusammengefasst wird und damit abstrahiert wird.
Zum Beispiel möchte ich als erstes einen führenden Datenabstraktionen.
Vielleicht lingelt es da bei Ihnen, Sie haben vielleicht in Erinnerung,
dass abstrakter Datentyp das Konzept ist,
was man bei Objekten bei Klassen macht.
Und deswegen ist es hier, wäre das eine Möglichkeit,
so etwas, so eine Kapselung einzuführen,
anhand von Daten mit ihren Zugriffsoperationen,
nämlich das,
was Klassen und Objekte machen
Und das könnte man dann nutzen, dazu nutzen,
dass man global genutzte Datenbereiche entkoppelt. Ich vermute,
die meisten von Ihnen sind globale Daten noch nicht so untergekommen.
Es gibt tatsächlich in den traditionellen Programmiersprachen vor der Objektorientierung,
denen war es durchaus üblich, dass man Zustandsvariable für das ganze Programm definiert.
Manche Programmiersprachen wissen das gar nicht anders zu,
dass man es entkotteln kann,
aber dass man die definiert,
bewusst zugreifbar von überall her
Und das ist für die Testbarkeit ganz schwierig,
um zu nachzuverfolgen, was ist denn jetzt hier gerade passiert,
wieso steht dann plötzlich Zustand Nummer drei drin,
wo wir doch eben noch bei der Fünf waren.
Irgendjemand muss da jetzt gerade darauf zugegriffen haben,
was war denn das? Das ist erstmal schwierig.
Ja, global benutzte Bereiche entkoppeln wäre ein solcher Punkt.
Ein nächstes, nächstes, nächstes Kriterien der Modularisierung wäre,
dass man Hardware-Abstraktionen bildet
Alles, was zu einem Gerät gehört und zu einer Funktion.
Oder auf eine Technologie. Sowas wie den Gedanken der Plattform
Meinen wir so etwas ähnliches, wie sie das für ein Betriebssystem herkennen.
Da sagt man, die ganze Geräte spezifischen Teile,
das war normalerweise das Bios, dann die eher diensteorientierten Teile,
wo Hardware, wo die Hardware von der Hardware schon abstrahiert wird.
Da gibt es nicht mehr den Datenblock im Speicher,
sondern da gibt es schon wirklich die Datei.
Und da gibt es Nateioperationen, eine Ebene höher,
die Anwendungsebene, wo ich tatsächlich mit das Dateiverzeichnis schon habe,
mit Wiederherstellungsfunktionen, Servicefunktionen und so etwas.
Und das Gleiche gab es auch,
sollten Sie auch kennen, sowas ähnlich,
solche Hardware-Abstraktionen bei dem OSI7-Schichten-Modell
für verteilte Systeme für Telematik
Ja, wo wir dann die physikalische Ebene haben,
wo wirklich Elektronen fließen, über die Ebene,
wo Protokolle laufen, auf verschiedenen Ebenen, bis oben,
wenn es oben die Anwendungsebene.
All solche Sachen, das ist damit gemeint, bilden Sie Blöcke,
bilden Sie Module nach Abstraktionen von dem Grad der Abstraktion von Hardware.
Dann können wir natürlich nach funktionalen Kriterien gliedern.
Funktionsmodule, das sind funktionale Blöcke
Entsprechend der Gliederung der Domäne. So wie ihre
fachliche Objekte haben, haben wir häufig auch fachliche Funktionsblöcke.
Wie eben, es gibt die Benutzerverwaltung. Es gibt die Mitarbeiterverwaltung,
da gibt es die Artikelverwaltung, die Verwaltung von Ausleihvorgängen oder
die Verwaltung des Abnutzungsgrads oder der Auslastung von Maschinen, die einzelne Maschinenstörung.
Also solche Blöcke, wo der Mensch aus dem Auftraggeberseite,
der das Domänenmissen hat, ihnen sagen wird, das ist ein Teilbereich,
das ist ein Teilbereich, das ist ein Teilbereich.
Und die unterschiedlichen Teilbereiche, einzelne Blöckegliedern,
ist eine Sache, was zur Verständlichkeit beiträgt,
was wir hier gerade vorher bei den Zielen hatten, was dazu beiträgt,
die Verständlichkeit zu erhöhen, indem wir diese Abstraktion einführen,
wie eine bessere Abbildung in Essen erlauben,
wo bin ich denn gerade?
Und dass wir es auch besser von der Mutter trennen können,
nicht, dass alles durchvermischt ist, vermischt, zur Matscht letztlich.
So, dass wir ein Funktionsmodule und dann könnte man durchaus
das auch noch gliedern nach Geschäftsprozess Gesichtspunkten
Alles, was zu einem Geschäftsprozess gehört, packt man Momentgeschäftsprozess, soll das heißen?
Das packt man in ein Modul. Dieses Geschäftsprozess denken geht
natürlich nicht für den ganzen Prozess und man wird immer versuchen,
Teilschritte Oder Aktivitäten dabei zusammenzufassen, zu blöcken,
die man dann vielleicht auch wieder kombinieren kann,
die neuen Geschäftsprozesse, aber erstmal,
dass man das pro Tätigkeitsbereich gemeinsam hat.
Diese Restrukturierung des Steuerflusses, die wir eben im Beispiel,
das war erstmal zu der Frage modularisierung.
Modialisierung hilft uns, Löcke zu bilden,
das wäre so ein bisschen die größere Einheit,
das war nicht das,
was wir
im Beispiel gesehen haben
Im Beispiel ging es vor allen Dingen um den Steuerfluss,
lassen wir uns das separat nochmal betrachten.
Beim Steuerfluss kommt es uns darauf an, diesen besser lesbar zu machen,
aber die Ziele sind letztlich die gleichen wie bei Modularisierung,
Restruktur, Rioko, das Steuerfluss.
Dabei geht es darum, dass man die Struktur klarer macht.
Die Ziele sind letztlich weg,
gehen wir hier zurück zu der Zeit mit den Zielen.
Ja, also das ist wieder die Verständlichkeit erhöhen.
Das ist, dass wir es neu organisieren.
Die Struktur wäre eben jetzt die Steuerflussstruktur,
weniger dieses Module bilden, sondern eher so Einheiten bilden.
Ja, und den Änderungsaufwand senken vor allen Dingen dadurch,
dass man klare Einheiten hat, klare Strukturen hat.
So, dieser Restrukturen des Steuerflusses ist vor allen Dingen,
hat vor allen Dingen das Ziel, Nein,
ich schreibe das mal ein bisschen anders.
Sprünge mit Kung-To reduzieren. Indem man Schleifen einführt,
Schleifen sind doch sehr viel bessere Einheiten,
die man besser überschaut,
wo sie lang gehen
Die Grundidee ist, dass alle Go-To-Sprünge durch Schleifen ersetzbar sind.
Das ist das, wo ich sagte, da haben sich
Wissenschaftler und Branden abgearbeitet. Dafür gibt es sogar einen Beweis,
dass das möglich ist und entsprechend können das Maschinen tun.
Wenn es nur einen Algorithmus gibt,
ist sowas automatisiert möglich, aber das hat
ein paar Nachteile
Das wäre also die automatisierte Programmrestrukturierung. So, da würde das so umgesetzt,
das ist nicht ganz, die entspricht nicht ganz dem,
was wir im Beispiel haben. Also hier das gegen das nächste ersetzen,
das ist nicht ganz automatisch erfolgt, weil wir ja Hier sehen wir,
also die Bezeichner sind alle die gleichen geblieben, ja,
aber wir haben tatsächlich hier ein paar Anweisungen noch reinbekommen,
die uns helfen, das besser zu verstehen,
insbesondere der Kommentar zu Anfang ist senkreich und sie können sich gut vorstellen,
dass ein Tool das nicht schafft,
so einen hilfreichen Kommentar zu generieren.
Die Nachteile einer solchen Automaten sind,
dass genau diese Information zur Verfügung
zu verloren geht
Und die Kommentare gehen verloren, Dokumentation wird ungültig oder geht verloren.
Weil ihr die Struktur nicht mehr dem Ganzen entspricht.
Natürlich müssen wir noch sagen,
es ist hoher Rechenaufwand notwendig, das schreibe ich mal
in Klammern
Das ist eigentlich so nicht das Thema,
weil wir machen es ja nur einmal und wir haben typischerweise
relativ leicht Rechenleistung zur Verfügung.
Und deswegen wird man das nicht komplett automatisch machen.
Man macht das automatisch
nur für Teilbereiche eines Programms
Und diese Entscheidungen treffen wir genau danach, was wir bis jetzt unter Analyse besprochen haben,
man analysiert, wo sind die Schwerpunkte, wo sind die Probleme.
Von mir aus auch mit der 80-2-20-Regel,
dass man sagt, okay, das sind die 20 Prozent,
die wirklich Probleme machen, wo die Verständlichkeit gering ist,
wo die Dokumentation schlecht ist,
und dort führen sie diese so eine Maßnahme durch.
Das wäre, Metriken könnten uns auch dabei helfen.
Damit hätten wir diese Fragen, 1 und 2 behandelt,
die Nachteile war das eben,
und die Ziele waren das vorher, Maßnahmen wäre dann,
dass es solche Blöcke bildet,
das refektorisieren