Beiträge

Ein CEO Fraud ist eine Art von Betrug, der in der Manipulation eines entsprechend befugten Mitarbeiters zur Ausführung einer großen Überweisung besteht. Diese Überweisung wird durch eine gefälschte Anweisung ausgelöst, die vom CEO oder Chief Executive Officer zu stammen scheint. Das von den Betrügern angegebene Zielkonto für diese Überweisung befindet sich üblicherweise nicht in Reichweite des Rechtssystems am Unternehmenssitz.

Wie läuft ein CEO Fraud ab?

Voraussetzung für den Erfolg durch einen Betrug dieses Typs ist die Abwesenheit des CEO des Zielunternehmens.

Eine entsprechend ausgewählte Person im Unternehmen erhält von den Tätern einen gefälschten Auftrag, die Überweisung einer großen Summe auf ein ausländisches Bankkonto zu veranlassen. Der Auftrag kann per E-Mail, per Brief oder auch per Telefonanruf übermittelt werden.

Die Nachricht mit diesem Auftrag enthält oft weitere Details, die den Erfolg durch diesen Betrug wahrscheinlicher machen sollen. Als Begründung kommt in Frage, dass der CEO sich in Verhandlungen betreffend die Übernahme eines Unternehmens befindet. Dieser Umstand legt schon selbst eine Dringlichkeit nahe. Für diese Übernahme wird strikte Geheimhaltung gefordert, weswegen der entsprechende Mitarbeiter keine anderen Personen informieren darf, die eventuell Verdacht schöpfen könnten. Auch die Kontaktaufnahme mit dem CEO etwa per Mobiltelefon kann vor diesem Hintergrund untersagt werden, weil auf diese Weise die Verhandlungspartner von dieser Überweisung Kenntnis erhalten könnten und das die Verhandlungsposition des CEO schwächen würde.

Voraussetzungen und Vorbereitungen für einen Betrug vom Typ CEO Fraud

Die Kommunikation der Täter mit den ausgesuchten Opfern muss für einen erfolgreichen CEO Fraud einwandfrei sein. Es müssen die Namen aller Beteiligten den Tätern bekannt sein und auch ihre übliche Art zu kommunizieren. Das ist ein großer Unterschied zu anderen Modellen, bei denen eine große Zahl von E-Mails mit dem Ziel versandt wird, nur einige besonders leichtgläubige Opfer für einen Betrug zu ködern.

Des Weiteren müssen die Täter natürlich herausfinden, welche Personen im Unternehmen überhaupt für eine große Überweisung zeichnungsberechtigt sind. Zumindest sehr nützlich ist eine realistische Einschätzung, welche dieser Personen sich besonders leicht unter psychischen Druck setzen lassen. Diese Informationen sind zu einem gewissen Teil öffentlich zugänglich. Fast immer werden aber entweder technische Angriffe auf die Systeme des Unternehmens oder Methoden des Social Engineering zum Einsatz kommen müssen. Beides sind klassische Methoden von kriminellen Hackern, deren Ziel erfolgreiche Computerkriminalität in allen Ausprägungen ist.

Unter Social Engineering versteht man Angriffe auf menschliche Schwächen. Als einfaches Beispiel könnten die Täter über Social Media ein persönliches Interesse einer Zielperson identifizieren. Diese Person wird dann viel wahrscheinlicher auf eine E-Mail reagieren, in der es um diesen Fachbereich geht. So wird ein Vertrauen über ein angeblich gemeinsames Interesse aufgebaut, das sich dann für mehr Offenheit ausnützen lässt, als die Zielperson üblicherweise einem Fremden entgegenbringen würde.

Für einen Betrug in der Form eines CEO Frauds ist Social Engineering sogar verhältnismäßig einfach, denn viele Details über die Kommunikation im Unternehmen und auch Hinweise auf die Stressresistenz einer Person ergeben sich ganz von selbst aus einem harmlosen Austausch von Nachrichten. Die Zielperson muss nicht einmal zu einem für sie selbst erkennbaren Vertrauensbruch gebracht werden.

Welche Folgen hat ein CEO Fraud?

Wird die von den Tätern angestrebte und mit einer Fälschung in Auftrag gegebene Überweisung durchgeführt, ist das Geld in fast allen Fällen verloren. Von den für einen solchen Betrug eingesetzten Konten ist eine einmal überwiesene Summe kaum wieder zurückzuerhalten.

Viele Firmen entscheiden sich nach einem Schaden durch einen CEO Fraud nicht für eine Veröffentlichung. Die Wahrscheinlichkeit ist sehr gering, der Täter habhaft zu werden und in jedem Fall ist mit einem Imageschaden für das Unternehmen zu rechnen.

Einige Beispiele sind öffentlich bekannt. Das österreichische Unternehmen der Luftfahrtindustrie FACC AG wurde im Jahr 2016 um eine Summe von 50 Millionen Euro durch einen CEO Fraud geschädigt.

Wie können Sie sich gegen einen CEO Fraud wehren?

Die Abwehr gegen diese Form von Betrug besteht fast nur aus vorbereitenden Maßnahmen. Eine erfolgte Überweisung ist kaum mehr rückgängig zu machen. Das würde auch ein Problem für das Bankensystem darstellen und nicht für Ihre Informationssicherheit.

