Software-Design für gute Codequalität, Teil 1 Embedded Code erfordert hohe Sorgfalt

Autor / Redakteur: Dr. Val Lynch und Steve Norman * / Sebastian Gerstl

Guter Code ist Code, der offensichtlich korrekt ist. Offensichtlich korrekter Code ist einfach lesbar, einfach zu warten und einfach überprüfbar. Wie erstellt man also guten Code?

Firmen zum Thema

Um guten, korrekten und sauber lesbaren Code zu generieren, ist vor allem gutes Design essentiell. Hier sind Kompetenz, Erfahrung und die Wertschätzung des künstlerischen Aspektes der Softwareentwicklung entscheidend.
Um guten, korrekten und sauber lesbaren Code zu generieren, ist vor allem gutes Design essentiell. Hier sind Kompetenz, Erfahrung und die Wertschätzung des künstlerischen Aspektes der Softwareentwicklung entscheidend.
(Bild: Renesas Electronics)

Um gutes Software-Design zu erreichen, bestimmen drei Definitionen das Umfeld:

Software-Architektur: Die Definition der Organisation eines Softwaresystems, das die Anforderungen erfüllen kann und Änderungen sowie eine zukünftige Wiederverwendung erlaubt.

Objekte: Code-Blöcke, die bestimmte Funktionen innerhalb der Software-Architektur ausführen. Objekte lassen sich kombinieren. Diese werden oft auch als Funktionen, Prozeduren oder Module bezeichnet. Die Benennung solcher Blöcke ist oft abhängig von der verwendeten Software-Sprache.

Software-Schnittstellen: Spezifikationen, die Definitionen darüber enthalten, wie ein Teil der Software-Architektur mit einem anderen verknüpft ist. Schnittstellen gibt es auf allen Ebenen der Architektur, zwischen einzelnen Code-Blöcken, zwischen diesen Blöcken und High-Level-Funktionen sowie zu externen Systemen oder Anwendern.

Die mit der Softwareentwicklung einhergehenden Herausforderungen sollten nie unterschätzt werden. Selbst das kleinste Detail von der genauen Benennung eines Objektes bis zur erforderlichen Zeit für die Ausführung einzelner Instruktionen spielt eine Rolle. Sorgfalt und Aufmerksamkeit für Details sind hier wesentlich.

Bildergalerie

Der wohl wichtigste Merksatz im Software-Design lautet: Es gibt kein Konzept, das universell passt. Fasst man jedoch alle relevanten Daten, Eingaben und Anforderungen zusammen und überprüft ihr Zusammenspiel, bildet dies die Grundlage für ein praktikables Konzept. Dieses muss vor allem das Geschäftsszenario für die Entwicklung erfüllen. In der Literatur gibt es reichlich Beispiele für Konzepte wie etwa Software-Pattern, die sich in solchen Fällen als besonders nutzbringend erwiesen haben. Sie bilden einen nützlichen Ansatzpunkt für den Aufbau einer Architektur.

Pattern beschreiben gängige Code-Merkmale wie Zustandsmaschinen, Model View Controller und Objekt-Observer. Ein nach einem bestimmten Pattern aufgebauter Code ist in der Regel einfacher nachzuverfolgen und zu validieren. Er lässt sich auch für eine Definition zum Aufbau von Code-Objekten nutzen. Pattern sollten allerdings nur verfolgt werden, solange dies angemessen ist. Letztendlich muss der Entwickler sicherstellen, dass der gesamte Code gut organisiert und klar verständlich ist. Nur dann kann er als offensichtlich richtig bewertet werden. Besondere Aufmerksamkeit ist dabei den Schnittstellen zwischen den verschiedenen Objekten zu widmen.

Ordentliche Dokumentation ist unverzichtbar

