Bei Code-Generierung denken viele an eine automatisierte und daher schnelle Erzeugung von bereits implizit qualitätsgesichertem Code.
Diese Hoffnungen werden nicht immer erfüllt. Trotzdem bieten Code-Generatoren Vorteile speziell für Hersteller in regulierten Branchen wie die der Medizinprodukte.
1. Einführung in die Code-Generierung
a) Was versteht man unter Code-Generierung?
Ein Code-Generator ist ein Softwareprogramm, das den Quellcode in einer gewählten Programmiersprache erzeugt aus
- Modellen (z. B. UML, SysML),
- einer anderen formalen Sprache (XML, Domain Specific Language) oder
- anderen Formaten (z. B. Entscheidungstabellen).
Das folgende Beispiel zeigt ein Modell und den daraus generierten Quellcode.
Aus solch einem Modell erzeugt ein Code-Generator folgenden Quellcode:
b) Wo setzt man Code-Generatoren ein?
Code-Generatoren kommen v. a. dann zum Einsatz, wenn Boiler-Plate-Code erzeugt werden muss oder sich die Funktionsweise des Codes gut in einem Modell beschreiben lässt.
Datenbankzugriff
Viele Entwicklungsframeworks bieten Code-Generatoren an, z. B. Ruby on Rails.
Besonders beim Zugriff auf Datenbanken haben sich Code-Generatoren bewährt, die für ein gegebenes Datenbank-Schema die Zugriffsklassen für die üblichen CRUD-Operationen erzeugen oder für gegebene Geschäftsklassen den Code zur Datenspeicherung (Persistenz) und für die entsprechenden DDL-Befehle schreiben.
Stubs und Skeletons
Bei verteilten Systemen müssen Daten serialisiert bzw. deserialisiert werden, z. B. von Objekten nach JSON, XML oder proprietären Binärformaten bzw. umgekehrt. Auch ein solcher Code lässt sich in vielen Fällen vollständig erzeugen.
Signalverarbeitung
Bei der elektronischen Signalverarbeitung entwickeln viele Firmen die Komponenten zuerst mit Hilfe von Simulationswerkzeugen wie MATLAB/Simulink. Nach der erfolgreichen Verifizierung besteht der nächste Entwicklungsschritt darin, diese Lösungen in Hardware oder/und Software zu realisieren.
Im Fall von Software liegt der Gedanke nah, den Quellcode direkt aus dem Modell im Simulationswerkzeug zu generieren. In der Tat bieten deren Hersteller oft entsprechende Möglichkeiten.
Falls diese Möglichkeiten nicht ausreichen, bleibt den Entwicklern noch der Weg, einen eigenen (besseren) Code-Generator zu entwickeln. Solch ein Code-Generator nutzt dann entweder eine API des Simulationswerkzeugs oder liest die Modelldateien ein, die dieses Tool erzeugt.
c) Welchen Nutzen verspricht die Code-Generierung?
Viele Vorteile der Code-Generierung liegen auf der Hand, andere sind weniger offensichtlich, und wieder andere erfüllen sich in der Praxis nicht:
- Höhere Geschwindigkeit bei der (Weiter-)Entwicklung der Software
Code-Generatoren können Hunderttausende Zeilen Code pro Tag erzeugen und sind damit jedem Entwickler haushoch überlegen. Allerdings verschieben diese Generatoren die Entwicklung von der Programmierung zur Modellierung.
Die Pflege von Modellen ist oft einfacher als die Pflege von Quellcode, da Modelle einen schnelleren Überblick erlauben und unabhängiger vom „Programmierstil“ des Einzelnen sind.
Besonders bei Hardware-nahem Code wie in der Mess- und Regeltechnik beschleunigt die Verknüpfung von Modellierung und Simulation die Entwicklung nennenswert. Der Großteil des Designs erfolgt anhand von „Digital Twins“ und erspart die aufwendige Entwicklung vieler Hardware-Prototypen. - Besserer Code
Modelle erlauben formale Prüfungen, z. B. von deren Konsistenz und der Einhaltung von Constraints.
Zudem unterlaufen Code-Generatoren keine Flüchtigkeitsfehler. Sie können Code erzeugen, der übliche Codier-Richtlinien automatisiert einhält.
Der generierte Code und damit dessen Architektur ist konsistent und idealerweise bereits durch den Code-Generator qualitätsgesichert. - Einfachere regulatorische Compliance
Eine regulatorische Anforderung (z. B. MDR Anhang II, IEC 62304 Kapitel 5.3) besteht darin, dass Hersteller die Software-Architektur beschreiben und verifizieren müssen. Die Modelle entsprechen bereits dieser Dokumentation.
Sie lassen sich zudem besser formal verifizieren, als das bei text- bzw. dokumentenorientierten Architekturbeschreibungen möglich ist. Die IEC 62304 fordert die Verifizierung der Software-Architektur.
Zudem verlangt die IEC 62304 in Kapitel 5.5, dass der Hersteller prüfen muss, ob der Software-Code die Architektur umsetzt. Das ist bei generiertem Code automatisch der Fall. - Höhere Zukunftsfähigkeit
Programmiersprachen entwickeln sich ständig weiter. Dies erfordert regelmäßige Wartungsprojekte, um die Kompatibilität der Software mit neuen bzw. „deprecated“ APIs und Sprachkonstrukten zu gewährleisten und damit dem Stand der Technik zu entsprechen.
Bei generiertem Code ist „nur“ die Anpassung des Code-Generators notwendig, aber nicht die Anpassung der ganzen Software-Anwendungen.
Hersteller, die Modelle verwenden, haben langfristig die Möglichkeit, auf die Code-Generierung zu verzichten und die Modelle in entsprechenden Laufzeitumgebungen auszuführen.
2. Regulatorische Anforderungen an die Code-Generierung
a) Anforderungen der ISO 13485
Die ISO 13485 verpflichtet die Hersteller zur
- „Validierung der Anwendung der Computersoftware im Qualitätsmanagementsystem“ (Computerized Systems Validation) und
- „Validierung von Prozessen zur Produktion- und Dienstleistungserbringung“ einschließlich „Qualifizierung der Ausrüstung“ und Validierung der dazu eingesetzten Software.
Damit unterliegen Code-Generatoren der Validierungspflicht.
Lesen Sie im Fachartikel zur Computerized Systems Validation, wie Sie diese Pflicht effizient und normenkonform erfüllen. Beachten Sie, dass sich die Software-Validierung nicht auf die Prüfung der entwickelten Software (als Blackbox) beschränkt. Mehr zu den verschiedenen Definitionen des Begriffs Validierung erfahren Sie im Video zur Verifizierung und Validierung.
b) Anforderungen der IEC 62304
Hersteller haben zwei Möglichkeiten, den generierten Code aus Sicht der IEC 62304 zu behandeln:
- Der generierte Code wird den gleichen Maßnahmen zur Qualitätssicherung unterworfen wie handgeschriebener Code. Auf bestimmte Aktivitäten, wie die statische Code-Analyse oder Code-Reviews, kann ggf. verzichtet werden.
- Der generierte Code wird als SOUP (Software of Unknown Provenance) klassifiziert. Damit müssten Hersteller die SOUP-Anforderungen (u. a. im Kapitel 5.3) erfüllen.
Achtung: Auf Medizinprodukte, die in den USA vertrieben werden, ist der SOUP-Ansatz nicht direkt übertragbar, da die FDA das Konzept von OTS (Off-the-Shelf Software) kennt. Eigenentwickelter bzw. selbst-generierter Code fällt aber nicht darunter. Lesen Sie hier mehr zu den Gemeinsamkeiten und Unterschieden von SOUP und OTS, um Probleme bei Audits und Inspektionen zu vermeiden.
3. Herausforderungen bei der Code-Generierung
Hersteller, die Software mit Hilfe von Code-Generatoren erzeugen wollen, müssen einige Herausforderungen bewältigen. Wie das gelingen kann, zeigt dieses Kapitel.
a) Regulatorische Anforderungen
Dass die Hersteller die o. g. regulatorischen Anforderungen erfüllen müssen, ist offensichtlich. Hierzu ist es wichtig, frühzeitig eine Strategie festzulegen, wie die Qualität des Code-Generators und des erzeugten Codes erreicht und nachgewiesen werden soll.
Dabei sollten Hersteller auf das Folgende achten:
- Entscheiden, ob der erzeugte Code als SOUP betrachtet wird
- Im Entwicklungsplan des Medizinprodukts die Verifizierung des Modells festlegen
- Im Entwicklungsplan des Medizinprodukts die Verifizierung des erzeugten Codes festlegen
- Die Anforderungen des Code-Generators vor dessen Entwicklung spezifizieren
- Die Architektur des Code-Generators beschreiben
- Die Software des Code-Generators verifizieren, z. B. durch Code-Reviews, statische Code-Analyse, Unit-, Integrations- und Systemtests
- Diese qualitätssichernden Maßnahmen vor (!) Entwicklung des Code-Generators festlegen
Hinweis: Zum Zeitpunkt der Entwicklung des Code-Generators steht oft noch nicht fest, bei welchen Medizinprodukte-Projekten er zum Einsatz kommen wird. Daher ist eine risikobasierte Entwicklung schwierig. Die Entwicklung sollte also mindestens den gleichen Anforderungen genügen wie die Entwicklung von (kritischen) Medizinprodukten.
b) Aufwand zur Erstellung und Qualitätssicherung
Nicht nur die regulatorischen Anforderungen führen zu einem nennenswerten Aufwand bei der Entwicklung von Code-Generatoren. Dieser rechnet sich meist nur, wenn ein Generator in mehreren Projekten (mehrere Produkte, mehrere Versionen eines Produkts) zum Einsatz kommt.
Gegebenenfalls fallen neben der Arbeitszeit noch Lizenzkosten an.
c) Make or Buy?
Daher sollten Hersteller immer auch den Kauf bestehender Lösungen in Betracht ziehen. Bei der Make-or-Buy-Entscheidung und bei der Entscheidung zwischen mehreren (kommerziellen) Produkten helfen die folgenden Kriterien:
- Passgenauigkeit der funktionalen Anforderungen, z. B. bezüglich Einsatzgebiet, Modellierungssprache und Zielsprache (Programmiersprache)
- Güte des erzeugten Codes (z. B. Konformität mit Codier-Richtlinien)
- Entstehende Abhängigkeit vom Hersteller des Code-Generators
- Preis des Code-Generators
- Güte der Anwenderdokumentation
- Möglichkeit, die Güte des Code-Generators und der zugehörigen Entwicklungsprozesse zu bewerten, z. B. anhand von Entwicklungsdokumenten oder Lieferantenaudits
- Verfügbarkeit und Güte des Supports für den jeweiligen Code-Generator
- Erfüllung nicht-funktionaler Anforderungen wie Geschwindigkeit, Stabilität, Hardware-Voraussetzungen, Betriebssystem.
d) Entwicklung eines Code-Generators
Wenn sich ein Hersteller entscheidet, einen Code-Generator selbst zu entwickeln, muss er nicht nur in der Lage sein, die Aufwände dafür zu tragen. Der Hersteller muss auch den Herausforderungen der Software-Entwicklung begegnen und diese umsetzen können.
Wahl der Beschreibungssprache
Es ist entscheidend, eine Beschreibungssprache (z. B. UML) zu wählen, die sich eignet, um die jeweilige Domäne zu modellieren. Die Notationen unterscheiden sich bei flowbasierter und zustandsbasierter Softwareentwicklung. Die Generierung von Software für die Batch-Verarbeitung unterscheidet sich von der kontinuierlichen Verarbeitung.
Validierung von Modellen
Es wäre hilfreich, wenn der Code-Generator automatisch Inkonsistenzen und den Verstoß gegen Vorgaben und Constraints bemerken und so die Modelle validieren könnte. Das bedingt, dass diese Vorgaben und Constraints formal beschrieben werden können.
Balance von Komplexität und Leistungsfähigkeit
Je komplexer die Modelle sind, die der Code-Generator zu erstellen erlaubt, desto schwieriger wird nicht nur seine Entwicklung, sondern auch seine Nutzung.
Einige Firmen erlauben, Modelle durch Skripte zu ergänzen, und versuchen so eine Balance zu erreichen. Damit beginnt aber eine Verlagerung der Software-Entwicklung in der Zielumgebung zu einer Software-Entwicklung in der Modellierungsumgebung. Das wiederum ist verbunden mit allen regulatorischen Herausforderungen und Anforderungen an die Qualitätssicherung von Modellen und Skripten.
Synchronisation von Modell und generiertem Code
Wenn das Modell es nicht erlaubt, den Code vollständig zu generieren, müssen die Entwickler in der „Zielsoftware“ Ergänzungen vornehmen. Solche Bereiche müssen davor geschützt werden, bei einer Überarbeitung des Modells überschrieben zu werden.
Änderungen des Modells können dennoch dazu führen, dass der ergänzte Code im schlechtesten Fall nicht einmal mehr kompiliert. Das bedeutet, dass die Zielsoftware – die generierte und manuell ergänzte Software – einer vollständigen Qualitätssicherung unterliegen muss.
In jedem Fall sollten Hersteller auch für den generierten Code ein Versionskontrollsystem verwenden.
e) Überkomplexe Modelle
Meist nutzen die grafischen Modellierungswerkzeuge eine hierarchische Darstellung. Dadurch erscheinen die Modelle bzw. Modellausschnitte weniger komplex, als sie es tatsächlich sind. Der generierte Code hingegen ist oft so komplex, dass eine sinnvolle Qualitätssicherung durch Code-Reviews und Software-Unit-Tests nur schwer möglich ist.
Hierarchische Strukturen sind nicht notwendigerweise modulare Strukturen. Ein komponentenorientiertes Design ist aber die Voraussetzung für die
- Wartbarkeit,
- Wiederverwendbarkeit,
- Testbarkeit und
- Austauschbarkeit von Software-Komponenten.
Prof. Johner diskutiert in dieser Episode mit Matthias van der Staay, wann sich der Einsatz von Code-Generatoren bei Medizinprodukten rentiert, welche regulatorischen Rahmenbedingungen dabei zu beachten sind und wie Hersteller diese erfüllen können, um Ärger im Audit zu vermeiden. Matthias van der Staay berichtet von seiner Erfahrung als ein Hersteller und als ein Anwender solcher Code-Generatoren.
Diese und weitere Podcast-Episoden finden Sie auch hier.
4. Fazit
a) An der modellbasierten Entwicklung führt kein Weg vorbei …
Die Code-Generierung aus Modellen hat ähnlich wie die künstliche Intelligenz (KI) schon viele Sommer der Begeisterung und Winter der Ernüchterung erlebt. Es besteht jedoch kein Zweifel daran, dass viele Firmen auf Dauer den Anschluss verlieren, wenn sie sich der Code-Generierung gänzlich verweigern.
- Die Entwicklungsgeschwindigkeit nimmt dank des Einsatzes von „Digital Twins“ weiter zu. Die Code-Generierung ist die ideale Ergänzung.
- Der Fachkräftemangel wird auch bei Software-Entwickler:innen immer deutlicher. Daher ist es wichtig, auch deren Arbeit durch Automatisierung zu unterstützen.
- Die Entwicklungszyklen von Produkten werden immer kürzer. Treiber sind neue technische Möglichkeiten, höhere Kundenanforderungen und agile Vorgehensmodelle. Bei vielen iterativen Änderungen von Produkten sind die Automatisierung und damit die Code-Generierung besonders wirtschaftlich.
Es ist zu vermuten, dass in Zukunft in vielen Anwendungsbereichen direkt ausführbare Modelle den Code-Generatoren den Rang ablaufen werden.
b) … aber “a fool with a tool is still a fool”
Entwicklung und Einsatz von Code-Generatoren erfordern besonders hoch qualifizierte Expert:innen. Die Anforderungen an die Abstraktionsfähigkeit sind regelmäßig höher als in anderen Software-Projekten.
Ein noch so leistungsfähiger Code-Generator ersetzt weder die Fähigkeit, Modelle zu erstellen, noch jene Produktstrategien zu erarbeiten. Wer die Kundenanforderungen nicht systematisch erhebt, wird dies mit der Code-Generierung bestenfalls nur schneller feststellen.
c) Eine Abwägung ist notwendig
Firmen müssen wesentliche Entscheidungen treffen:
- Wollen Sie Code-Generatoren einsetzen?
- Für welche Produkte, Projekte und Komponenten?
- Sollen Sie einen Code-Generator entwickeln oder lizenzieren?
Es gibt keine allgemeingültigen Antworten. Lassen Sie sich für Ihren konkreten Anwendungsfall von Personen beraten, die damit Erfahrungen gesammelt haben. Das Team des Johner Instituts vermittelt gerne entsprechende Kontakte.
Beachten Sie auch den Podcast zum Thema Code-Generierung mit Matthias van der Staay. Er hat wichtigen Input zu diesem Artikel geliefert. Sein Arbeitgeber, die Firma IMT, setzt Code-Generatoren bei der Entwicklung von Medizinprodukten ein und bietet solche Code-Generatoren auch kommerziell an. Wenden Sie sich bei Fragen an Herrn van der Staay.
Ein wirklich interessanter Artikel über Code-Generierung! Die klare Erklärung und die praxisnahen Beispiele machen komplexe Themen verständlich. Besonders toll fand ich die Einbindung von Podcasts und die Expertenmeinungen, die dem Ganzen eine persönliche Note verleihen. Der Fokus auf regulatorische Anforderungen zeigt, dass der Artikel nicht nur informativ, sondern auch praxisrelevant ist. Weiter so!