Die ersten zwei Schritte betreffen eine gut funktionierende IT-Sicherheit, was gegen alle Arten von Cyberangriffen wichtig ist. Diese Maßnahmen betreffen eine gute technische Absicherung der Systeme in Ihrem Unternehmen. Neben anderen Vorteilen machen Sie es dann den Tätern schwerer, an die für einen erfolgreichen CEO Fraud notwendigen Informationen zu kommen. Diese Sicherheitsmaßnahmen sollten sich aber auch auf eine Vorbereitung Ihrer Mitarbeiter auf Spear-Phishing erstrecken, das auf einen einzelnen Mitarbeiter individuell zugeschnitten wird. Des weiteren sollten Kommunikationskanäle festgelegt und eventuell ein 4-Augen-Prinzip für größere Überweisungen eingeführt werden.

Trotzdem wird es sich nicht ganz vermeiden lassen, dass Täter an die Informationen für einen möglichen CEO Fraud kommen können.

Die Abkürzung API ist englischen Ursprungs und steht für Application Programming Interface. API bezeichnet eine Programmierschnittstelle, deren Anbindung auf Source-Code-Ebene realisiert wird. Programmierschnittstellen kommen in einer Vielzahl unterschiedlicher Anwendungen zum Einsatz und werden im Bereich der Webentwicklung häufig in Form von Web-APIs eingesetzt.

Was genau ist eine Programmierschnittstelle?

Eine API wird in der Regel eingesetzt, um Daten zwischen einem zentralen Computer-Programm und einzelnen Anwendungsteilen einheitlich und standardkonform auszutauschen. Der Austausch der Informationen und Befehle wird einheitlich nach einer zuvor definierten Struktur und strikten Syntax vollzogen. Eine Programmierschnittstelle bietet Entwicklern die Möglichkeit, ein Computer-Programm zu modularisieren und dadurch sowohl Entwicklung als auch Verwaltung der Anwendung wesentlich zu vereinfachen. Die einzelnen Programmteile, die über eine API miteinander verbunden sind, stellen bestimmte Funktionalitäten bereit und sind von dem Rest der Anwendung klar getrennt.

Die gesamte Kommunikation zwischen den einzelnen Anwendungsmodulen wird ausschließlich über die genau spezifizierte Programmierschnittstelle vollzogen. Wenn Entwickler eine API bereitstellen, erfolgt das in vielen Fällen in Kombination mit einer detaillierten Dokumentation der genauen Syntax, der bereitgestellten Funktionen und Features und der möglichen Argumente. Moderne APIs kommen in einer Vielzahl unterschiedlicher Bereiche zum Einsatz. So kann beispielsweise über ein Application Programming Interface auf einzelne Hardwarekomponenten, eine bestimmte Datenbank, Betriebssystembefehle, Benutzeroberflächen und viele weitere Komponenten zugegriffen werden.

Das Application Programming Interface ist von einem User Interface (Benutzeroberfläche) zu unterscheiden. Während ein User Interface in erster Linie als Schnittstelle zwischen der Anwendung und dem Anwender fungiert, kann eine API als Äquivalent zur maschinenverständlichen und automatisierten Kommunikation betrachtet werden. Die Benutzerschnittstelle nimmt dabei die Daten von Anwendern entgegen, leitet diese an die richtige Anlaufstelle im Rahmen der Anwendung weiter und stellt die Ergebnisse dem Benutzer bereit.

Eine API hingegen hat keine Interaktion mit dem Benutzer, sondern ist in erster Linie für die Verarbeitung der von einem Anwendungsmodul entgegengenommenen Daten verantwortlich.

Welche API-Typen gibt es?

Application Programming Interfaces gibt es in unterschiedlichen Variationen, die jeweils auf die speziellen Anforderungen und Bedürfnisse des jeweiligen Einsatzszenarios angepasst sind. Moderne APIs lassen sich prinzipiell in vier verschiedene API-Klassen einteilen, und zwar:

– objektorientierte APIs

– dateiorientierte APIs

– protokollorientierte APIs

– funktionsorientierte APIs

Während dateiorientierte Programmierschnittstellen primär durch den Einsatz verschiedener Dateisystemaufrufe einzelne Dateien und Dateisysteme ansprechen, verwenden funktionsorientierte APIs in erster Linie Funktionen und deren Parameter zur Kommunikation. Objektorientierte APIs arbeiten in Kombination mit sogenannten „Schnittstellenanzeiger“ und bieten im Vergleich zu den rein funktionsorientierten Programmierschnittstellen eine höhere Flexibilität. Das wesentliche Charakteristikum von protokollorientierten Schnittstellen spiegelt sich in ihrer Unabhängigkeit von bestimmten Betriebssystemen und Hardwarekonfigurationen wider.

Welche Vorteile bietet der Einsatz einer API?

Der konsequente Einsatz von APIs bringt eine Reihe unterschiedlicher Vorteile mit sich. Sehr umfangreiche und komplexe Software-Projekte lassen sich durch die Verwendung von Programmierschnittstellen modularisieren und besser strukturieren, sodass die Entwicklung und Wartung des Software-Produkts wesentlich vereinfacht wird. Einzelne Funktionalitäten und Features lassen sich als Programmmodule realisieren, was zu einer sauberen und übersichtlichen Gesamtstruktur führt. Darüber hinaus macht der Einsatz des modularen Programmcodes in Kombination mit den Programmierschnittstellen die Anwendung weniger Anfällig für Fehler und Bugs, die sich später nur mit großer Mühe beheben lassen. Werden einzelne Funktionen nicht korrekt ausgeführt, dann müssen lediglich die betroffenen Module näher inspiziert werden.

