Vorlesung Softwarequalität:
Die Folien zum Thema Source-Code-Metriken.
Inkl. McCabes zyklomatischer Komplexität, Halsteads Komplexitätsmetriken, Uncle Bob's Distance und den C&K OOD Metriken.
Die Fragen im zweiten Teil stammen von den Studenten des Master-Studienganges 2012 der Westsächsichen Hochschule Zwickau.
4. McCabes zyklomatische Komplexität
● Literatur: A Complexity Measure; Thomas J. McCabe
● IEEE Transactions on Software Engineering, Vol. SE-2, No.4, December 1976
● http://www.literateprogramming.com/mccabe.pdf
● Die zyklomatische Komplexität basiert auf der Graphentheorie
● Ursprünglich für FORTRAN erdacht
● Auf alle strukturierten und prozeduralen Sprachen anwendbar
● Entscheidungen im Programm werden zu Knoten im Graph
● Programmlogik wird als Kanten des Graphs interpretiert
v (G)=e−n+2∗p
● Zyklomatische Komplexität:
● e = edges, Kanten im Graph
● n = nodes, Knoten im Graph
● p = parts, (unabhängige) Teile des Graph
4
5. Algorithmische Ermittlung der zyklomatischen Komplexität
● Theorem: v(G) ist gleich der Anzahl der A
unabhängigen Zyklen des Graph.
● Ermittlung durch Zweigüberdeckung:
B C D
● Übertragung des Graphen in einen
Baum
● Jeder Pfad im Graph entspricht E
einem Pfad im Baum
● Anwendung der Tiefensuche A F
● Es werden nur Knoten untersucht,
die noch nicht besucht wurden B C D
● Wurde ein Knoten besucht, ist ein
neuer unabhängiger Kreis entdeckt E F C
● Vorgehen liefert gleichzeitig Testfälle für
den Graph
B A F
A
5
6. Anwendung der zyklomatischen Komplexität auf objektorienten Code
● Methodenbasiert
● Es werden die Kontrollstrukturen innerhalb von Methoden untersucht
● Mögliche Ergebnisse:
● v(G) für konkrete Methode, avg v(G) pro Methode / Klasse / Package (sinnfrei)
● Prozessbasiert
● Sämtliche für einen Prozess relevanten Methoden werden als unabhängige
Teilgraphen (Components) betrachtet
● e sind die Kanten der Kontrollstrukturgraphen aller Methoden
● n sind die Knoten der Kontrollstrukturgraphen aller Methoden
● p ist die Anzahl der beteiligten Methoden
● Berechnung ist aufwändig (abhängig von Kopplung)
● Algorithmus liefert aber sehr interessante Aussagen
u.a. über die Gesamtkomplexität von Prozessen
6
8. Die Halstead-Metriken
● Literatur: Elements of Software Science; Maurice H. Halstead
● Elsevier Science Inc., New York, 1977
● Halsteadt definierte eine Reihe von Metriken zur Komplexitäts- und Aufwandsschätzung
● Program vocabulary (n)
● Program length (N)
● Calculated program length
● Program volume (V)
● Program difficulty level (D)
● Program level (L)
● Effort to implement (E)
● Time to implement (T)
● Number of delivered bugs (B)
8
9. Berechnung der Halstead-Metriken
● Unique Operators and Operands: n1, n2
● Total amount of Operators and Operands: N1, N2
● Program vocabulary: n=n1+n2
● Program length: N =N1+N2
● Calculated program length: ̂
N =n1∗log 2 (n1)+n2∗log 2 (n2)
● Program volume: V =N∗log2 (n)
N1 n2
● Program difficulty level: D=( )∗( )
2 2
Program level: 1
●
L=
D
● Effort to implement: E=V ∗D
E
● Time to implement: T=
18 2
● Number of delivered bugs: E3 V
B= oder neu : B=
3000 3000
9
10. Kritik an Halsteadts Metriken
● Definition von Operator und Operand ist nicht festgelegt
● Fenton, N., Software Measurement: A Necessary Scientific Basis. In IEEE Transactions on
Software Engineering, 1004, vol. 20(3), pp. 199-206.
● Halsteads Metriken liefern keine Aussagen zur Komplexität, werden aber oft dafür
herangezogen
● Al-Qutaish, R.E., and Abran, A., An analysis of the design and definitions of Halstead’s
metrics, In 15th Int. Workshop on Software Measurement, 2005, pp. 337-352.
● Die Unklarheit von Halsteads Definitionen führt zu verschiedenen Interpretationen
● Die Anwendbarkeit auf moderne Programmiersprachen ist nicht festgelegt
● Beser, N., Foundations and experiments in software science. In Selected Papers of the
1982 ACM SIGMETRICS Workshop on Software Metrics: Part 2, 1982, pp. 48-72. und
Davies, G., and Tan, A., A note on metrics of Pascal programs. In ACM SIGPLAN Notices,
1987, vol. 22(8), pp. 39-44.
● Die Formel für N überschätzt die Länge kleiner Programme und unterschätzt die
Länge großer Programme
10
12. Der Maintainability Index
● Literatur: Oman, P., Hagemeister, J.: Metrics for assessing Software System Maintainability
● IEEE Int. Conference on Software Maintenance, 1994, S. 337
● Zusammenhang zwischen Codeeigenschaften und Wartungsaufwand
● Basiert auf anderen Metriken
● Aufwand nach Halstead (E)
● Zyklomatische Komplexität nach McCabe (G)
● Modulgröße (LOC)
● In einer Überarbeitung kam noch hinzu
● Kommentierungsgrad (CMT) prozentualer Anteil an den LOC
● Halstead-Volumen (V) alternativ zum Aufwand nach Halstead (E)
12
13. Der Maintainability Index
● 1992: ursprüngliche Formel
MI =171−5,2∗ln (E)−0,23∗ln (G)−16,2∗ln (LOC )
● 1994: Berücksichtigung von Kommentaren
MI =171−5,2∗ln (V )−0,23∗ln (G)−16,2∗ln (LOC )+50∗sin √ 2,4∗CMT
● Interpretation
● MI > 85: gute Wartbarkeit
● 65<MI<85: mittlere Wartbarkeit
● MI<65: schlechte Wartbarkeit
● Normalisierter MI von Microsoft
MI =MAX (0,(171−5,2∗ln (V )−0,23∗ln (G)−16,2∗ln (LOC ))∗100/171)
● Interpretation
● 0-9 = Rot
● 10-19 = Gelb
● 20-100 = Grün
13
14. Kritik am Maintainability Index
● Korrektheit von MI wurde nur über Korrelation mit subjektivem Empfinden von
Wartbarkeits-Experten geprüft (0,81-0,93)
● Reduzieren von Software auf einen einzigen Wert ist nur als Trend aussagekräftig
● Beschränkung auf spezifische Metriken reduziert die Anwendbarkeit auf moderne
Programmiersprachen
● Sneed, H.: “Software muss messbar werden”, Zeitschrift für Information Management, Nr.
4, 1991, S. 39
● Nur 40% der Wartungskosten werden von MI tangiert, der Rest teilt sich zwischen
Wartungspersonal und Wartungsumgebung auf
14
16. Die Robert C. Martin-Metriken
● Literatur: OO Design Quality Metrics; An Analysis of Dependencies; By Robert Martin
● http://www.objectmentor.com/resources/articles/oodmetrc.pdf
● Die Martin-Metriken zielen auf folgende Clean Code Prinzipien ab
● Single Responsibility Principle (SRP)
● Separation of Concerns (SOC)
● Interface Segregation Principle (ISP)
● Dependecy Inversion Principle (DIP)
● Information Hiding Principle (IHP)
● Open Closed Principle (OCP)
16
17. Instabilität
● Ca: Afferent Couplings: Anzahl der Klassen außerhalb der Kategorie, die von Klassen
innerhalb der Kategorie abhängen – eingehende Abhängigkeiten
● Ce: Efferent Couplings: Anzahl der Klassen außerhalb der Kategorie, von denen Klassen
innerhalb der Kategorie abhängen – ausgehende Abhängigkeiten
● Eselsbrücke: Inversion Ca = eingehend, Ce = ausgehend
Ce
● Instability: I = , I ∈[0,1]; ∑ Ce= ∑ Ca
Ca+Ce Kategorien Kategorien
● Keine ausgehenden Abhängigkeiten:
Hohe Stabilität, Tendenz ist I = 0
● Keine eingehenden Abhängigkeiten:
Hohe Instabilität, Tendenz ist I = 1
● Grenzwertbetrachtungen:
Ce Ce Ce Ce
lim =0 lim =1 lim =1 lim =0
Ce → 0 Ca+Ce Ce → ∞ Ca+Ce Ca → 0 Ca+Ce Ca →∞ Ca+Ce
17
18. Instabilität
● Hohe Stabilität (I nahe 0) ist erforderlich für
● System-Kerne
Komponenten, um die eine Software herum gebaut wird.
● Datenmodelle
Ein gutes Beispiel sind EJB3 Entities. Diese sollten von keinen anderen
Komponenten einer Software abhängen.
● Hohe Instabilität (I nahe 1) entsteht bei
● Implementierung von externen Schnittstellen
Als Beispiel kann die Implementierung eines WebService dienen, der
Funktionalität nach außen zur Verfügung stellt.
Von solchen Komponenten darf innerhalb des Systems nichts abhängen.
● komplexen User Interfaces
User Interfaces führen oftmals viele Komponenten zusammen.
Somit entstehen hohe Werte für ausgehende Abhängigkeiten.
18
19. Instabilität
● Keine Pakete mit I=0 →
● Kein Systemkern
● Zyklische Abhängigkeiten vorhanden
● Viele Pakete mit I=1 →
● Hohe Wartungsaufwände bei kleinen
Änderungen
● Prinzip:
Je mehr Pakete mit höherer Instabilität,
desto größer ist der Domino-Effekt bei
Änderungen.
● Ziel:
Möglichst viele stabile Pakete.
Software neigt leider dazu, sich
entgegengesetzt zu entwicklen.
19
20. Abstraktion
● NoAC: Number of Abstract Classes: Alle abstrakten Klassen eines Paketes
● NoCC: Number of Concrete Classes: Alle nicht abstrakten Klassen eines Paketes
● NoI: Number of Interfaces: Alle Schnittstellen eines Paketes
● NoC: Number of Classes = NoAC+NoCC: Alle Klassen eines Paketes
Abstractness A= NoAC+ NoI NoACI
●
= =, A ∈[0, 1]
NoCC+NoAC+NoI NoCI
● Keine abstrakten Klassen und Schnittstellen:
Niedrige Abstraktion, Tendenz ist A = 0
● Ausschließlich abstrakte Klassen und Schnittstellen:
Hohe Abstraktion, Tendenz ist A = 1
● Grenzwertbetrachtungen:
NoAC+NoI NoAC+NoI
lim =0 lim =1
NoAC+ NoI → 0 NoCC+NoAC+NoI NoAC+ NoI → ∞ NoCC+NoAC+NoI
NoAC+NoI NoAC+NoI
lim =1 lim =0
NoCC →0 NoCC+ NoAC+NoI NoCC →∞ NoCC+NoAC+NoI
20
21. Abstraktion
● Keine Pakete mit A=1 →
● Schnittstellen nicht einzeln
distributierbar
● Viele Pakete mit A=0 →
● Erweiterungen (OCP) nicht möglich
● Prinzip:
Abstrakte Pakete sind entsprechend des
OCP leichter zu erweitern als nicht
abstrakte Pakete.
● Ziel:
Definierte abstrakte Pakete, um
Schnittstellen zu separieren. Gute
Abstraktion benötigt viel Zeit.
21
22. Distanz
● Pakete sollten ausschließlich von stabileren Paketen (idealerweise auch abstrakteren
Paketen) abhängen. (ISP)
● Das ist die Grundlage für Inversion of Control bzw. Dependency Injection
● Zusammenhänge zwischen Abstraktion und Instabilität
● Abstrakte Pakete (A=1) sollten stabil sein (I=0), d.h. keine ausgehenden
Abhängigkeiten besitzen. Damit sind sie offen für Erweiterungen und geschlossen
gegenüber Modifikationen. (OCP)
● Instabile Pakete (I=1) sollten nicht abstrakt (A=0) sein. Sie sind nicht mehr
erweiterbar, unterliegen aber eine hohe Änderungswahrscheinlichkeit.
● Pakete mit balancierter Abstraktion (A=0,5) und Instabilität (I=0,5) sind noch
teilweise erweiterbar, unterliegen allerdings schon einer gewissen
Änderungswahrscheinlichkeit.
● Abstraktion und Instabilität sollten ausbalanciert sein.
22
23. Distanz
● Balance zwischen A und I ergibt einen
Graphen, der folgender Formel genügt:
● Distance: Dn=∣A+I−1∣, Dn∈[0,1]
● Pakete, die sich nahe der Main Sequence
befinden, sind ausbalanciert.
● Je weiter ein Paket von der Main
Sequence entfernt ist, desto schwieriger
wird seine Verwendung (Area of
Uselessness bei A=1 und I=1) oder seine
Wartung (Area of Pain bei A=0 und I=0)
● Ziel:
Optimale Pakete befinden sich an einem
der Endpunkte der Main Sequence, die
Entfernung zur Main Sequence (=Distanz)
Quelle: http://www.objectmentor.com/resources/articles/oodmetrc.pdf
sollte minimal sein.
23
25. Chidamber & Kemerers OO-Metriken
● Literatur: S. R. Chidamber, C.F. Kemerer, A Metrics Suite for Object Oriented Design
● IEEE Transactions on Software Engineering, 20(6), 1994, S. 476-493
● Sammlung von Metriken zur Bewertung objektorientierter Systeme
● Weighted Method Count (WMC)
● Coupling Between Object Classes (CBO)
● Depth of Inheritance Tree (DIT)
● Number of Children (NOC)
● Response For a Class (RFC)
● Lack of Cohesion in Methods (LCOM)
25
26. Weighted Method Count (WMC) / Coupling Between Object Classes (CBO)
WMC CBO
n
● Formel: WMC=∑ c i ● Anzahl der Klassen, die von einer Klasse
i=1
● Als Komplexitätsfunktion kann z.B. die benutzt werden
zyklomatische Komplexität dienen ● Ein hoher Wert für CBO deutet auf
● Kann als Wartungsmaß dienen, da eine Änderungsaufwände hin
größere Anzahl komplexer Methoden ● Entspricht dem Ce der Martin-Metrik auf
höhere Wartungsaufwände verursachen Klassenebene
kann ● Je höher der Wert von CBO, desto höher
● Bei Vererbung führen hohe Werte von der Wert der Instability
WMC zu engen Kopplungen ● Fokus auf Struktur
● Kritik: Attribute von Klassen werden
nicht berücksichtigt
● Clean-Code-Prinzip: SRP
Single Responsibility Principle
26
27. Number of Children (NOC) / Depth of Inheritance Tree (DIT)
NOC DIT
● Maß für die Anzahl unmittelbar ● Tiefe der Verbungshierarchie einer Klasse
abgeleiteter Klassen ● Anzahl geerbter Eigenschaften steigt mit
● Ein hoher Wert für NOC ist ein Indiz für höherer DIT
häufige Wiederverwendung ● Klassen mit hoher DIT können nicht
● Änderungsaufwand für Klassen mit isoliert betrachtet werden
hohem Wert für NOC ist hoch ● Als Maximalwert für den DIT wird im
● Testaufwand für Klassen mit hohem NOC Allgemeinen 7 angesehen
ist sehr hoch ● Clean-Code-Prinzip: FCoI
● Clean-Code-Prinzip: FCoI Favour Composition over Inheritance
Favour Composition over Inheritance ● Clean-Code-Prinzip: IHP
● Clean-Code-Prinzip: OCP Information Hiding Principle
Open Closed Principle ● Clean-Code-Prinzip: OCP
Open Closed Principle
27
28. Response For a Class (RFC) / Lack of Cohesion in Methods (LCOM)
RFC LCOM
● Response Set: Alle Methoden einer Klasse ● Maß für die gemeinsame Nutzung von
und die von den Methoden benutzten Attributen einer Klasse durch ihre
Methoden anderer Klassen Methoden
● Hoher Wert für RFC deutet auf schlechtes ● Ein hoher Wert von LCOM weist auf
Design hinsichtlich der Separation of schlechtes Design im Sinne der
Concerns hin Separation of Concerns hin
● RFC und CBO korrellieren im Allgemeinen ● Klassen mit hohem LCOM sollten geteilt
● Fokus auf Interaktion werden
● Clean-Code-Prinzip: SRP
● Clean-Code-Prinzip: SRP
Single Responsibility Principle Single Responsibility Principle
● Clean-Code-Prinzip:
Tell, don't ask
28
31. Das Problem mit der Kopplung
● Reale Anwendung
● Anwendung enthält rund 35 Entitäten
● Durchschnittliche Kopplung liegt bei
mehr als 30!
● Wartung nahezu unmöglich
● Unglücklicherweise sagt der
Maintainability Index: 165
31
33. Welche Metriken sind wichtig und weit verbreitet?
● Am weitesten verbreitet sind mit Sicherheit die Metrik der Lines of Code, die
zyklomatische Komplexität und der Maintainability Index
● Die Verbreitung sagt aber nichts über den Nutzen einer Metrik in einem konkreten Projekt
aus
● Oft werden weit verbreitete Metriken völlig falsch angewendet und damit mehr Schaden
produziert, als Nutzen geschaffen
● Wichtig sind immer genau die Metriken, die die Antworten auf die Fragen liefern, die sich
aus dem Ziel eines Projektes ergeben
● Es sollte nie nur eine Metrik herangezogen werden, sondern idealerweise Metriken, die
orthogonal zueinander messen
● Gut ist auch der Ansatz, immer zwei Metriken zu nutzen, die die gleiche Frage
beantworten: Ist die Antwort identisch, ist sie mit höherer Wahrscheinlichkeit richtig
33
35. Welche Tools können verwendet werden?
● Unter Java
● JDepend: Martin
● DependencyFinder & OOMetrics: Martin, Chidamber & Kemerer
● PMD: Zyklomatische Komplexität, NPath
● CheckStyle: Zyklomatische Komplexität, NPath
● Unter PHP
● PHP Mess Detector: Zyklomatische Komplexität, NPath
● PhpDepend: Martin
● Unter .NET
● Dependometer: Chidamber & Kemerer
35
36. Wie würde ein ausbalanciertes Klassendesign
aussehen (z.B. I = 0.5 und A=0.5)?
36
37. Wie würde ein ausbalanciertes Klassendesign aussehen?
● Balanciert ist das Design nicht nur bei I=0,5 und A=0,5, sondern entlang der gesamten
Main Sequence
● Der Idealzustand ist, dass jedes Paket entweder bei I=1 und A=0 oder I=0 und A=1
anzusiedeln ist.
● Praktisch ist das nicht zu realisieren (im Sinne einer wirtschaftlichen Entwicklung),
allerdings ist es nicht das Ziel, I=0,5 und A=0,5 zu erreichen.
● Das Abstract-Stable-Principle besagt, dass ein Paket so stabil wie abstrakt sein soll:
A ≃1−I
37
38. Wie würde ein ausbalanciertes Klassendesign aussehen?
IF Ca Ce I A
Bild 1
M E
Model 2 0 0 0
IM Interfaces 1 1 0,5 1
Implementierung 0 3 1 0
Exceptions 1 0 0 0
IF Bild 2
Model 2 0 0 0
M E Interfaces 1 2 0,66 1
IM Implementierung 0 3 1 0
Exceptions 2 0 0 0
38
39. Wie würde ein ausbalanciertes Klassendesign aussehen?
IF Ca Ce I A
Bild 3
M E
Model 3 0 0 0
IM Interfaces 2 1 0,33 1
Implementierung 0 3 1 0
Exceptions 2 0 0 0
IF Model 2 1 0,33 0
Interfaces 1 1 0,5 1
M E Implementierung 0 5 1 0
IM Exceptions 1 0 0 0
39
40. Wann ist es sinnvoll die Komplexität zu verteilen,
bereits während der Programmierung oder erst beim
Refactoring?
40
41. Wann ist es sinnvoll die Komplexität zu verteilen,
bereits während der Programmierung oder erst beim Refactoring?
● Refactoring ist Programmierung
● Im Sinne des Test Driven Development
● Zunächst Funktionalität realisieren
● Danach Komplexität reduzieren
41
42. Stellt die "Auslagerung" der Komplexität (z.B. einer
Methode) nicht einen Widerspruch hinsichtlich der
Wartbarkeit dar?
42
43. Stellt die "Auslagerung" der Komplexität (z.B. einer Methode)
nicht einen Widerspruch hinsichtlich der Wartbarkeit dar?
● Frage wurde bezüglich der zyklomatischen Komplexität gestellt
● Widersprucht besteht nicht im Sinne der Separation of Concerns
● Inhaltlich verschiedenes voneinander Trennen schafft Übersichtlichkeit
● In objektorientierten Sprachen Polymorphismus als Ersatz für Kontrollstrukturen
verwenden führt zum Verschwinden von Knoten aus dem Graph
● Polymorphe Methoden bearbeiten jeweils nur einen konkreten Typ:
Daraus resultierende Vereinfachung leuchtet ein :-)
43
44. Wie wirkt sich die Verteilung der Komplexität auf
das Laufzeitverhalten (und den Speicherverbrauch)
von Programmen aus?
44
45. Wie wirkt sich die Verteilung der Komplexität auf das Laufzeitverhalten
(und den Speicherverbrauch) von Programmen aus?
● Im besten Falle positiv, manchmal gar nicht und hin und wieder negativ.
● Sichtweise 1: Dynamisches Laden von Programmteilen
● Es werden nur die Klassen überhaupt geladen, die auszuführenden Code beinhalten
(z.B. Perl, PHP, teilweise auch Java)
● Sichtweise 2: Wie wirken Kontrollstrukturen im Vergleich zu Methodenrufen?
● Auf der niedrigsten Ebene (Prozessor) wirken Kontrollstrukturen ebenso wie
Methodenaufrufe wie ein GOTO: Die Ausführung des Programms wird an einer
anderen Adresse fortgesetzt.
● Einziger Unterschied: Beim Methodenaufruf wird die Rücksprungadresse auf dem
Stack gesichert
● Der Zugriff auf Daten benötigt einen Schritt mehr, nämlich das Auslesen der
Parameter von Stack
● Auswirkungen zeigen hier vor allem komplexe Datenstrukturen, die Call-by-Value
übergeben werden
45
46. Ist die zyklomatische Komplexität auch in
funktionalen Programmiersprachen einsetzbar?
46
47. Ist die zyklomatische Komplexität auch in
funktionalen Programmiersprachen einsetzbar?
● Prinzipiell: Ja, denn der Kontrollfluss existiert auch in funktionalen Sprachen
● Schwierig ist die Definition der Kontrollstrukturen
● If, Else etc. sind klar
● Stellen Listenoperationen Kontrollstrukturen dar?
1 val twoThree = List(2, 3)
2 val oneTwoThree = 1 :: twoThree
3
4 myList.count(s => s.length == 4)
5 myList.sort((s, t) => s.charAt(0).toLowerCase < t.charAt(0).toLowerCase)
● Die zyklomatische Komplexität berücksichtigt Rekursion nicht – ein Methodenaufruf ist
keine Kontrollstruktur
47
48. Was ist unter "Nichtäquivalenz der Interaktion" zu
verstehen?
48
49. Was ist unter "Nichtäquivalenz der Interaktion" zu verstehen?
● Gegeben sind drei Klassen: P, Q und R
● Metriken liefern für P und Q die gleichen Werte: μ(Q)=μ( P)
● Sowohl P als auch Q interagieren mit R
● Metriken für P+R und Q+R muss nicht gleich sein
49
50. Sollte man die Metrikwerte für jedes Projekt
spezifisch normieren?
50
51. Sollte man die Metrikwerte für jedes Projekt spezifisch normieren?
● Nein!
● Nicht für jedes Projekt, damit wäre kein Vergleich möglich
● Metriken gewinnen an Wert durch Verwendung in verschiedenen Projekten
● Erfahrungspotential der Entwickler ginge verloren
● Aber: Technologische Einflüsse auf Metriken müssen berücksichtigt werden
● Programmiersprachen
● Konzepte (z.B. Aspektorientierte Programmierung, Lombok)
● Wichtig ist, den Berechnungsweg der Metriken transparent zu machen
51
52. Wie viel Metriken sollte man in einem Projekt auf
einmal betrachtet?
52
53. Wie viel Metriken sollte man in einem Projekt auf einmal betrachtet?
● 42
● So wenig wie möglich, so viele wie nötig
● Zu viele Metriken verwirren Entwickler und stören sich u. Ust. Gegenseitig
● Aber: verschiedene Metriken beleuchten unterschiedliche Aspekte
● Empfehlung für Objektorientierte Softwareentwicklung
● Martin Metriken liefern Überblick
● Chidamber & Kemerer liefern Detailsicht
● Zyklomatische Komplexität für Methoden
53
54. Verwendung dieser Unterlagen
● Wir stellen diese Unterlagen unter der Creative Commons Lizenz CC-BY-NC-SA zur allen
am Thema Interessierten Verfügung.
● Es ist erlaubt, die Unterlagen unter gleichen Bedingungen zu
● kopieren
● verteilen
● übertragen und
● adaptieren, wenn
● die ursprünglichen Autoren genannt werden und
● die Verwendung nicht zu kommerziellen Zwecken stattfindet.
● Details zur Lizenz sind hier zu finden:
http://creativecommons.org/licenses/by-nc-sa/3.0/
54