

Wir beschreiten seit einigen Jahren den Weg von „Wir machen Embedded C++“ zu „Wir verstehen Embedded C++“. Dabei begegnen uns regelmäßig Stolpersteine auf unserem Weg, die sich bisher nach und nach in Wohlgefallen auflösten. In diesem Artikel möchte ich unsere Erfahrungen teilen und Ihnen Lust auf modulares Architekturdesign und Denken in Modulen machen.
Als wir 2017 unsere Vorgehensweise in der Embedded-Software-Entwicklung umgekrempelt haben, gab es noch keine Library für das tägliche Brot im Embedded-Bereich. Daher mussten wir fast alles selbst machen.
Seitdem stellen wir uns vor der Implementierung einer Aufgabe folgende Fragen:
Warum stellen wir uns diese Fragen?
In den letzten Jahren haben sich intern immer wieder unterschiedliche Trends abgezeichnet, die es zu kontrollieren galt. Zum Beispiel gab es eine Zeit, in der das Implementer-Pattern Teil jedes zweiten Lösungsansatzes war. Mit diesen vier einfach zu stellenden Fragen versuchen wir Module für uns zu schaffen, die sinnhaft sind. Sinnhaft, weil sie nicht die Standard Library nachimplementieren, an anderen Stellen wiederverwendet werden können und möglichst effizient sowie Embedded-tauglich umgesetzt sind. Das alles hat unser Vorgehen erst einmal auf den Kopf gestellt und dann neu geordnet. Die Wertigkeit, Robustheit und Verständlichkeit von Entwicklungsergebnissen ist spürbar gestiegen. Auch unsere Kunden danken es uns.
Über Architektur kann man streiten – und das ist auch gut so. Ich glaube daran, dass jede konstruktive Diskussion, auch wenn sie teilweise hitzig ist, früher oder später einen Sprung an Source-Code-Professionalität nach sich zieht.
Ob eine Architektur auch verständlich und nutzerorientiert ist, zeigt sich erst, wenn Menschen damit arbeiten, die an der Entwicklung nicht beteiligt waren. In unserem Fall holen wir regelmäßig Feedback von unseren Kunden ein und fragen nach, inwieweit sie verstehen, was in dem Code passiert und wo sie welche Funktionalität vermuten. Noch eine Stufe tiefer gehen wir mit neuen Mitarbeitern, die noch eine externe Sichtweise haben und uns helfen können Strukturprobleme aufzulösen, die wir selbst nicht mehr sehen. Iterativ sind wir zu folgendem Zwischenergebnis gekommen: Architektur, die immer wieder für unsere Kunden und uns funktioniert, ist in den Basis-Layern immer gleich aufgebaut und damit generisch.
Unser Ziel ist es, kleine und verständliche Software-Module zu produzieren, die in unterschiedlichen Projekten und Anwendungsfällen eindeutig Mehrwert bieten und die man als Entwickler gerne wiederverwendet.
Soweit die Theorie. In der Praxis braucht es eine Philosophie und klare Regeln, nach denen entwickelt wird. Für mich hat sich herauskristallisiert, dass alle Module folgende vier Kriterien klar erfüllen müssen:
Als kleines Beispiel soll hier die Average-Klasse dienen. Die beiden statischen Funktionen der Klasse bilden einen buchhalterisch korrekten Mittelwert aus dem übergebenen Datenarray oder aus dem Inhalt eines Puffer-Objekts, der zum Beispiel ein Ringpuffer sein kann, und gibt diesen zurück. Buffer ist in diesem Beispiel ein Interface für alle Puffer-Implementierungen. Die Rechenoperationen in den beiden value()-Funktionen sind für Embedded optimiert.
Ich denke es ist klar, was man von der Klasse an Funktionalität erwarten kann und wie man sie verwendet. Was Sie jetzt nicht sehen, aber sicherlich vermuten, kann ich Ihnen versichern: Die Klasse ist leicht testbar und leicht wiederverwendbar.
Den ausführlichen Bericht mit Code-Beispielen, Erläuterungen und Lessons-Learned finden Sie hier als PDF:
Viele gute quergedachte Ideen wünscht Ihnen die
querdenker engineering