Ein weiterer wesentlicher Vorteil einer gut dokumentierten und sauber programmierten API gegenüber Apps ohne Programmierschnittstelle ist die Auslagerung von Entwicklungsarbeiten. So kann die Entwicklung bestimmter Komponenten mit relativ geringem Aufwand an eine externe Software-Schmiede oder einen Freelance-Entwickler outgesourced werden. Außerdem können externe Entwickler selbst Funktionalitäten für die Anwendung implementieren. Dies wirkt sich  positiv auf die Flexibilität und Attraktivität des Software-Projektes aus, was  klare Wettbewerbsvorteile mit sich bringt. Ein Pluspunkt, der für den Einsatz von APIs spricht, spiegelt sich in der Langzeitstabilität des Software-Produkts wider. Entwickler können den Programmcode anpassen, ohne dass Programmmodule betroffen sind. Funktionalitäten lassen sich dadurch relativ einfach implementieren bei einer gleichzeitigen Senkung der Kosten und des Arbeitsaufwandes.

Welche APIs sind besonders beliebt?

Programmierschnittstellen kommen heutzutage in vielen unterschiedlichen Bereichen moderner Software-Entwicklung zum Einsatz. Im World Wide Web sind beispielsweise viele öffentliche Web-APIs vorzufinden, mit denen sich Angebote bekannter Online-Services, wie beispielsweise Spotify oder YouTube, in eigene Anwendungen einbinden lassen. Beispielsweise sind APIs zu folgenden Web-Services verfügbar:

– DHL

– PayPal

– YouTube

– TikTok

– Twitter

– Spotify

– Google Maps

– Twitch

– Instagram

Im Bereich der Webentwicklung kommen Programmierschnittstellen oft bei Content-Management-Systemen und Web-Shops zum Einsatz. Dadurch lassen sich verschiedene Online-Börsen, Bewertungssysteme, Bezahldienste und Versanddienstleister sowie viele weitere Web-Services mit relativ wenig Aufwand in die eigene Plattform integrieren. Einen besonderen Typ von Web-Schnittstellen stellen APIs zur Authentisierung und Autorisierung im World Wide Web dar. Standardisierte APIs wie OAuth (Open Authorization) oder OpenID bieten Usern die Möglichkeit, sich auf anderen Portalen einzuloggen, ohne vorher explizit ein Benutzerkonto anlegen zu müssen. So ist zum Beispiel eine einzige Benutzeridentität durch den Einsatz dieser APIs auf vielen verschiedenen Portalen und Web-Services nutzbar.

Ein Decompiler ist ein Computerprogramm, das aus Objekt- oder Maschinencodes einen erkennbaren Text in einer Hochsprache hervorbringt. So ist dieser Quelltext für den Menschen lesbar. Andere Bezeichnungen für den Decompiler sind Dekompilierer, Reverse Compiler oder Reverse Engineering Compiler. Beim Dekompilieren versucht das Programm, den Vorgang des Kompilierens rückgängig zu machen. Oft kommt es zu Verwechslungen zwischen Decompiler und Disassembler. Die Assemblersprache ist jedoch nur ein anderes Darstellungsformat des Maschinencodes.

Wie funktioniert ein Decompiler?

Für die Kompilierung gibt es häufig keine Wandlungsfunktion. Die Dekompilierung macht das mit der Reverse-Engineering-Technik möglich. Diese Technik erzeugt nachträglich einen Quellcode, der die Basis eines ausführbaren Programmes ist. Der wiederhergestellte Code ist dem Quellcode der ursprünglichen Fassung sehr ähnlich, der zur Bildung des durchführbaren Programmes angewendet wurde. Sind in dem Programm auch noch Debug-Informationen hinterlegt, dann sind die angewandten Funktionsnamen, Module und Variablennamen des ursprünglichen Autors erzeugbar. In der Regel gehen Formatierungen des Ursprungs sowie Kommentare verloren, weil diese Infos üblicherweise nicht im Kompilat einbezogen sind.

Das Dekompilieren von Bytecodes (zum Beispiel .NET- und Java-Programme) ist im Allgemeinen einfacher als das Dekompilieren von Maschinencodes. Das liegt daran, weil die Systeme eine Menge Informationen des basierten Quellcodes in die Objektdatei aufnehmen. Zu vergleichen ist das mit der Debug-Version eines C++- oder C-Programmes. Die Namen der öffentlichen Bezeichner sowie die Typinformationen bleiben bestehen. Die vom Decompiler erzeugten Programmcodes sind allerdings nur funktional deckungsgleich mit der Quelldatei des Ursprungs.

Welche Einschränkungen bestehen beim Dekompilieren?