Nach gängiger Praxis ist stets zu berücksichtigen, welchen Zweck jede Schnittstelle hat und wie diese in die Gesamtarchitektur passt. Schnittstellen sollten schriftlich und klar in allen Entwicklern zugänglichen Dokumenten definiert werden. Vor einer Entscheidung über Details sind beide Seiten der Schnittstelle zu untersuchen. Dies gilt besonders, wenn der Code durch unterschiedliche Entwickler oder sogar verschiedene Unternehmen für beide Seiten zu schreiben ist.

Dokumentation ist oft das Stiefkind der Softwareentwicklung und etwas, wovor Entwickler zurückschrecken. Eine gut geschriebene Schnittstellen-Spezifikation kann aber viele Arbeitsstunden einsparen. Die Kunst der Schnittstellen-Entwicklung besteht darin, dass man sie so generisch wie möglich anlegt, ohne dass dabei Stabilität oder Zielsetzung verloren gehen. Nur dann bietet die Schnittstelle die Möglichkeit, von beiden Seiten aus erforderliche Änderungen vorzunehmen. Dabei ist vor allem sicherzustellen, dass der Code immer der Schnittstellen-Spezifikation folgt und nicht andersherum.

Die Entwicklung von Software für Mikrocontroller wie etwa der Renesas Synergy Plattform erfordert besondere Sorgfalt aufgrund der davon betroffenen Hardware-Schnittstellen. Jede Peripherieschaltung innerhalb des Mikrocontrollers ist so zu konfigurieren, dass sie die von der Software benötigten bzw. genutzten Daten liefern kann. Zudem müssen sämtliche nicht verwendeten Pins angesprochen werden. Betrachtet man jede dieser Peripherieschaltungen als Objekte innerhalb des Systems, dann lässt sich die Schnittstelle effektiv adressieren.

Bei der Sprach-Wahl sind Effizienz und Flexibilität wichtig

Die Wahl der Sprache für die Software-Erstellung wirkt sich auf das Software-Design aus. Die Entscheidung für eine dieser Optionen ist daher Teil der Architektur-Überlegungen, und sollte sich weniger danach richten, womit der Entwickler vertraut ist. Für einen Web-gestützten Einsatz ist Java sinnvoll. Bei manchen Anwendungen sind Skript-basierte Sprachen wie Python angemessen.

Für die meisten auf der Synergy-Plattform ausgeführten Embedded-Anwendungen empfiehlt sich eine Kodierung in C und C++. C++ bietet die nötige Flexibilität für den Umgang mit komplexen Architekturen, während es C erlaubt, kompakten und zielgerichteten Code zu schreiben, wenn Effizienz wichtig ist. Bei besonders anspruchsvollen Anwendungen mit eng definiertem Timing für einzelne Instruktionen sollte auch Assembler-Code in Betracht kommen.

Beim Einstieg in eine Design-Aufgabe entwickeln Ingenieure innovative Ideen, um das Beste bzw. wenigstens das Nächstbeste erstellen zu können. Die Ziele umfassen mehr Qualität, besseren Funktionsumfang oder einen günstigeren Preis. Dieser Prozess kann neue Methoden oder Techniken hervorbringen, doch besteht manchmal auch die Gefahr, dass die geleistete Entwicklungsarbeit frühere Ergebnisse wiederholt. In solchen Fällen scheint es nur, als ob „das Rad neu erfunden wurde“.

Wie bereits erwähnt, ist die Wiederverwendung oder eine Rekonfigurierung von Software eine gute Möglichkeit, das Beste aus einem Software-Investment zu machen. Meist trifft dies nur zu, wenn sich nachweisen lässt, dass sich die Software bewährt hat. Hier kommen drei weitere Definitionen ins Spiel:

COTS: Kommerzielle, einsatzbereite Hard- und Software-Komponenten (COTS - Commercial-off-the-Shelf), die sich in ein System einbinden lassen.

Bewährt (Proven): Getestet und verifiziert, um zu belegen, dass ein vorgegebener Standard erreicht wurde. Hier ist nachzuweisen, dass sich Hard- und Software-Komponenten bewährt haben.

