1. Dezember 2012
AIM: mein erstes Projekt — ein Webservice, den Handcode-Entwickler wirklich nutzten
Das Enterprise-Architect-Reverse-Modell half der Vorentwicklung, aber Serien-Handcode-Entwickler empfanden es als zusätzlichen Pflegeaufwand. AUTOSAR 3.1.4 bildete Schnittstellen nur flach ab und passte nicht zu handcode-typischen Strukturen (verschachtelte Structs, Pointer).
Einen einfachen, webbasierten Service schaffen, mit dem Handcode-Entwickler ihre Schnittstellen selbst pflegen, versioniert vergleichen und daraus automatisiert konforme Header-Dateien generieren können — mit sofortigem Mehrwert statt zusätzlichem Prozessaufwand.
AIM (Architecture and Interface Manager): ein Django-Webservice (WebForm + REST-API, LDAP-Auth) für ~40–50 SWCs mit Schnittstellensuche, versioniertem Diff, konformer Header-Generierung und Testbett-Anbindung. Der einmalige Header-Import wurde zugleich zum Compliance-Audit für den Kunden; nach gut einem Jahr produktiv, später Pflicht im Handcode-Prozess und an die CI/CD-Pipeline angebunden.
Das hier war mein Leuchtturm: die erste echte Projektverantwortung meiner Laufbahn — technisch, fachlich und personell. Und sie begann mit einer unbequemen Wahrheit: Wir bekamen drei Monate, um eine Idee zu beweisen, für die uns die wichtigsten Fähigkeiten noch fehlten.
Ausgangslage: ein Modell, das die Serie nicht erreichte
Das Enterprise-Architect-Modell aus dem RDU3/RDU4-Projekt hatte einen Nerv getroffen — aber nur bei der Vorentwicklung. Bei den Serien-Handcode-Entwicklern kam etwas anderes an: Ein Architekturmodell muss kontinuierlich gepflegt werden, und dieser „jemand” waren am Ende wir zu zweit. Der Bedarf war trotzdem real — gerade in der C-Handcode-Welt, wo Schnittstellen kaum zugänglich und noch schwerer pflegbar waren.
Warum AUTOSAR für den Handcode nicht reichte
AUTOSAR existierte, und Daimler betrieb dafür sogar ein weltweit eingesetztes Werkzeug. Nur: Auch das war den Handcode-Entwicklern zu schwer für den Alltag. Ihr Kopf steckte woanders — in Sensordatenfusion, Fahrdynamik-Regelung, den harten Prozessauflagen der Serie.
Dazu kam eine harte technische Grenze der damaligen AUTOSAR-Version 3.1.4: Schnittstellen ließen sich nur flach abbilden. Structs ja — aber nur eine Hierarchieebene; verschachtelte Structs oder Pointer waren nicht darstellbar. Das hatte einen guten Grund: Eine AUTOSAR-SWC ist verschiebbar zwischen Steuergeräten, und ein Pointer ist eine feste Speicheradresse — auf einer verschiebbaren Komponente ergibt das keinen Sinn. Handcode dagegen war eng aufs jeweilige Target optimiert.
Man konnte die Entwickler zwingen, sofort auf den Standard umzustellen — oder man konnte sie dort abholen, wo sie standen. Wir entschieden uns für Letzteres.
Die Idee: ein Werkzeug in der Sprache der Entwickler
Ein teures, mächtiges Kommerzwerkzeug hat einen unterschätzten Nachteil: Man wird erschlagen von Möglichkeiten, Schaltflächen, Begriffen. Eine Individualentwicklung, die exakt auf die Bedürfnisse eines Kunden zielt, fühlt sich völlig anders an — schlank, verständlich, sofort nützlich. Genau das wollten wir bauen: kein weiteres Architektur-Framework, sondern einen Webservice, fokussiert auf C-Header und Schnittstellen. So entstand AIM — Architecture and Interface Manager.
Der Fokus lag bewusst auf der Provided-Seite des einzelnen SWC-Entwicklers, nicht auf der Required-Seite. Architektonisch nicht perfekt — jeder konnte weiter per #include alles ziehen. Aber genau dort war der Bedarf, und irgendwo fängt man an.
Was AIM konnte
Entwickler pflegten ihre Schnittstellen auf zwei Wegen: über die WebForm des Services oder über die REST-API (Django REST Framework). Die Authentifizierung lief über LDAP, und über das Django-interne User-Management konnten wir API-Tokens ausgeben — so ließ sich AIM auch von anderen Werkzeugen automatisiert ansprechen.
AUTOSAR im Hintergrund: wie AIMs Datenmodell entstand
An der Oberfläche blieb AIM bewusst C-vertraut: eine SWC war ein Ordner, ein Interface eine Header-Datei, ein struct ein Record Type. Eine SWC durfte an ihrer Provided-Seite mehrere Header anbieten, und Header hatten gerichtete Beziehungen zueinander — die nicht rekursiv sein durften (keine Zyklen). Unter der Haube aber orientierten wir uns von Anfang an am AUTOSAR-Standard (Standard- und vor allem Implementation Data Types), um eine spätere Migration in die AUTOSAR-Welt vorzubereiten. Rückblickend war AIM ein Werkzeug zur stufenweisen Transition dorthin.
| C-Welt (vertraut) | AUTOSAR-Konzept |
|---|---|
| Ordner | Software-Komponente (SWC) |
| Header-Datei | (Provided) Interface |
struct | Record Type |
primitiver Typ (uint16) | StdType / Implementation Data Type |
| Array | homogene Liste (Array Type) |
| Pointer | Data Reference (in ISO 26262 nur restriktiv) |
| — | Type Reference · Union Type |
Der eigentliche Kern von AIM war die Verwaltung der Datentypen. Und hier lag die Knacknuss: Der AUTOSAR-Standard liest sich wie UML-Klassen mit Vererbung und zielt auf XML-Generierung. Eine relationale Datenbank kennt aber keine Vererbung, und eine Django-models-Klasse erbt anders, als es die klassische OOP lehrt. Die elegante Lösung war django-polymorphic:
from django.db import models
from polymorphic.models import PolymorphicModel
class AutosarDataType(PolymorphicModel):
"""Basistyp — liest sich wie eine UML-Basisklasse."""
name = models.CharField(max_length=128, unique=True)
class PrimitiveType(AutosarDataType): # StdType, z. B. uint16
base_type = models.CharField(max_length=32) # uint8/uint16/…
bit_size = models.PositiveSmallIntegerField()
class RecordType(AutosarDataType): # C-struct → Record Type
pass # Felder über RecordMember (geordnet)
class RecordMember(models.Model):
record = models.ForeignKey(RecordType, related_name="members", on_delete=models.CASCADE)
member_type = models.ForeignKey(AutosarDataType, on_delete=models.PROTECT, related_name="+")
name = models.CharField(max_length=128)
position = models.PositiveSmallIntegerField()
class ArrayType(AutosarDataType): # homogene Liste
element_type = models.ForeignKey(AutosarDataType, on_delete=models.PROTECT, related_name="+")
length = models.PositiveIntegerField()
class TypeReference(AutosarDataType): # Referenz auf einen Typ
target = models.ForeignKey(AutosarDataType, on_delete=models.PROTECT, related_name="+")
class DataReference(AutosarDataType): # Pointer — ISO 26262: restriktiv
points_to = models.ForeignKey(AutosarDataType, on_delete=models.PROTECT, related_name="+")
class UnionType(AutosarDataType): # Union
variants = models.ManyToManyField(AutosarDataType, related_name="+")
Weil member_type, element_type & Co. immer auf den Basistyp AutosarDataType zeigen, kann ein Record jeden Typ enthalten — auch einen weiteren Record oder ein Array. Verschachtelte und gemischte Konstrukte (etwa ein Array eines Record Types) ergeben sich damit von selbst. Und der Clou von django-polymorphic: AutosarDataType.objects.all() liefert jedes Objekt direkt als seinen konkreten Subtyp zurück — im Code liest sich alles wie normale Vererbung.
Dass wir uns so früh am Standard orientierten, zahlte sich aus: Später erzeugte ein Feature aus AIM heraus ARXML — das AUTOSAR-XML — und ebnete damit den Weg in die AUTOSAR-Welt. Und es gab sogar einen in Enterprise Architect gepflegten AUTOSAR-Modellierungsleitfaden, der vorgab, wie ein an AUTOSAR angelehntes Werkzeug zu designen ist — eine wertvolle Orientierung.
Der Import, der heimlich zum Compliance-Audit wurde
Ein Detail, auf das ich bis heute stolz bin: Bevor AIM in Betrieb gehen konnte, mussten die bestehenden Header aller relevanten Schnittstellen hinein. Also schrieben wir ein einmaliges Import-Werkzeug („one shot”). Und dieses Tool tat mehr als importieren — es prüfte jede Header-Datei gegen die Kodierrichtlinien des Kunden.
Was dabei herauskam, war unerwartet wertvoll: Statt still zu scheitern, erzeugte der Import bei jedem Verstoß (nicht eingehaltene Kodierstandards, ungültige Konstrukte, nicht-konforme Elemente) ein Reporting an Daimler — eine ehrliche Momentaufnahme, wie konform die Schnittstellen der einzelnen Entwickler tatsächlich waren. Aus einem technischen Importer wurde so ein Compliance-Instrument. Erst als alle Header konform waren, wurden sie übernommen und AIM ging live.
Technik-Box: Wie eine Datenbank-Migration wirklich funktioniert
Ein Punkt, den viele unterschätzen — und den ich hier zum ersten Mal richtig lernte. In Django beschreibst du deine Daten als Python-models. Änderst du ein Modell (Feld hinzufügen, Typ ändern, Feld aufteilen), passiert Folgendes:
makemigrationserzeugt eine nummerierte, geordnete Migrations-Datei mit den nötigen Schema-Operationen (AddField,AlterField, …).migratewendet die offenen Migrationen auf die Datenbank an.
Der entscheidende Unterschied, den man erst in Produktion schmerzhaft merkt:
- Schema-Migration ändert die Struktur (Spalten, Typen). Django generiert sie automatisch. Auf einer leeren Entwickler-Datenbank ist damit alles getan.
- Datenmigration transformiert die vorhandenen Zeilen. Die schreibt man selbst — als
RunPython-Schritt in derselben Migrations-Datei (vorwärts und rückwärts, damit sie reversibel bleibt). Beispiel: einen alten Datentyp umrechnen, ein Feld in zwei aufteilen, eine neue Pflichtspalte sinnvoll befüllen.
Der schwierige Start: drei Monate, ohne die Skills
Und hier kommt der ehrliche Teil. Mein Gesamtprojektleiter Harald Braun war Python-Enthusiast und hatte kurz zuvor Django für sich entdeckt. Ich bekam meine ersten beiden Mitarbeiter — darunter Marc Hirth — und wurde als kleiner technischer Projektleiter eingesetzt. Für mich war das ein Riesending: das erste Mal Verantwortung für Umsetzung, Personal, Kundenkontakt und Regelmeetings.
Nur: Wir waren keine Webentwickler. Django, Datenbanken, JavaScript, LDAP-Auth, Webserver — alles Neuland. Und wir hatten drei Monate Zeit, um mit einem Mockup zu beweisen, dass die Idee trägt, gegen echten Zeitdruck und den brennenden Wunsch, erfolgreich zu sein. Diese Anfangsphase war mit Abstand die härteste. Ich erinnere mich an unzählige Stunden Pair Programming mit Marc — Seite an Seite ausprobiert, wie man eine VM bestellt, Apache installiert, Firewall-Regeln freischaltet. Zwischen uns entstand eine Symbiose: Ich konnte tagelang weg sein und beim Zurückkommen sofort verstehen, was entstanden war — und umgekehrt.
Der erste, zugegeben etwas hässliche Prototyp überzeugte die Verantwortlichen auf Kundenseite. Und danach lief es — ehrlich gesagt — richtig gut.
Scrum, wie wir ihn wirklich gelebt haben
Prozesstechnisch war AIM mein Einstieg in Scrum und das agile Manifest, nach Jahren im Wasserfall. Ich machte meine Scrum-Master-Zertifizierung, setzte mein erstes Product Backlog auf und etablierte Requirements Engineering im Projekt.
Aber „nach Lehrbuch” war das nicht — und genau das ist die ehrliche Lektion:
Das eigentliche Aha war nicht die Methode, sondern der Rhythmus: alle zwei Wochen liefern statt nach Monaten. Kontinuierlich entwickeln und verbessern, bei jeder neuen Anforderung Aufwand gegen Nutzen abwägen — und sich an die Gegebenheiten anpassen, statt an einem alten Plan festzuhalten. Selbst Sprints, in denen wir Redesigns machten, akzeptierte der Kunde, weil am Ende jeder zwei Wochen ein greifbarer neuer Stand stand. Und ich glaube, dem Kunden gefiel besonders, dass sein eigenes Wissen mit dem Produkt zusammen wuchs — ein Vorteil, den kein fertiges Kommerzwerkzeug bietet.
Von Akzeptanz zu Pflicht — und in die Pipeline
In einer dreimonatigen Rollout-Phase machte ich die Handcode-Entwickler teils persönlich mit AIM vertraut. Kundenseitig wurde zunehmend eingefordert, Schnittstellen nur noch über AIM zu verwalten — der Umstieg wurde sogar getrackt. Wir krempelten gemeinsam den gesamten Handcode-Schnittstellenprozess um. AIM sollte laut Plan Teil der CI/CD-Pipelines werden — auch das erreichten wir, und mit den Pipeline-Ingenieuren setzten wir für AIM selbst einen Jenkins auf: automatisierte Unit-Tests, C0/C1-Testabdeckung von mindestens 80 %.
Nach der Embedded-Welt war dieses Tempo eine Offenbarung — externe Libraries, Staging-Umgebungen (lokal, Dev-VM, QM-VM, Produktiv), ein Wartungsfenster und zwei Stunden später geht’s weiter. Ich fing an, Open Source und die Ideen dahinter viel besser zu verstehen. Am Ende betreute AIM die Schnittstellen von rund 40–50 SWCs — ein Werkzeug, das wirklich benutzt wurde.
Wachstum verändert Dynamik
Mit dem Erfolg wuchs das Team — und mit dem Wachstum änderte sich die Dynamik. Was vorher eine eingespielte kleine Gruppe auf Augenhöhe war, wurde komplexer; etablierte Entscheidungen standen wieder zur Debatte. Mir fehlte damals schlicht das Handwerkszeug, so eine Dynamik konstruktiv zu moderieren — Konfliktmoderation lernt man nicht nebenbei. Aus einem Zustand, in dem ich fast täglich mit Energie zur Arbeit ging, wurde eine Belastung, und ich bat darum, das Projekt zu übergeben.
Nach außen liest sich der nächste Schritt schöner — „mehr Verantwortung nach dem AIM-Erfolg”, und das stimmt auch: Ich übernahm danach als Scrum Master und stellvertretender Projektleiter ein 8–13-köpfiges Team im ESP-Längsregler-Projekt. Aber ehrlich ist auch: Der Auslöser war eine Teamdynamik, die ich damals nicht steuern konnte. Meine Lektion — bis heute gültig: Ein wachsendes Team ist nicht automatisch ein besseres. Wachstum verändert Dynamiken, und Führung heißt, das aktiv zu gestalten. Das musste ich erst lernen.
Was ich mitgenommen habe
AIM war meine erste echte Führungsrolle — technisch, fachlich, personell. Drei Dinge sind geblieben:
- Nähe schlägt Eleganz. Ein Service, der wirklich genutzt wird, entsteht näher an den Menschen, die ihn brauchen, als an der schönsten Architektur.
- Rhythmus schlägt Plan. Alle zwei Wochen etwas Greifbares liefern verändert alles — für das Team und für das Vertrauen des Kunden.
- Python & Django wurden eine Kompetenzlinie, die mich bis heute begleitet — Jahre bevor ich sie bei Bosch im WARP-Projekt wieder aufgriff.
Danke
Herzlichen Dank an Marc Hirth, meinen engsten Weggefährten bei AIM — für unzählige Stunden Pair Programming und die beste Symbiose, die ich in einem Team erlebt habe.
Herzlichen Dank auch an Harald Braun — für das Vertrauen und die Unterstützung während des AIM-Projekts und über meine gesamte Elektrobit-Zeit hinweg. Gerade mit AIM konnte ich dadurch wachsen wie nie zuvor.