Der hergestellte Quellcode kann in einzelnen Fällen bis zur Unbenutzbarkeit verzerrt sein. Das ist der Fall, wenn keine Debug-Informationen enthalten sind und das Programm mit einer Optimierungsoption des Compilers übersetzt wurde. Wegen dieser Einschränkung ist das Dekompilieren dem Grunde nach ungeeignet, um verlorene Quelltexte wieder aufzuarbeiten. Die Quelltexte sollten deshalb in mehreren Sicherungen zur Verfügung stehen.

Im allgemeinen Gebrauch setzt ein Programmierer eher selten einen Decompiler ein. Hin und wieder kann es vorkommen, dass bei sehr alten Softwareversionen die ursprünglichen Quellen nicht mehr vorhanden oder auf Datenträgern gespeichert sind, für die kein geeignetes Lesegerät mehr vorhanden ist. Zu Beginn des elektronischen Datenverarbeitens war es zudem geläufig, kleinere Fehler durch Patchen der Objektdateien zu beseitigen. Diese Fälle sind neben der Rückentwicklung einer fremden Software die alleinigen Anwendungsgebiete, für die das Dekompilieren zur Anwendung kommt.

Welche rechtlichen Bestimmungen sind beim Anwenden der Decompiler zu beachten?

Softwareanbieter verweisen häufig in den Lizenzen darauf, dass die Dekompilierung der Produkte untersagt ist. Das Verbot soll auch für das Verändern der Software für den eigenen Gebrauch sowie für Studienzwecke gelten. Dem steht allerdings eine gesetzliche Regelung entgegen (§ 69e Urheberrechtsgesetz), die unter gewissen Voraussetzungen gestattet, ein Programm zu dekompilieren. Der Einsatz eines Decompilers ist nach dieser Regelung erlaubt, um die Kompatibilität mit einem unabhängig vom Ursprungsprogramm geschaffenen Computerprogramm zu erreichen. Die gesetzliche Bestimmung weicht somit die Lizenzvereinbarungen auf und macht diese ungültig.

Was ist ein Compiler?

Programmiersprachen wie JavaScript, Python oder Java sind so aufgebaut, dass diese vom Programmierer ohne Weiteres zu schreiben und zu lesen sind. Damit der Computer mit den jeweiligen Programmbefehlen etwas ausführen kann, muss der Code zuerst in eine begreifliche Sprache umgewandelt werden. Je nach Plattform und Programmiersprache erfolgt das Umwandeln von einem Interpreter oder Compiler. Ein Compiler ist das Gegenteil vom Decompiler, denn der Compiler ist eine Software, die Quellcodes in Maschinensprache umgestaltet. Beim Kompilieren übersetzt die Software das ganze Programm von einer Programmiersprache in eine Maschinensprache. Bevor das Computerprogramm ausgeführt werden kann, wird der Code in seiner Gesamtheit übersetzt.

Was ist ein Betriebssystem?

Das System stellt die Verbindung zwischen der Hardware und den Anwendungsprogrammen her. Ein Betriebssystem trägt auch die Bezeichnung OS (Operating System). Für die Vermittlung der Zugriffe auf die Hardware-Ressourcen ist das Betriebssystem zuständig. Das können Festplatten, Arbeitsspeicher, Drucker sowie USB-Ports sein. Auch Smartphones und Tablets benötigen ein Betriebssystem. Die gängigsten Systeme sind Linux, Android, Windows, Unix, iOS und Mac OS.

 

Die Verwaltung und Kontrolle der Hardware übernimmt das jeweilige Betriebssystem des Computers. Dazu zählen auch Geräte wie das DVD-Laufwerk, die Tastatur, der Drucker, die Maus und anderweitige Hardware-Schnittstellen, zum Beispiel USB-Ports. Eine Anwendungssoftware (beispielsweise MS Word) kann diese Tätigkeiten auch eigenständig durchführen. In diesem Fall müsste jedoch das Programm für die unterschiedlichen Hardwareausführungen eigene MS-Word-Versionen vorhalten. Ein Betriebssystem reduziert den Aufwand für die Programme und schafft zudem eine konforme Oberfläche, auf die eine Drittanbietersoftware ansetzen kann.

Was ist ein Server?

Ins Deutsche übersetzt steht das Wort Server für Diener. Der Begriff wird in der Informatik doppeldeutig gebraucht. Ein Server bezeichnet zum einen den Computer, der Ressourcen über ein Netzwerk bereitstellt. Zum anderen beschreibt ein Server das Programm, welches auf dem Computer läuft.

  1. Server (Hardware):

Ein Server, der hardwarebasiert agiert, ist eine in ein Computernetz eingefasste physische Maschine. Auf dieser laufen neben dem Betriebssystem ein oder auch mehrere softwarebasierte Server. Eine andere Bezeichnung für einen Server, der auf Hardware basiert, ist Host.

 

  1. Server (Software):

Ein softwarebasierter Webserver ist ein Computerprogramm, welches einen speziellen Dienst zur Verfügung stellt. Dieser Dienst kann von anderen Programmen (= Clients) lokal oder über ein Netzwerk genutzt werden. Es ist abhängig von der Art der Server-Software, welcher Dienst verfügbar ist. Beim Austausch der Daten setzen dienstspezifische Übertragungsprotokolle ein.

 

 

 

