Funktionale vs nicht-funktionale Anforderungen
Wir gebrauchen die Begriffe jeden Tag in der Softwareentwicklung: funktionale Anforderung, nicht-funktionale Anforderung. Doch mein Eindruck ist, dass selbst sie, die so grundlegend sind, keine ganz präzise Definition haben.
Hier ist, was Wikipedia dazu zu sagen hat:
Broadly, functional requirements define what a system is supposed to do and non-functional requirements define how a system is supposed to be.
Funktional oder nicht-funktional, to do oder to be? Ist es das? Das bedeutet:
[A] system can still work if [non-functional requirements] are not met, [however] it may not meet user or stakeholder expectations, or the needs of the business.
Ja, damit kann ich etwas anfangen.
Allerdings ist mir neulich eine, wie ich glaube, noch präzisere Definition eingefallen:
Funktionale Anforderungen beschreiben Zustände: Ausgangszustände und zugehörige Zielzustände.
Alle anderen Verhaltensanforderungen sind nicht-funktionale Anforderungen.
Funktionale Anforderungen sind Verhaltensanforderungen. Verhalten erkennt der Nutzer daran, dass sich ein Zustand verändert, sei das in der Benutzerschnittstelle oder in einem anderen Medium.
Dass Verhaltensanforderungen nicht alle Anforderungen an ein Softwaresystem sind, wissen wir mindestens, seit die Notwendigkeit für Clean Code Development in unser Bewusstsein getreten ist.
Schon die Formulierung “nicht-funktional” weist darauf hin, dass diese Anforderungen etwas “eigenartig” sind. Sie sind nämlich “nur”, das was übrig bleibt, wenn die funktionalen Anforderungen von den Verhaltensanforderungen abgezogen worden sind:
Ob funktionale wie nicht-funktionale Anforderungen erfüllt werden, kann man spüren, wenn man das Softwaresystem (lange genug) benutzt. Um ihre Erfüllung zu beurteilen, genügt eine “Außensicht”; Quellcode oder allgemeiner das Repository eines Softwaresystems ist dafür nicht zu betrachten.
Aber für funktionale Anforderungen genügen auch vorher-nachher Schnappschüsse: Wie waren Zustände (z1) zum Zeitpunkt t1, wie waren sie (z2) zum Zeitpunkt t2>t1, nachdem das Softwaresystem durch Trigger tr angestoßen wurde?
(z1, tr) → (z2)
Funktionale Anforderungen definieren solche Transformationen. Aufgabe der Softwareentwicklung ist es, sie mit Logik zu codieren.
Oder umgekehrt: Wenn Anforderungen sich als solche Transformation beschreiben lassen, dann sind es funktionale Anforderungen.
Kann eine Verhaltensanforderunge hingegen nicht mit einer solchen Transformation beschrieben werden… ist sie eine nicht-funktionale Anforderung.
Nicht-funktionale Anforderungen lassen sich also nicht in Schnappschüssen fassen. In ihnen spielt die Zeit eine Rolle. Ob nicht-funktionale Anforderungen erfüllt wurden, lässt sich nicht beurteilen, wenn ein Softwaresystem gestoppt ist und man auf seine Zustände schaut. Nicht-funktionale Anforderungen werden nur “in Bewegung” erfüllt; ihre Erfüllung lässt sich nur während des Verhaltens beobachten.
Für die typische Verhaltensanforderung Verarbeitungsgeschwindigkeit (performance) ist das offensichtlich. Ob auf Trigger tr hin z1 in z2 in 1 Sekunde oder 10 Sekunden transformiert wurde, lässt sich aus den Zuständen nicht ablesen. z2 kann korrekt hergestellt worden sein — aber langsamer, als es gefordert war. Eine bestimmte Vertarbeitungsgeschwindigkeit ist eine nicht-funktionale Anforderung. Dito die Skalierbarkeit (throughput bei Wikipedia).
Aber wie steht es mit all den nicht-funktionalen Anforderungen bei Wikipedia? Die Liste dort ist lang. Für mich bleiben mit meinem Definitionsvorschlag nicht mehr wirklich viele wirklich nicht-funktionale Anforderungen übrig. Einige Beispiele dafür, wie ich einteilen würde:
Backup: Eine funktionale Anforderung. Es lassen sich Zustände und Trigger definieren.
Documentation: Weder eine funktionale noch eine nicht-funktionale Anforderung, da keine Verhaltensanforderung. Eine “sich-nicht-verhaltende” Anforderung.
Fault tolerance: Eine funktionale Anforderung. Es lassen sich Zustände und Trigger definieren.
Testability: Eine sich-nicht-verhaltende Anforderung. Quellcode ist testbar oder nicht. Mit dem Laufzeitverhalten hat das nichts zu tun.
Was sich ergibt, sind also drei Anforderungsbereiche:
Funktionale Anforderungen
Nicht-funktionale Anforderungen
Sich-nicht-verhaltende Anforderungen
Für die Erfüllung von Anforderungen in diesen Bereichen sind relevant:
Logik: funktionale Anforderungen und einige nicht-funktionale Anforderungen
Verteilung: einige nicht-funktionale Anforderungen (s. dazu auch hier Anforderungen entwicklungsgerecht kategorisieren)
Artefakte: sich-nicht-verhaltende Anforderungen; sie werden erfüllt durch Inhalt und Struktur von Einträgen im Repository eines Softwaresystems
Ich fühle mich mit meiner Reduktion von funktionalen Anforderungen auf Zustandsveränderungen sehr wohl. Sie schafft mir mehr Klarheit in der Anforderungsanalyse. Weniger hand-waving und Du-weißt-schon-was-ich-meine.