Unser IT-Experte Silvan Lindner erklärt, wie sich im Laufe der Jahre das Schreiben und Entwerfen von Software verändert hat und inwieweit diese Veränderungen Entwicklern das Leben vereinfachen.
Die Softwareentwicklung benötigt verschiedene Tools, die den Code in ein ausführbares Programm umwandeln, die sogenannten Toolchain. Für ein Softwareunternehmen ist dabei vor allem wichtig, dass die erstellten Programme immer identisch (wiederholbar, reproduzierbar, standardisiert) erzeugt werden – unabhängig davon, auf welchem Computer der Code verarbeitet wird. Dafür müssen das Build System und die Zielarchitektur ebenfalls eindeutig identifiziert sein. Das Build System beschreibt die Umgebung in der die Toolchain arbeitet: also Compiler, Compiler Version, Betriebssystem, Versionen der Abhängigkeiten und Tools. Im Folgenden zeigen wir einen solchen standardisierten Ablauf auf.
So entsteht ein Programm
Ein Source Code definiert ein Programm. Ein Compiler ermöglicht es, diesen in eine ausführbare Applikation zu übersetzen. Im einfachsten Fall, mit nur einer Source-Datei, kann ein Compiler beispielsweise direkt durch „clang++ main.cpp“ aufgerufen werden. Es gibt hier eine Vielzahl weiterer Optionen, die zusätzlich als Instruktionen dienen, wie das Einbinden von Third Party Libraries oder zusätzliche Compilerflags. Wächst das Projekt, steigt die Komplexität dieser manuellen Compileraufrufe immens.
Um diese Komplexität zu mildern, wurde zunächst die Software Make entwickelt. Diese erlaubt das Erstellen von „Rezepten“, sogenannten Make Files, die in einfacher Syntax den Build-Prozess definieren und automatisch Compilerinstruktionen generieren. Allerdings besteht eine Make File irgendwann aus so vielen Libraries, Tools und Text, dass auch das unübersichtlich wird.
Um dieses Problem zu lösen, entstand vor etwa 15 Jahren der Build System Generator CMake. Die Idee hinter dem dazugehörigen CMake File ähnelt der von Make, befindet sich aber auf einem deutlich höheren Level. Dadurch vereinfacht sich das Anlegen neuer Projekte und diese werden wesentlich übersichtlicher gestaltet. Weitere Funktionen werden einfach in den Build-Prozess integriert. Unternehmen nutzen CMake zusätzlich zur Verschlüsselung von Projekten für ein Deployment und um Installer zu erzeugen.
Abhängigkeiten und Build Umgebungen
Eine Library mit zusätzlichen Funktionalitäten wird als Abhängigkeiten bezeichnet. Diese müssen nicht selbst implementiert werden. Dazu gehören beispielsweise
- Codesammlungen, wie das System Punktewolken oder Bilder verarbeitet und deren grafische Darstellung,
- Werkzeuge zu Logging, Datenkonvertierung sowie Datei Import/Export,
- Kamera und andere APIs,
- Eigene Entwicklungen, die in anderen Projekten wiederverwendet werden können.
Diese müssen jeweils separat kompiliert werden, bevor ein Programmierer sie zu einem Projekt hinzugefügt. Das Verwalten dieser Abhängigkeiten erweist sich jedoch teilweise als schwierig. Es ist möglich, alle Libraries eines Projekts durch eine Baumstruktur zu visualisieren. Hier kann es vorkommen, dass in diesem Baum öfter die gleiche Abhängigkeit auftaucht. Wenn eine Applikation beispielsweise von Library 1 und Library 2 abhängt und Library 1 zusätzlich von Library 3 und Library 2 abhängt, ist es möglich, dass Library 2 in unterschiedlichen Versionen vorliegt. Dies führt häufig dazu, dass das Programm nicht mehr oder nur noch fehlerhaft funktioniert.
Eine das Leben erleichternde Datei
Wenn dies der Fall ist, müssen alle Libraries neu gebaut werden, damit sie von der gleichen Version abhängen. Manuell ist das schwierig und sehr zeitaufwendig. Um diese händische Veränderung zu umgehen, verwenden Experten ein Conan File. Conan ist eine Paketverwaltungssoftware. Sie handhabt Abhängigkeiten, Build-Umgebungen und Versionierungen. So ist sichergestellt, dass alle Abhängigkeiten (Versionen, Unterabhängigkeiten und Optionen) und Buildumgebungen (Compiler, Compiler-Optionen, Betriebssysteme und Architektur) konsistent sind. Artifactory kann als Conan Remote verwendet werden. Hier liegen alle Conan-Rezepte, durch die es möglich ist, nach Libraries zu suchen. So existiert keine Library mehr, die von einer veralteten Version einer anderen Library abhängt.
Weitere hilfreiche Tools
Um Probleme effizient zu lösen, ist eine Versionierungskontrolle unabdingbar. Hierfür verwenden Programmierer beispielsweise die Versionierungssoftware Git. Mit Git verfolgen Entwickler Änderungen im Code, implementieren sie sauber in die Kundensoftware, finden Fehler besser und können Überarbeitungen bei Bedarf rückgängig machen. Außerdem ist es möglich, dass mehrere Programmierer Änderungen bewerten und erst nach einer Überprüfung freigegeben. Durch Git hat eine Firma so den Überblick über die Verbesserungsvorschläge aller Programmierer und deren Anpassungen.
Um sicherzustellen, dass ein Programm zur Auslieferung an einen Kunden bereit ist, kommt das Konzept der Continous Integration zum Einsatz. Dies ist unter anderem mit Hilfe von Jenkins realisierbar. Dabei werden unterschiedliche Schritte durchgeführt, die das Programm bauen und testen sollen. Nur wenn dabei kein Fehler auftritt, ist ein Produkt fertig für den Release. Diese Schritte sehen in den meisten Fällen folgendermaßen aus:
- Programm vollständig auf einem eigenen Rechner neu bauen,
- Tests ausführen, um die Funktionalität der Software zu überprüfen,
- Installer erstellen,
- Installer auf einem Server mit Kundenzugriff ablegen.
Sobald in einer Stage ein Fehler auftritt, bricht die Jenkins Pipeline sofort ab. Die Stelle, an der ein Fehler festgestellt wurde, wird dabei visualisiert. So hat der Entwickler ein direktes Feedback und kann das Problem beheben. Bei jeder Änderung, die in Git vorgenommen wird, läuft das Programm erneut durch. Wenn Jenkins keine Fehler mehr findet – es ist alles grün hinterlegt –, kann das fertige Produkt an den Kunden ausgeliefert werden.