Bei einer Programmiersprache handelt es sich um eine formale Sprache, mit denen sich Algorithmen und Datenstrukturen für den Computer formulieren lassen. Diese sogenannten Rechenvorschriften werden dann von einem Computer interpretiert und ausgeführt. Sie bestehen normalerweise aus schrittweisen Anweisungen aus erlaubten textuellen Befehlen und Strukturen, die mit dem Begriff Syntax bezeichnet werden. Während die ersten Programmiersprachen noch direkt an die Eigenschaften des jeweiligen Computers ausgerichtet waren, kommen heute vorwiegend Programmiersprachen höherer Ebenen zum Einsatz.

Die Funktionsweise einer Programmiersprache

Die Gesamtheit aller Befehle und Anweisungen, aus denen sich ein bestimmtes Computerprogramm zusammensetzt, wird als Quellcode bezeichnet. Der Quellcode eines Programms lässt sich in einem einfachen Texteditor erstellen, wie beispielsweise Notepad oder Sublime Text. Bei größeren Software-Projekten kommen allerdings sogenannte integrierte Entwicklungsumgebungen (IDE) zum Einsatz. Moderne IDEs, wie zum Beispiel Visual Studio oder Intellij IDEA, unterstützen den Entwickler bei seiner Programmiertätigkeit und tragen wesentlich dazu bei, die Produktivität des Entwicklers zu optimieren. Damit ein Computer die im Quelltext enthaltenen Befehle und Anweisungen verarbeiten und ausführen kann, muss der Quellcode zunächst in die Maschinensprache des jeweiligen Computersystems übersetzt werden. Dieser Vorgang wird als Kompilierung bezeichnet.

Die Maschinensprache ist ein Binärcode, der für Menschen nur schwer verständlich ist und primär an die Anforderungen und Bedürfnisse von Computersystemen ausgerichtet ist. Der Quellcode kann zu verschiedenen Zeitpunkten in die Maschinensprache kompiliert werden. Falls der Quellcode zur Laufzeit des Programms kompiliert wird, kommt ein sogenannter „Just-in-Time-Compiler“ oder Interpreter zum Einsatz. Bei einigen höheren Programmiersprachen, wie beispielsweise Java, wird eine Kombination aus traditioneller und der JiT-Kompilierung eingesetzt. So wird beispielsweise noch vor der Programmausführung der Java-Code in einen Zwischencode, den sogenannte „Bytecode“ überführt. Dieser wird dann während der Ausführung des Programms in Maschinencode übersetzt.

Die einzelnen Bestandteile einer Programmiersprache

Eine jede formale Programmiersprache lässt sich anhand verschiedener Merkmale näher definieren. Zu diesen Merkmalen gehören neben der Syntax auch der Zeichensatz und das Vokabular.

 

Syntax: Bei der Syntax einer Programmiersprache handelt es sich um deren „Grammatik“. Die Syntax gibt die zulässigen Sprachelemente explizit an. Außerdem definiert sie auch, wie diese Elemente zu verwenden sind.

Vokabular: Das Vokabular bezieht sich auf reservierte Schlüsselwörter, die nicht als Namen für Variablen, Klassen, Funktionen und Methoden gewählt werden dürfen.

Zeichensatz: Der Zeichensatz einer Programmiersprache setzt sich prinzipiell aus alphanumerischen und numerischen Zeichen und einigen Sonderzeichen zusammen.

 

Die Leistungsfähigkeit und der Umfang einer Programmiersprache hängen in erster Linie von der Mächtigkeit des Befehlssatzes ab. Moderne Programmiersprachen besitzen mindestens die folgenden Befehle:

– Befehle zur Deklaration von Variablen und anderen Datentypen und Datenstrukturen, wie beispielsweise Arrays, Klassen, Hashmaps, die bei der Zwischenspeicherung von Daten genutzt werden

– Befehle, die bei der Ein- und Ausgabe von Daten zum Einsatz kommen

– Mathematische Funktionen, wie beispielsweise Addition, Division oder Multiplikation

– Funktionen zur Verarbeitung von Strings (Zeichenkette)

– Bedingte Anweisungen und Verzweigungen, die bei der Implementierung von Programmlogik zum Einsatz kommen.

– Steueranweisungen und Schleifen für die wiederholte Ausführung bestimmter Programmteile

Aus der Kombination dieser Grundfunktionalitäten lassen sich komplexere Strukturen und Funktionen erstellen. Viele Programmiersprachen bieten außerdem die Möglichkeit, gängige Befehle als Funktionen höherer Ordnung in sogenannte „Bibliotheken“ zu bündeln und somit programmübergreifend wiederverwendbar zu machen.

Gängige Programmierparadigmen im Überblick