Wert: Relativer Wert oder Nutzen einer Sache. Dies umfasst unter anderem den Geldwert. Gewonnenes Wissen, eingesparte Zeit, Qualität oder Erfahrung sind Beispiele für alternative Maßstäbe.

Das Code-Archiv nicht außer Acht lassen

Weiterhin ist noch ein anderer wichtiger Punkt zu beachten: Im Laufe jedes Projekts entsteht ein Archiv mit Code, Designs und Wissen. Dieses Archiv sollte am Ende des Projekts nicht außer Acht gelassen werden, da es darüber hinaus von Wert sein könnte.

Softwareentwickler generieren viel Wissen zu bestimmten Technologien und Strukturen, das auch für zukünftige Projekte nützlich sein kann. Bewährter Code ist eine Erweiterung dieses Wissens, wobei der Code (womöglich innerhalb eines Systems) bereits im Feld validiert wurde und für spätere Arbeiten nutzbar ist. Der Einsatz von bewährtem Code ist eine attraktive Option für Entwicklungsprojekte, da er frühere Investitionen in Softwareentwicklung nutzt. Hier lässt sich Zeit und Geld sparen, die Qualität verbessern und Mehrwert erzeugen. Um maximalen Mehrwert zu erzielen, sollte jedoch bewährte Software und die Art ihres Einsatzes sorgfältig ausgewählt werden.

Beim Import von bewährtem Code – entweder aus einem früheren Archiv innerhalb der Firma oder als COTS von externen Anbietern ist am wichtigsten, dass sich der Code nicht nur für die Anwendung eignet, sondern auch geltende Richtlinien erfüllt. Material wieder zu verwenden ist zwar verlockend, doch die Auswirkungen eines solchen Einsatzes in einer neuen Umgebung sollten stets evaluiert werden. Auch wenn sich für bewährten Code ein bestimmter Qualitätsstandard belegen lässt, so kann kein Code 100-prozentige Fehlerfreiheit garantieren.

Realistischerweise sollte man akzeptieren, dass jeder Code Fehler enthält und daher in einer neuen Umgebung Tests durchlaufen muss. Dies kann eine Herausforderung sein, insbesondere wenn der Quellcode nicht immer verfügbar ist, doch es ist nicht unmöglich. Es kommt darauf an, welche Testabdeckung sich erreichen lässt, und ob diese akzeptabel ist. In jedem Fall sollten seine Vor- und Nachteile untersucht werden. Kommt jedoch bewährte Software zum Einsatz, so kann ein sonst kaum tragfähiges Geschäftsszenario realisierbar werden.

Open-Source-Code vs. validiertem Code

Als Unterstützung beim Start eines Projektes oder um wichtige Funktionen wie Hardware-Schnittstellen und Betriebssysteme bereitzustellen, nutzen Ingenieure oft Open-Source-Code oder lizenzgebührenfreien Code aus anderen Quellen wie etwa von Halbleiterherstellern. Dabei ist stets zu berücksichtigen, dass dieser Code nicht unbedingt schon validiert wurde. Der Unterschied zwischen validiertem und nicht-validiertem Code ist die Evidenzbasis. Code ohne nachgewiesene Validierung kann für ein Projekt immer noch nützlich sein, erfordert jedoch eine Qualitätsbewertung und bei seinem Einsatz ist Vorsicht geboten.

Bei der Nutzung von offenem Quellcode können die Größe der Community, die diesen Code nutzt, und der Umfang der seitens der Community gebotenen Wartung und Unterstützung als Indikator für die Qualität des Codes dienen. Weiterhin ist zu überlegen, ob das unternehmensinterne Wissen durch die Erstellung eines neuen Codes erweitert werden soll, anstatt Code wieder zu verwenden oder extern zu beschaffen. Neuer Code, den Entwickler selbst validieren können, bietet langfristig womöglich einen größeren Mehrwert. Auch diese Entscheidung muss mit der eigenen Geschäftsstrategie im Einklang stehen.