Die erste höhere Programmiersprache wurde in den USA im Jahr 1954 entwickelt. Der US-amerikanische Informatiker John Warner Backus war für den Entwurf der Programmiersprache Fortran zuständig, die heutzutage als die älteste sich noch im Gebrauch befindliche Programmiersprache gilt. Einige Zeit später im Jahr 1959 machte der Logiker John McCarthy die Programmiersprache LISP der breiten Öffentlichkeit zugänglich. Noch im selben Jahr wurde mit COBOL die erste Programmiersprache für kommerzielle Anwendungsbereiche vorgestellt. Im Laufe der Jahre kamen noch zahlreiche Programmiersprachen hinzu. Alle formalen Sprachen lassen sich in Klassen einteilen, die als Programmierparadigmen bezeichnet werden. Zu den bedeutendsten Programmierparadigmen gehören die prozedurale, die funktionale und die objektorientierte Programmierung.

  1. Prozedurale Programmierung: Hierbei handelt es sich um das älteste Programmierparadigma. Bei der prozeduralen Programmierung setzt sich ein Computerprogramm aus einer Reihe von Anweisungen und Befehlen zusammen, die nacheinander ausgeführt werden. Der Programmablauf wird durch bestimmte Kontrollkonstrukte, wie Verzweigungen oder Schleifen, gesteuert. Zu den Programmiersprachen, die dieses Paradigma unterstützen, gehören Sprachen wie Fortran, Go oder C.
  2. Funktionale Programmierung: Bei dem funktionalen Programmierparadigma setzt sich ein Computerprogramm aus einzelnen Funktionen zusammen, die untereinander zu Funktionen höherer Ordnung verknüpft werden. Seinen Ursprung hat die funktionale Programmierung in der wissenschaftlichen Forschung rund um das sogenannte „Lambda-Kalkül“, das eine formale, mathematische Sprache zur Untersuchung von Funktionen darstellt. Zu den beliebtesten Sprachen, die das funktionale Programmierparadigma unterstützen, gehören Programmiersprachen wie Haskell, JavaScript und LISP.
  3. Objektorientierte Programmierung: Bei dem objektorientierten Programmierparadigma stehen Objekt im Mittelpunkt. Bei objektorientierten Sprachen, wie Python, C++ oder Java bestehen Computerprogramme aus kooperierenden Objekten. Ein Objekt zeichnet sich dadurch aus, dass es einer bestimmten Klasse angehört, dass es Eigenschaften (Attribute) besitzt und verschiedene Handlungen (Methoden) ausführen kann. Einzelne Objekte sind außerdem in der Lage, Nachrichten an andere Objekte zu senden und zu empfangen.

Ein Computer ist nicht selbständig in der Lage, die Anweisungen, die ein Entwickler in Form von Programmcode schreibt, zu verstehen. Die Codebefehle müssen entweder von einem sogenannten Compiler in Maschinensprache übersetze werden oder von einem sogenannten Interpreter zur Laufzeit interpretiert werden. Im folgenden Artikel gehen wir auf das Thema Compiler im Detail ein und schauen uns die Besonderheiten dieser Technologie im Kontext anderen Techniken an.

Was ist ein Compiler?

Moderne Programmiersprachen wie Java, Python oder JavaScript sind so konzipiert, dass sie von Programmierern ohne größere Probleme gelesen und geschrieben werden können. Damit ein Computer/PC mit den einzelnen Befehlen eines Programms etwas anfangen kann, muss der Quellcode erst in eine für den Computer verständliche Sprache übersetzt werden. Je nach Programmiersprache und Plattform wird das beispielsweise von einem Compiler oder Interpreter realisiert. Bei einem Compiler handelt es sich um eine Software, die Quellcode in Maschinensprache umwandelt. Konkret bedeutet das, dass ein Compiler das gesamte Computerprogramm von einer Programmiersprache in Maschinensprache übersetzt. Dabei wird der Programmcode in seiner Ganzheit übersetzt, bevor das Programm auf dem Computer ausgeführt wird.

In vielen Fällen wird noch ein Zwischenschritt eingeleitet, bevor das Programm in Maschinencode umgewandelt wird. In diesem Schritt wird der Quellcode des Programms zunächst in einen sogenannten „Zwischencode“ übersetzt, wie beispielsweise Objektcode oder Bytecode. Der Zwischencode bietet den entscheidenden Vorteil, dass er in den meisten Fällen auf unterschiedlichen Plattformen ausgeführt werden kann, ohne neu kompiliert werden zu müssen. Außerdem kann er auch von einem Interpreter verarbeitet werden, was beispielsweise bei der Programmiersprache Java der Fall ist. Aus diesem Zwischencode übersetzt der Interpreter dann Maschinencode, der von der jeweiligen Zielplattform verstanden wird. Per Linker wird dann eine ausführbare Datei (EXE-Datei) erstellt. Programmiersprachen höherer Ebenen, wie zum Beispiel Java oder C# arbeiten häufig mit Objekt- bzw. Bytecode, während Programmiersprachen, die nähere an der Hardwareebene sind, ausschließlich mit Maschinencode arbeiten.

Im Rahmen der Kompilierung leitet der Compiler mehrere Schritte ein, um den jeweiligen Quellcode in ein lauffähiges Computerprogramm umzuwandeln. Je umfangreicher und komplizierter der Quellcode ist, umso mehr Zeit und Ressourcen werden bei der Kompilierung benötigt. Sobald das Programm jedoch lauffähig ist, kann es viel schneller und effizienter ausgeführt werden als interpretierte Programme. Dies ist auf die Tatsache zurückzuführen, da alle Anweisungen und Systemaufrufe bereits vollständig in einer für den Computer verständlichen Maschinensprache vorliegen. Beispiele für reine Compiler-Sprachen sind Pascal, C und C++.

Was ist ein Interpreter?

Bei einem Interpreter, wie beispielswiese bei der BASIC-Programmiersprache, handelt es sich um ein Computerprogramm, das den Quellcode einer Anwendung zur Laufzeit verarbeitet. Der Interpreter geht dabei Zeile für Zeile vor: Ein Befehlt wird erfasst, analysiert und sofort ausgeführt. Danach geht es mit dem nächsten Befehl weiter, bis das Ende des Quellcodes erreicht ist oder alternativ ein Fehler den Vorgang zum Stillstand bringt. Sobald etwas nicht stimmt, unterbricht der Interpreter seine Arbeit. Dies liefert Entwicklern wichtige Informationen zur Fehlerbehebung. Man weiß als Entwickler sofort an welcher Stelle im Quellcode sich der Fehler befindet und man kann das Problem so schneller beseitigen.

Im Gegensatz zum Compiler erzeugt ein Interpreter keine ausführbare Datei, die man verteilen, kopieren oder mehrmals ausführen kann. Außerdem fertigt er auch keine Umwandlung des Quellcodes in Maschinensprache an, sondern er fungiert viel mehr als eine Zwischenschicht zwischen der Programmiersprache und dem Computer. Ein Interpreter wertet zur Laufzeit jeden einzelnen Befehl eines Computerprogramms aus und ruft die entsprechenden Funktionen und Systemaufrufe auf, welche die gewünschten Funktionen auf dem Zielsystem auslösen. Da ein Interpreter in Echtzeit arbeitet, wobei jeder einzelne Befehl bearbeitet werden muss, sind interpretierte Sprachen, wie beispielsweise Python oder JavaScript, langsamer und weniger effizienter als kompilierte Sprachen. So werden beispielsweise auch wiederkehrende Anweisungen immer wieder aufs Neue aufgerufen, was die Effizienz äußerst negativ beeinflusst.

Das Beste aus beiden Welten: der Just-in-time Compiler

Heutzutage gibt es moderne Ansätze, die Interpreter und Compiler vereinen und so die Nachteile der jeweiligen Systeme eliminieren. Der Just-in-time-Compiler übersetzt den Quellcode erst zur Laufzeit in Maschinensprache. Die Kompilierung wird also nicht bereits vorab realisiert. Nachdem der Quellcode erfolgreich kompiliert wurde, wird er vom Prozessor des Zielsystems verarbeitet. Gegenüber der traditionellen Kompilierung hat diese Vorgehensweise wesentliche Performance-Vorteile. Bei der Just-in-time-Kompilierung werden gesamte Codeblöcke reihenweise bearbeitet. Auch das bringt gegenüber der sonst üblichen zeilenweisen Bearbeitung des Quellcodes eine Leistungssteigerung mit sich.

Moderne JiT-Compiler sind in der Lage, einen für dynamische Sprachen optimierte Code zu generieren. Darüber hinaus bietet die Just-in-time-Kompilierung den entscheidenden Vorteil, dass vor dem Programmstart nur ein geringer Teil kompiliert wird, wodurch das Problem der Verzögerung des Programmstarts so gut wie eliminiert wird. Darüber hinaus wird äußerst effizient mit den System-Ressourcen umgegangen. Codefragmente, die überhaupt nicht durchlaufen werden, werden auch nicht kompiliert. Im Rahmen der JiT-Kompilierung werden einmal fertig kompilierte Codeblöcke in einem Zwischenspeicher aufbewahrt. Bei einer erneuten Kompilierung werden die benötigten Codeblöcke einfach aus dem Zwischenspeicher geladen und müssen nicht neu kompiliert werden.

Softwareprodukte werden heutzutage in der Regel in Teams entwickelt, die ihre Arbeitsergebnisse in einer zentralen Build-Umgebung zu einer Einheit zusammenführen müssen. Der Continuous Integration-Ansatz (CI) sorgt dafür, dass neue Softwarekomponenten sofort flächendeckenden Tests unterzogen und danach zusammengeführt werden. Anstatt dies beispielsweise nur einmal täglich zu machen, werden im Rahmen des CI-Ansatzes neue Software-Builds erstellt, sobald eine Komponente für die Integration zugelassen wurde.

Softwareentwicklung und Kompilierung: ein Blick in die Vergangenheit

Eine Softwareanwendung setzt sich in der Regel aus einer Vielzahl einzelner Module zusammen. Dementsprechend ist die Vorgehensweise bei der Softwareentwicklung an diese speziellen Gegebenheiten angepasst, sodass das Gesamtprojekt häufig analog zu diesen Modulen von mehreren einzelnen Teams parallel entwickelt wird. Früher wurden Änderungen und Erweiterungen an dem Softwareprodukt in vielen Fällen in Form eines „Tagewerks“ realisiert. Konkret bedeutet das, dass die Zusammenführung der Änderungen, die von den isolierten Entwicklerteams innerhalb eines Arbeitstages erschaffen wurden, nur einmal täglich im Rahmen einer Kompilierung auf dem zentralen Build-Server konsolidiert wurden.

Erst danach wurden die neuen Funktionen und Features des Softwareprodukts im Kontext der erweiterten Codebasis getestet. Dieser traditionelle Ansatz der Softwareentwicklung birgt enorme Gefahren und Risiken. Falls ein neu geschaffener Code nicht kontinuierlich integriert und flächendeckenden Tests unterzogen wird, werden eventuelle Fehler im Code zu spät erkannt. Die Folgen sind zeitintensive und kostspielige Rückkopplungsprozesse. Vor der Einführung der Continuous Integration mussten einzelne Teams auf die Fertigstellung anderer benötigter Softwarekomponenten anderer Entwicklerteams warten, was sich auf die Effizienz des gesamten Projekts äußerst negativ auswirkt.