Wenn die Implementation einer Lösung für eine bestimmte Problemstellung komplex ist und die Expertise des internen Teams überschreitet, oder wenn die Herausforderung Spezialwissen außerhalb des Schwerpunkts der eigenen Geschäftstätigkeit erfordert, dann könnte die Beschaffung von validiertem Code aus externen Quellen wirtschaftlicher sein. Würde andererseits die Entwicklungsarbeit den internen Erfahrungsschatz des Unternehmens erhöhen oder gäbe es die Möglichkeit zur Nutzung des Codes für weitere Projekte, dann wäre die Erstellung eines neuen Codes wirtschaftlich vertretbar.

Letzterer Fall würde zwar eine größere Anfangsinvestition erfordern, auf lange Sicht jedoch einen größeren Mehrwert bieten. Für einen Wirtschaftlichkeitsnachweis muss ermittelt werden, wo Wert geschaffen und sichergestellt wird, damit sich der erzeugte Wert erfassen und kommunizieren lässt.

Bildergalerie

Renesas hat das „Make-or-Buy“-Dilemma erkannt, vor dem Unternehmen am Beginn einer jeden Produktentwicklung stehen, und stellt validierte Software zum Einsatz auf Renesas Synergy™ Komponenten bereit. Die validierte Software umfasst Code für Hardware-Treiber, Betriebssystem und Security-Funktionen. Diese Software-Bereiche sind überall in der Entwicklung von elektronischen Produkten zu finden und adressieren beispielsweise keine spezifischen Produkt-Funktionen. Durch den Einsatz dieses Codes gewinnen Entwickler die Freiheit, sich ganz auf ihr Produkt und die Anwendungsbereiche des Systems zu konzentrieren. Dies entlastet Unternehmen außerdem von den Gesamtbetriebskosten dieser Software.

Für die Software-Komponenten bietet Renesas umfassende Gewährleistung, die zu denen der Hardware-Komponenten passt, und liefert bei Bedarf auch Software-Updates. Senkungen der Betriebskosten und Einsparungen beim Entwicklungsaufwand setzen wertvolle Kapazitäten frei. So können sich Entwickler auf die Erstellung von Software für den Kernbereich ihres Geschäfts konzentrieren und größeren Mehrwert erzielen.

Der Schlüssel zur Sicherstellung dieses Wertes heißt Testen. Tests beweisen die korrekte Implementierung validierter Software und machen eine Validierung der neu verfassten Software möglich.

Unabhängig vom gewählten Design, der genutzten Architektur oder Programmiersprache ist ohne die Einhaltung guter Codierungsrichtlinien alles vergeblich. Codierung als Disziplin unterscheidet sich von der Architekturerstellung und Entwicklung. Oft sind daran unterschiedliche Entwickler beteiligt. Codierungsstandards und -Richtlinien sind daher besonders wichtig.

Die Klarheit des Codes lässt sich mit einer sorgfältigen Benennung der Daten verbessern. Durch gut benannte Daten und verständliche Erklärungen, warum der Codierer die Software auf eine bestimmte Weise geschrieben hat, lassen sich später bei der Überprüfung und Wartung des Codes viele Arbeitsstunden einsparen. Darüber hinaus ermöglicht die Bereitstellung von ausreichend Debugging- und Testpunkten im Code erhebliche Zeiteinsparungen – ebenso wie eine stringente Verwaltung unterschiedlicher Code-Versionen.

Eine zielgerichtete Architektur und eine robuste, mit prüfbarem, konsistentem und kontrolliertem Code implementierte Schnittstelle helfen dem Entwickler, offenkundig korrekte und wartbare Software zu erstellen. In diesem Teil wurde speziell der Aspekt des Software-Designs betrachtet.

Dieser Beitrag stammt ursprünglich von unserem Schwesterportal Elektronikpraxis.de.

* Dr. Val Lynch ist CEO bei AND Technology Research.

* Steve Norman ist Manager Global Ecosystems bei Renesas Electronics Europe.

(ID:45017144)