Continuous Integration im Überblick

Die Continuous Integration-Methoden, die in innovativen Unternehmen in Kombination mit DevOps zum Einsatz kommen, beziehen sich auf die kontinuierliche Integration einzelner Softwarekomponenten in die Gesamtcode-Basis (Codebase) des Softwareprojekts. Die wesentlichen Vorteile dieser Arbeitsweise spiegeln sich in den überschaubaren Schritten wider, die einen kontinuierlichen Arbeitsfluss fördern und die Möglichkeit bieten, Fehler in der Programmierung frühzeitig zu erkennen und zu beseitigen. Durch die gesteigerte Arbeitseffizienz ergibt sich eine höhere Softwarequalität. Die Arbeitsweise im Rahmen des Continuous Integration-Ansatzes unterscheiden sich stark, von der im obigen Absatz beschriebenen traditionellen Vorgehensweise. In Unternehmen, bei denen die kontinuierliche Integration zum Einsatz kommt, wird eine hohe Flexibilität gefordert.

Konkret bedeutet das, dass die in den kleineren Schritten vorgenommenen Änderungen oder Erweiterungen an dem Softwareprodukt in regelmäßigen Abständen zusammengeführt und getestet werden. Die Einspeisung wird über ein Versionsverwaltungssystem wie beispielsweise GitHub oder Bitbucket in einem unterteilten Code-Repository realisiert. Auf diesem Wege lassen sich Versionskontrollen durchführen, indem Build-Prozesse automatisiert werden, sodass stets die aktuelle Code-Version aus dem Repository übernommen wird.

Vor- und Nachteile von Continuous Integration

Obwohl der Continuous Integration-Ansatz zahlreiche Vorteile mit sich bringt, zeigt sich im Alltag auch, dass CI nicht nur Vorteile hat. Dass die langwierige Integrationsphase am Ende eines Softwareprojekts abgekürzt werden kann, lässt sich nicht beschreiten. Auftauchende Probleme können frühzeitig beseitigt werden. Für eingespielte Teams ist die Umstellung auf Continuous Integration jedoch oft mit Komplikationen verbunden. Anstatt dann effizienter zu arbeiten, kann das Verfahren sogar mehr Zeit in Anspruch nehmen.

Vorteile:

– kontinuierliches Feedback

– Fehler lassen sich frühzeitig identifizieren

– eine granulare Arbeitsweise wird gefördert

aktuelle und funktionsfähige Versionen sind stets verfügbar

– alle Änderungen werden im Detail protokolliert

Nachteile:

– es müssen flächendeckende Test-Abläufe entwickelt und implementiert werden

– Umstellung von einem gewohnten Arbeitsprozess

– es werden zusätzliche Server und Entwicklungsumgebungen benötigt

Welche Tools kommen bei Continuous Integration zum Einsatz?

Der Continuous Integration-Ansatz lässt sich grundsätzlich ohne spezielle Tools umsetzen. Das ist jedoch oft mit viel Aufwand verbunden und erfordert einiges an Disziplin. Aus diesem Grund ist es viel einfacher, sich die Arbeit mit den richtigen Tools zu erleichtern. Diese helfen meist bei der Versionskontrolle und beim Kompilieren und Erstellen von Builds. Die bekanntesten CI-Werkzeuge sind:

Jenkins: Hierbei handelt es sich um ein bekanntes Java-Programm, das im Rahmen moderner Continuous Integration und Continuous Delivery-Prozesse eingesetzt wird.

Travis CI: Dieses Tools ist insbesondere wegen seiner reibungslosen Integration mit GitHub beliebt. Für Open Source-Projekte ist es kostenlos, für kommerzielle Softwareprojekte muss eine offizielle Lizenz gekauft werden.

Bamboo: Auch hier handelt es sich um ein Tool, das in der Programmiersprache Java erstellt ist. Wie Travis CI ist es für kommerzielle Projekte normalerweise kostenpflichtig, während es für Open Source-Projekte kostenlos genutzt werden kann.

CodeShip: Dieses Tool basiert auf der Container-Technologie, die von IT-Größen wie Google, Microsoft und Red Hat aktiv weiterentwickelt wird und aus der modernen Softwareentwicklung nicht mehr wegzudenken ist.

Einsatzgebiete

Continuous Integration ist insbesondere im Umfeld agiler Softwareentwicklung in Kombination mit DevOps sehr beliebt. Dieser moderne Ansatz hat immer zum Ziel, in kleinen, übersichtlichen Schritten zu arbeiten. Heutzutage gibt es keine Rechtfertigung, ein Softwareprojekt ohne einen Continuous Integration-Ansatz zu betreiben. Dies liegt vor allem an dem Erfahrungsschatz sowie der großen Anzahl an verfügbaren Tools. CI kann sein volles Potenzial jedoch erst dann entfalten, wenn alle Team-Mitglieder optimal in alle Prozesse eingebunden werden und das System mittragen. Aus diesem Grund kommt einer reibungslosen Kommunikation eine sehr wichtige Rolle zu.