Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 12 Min.

Codegenerierung per Bot

Ein selbst entwickelter Codebot erzeugt Lösungen für eine mathematische Funktion.
© dotnetpro
Projekte und die Softwareentwicklung im Allgemeinen werden durch die Vielzahl der Anforderungen und Systeme heute und in Zukunft immer komplexer. Auf der anderen Seite sollen sie aber auch immer schneller und kostengünstiger gelöst werden. Daher rücken Technologien, die die automatische Generierung von Programmcode ermöglichen, auch immer stärker in den Fokus von Softwareentwicklern und Projektverantwortlichen.Inzwischen gibt es für das automatische Generieren von Programmcode eine beachtliche Anzahl von Codegeneratoren, die in der Lage sind, nach Vorgabe eigenständige Programmieraufgaben zu erledigen. Hierbei funktionieren die meisten Codegeneratoren wie Compiler, die im einfachsten Fall Importe verarbeiten und einen entsprechenden Output dazu erzeugen. Auch bei der Entwicklung von Web-Apps, zum Beispiel mit dem Angular CLI, wird auf Basis von Regeln und anhand der Best Practices der Angular-Entwickler über einen Codegenerator ein neues Angular-Projekt erstellt, das alle benötigten Abhängigkeiten in die package.json-Datei des neuen Projekts einträgt.Durch den Einsatz von Modellierung und Codegenerierung kann man sowohl den Entwicklungsaufwand verringern als auch die Softwarequalität verbessern. Die Generierung von Code ermöglicht es Entwicklern, sich im Projekt auf ein hohes Abstraktionsniveau zu konzentrieren und sich einer Menge Tipparbeit für Routineaufgaben zu entledigen.Natürlich hängt die Wahl eines Tools zur Codegenerierung zur Entwurfszeit von einer Vielzahl von Faktoren ab, dazu zählen zum Beispiel die verwendete Sprache, die Art der Anwendung und gelegentlich auch die verwendete Entwicklungsumgebung.

Verwendung

Für die Verwendung von Codegeneratoren sprechen vor allem die Produktivität, die Vereinfachung von Code, die Portabilität und die Code-Konsistenz. Beim Einsatz von Generatoren schreiben Sie den Code für die benötigte Codegenerierung ja nur ein Mal. Des Weiteren entsteht der Code in den meisten Fällen aus einer abstrakten Beschreibung des zu lösenden Problems. Durch diese Beschreibung sind eine Analyse und die entsprechende Überprüfung der Richtigkeit einfacher, als den gesamten generierten Code zu überprüfen.Der Prozess der Codegenerierung ermöglicht es auch, unterschiedliche Plattformen anzusprechen. So können Sie beispielsweise mit einem Parser-Generator einen entsprechenden Parser in C#, Java und auch C++ erhalten.Ein weiterer großer Vorteil ist die Konsistenz des erzeugten Codes. Der generierte Code wird immer nach den gleichen Prinzipien entworfen. Daher ist die Qualität des erzeugten Codes konsistent.Die wichtigsten Anwendungsbereiche für die Codegenerierung sind heute folgende:
  • Code, der sich wiederholt, kann aus Schemas oder Informationsquellen generiert werden.
  • Assistenten generieren Code für die unterschiedlichsten Aufgaben.
  • Es lassen sich einfache Anwendungen oder Codeklassen aus Modellen wie zum Beispiel UML- oder XML-Dateien erstellen.
  • Die Erzeugung vollständiger Anwendungen aus domänenspezifischen Sprachen (DSL) ist möglich.
  • Code lässt sich aus der Information generieren, die mit anderen Sprachen oder Frameworks erstellt wurde.
  • Quellcode-Generierung für Test-Driven Development (TDD).
Generierter Code kann somit heute für kleine Codesegmente, aber auch für ganze Anwendungen verwendet werden. Arbeitet man bei der Quellcodegenerierung mit UML-Modellen beziehungsweise XML-Dateien, so ist der erzeugte Programmcode immer synchron zu den Modellen.Aus diesen unterschiedlichen Gründen rücken Quellcode-Generatoren aus technischer und qualitativer Sicht in den Fokus. Auch Microsoft stellt mit der neuesten Version von .NET 5 in C# 9 beziehungsweise 10 einen neuen C#-Quellcode­generator vor, der als eine Art Komponente integriert ist und daher von C#-Entwicklern sehr gut zur Entwicklungszeit genutzt werden kann, um entsprechende Sourcecode-Generatoren zu entwickeln.Das heißt, es wird dann hoffentlich in absehbarer Zeit eigene von Microsoft erstellte Quellcodegeneratoren geben, die den Entwicklern eine Menge Routinearbeiten abnehmen können.

Die Zukunft der Softwareautomatisierung

Neben der allgemeinen Verfügbarkeit von Codegeneratoren hilft inzwischen auch die künstliche Intelligenz (KI) den Entwicklern bei der Erstellung von Programmcode. Sogenannte Low-Code-Full-Stack-Anwendungsgeneratoren, auch als Codebot bezeichnet, drängen immer stärker auf den Markt. Diese Bots sind in der Lage, Datenbank-, API- und UI-Code aus UML-Modellen zu erstellen. So kann über die Interpretation eines UML-Domänenmodells eine vollständige Anwendung mit funktionierendem Datenbankzugriff und einem REST-API erstellt werden.Schon einen Schritt weiter geht das kalifornische Unternehmen OpenAI [1] mit seinem im letzten Jahr vorgestellten Sprachmodell Generative Pretrained Transform 3, kurz GPT-3; es kann Anforderungen, die in natürlicher Sprache formuliert werden, vollautomatisch in ein Computerprogramm übersetzen. GPT-3 soll somit in der Lage sein, Websites über entsprechende Sprachmodelle durch automatische Code­generierung zu erzeugen. Durch diesen Ansatz rückt dann auch immer mehr die Programmierung mit Sprache, Gestik und Mimik in den Mittelpunkt der Entwicklung.Ein weiteres Tool, das aus GPT-3 entstanden ist, nennt sich Codex und stellt eine Weiterentwicklung von GPT-3 dar. Codex soll seinen Entwicklern zufolge in der Lage sein, die natürliche englische Sprache in Code zu übersetzen. Bild 1 zeigt den Einsatz des Natural Language to OpenAI API.
Der Einsatzdes OpenAI API(Bild 1) © Autor
Inzwischen nutzt auch GitHub mit seinem Tool Copilot (basierend auf Codex) die Möglichkeiten von künstlicher In­telligenz: Copilot analysiert hierfür Kommentare aus dem Code, an dem der Entwickler arbeitet, und schlägt einzelne Codezeilen oder Funktionen während der Entwicklung vor. So soll der Entwickler alternative Wege zur Pro­blemlösung finden, Tests schreiben und APIs erforschen, ohne im Internet nach Antworten suchen zu müssen.Ein weiteres sogenanntes Code-Completion-Tool ist Tabnine [2]. Tabnine macht ähnlich wie Copilot dem Programmierer während des Editierens Codevorschläge, wie die Zeile oder Funktion weitergehen könnte. Tabnine basiert im Hintergrund auf GPT-2, dem Vorgänger von GPT-3.Die bisher vorgestellten Sprachmodelle stecken derzeit zwar noch sehr tief in den Kinderschuhen, sie zeigen aber immerhin auf, wohin der Weg in Zukunft führen wird, auch wenn es sehr komplex und schwierig ist, für eine beliebige Programmieraufgabe zuverlässigen Code zu generieren. Die ersten Versuche mit GPT-3 und Codex sind vielversprechend. So kann KI in den nächsten Jahren mit Sicherheit auch Entwickler bei komplexen Programmieraufgaben unterstützen.

Unit Testing und Test-Driven Development (TDD)

Auch für den Bereich Unit Testing und Test-Driven Development, kurz TDD, lässt sich die Codegenerierung für die Testautomatisierung einsetzen.Als Unit-Test bezeichnet man ein Verfahren, um das Verhalten einer Komponente ohne ihre Abhängigkeiten zu anderen Komponenten zu überprüfen. Daher spricht man in Verbindung mit Unit-Tests auch häufig von sogenannten Komponententests.Das Ziel des Unit-Tests besteht da­rin, einen sehr kleinen Teil der Funktionalität in einer Anwendung zu überprüfen, um festzustellen, ob dieser Anwendungscode funktioniert. Der Idealfall sieht so aus, dass dieser Code isoliert und ohne Abhängigkeiten getestet wird. Daher werden bei einem Unit-Test nur einzelne Aspekte einer Komponente getestet.Auch in dem Bereich des Unit Testing bietet der Einsatz von künstlicher Intelligenz inzwischen Möglichkeiten, dem Entwickler Routineaufgaben abzunehmen. Die KI kann dem Entwickler etwa bei der automatisierten Testfallerstellung, beim Reduzieren und Priorisieren von Testfällen und bei der automatisierten Testfalladaption helfen. Es wird auch hier in der Zukunft noch eine Vielzahl weiterer Möglichkeiten im Bereich KI und Unit Testing geben.

Test-Driven Development

TDD ist im Unterschied zum Unit Testing eine Designstrategie, die das Testen vor dem Erstellen des eigentlichen Quellcodes ansiedelt und mit Bezug auf die Abläufe vorrangig behandelt. Die Idee von TDD besteht also darin, dass Sie Ihren Testcode erstellen, bevor Sie Ihren Anwendungscode schreiben. Also wird erst der Test geschrieben und dann dazu passend implementiert. TDD orientiert sich an den Ergebnissen der von Ihnen bestimmten Testfälle.In TDD werden hierbei die Codebestandteile so oft refaktorisiert und neu getestet, bis der Test nicht mehr als fehlerhaft angezeigt wird. Das Resultat des TDD ist somit eine Software auf qualitativ hochwertigem Niveau. Denn die zyklische Verfahrensweise stellt sicher, dass der Code erst dann in das Produktivsystem übertragen wird, wenn alle Anforderungen an die Software erfüllt sind.Es geht beim Test-Driven Development also nicht nur da­rum, eine gute Testqualität und Testabdeckung zu erzielen, sondern auch darum, besseren Sourcecode zu schreiben. Mittels einer testgetriebenen Entwicklung wie TDD ist es möglich, durch eine reduzierte Komplexität in den meisten Fällen eine zuverlässigere Lösung zu erzielen.

Die Idee zum eigenen Codebot

Nachdem der Einsatz – also was Codegeneratoren sind und wie sie verwendet werden können – geklärt ist, nun ein Gedanke zum Einstieg für meine Perspektive, einen Codebot zu entwickeln.Bei TDD schreiben die Entwickler erst den Test für eine Funktionalität und dann den eigentlichen Produktivcode. Das inkrementelle Vorgehen aus kleinen, nur wenige Minuten dauernden Tests und die Implementierung des Codes sorgen dafür, dass Testen und Entwickeln eng miteinander verzahnt sind. Da ­einige Codegeneratoren während der Laufzeit entsprechenden Code generieren können, kann es auch sinnvoll sein, Code während der Testphase beziehungsweise für die Testphase zu generieren. Diese Art der Codegenerierung bietet die Möglichkeit, den gesamten Code zu testen, also sowohl einen manuell erzeugten als auch den von einem Codebot generierten Anteil.Um also Code zur Laufzeit als Test zu entwickeln, müssen grundsätzlich für die Erstellung einer testgetriebenen Codegenerierung die benötigten Geschäftsdaten modelliert und die Geschäftsprozesse definiert werden. Um Geschäftsdaten zu modellieren, bestimmen Sie, welche Daten Ihre Anwendung benötigt und wie sich diese Daten auf andere Daten beziehen. Durch die Analyse der Daten und den Ansatz, den Code für das Testen zu automatisieren, landet man ganz schnell im Bereich des sogenannten maschinellen Lernens.

Machine Learning

Machine Learning, kurz ML beziehungsweise maschinelles Lernen, stellt eine Datenanalyse-Methode dar und ist eines der bekanntesten Teilgebiete der KI.ML verfolgt das Ziel, aus Daten zu lernen und möglichst treffende Vorhersagen zu generieren. Das heißt, ein ML-System lernt aus Beispieldaten und kann nach Beendigung der Lernphase das Gelernte verallgemeinern. Für den Softwarebereich hat Thomas Mitchell es wie folgt beschrieben: Ein Computerprogramm lernt beim Lösen einer bestimmten Klasse von Aufgaben (T), wenn seine messbare Leistung (P) sich mit der Erfahrung (E) im Lauf der Zeit erhöht [3]. Diese Logik zu finden wird als maschinelles Lernen bezeichnet.Da sich der Testerstellungsprozess bei TDD auf die Geschäftsanforderungen bezieht, sollten diese Daten einen Abstraktionsgrad aufweisen, der hoch genug ist, um dem Test­er­steller eine bequeme Möglichkeit zu geben, Tests basierend auf den Geschäftsanforderungen zu entwickeln. Zu beachten ist allerdings, dass ein hoher Abstraktionsgrad und eine große Datenmenge für das Testdesign zu mehr Komplexität gegenüber dem klassischen Testansatz führen.Bedenken Sie bitte, dass es sich bei der automatisierten Codegenerierung um eine separate Technik handelt, die nicht Teil von TDD ist. Die automatische Codegenerierung hat jedoch einen engen Bezug zu TDD und wird durch die anderen Informationstechnologien rund um KI noch enger mit TDD verzahnt werden. Daher spricht man bei diesem Technologie-Stack auch schon direkt von der Automated Test-Driven Code Generation. Betrachtet man dann die automatische Softwareentwicklung als Weiterentwicklung des TDD-Prozesses, so kommt man an ML nicht mehr vorbei.Bei ML geht es also darum, Muster und Gesetzmäßigkeiten in großen Datenmengen zu erkennen. Diese Muster können dann wiederum genutzt werden, um spätere Entscheidungen und Handlungen abzuleiten. Das Ziel von ML ist damit, Daten intelligent miteinander zu verknüpfen, Zusammenhänge zu erkennen, Rückschlüsse zu ziehen und dann entsprechende Vorhersagen treffen zu können. Gerade dieser Umstand inspiriert dazu, einen eigenen Codebot zu programmieren und dabei die Zusammenhänge im Detail zu betrachten. Das Erstellen eines Tests und das Ausführen der automatischen Codegenerierung kann so beschrieben werden:
  • Tests in deklarativer Form erstellen und Menge realer physischer Daten berücksichtigen.
  • Betrachten Sie erstellte Tests oder Teile davon als Trainingsdaten für ML und nutzen Sie das Verfahren dann zur automatisierten Erstellung von Softwareeinheiten.
Durch den Einsatz dieser Techniken kann man dann je nach Testfall und Komplexität Machine Learning in der automatisierten Codegenerierung verwenden.Der hier gezeigte Programmierworkshop versteht sich als reines Lernprojekt. Daher ist der Code auf das Einfachste reduziert und es wird auf eine unnötige Komplexitätssteigerung verzichtet. Der hier entwickelte Codebot soll Sie in erster Linie zu weiteren Entwicklungen inspirieren und kann von Ihnen natürlich zu jeder Zeit nach Lust und Laune erweitert werden.

Die Aufgabe für den Codebot

Die Aufgabe für das Beispiel der automatisierten Codegenerierung mithilfe von Trainingsdaten soll möglichst unkompliziert und überschaubar bleiben.Der Codebot soll eine sehr einfache Funktion, die anhand der Trainingsdaten über einen Algorithmus ermittelt wird, als eine minimale C#-Klasse in einer Konsolenanwendung ausgeben. Das heißt, der Codebot soll die Lösung zu einer Funktion vom Typ f(a, b) erstellen, wobei das Ergebnis eine beliebige Kombination seiner Summanden sein darf. Die Lösung soll dann als Code-Snippet in der Konsole wie in Bild 2 dargestellt ausgegeben werden. Die Aufgabe des Algorithmus besteht darin, die Codezeile für die entsprechende Funktion zu finden. Alle anderen Angaben sind bekannt und bilden das vollständige C#-Programm ab.
Ausgabedes Code-Snippets(Bild 2) © Autor

Trainingsdaten

Die Trainingsdaten stellen die Wissensbasis für den Codebot bereit, mit dem der Algorithmus trainiert wird. Der Algorithmus lernt anhand der Daten, eine bestimmte Datenkategorie zu erkennen.Im Beispiel geht es darum, die entsprechende Funktion für das Ergebnis f(a, b) zu ermitteln. Für das Beispiel ist das Resultat der Funktion schon einmal bekannt. Die Eingabeargumente Eingabe A und Eingabe B und das Ergebnis (f) sind in der Excel-Tabelle in Bild 3 dargestellt und werden dem Codebot als Trainingsdaten übergeben.
Testdatensatzfür den Codebot(Bild 3) © Autor
Das Ergebnis (Resultat) dieser Daten setzt sich aus der Funktion = a + 5 * b + 7 zusammen. Durch die Vorgabe der Lösung ist es jetzt möglich, das Ergebnis des Code-Snippets auf Korrektheit zu überprüfen.

Der Codebot

Zur Erstellung dieses Beispiels wird als Entwicklungsumgebung die Visual Studio Community 2019-Version mit dem .NET Framework 4.7.2 verwendet. Wählen Sie als Projektvorlage Console App (.NET Framework) aus und vergeben Sie als Vorbereitung für die Beispielanwendung den Namen DemoCodebot. Der zu implementierende Codebot besteht wiederum aus sechs C#-Klassen:
  • CoachingData.cs
  • CreateCompiledItems.cs
  • Program.cs
  • ProgramCode.cs
  • SelectedItem.cs
  • Simulation.cs
Erstellen Sie die benötigten Klassen in Visual Studio. Der Solution Explorer sollte jetzt aussehen wie in Bild 4 dargestellt.
Die Projektstrukturim Solution-Explorer(Bild 4) © Autor
Als Nächstes fügen Sie in der Klasse CoachingData die benötigten Trainingsdaten als Arraydatenstruktur hinzu. Dafür deklarieren Sie einfach die eindimensionalen Arrays aus Listing 1.
Listing 1: Anlage der Trainingsdaten
namespace DemoCodeBot <br/>{ <br/>  static class CoachingData <br/>  { <br/>    public static int CoachingDataSize = <span class="hljs-number">15</span>; <br/>    public static int[] columnA = { <span class="hljs-number">1</span>, <span class="hljs-number">21</span>, <span class="hljs-number">33</span>, <span class="hljs-number">12</span>, <br/>      <span class="hljs-number">8</span>, <span class="hljs-number">44</span>, <span class="hljs-number">77</span>, <span class="hljs-number">67</span>, <span class="hljs-number">82</span>, <span class="hljs-number">6</span>, <span class="hljs-number">100</span>, <span class="hljs-number">56</span>, <span class="hljs-number">49</span>, <span class="hljs-number">12</span>, <span class="hljs-number">8</span> }; <br/>    public static int[] columnB = { <span class="hljs-number">3</span>, <span class="hljs-number">14</span>, <span class="hljs-number">9</span>, <span class="hljs-number">55</span>, <br/>      <span class="hljs-number">33</span>, <span class="hljs-number">43</span>, <span class="hljs-number">94</span>, <span class="hljs-number">66</span>, <span class="hljs-number">57</span>, <span class="hljs-number">7</span>, <span class="hljs-number">102</span>, <span class="hljs-number">77</span>, <span class="hljs-number">56</span>, <span class="hljs-number">4</span>, <span class="hljs-number">6</span> }; <br/>    public static int[] functionResult = { <span class="hljs-number">23</span>, <span class="hljs-number">98</span>, <br/>      <span class="hljs-number">85</span>, <span class="hljs-number">294</span>, <span class="hljs-number">180</span>, <span class="hljs-number">266</span>, <span class="hljs-number">554</span>, <span class="hljs-number">404</span>, <span class="hljs-number">374</span>, <span class="hljs-number">48</span>, <span class="hljs-number">617</span>, <br/>      <span class="hljs-number">448</span>, <span class="hljs-number">336</span>, <span class="hljs-number">39</span>, <span class="hljs-number">45</span> }; <br/>  } <br/>}  
In der Program-Klasse sind die Main-Methode und die Programmlogik zum Aufruf für den generischen Algorithmus zur Erstellung des Code-Snippets implementiert (Listing 2). Hier werden auch gleich zu Beginn die Instanzen für die weitere Klasse Simulation gebildet. Die while-Schleife wird so lange durchlaufen, bis das Ergebnis der Varianz 0 ergibt. Anschließend wird der erzeugte Code im Konsolenfenster ausgegeben.
Listing 2: Der Code der Klasse Program
<span class="hljs-keyword">using</span> System; <br/><br/><span class="hljs-keyword">namespace</span> DemoCodeBot <br/>{ <br/>  <span class="hljs-keyword">class</span> Program <br/>  { <br/>    <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> Main(<span class="hljs-keyword">string</span>[] args) <br/>    { <br/>      <span class="hljs-built_in">Console</span>.WriteLine(<span class="hljs-string">"Start Demo CodeBot"</span>); <br/>      Simulation simulation = <span class="hljs-keyword">new</span> Simulation(); <br/>      <span class="hljs-keyword">int</span> epoch = <span class="hljs-number">1</span>; <br/>      <span class="hljs-built_in">while</span> (true) <br/>      { <br/>        <span class="hljs-built_in">Console</span>.WriteLine(<span class="hljs-string">"Epoche:{0} --> </span><br/><span class="hljs-string">          Abweichung:{1}"</span>, epoch, <br/>          simulation.BestSelectedItem.Variance); <br/>        simulation.CreateNewEpoch(); <br/>        epoch++; <br/>        <span class="hljs-built_in">if</span> (simulation.BestSelectedItem.Variance != <span class="hljs-number">0</span>) <br/>        { <br/>          <span class="hljs-built_in">continue</span>; <br/>        } <br/>        <span class="hljs-built_in">break</span>; <br/>      } <br/>      <span class="hljs-built_in">Console</span>.WriteLine( <br/>        <span class="hljs-string">"Gelöst in Epoche: {0}"</span>, epoch); <br/>      <span class="hljs-built_in">Console</span>.WriteLine(<br/>        <span class="hljs-string">"Folgender Programmcode wurde erstellt:"</span>); <br/>      <span class="hljs-built_in">Console</span>.WriteLine(); <br/>      <span class="hljs-built_in">Console</span>.WriteLine(); <br/>      <span class="hljs-built_in">Console</span>.WriteLine(<span class="hljs-string">"Erstellter Programmcode:"</span>); <br/>      <span class="hljs-built_in">Console</span>.WriteLine(); <br/>      <span class="hljs-built_in">Console</span>.WriteLine(ProgramCode.GetCode(<br/>        simulation.BestSelectedItem.Item)); <br/>      <span class="hljs-built_in">Console</span>.WriteLine(); <br/>      <span class="hljs-built_in">Console</span>.WriteLine(<span class="hljs-string">"CodeBot beendet!"</span>); <br/>      <span class="hljs-built_in">Console</span>.ReadLine(); <br/>    } <br/>  } <br/>}  
Im ersten Schritt wird über die Ini­tialisierung der Klasse Simulation ein Durchlauf mit den Trainingsdaten als Trainings-Dataset durchgeführt. Hier erfolgt die Erstellung einer Epoche über die Trainingsdaten von kompilierten Items (Argumente der Funktion), die dem Programmcode in Form der vier arithmetischen Operationen Minus, Plus, Multiplikation und Division sowie zwei Variablen a und b und den Ziffern 1 bis 9 übergeben werden. Implementieren Sie die Klasse Simulation wie in Listing 3 dargestellt.
Listing 3: Die Klasse Simulation
<span class="hljs-keyword">using</span> System; <br/><br/><span class="hljs-keyword">namespace</span> DemoCodeBot <br/>{ <br/>  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> Simulation <br/>  { <br/>    SelectedItem[] selectedItems; <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> <span class="hljs-built_in">size</span> = <span class="hljs-number">10</span>; <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> CreateNewEpoch() <br/>    { <br/>      Resimulation(); <br/>      Array.Sort<SelectedItem>(<br/>        selectedItems, SelectedItemComparizon); <br/>    } <br/><br/>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> Resimulation() <br/>    { <br/>      <span class="hljs-keyword">int</span> <span class="hljs-built_in">position</span> = <span class="hljs-built_in">size</span>; <br/>      <span class="hljs-built_in">for</span> (<span class="hljs-keyword">int</span> item1 = <span class="hljs-number">0</span>; item1 < <span class="hljs-built_in">size</span>; item1++) <br/>        <span class="hljs-built_in">for</span> (<span class="hljs-keyword">int</span> item2 = <span class="hljs-number">0</span>; item2 < <span class="hljs-built_in">size</span>; item2++) <br/>        { <br/>          selectedItems[<span class="hljs-built_in">position</span>] = <br/>            CreateCompiledItems.CreateItem(<br/>            selectedItems[item1], selectedItems[item2],<br/>            item1 == item2); <br/>          <span class="hljs-built_in">position</span>++; <br/>        } <br/>    } <br/>    <span class="hljs-keyword">public</span> Simulation() <br/>    { <br/>      selectedItems = <span class="hljs-keyword">new</span> SelectedItem[<span class="hljs-number">110</span>]; <br/>      <span class="hljs-built_in">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < selectedItems.Length; i++) <br/>      { <br/>        selectedItems[i] = <br/>          CreateCompiledItems.CreateItem(); <br/>      } <br/>      Array.Sort<SelectedItem>(<br/>        selectedItems, SelectedItemComparizon); <br/>    } <br/><br/>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> SelectedItemComparizon(<br/>        SelectedItem item1, SelectedItem item2) <br/>    { <br/>      <span class="hljs-built_in">if</span> (item1.Variance < item2.Variance) <br/>        <span class="hljs-built_in">return</span> <span class="hljs-number">-1</span>; <br/>      <span class="hljs-built_in">else</span> <br/>      <span class="hljs-built_in">if</span> (item1.Variance > item2.Variance) <br/>        <span class="hljs-built_in">return</span> <span class="hljs-number">1</span>; <br/>      <span class="hljs-built_in">else</span> <br/>        <span class="hljs-built_in">return</span> <span class="hljs-number">0</span>; <br/>    } <br/><br/>  <span class="hljs-keyword">public</span> SelectedItem BestSelectedItem => <br/>      selectedItems[<span class="hljs-number">0</span>]; <br/>  } <br/>}  
Die Klasse SelectedItem erstellt die entsprechenden Items (Argumente) für die gewünschte Funktion und errechnet in der Methode CalculateVariance die Varianz der Werte. Listing 4 zeigt die Implementierung der Klasse. Die Varianz ist ein Streuungsmaß, welches die Verteilung von Werten um den Mittelpunkt kennzeichnet [4]. Listing 5 zeigt den Code für die Klasse CompiledItems mit den Methoden für die Kompilierung des Programmcodes. Hierbei wird über Reflection der Code im Speicher erstellt und kompiliert.
Listing 4: Die Klasse SelectedItem
<span class="hljs-keyword">using</span> System; <br/><br/><span class="hljs-keyword">namespace</span> DemoCodeBot <br/>{ <br/>  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> SelectedItem <br/>  { <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] Item; <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Variance; <br/>    <span class="hljs-keyword">static</span> Random <span class="hljs-built_in">random</span> = <span class="hljs-keyword">new</span> Random(); <br/>    <span class="hljs-keyword">public</span> SelectedItem() <br/>    { <br/>      Item = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[CoachingData.CoachingDataSize]; <br/>      Item[<span class="hljs-number">0</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>        <span class="hljs-number">0</span>, ProgramCode.variables.Length); <br/>      Item[<span class="hljs-number">1</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>        <span class="hljs-number">0</span>, ProgramCode.operations.Length); <br/>      Item[<span class="hljs-number">2</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>        <span class="hljs-number">0</span>, ProgramCode.variables.Length); <br/>      Item[<span class="hljs-number">3</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>        <span class="hljs-number">0</span>, ProgramCode.operations.Length); <br/>      Item[<span class="hljs-number">4</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>        <span class="hljs-number">0</span>, ProgramCode.variables.Length); <br/>      Item[<span class="hljs-number">5</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>        <span class="hljs-number">0</span>, ProgramCode.operations.Length); <br/>      Item[<span class="hljs-number">6</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>        <span class="hljs-number">0</span>, ProgramCode.variables.Length);      <br/>      Variance = <span class="hljs-keyword">int</span>.MaxValue; <br/>    } <br/>    <span class="hljs-keyword">public</span> SelectedItem(SelectedItem item1, <br/>        SelectedItem item2, <span class="hljs-keyword">bool</span> modify) <br/>    { <br/>      Item = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[CoachingData.CoachingDataSize]; <br/>      <span class="hljs-built_in">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < Item.Length; i++) <br/>        Item[i] = (<span class="hljs-built_in">random</span>.Next(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>) == <span class="hljs-number">0</span> ? <br/>          item1.Item[i] : item2.Item[i]); <br/>      <span class="hljs-built_in">if</span> (modify) <br/>      {        <br/>        <span class="hljs-built_in">if</span> (<span class="hljs-built_in">random</span>.Next(<span class="hljs-number">0</span>, <span class="hljs-number">8</span>) == <span class="hljs-number">0</span>) <br/>          Item[<span class="hljs-number">0</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>            <span class="hljs-number">0</span>, ProgramCode.variables.Length); <br/>        <span class="hljs-built_in">if</span> (<span class="hljs-built_in">random</span>.Next(<span class="hljs-number">0</span>, <span class="hljs-number">8</span>) == <span class="hljs-number">0</span>) <br/>          Item[<span class="hljs-number">1</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>            <span class="hljs-number">0</span>, ProgramCode.operations.Length); <br/>        <span class="hljs-built_in">if</span> (<span class="hljs-built_in">random</span>.Next(<span class="hljs-number">0</span>, <span class="hljs-number">8</span>) == <span class="hljs-number">0</span>) <br/>          Item[<span class="hljs-number">2</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>            <span class="hljs-number">0</span>, ProgramCode.variables.Length); <br/>        <span class="hljs-built_in">if</span> (<span class="hljs-built_in">random</span>.Next(<span class="hljs-number">0</span>, <span class="hljs-number">8</span>) == <span class="hljs-number">0</span>) <br/>          Item[<span class="hljs-number">3</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>            <span class="hljs-number">0</span>, ProgramCode.operations.Length); <br/>        <span class="hljs-built_in">if</span> (<span class="hljs-built_in">random</span>.Next(<span class="hljs-number">0</span>, <span class="hljs-number">8</span>) == <span class="hljs-number">0</span>) <br/>          Item[<span class="hljs-number">4</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>            <span class="hljs-number">0</span>, ProgramCode.variables.Length); <br/>        <span class="hljs-built_in">if</span> (<span class="hljs-built_in">random</span>.Next(<span class="hljs-number">0</span>, <span class="hljs-number">8</span>) == <span class="hljs-number">0</span>) <br/>          Item[<span class="hljs-number">5</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>            <span class="hljs-number">0</span>, ProgramCode.operations.Length); <br/>        <span class="hljs-built_in">if</span> (<span class="hljs-built_in">random</span>.Next(<span class="hljs-number">0</span>, <span class="hljs-number">8</span>) == <span class="hljs-number">0</span>) <br/>          Item[<span class="hljs-number">6</span>] = (<span class="hljs-keyword">byte</span>)<span class="hljs-built_in">random</span>.Next(<br/>            <span class="hljs-number">0</span>, ProgramCode.variables.Length); <br/>      } <br/>      Variance = <span class="hljs-keyword">int</span>.MaxValue; <br/>    } <br/>  <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> CalculateVariance(<span class="hljs-keyword">int</span>[] results) <br/>    { <br/>      <span class="hljs-keyword">int</span> v = <span class="hljs-number">0</span>; <br/>      <span class="hljs-built_in">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; <br/>          i < CoachingData.CoachingDataSize; i++) <br/>      { <br/>        <span class="hljs-keyword">int</span> variance = Math.Abs(<br/>          CoachingData.functionResult[i] - results[i]);<br/>        <br/>        <span class="hljs-built_in">if</span> (v < variance) <br/>          v = variance; <br/>      } <br/>      Variance = v; <br/>    } <br/>  } <br/>}  
Listing 5: Klasse zur Kompilierung des Code-Snippets
<span class="hljs-keyword">using</span> Microsoft.CSharp; <br/><span class="hljs-keyword">using</span> System; <br/><span class="hljs-keyword">using</span> System.CodeDom.Compiler; <br/><span class="hljs-keyword">using</span> System.Reflection; <br/><br/><span class="hljs-keyword">namespace</span> <span class="hljs-title">DemoCodeBot</span> <br/>{ <br/>  <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CreateCompiledItems</span> <br/>  { <br/>    <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> programmCode; <br/>    <span class="hljs-keyword">static</span> CSharpCodeProvider codeProvider = <br/>      <span class="hljs-keyword">new</span> CSharpCodeProvider(); <br/>    <span class="hljs-keyword">static</span> CompilerParameters compilerParameters = <br/>      <span class="hljs-keyword">new</span> CompilerParameters(); <br/>    <span class="hljs-keyword">static</span> <span class="hljs-keyword">object</span>[] functionParameter = <span class="hljs-keyword">new</span> <span class="hljs-keyword">object</span>[<span class="hljs-number">2</span>];    <br/>    <br/>    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-title">CreateCompiledItems</span>(<span class="hljs-params"></span>) </span><br/><span class="hljs-function">    </span>{ <br/>      compilerParameters.GenerateInMemory = <span class="hljs-literal">true</span>; <br/>      compilerParameters.GenerateExecutable = <span class="hljs-literal">false</span>; <br/>    } <br/>    <br/>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> SelectedItem <span class="hljs-title">CreateItem</span>(<span class="hljs-params"></span>) </span><br/><span class="hljs-function">    </span>{ <br/>      SelectedItem selectedItem = <span class="hljs-keyword">new</span> SelectedItem(); <br/>      CompilerResults results = <span class="hljs-literal">null</span>; <br/>      <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) <br/>      {        <br/>        programmCode = <br/>          ProgramCode.GetCode(selectedItem.Item); <br/>        results = <br/>          codeProvider.CompileAssemblyFromSource(<br/>          compilerParameters, programmCode); <br/>        <span class="hljs-keyword">if</span> (results.Errors.HasErrors) <br/>        {          <br/>          selectedItem = <span class="hljs-keyword">new</span> SelectedItem(); <br/>          <span class="hljs-keyword">continue</span>; <br/>        } <br/>        <span class="hljs-keyword">break</span>; <br/>      } <br/>  <br/>      Assembly assembly = results.CompiledAssembly; <br/>      Type program = assembly.GetType(<br/>        <span class="hljs-string">"Program.FunctionClass"</span>); <br/>      MethodInfo main = program.GetMethod(<span class="hljs-string">"Function"</span>); <br/>      <span class="hljs-keyword">int</span>[] functionresults = <br/>        <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[CoachingData.columnA.Length]; <br/>      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> itry = <span class="hljs-number">0</span>; itry < <br/>          CoachingData.columnA.Length; itry++) <br/>      { <br/>        functionParameter[<span class="hljs-number">0</span>] = <br/>          CoachingData.columnA[itry]; <br/>        functionParameter[<span class="hljs-number">1</span>] = <br/>          CoachingData.columnB[itry]; <br/>        functionresults[itry] = Convert.ToInt32(<br/>          main.Invoke(<span class="hljs-literal">null</span>, functionParameter)); <br/>      }      <br/>      selectedItem.CalculateVariance(functionresults); <br/>      <span class="hljs-keyword">return</span> selectedItem; <br/>    } <br/>  <br/>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> SelectedItem <span class="hljs-title">CreateItem</span>(</span><br/><span class="hljs-function"><span class="hljs-params">        SelectedItem item1, SelectedItem item2, </span></span><br/><span class="hljs-function"><span class="hljs-params">        <span class="hljs-keyword">bool</span> modify</span>) </span><br/><span class="hljs-function">    </span>{ <br/>      SelectedItem selectedItem = <span class="hljs-keyword">new</span> SelectedItem(<br/>        item1, item2, modify); <br/>      CompilerResults results = <span class="hljs-literal">null</span>; <br/>      <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) <br/>      {        <br/>        programmCode = ProgramCode.GetCode(<br/>          selectedItem.Item); <br/>        results = <br/>          codeProvider.CompileAssemblyFromSource(<br/>          compilerParameters, programmCode); <br/>        <span class="hljs-keyword">if</span> (results.Errors.HasErrors) <br/>        { <br/>          selectedItem = <span class="hljs-keyword">new</span> SelectedItem(<br/>            item1, item2, <span class="hljs-literal">true</span>); <br/>          <span class="hljs-keyword">continue</span>; <br/>        } <br/>        <span class="hljs-keyword">break</span>; <br/>      } <br/>    <br/>      Assembly assembly = results.CompiledAssembly; <br/>      Type program = assembly.GetType(<br/>        <span class="hljs-string">"Program.FunctionClass"</span>); <br/>      MethodInfo main = program.GetMethod(<span class="hljs-string">"Function"</span>); <br/>      <span class="hljs-keyword">int</span>[] functionresults = <br/>        <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[CoachingData.columnA.Length]; <br/>      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> itry = <span class="hljs-number">0</span>; itry < <br/>          CoachingData.columnA.Length; itry++) <br/>      {        <br/>        functionParameter[<span class="hljs-number">0</span>] = <br/>          CoachingData.columnA[itry]; <br/>        functionParameter[<span class="hljs-number">1</span>] = <br/>          CoachingData.columnB[itry]; <br/>        functionresults[itry] = Convert.ToInt32(<br/>          main.Invoke(<span class="hljs-literal">null</span>, functionParameter)); <br/>      } <br/>      <br/>      selectedItem.CalculateVariance(functionresults); <br/>      <span class="hljs-keyword">return</span> selectedItem; <br/>    } <br/>  } <br/>}  
Des Weiteren benötigen Sie noch die Klasse ProgramCode (siehe Listing 6). Diese Klasse erstellt den Header, den Footer und über die Methode GetFunction das Code-Snippet für die Ausgabe in der Konsole. Das Code-Snippet wird mithilfe der StringBuilder-Klasse als Zeichenfolge ausgegeben.
Listing 6: Klasse zur Erzeugung des Programmcodes
using System; <br/>using System.Text; <br/><br/>namespace DemoCodeBot <br/>{ <br/>  <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> ProgramCode <br/>  { <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">char</span>[] operations = { <span class="hljs-string">'-'</span>, <span class="hljs-string">'+'</span>, <span class="hljs-string">'*'</span>, <br/>      <span class="hljs-string">'/'</span>}; <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">char</span>[] variables = { <span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'1'</span>, <br/>      <span class="hljs-string">'2'</span>, <span class="hljs-string">'3'</span>, <span class="hljs-string">'4'</span>, <span class="hljs-string">'5'</span>, <span class="hljs-string">'6'</span>, <span class="hljs-string">'7'</span>, <span class="hljs-string">'8'</span>, <span class="hljs-string">'9'</span> }; <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Random random = <span class="hljs-keyword">new</span> Random(); <br/>  <br/>    <span class="hljs-keyword">static</span> string Header = <br/>          <span class="hljs-string">"namespace Program\n"</span> + <br/>          <span class="hljs-string">"{\n"</span> + <br/>          <span class="hljs-string">"  public class FunctionClass\n"</span> +<br/>          <span class="hljs-string">"  {\n"</span> + <br/>          <span class="hljs-string">"    public static int Function("</span> +<br/>          <span class="hljs-string">"int a, int b)\n"</span> + <br/>          <span class="hljs-string">"    {\n"</span> + <br/>          <span class="hljs-string">"      "</span>; <br/>    <span class="hljs-keyword">static</span> string Footer= <br/>          <span class="hljs-string">"\n"</span> + <br/>          <span class="hljs-string">"    }\n"</span> + <br/>          <span class="hljs-string">"  }\n"</span> + <br/>          <span class="hljs-string">"}"</span>; <br/>  <br/>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> string GetCode(<span class="hljs-keyword">byte</span>[] item) <br/>    { <br/>      StringBuilder code = <span class="hljs-keyword">new</span> StringBuilder(); <br/>      code.<span class="hljs-keyword">Append</span>(Header); <br/>      code.<span class="hljs-keyword">Append</span>(@<span class="hljs-string">"return "</span>); <br/>      GetFunction(code, item); <br/>      code.<span class="hljs-keyword">Append</span>(<span class="hljs-string">';'</span>); <br/>      code.<span class="hljs-keyword">Append</span>(Footer); <br/>      <span class="hljs-keyword">return</span> code.ToString(); <br/>    } <br/>  <br/>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> GetFunction(<br/>        StringBuilder code, <span class="hljs-keyword">byte</span>[] item) <br/>    { <br/>      code.<span class="hljs-keyword">Append</span>(<span class="hljs-string">' '</span>); <br/>      code.<span class="hljs-keyword">Append</span>(variables[item[<span class="hljs-number">0</span>]]); <br/>      code.<span class="hljs-keyword">Append</span>(<span class="hljs-string">' '</span>); <br/>      code.<span class="hljs-keyword">Append</span>(operations[item[<span class="hljs-number">1</span>]]); <br/>      code.<span class="hljs-keyword">Append</span>(<span class="hljs-string">' '</span>); <br/>      code.<span class="hljs-keyword">Append</span>(variables[item[<span class="hljs-number">2</span>]]); <br/>      code.<span class="hljs-keyword">Append</span>(<span class="hljs-string">' '</span>); <br/>      code.<span class="hljs-keyword">Append</span>(operations[item[<span class="hljs-number">3</span>]]); <br/>      code.<span class="hljs-keyword">Append</span>(<span class="hljs-string">' '</span>); <br/>      code.<span class="hljs-keyword">Append</span>(variables[item[<span class="hljs-number">4</span>]]); <br/>      code.<span class="hljs-keyword">Append</span>(<span class="hljs-string">' '</span>); <br/>      code.<span class="hljs-keyword">Append</span>(operations[item[<span class="hljs-number">5</span>]]); <br/>      code.<span class="hljs-keyword">Append</span>(<span class="hljs-string">' '</span>); <br/>      code.<span class="hljs-keyword">Append</span>(variables[item[<span class="hljs-number">6</span>]]);      <br/>    } <br/>  } <br/>}  

Programmablauf und Simulationsergebnis

Sind alle Klassen für das Beispiel implementiert, können Sie den Codebot über [F5] oder Start in Visual Studio ausführen. Das Programm durchläuft jetzt als ersten Schritt die Erstellung des gewünschten Codes durch Einfügen der Argumente, die zufällig aus dem char-Array ausgewählt werden. Danach erfolgt die Kompilierung im Arbeitsspeicher für den Code. Schlägt die Kompilierung fehl, so wird der erste Schritt wiederholt.Ist die Kompilierung erfolgreich, so wird das Code-Snippet gebaut und die tatsächliche Funktionsausgabe und die Ergebnisse aus dem Trainingsdatensatz verglichen. Wenn die Werte im Ergebnis abweichen, beginnt das Ganze wieder mit Schritt eins. Stimmen Ergebnis und Trainingsdatensatz überein, so wird die Funktion als Code-Snippet in der Konsole ausgegeben und das Programm beendet. Bild 5 zeigt ein Simulationsergebnis nach sechs Epochen mit der Funk­tion
5 * b + a + 7.
Simulationsergebnisnach der Ausführung(Bild 5) © Autor
Es gibt jetzt noch eine Vielzahl von Verbesserungsmöglichkeiten und Optimierungen für den Codebot. Sie können sich für entsprechende Anpassungen oder auch Erweiterungen in einzelnen Schritten ganz einfach herantasten und mit der automatischen Codegenerierung experimentieren. Durch eine Erweiterung der Funktionsargumente könnte man die Formel auch komplexer ausführen (Bild 6).
Die Funktionnach Erweiterung der Argumente(Bild 6) © Autor

Fazit

Dieser Programmierworkshop konnte lediglich einen kleinen Überblick über die Möglichkeiten der automatisierten Codegenerierung geben. Es sollte aber erkennbar sein, welche Möglichkeiten dieser Technologie-Stack in Zukunft bieten kann. Für uns Entwickler bleibt es spannend.
Projektdateien herunterladen

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Evolutionäres Prototyping von Business-Apps - Low Code/No Code und KI mit Power Apps
Microsoft baut Power Apps zunehmend mit Features aus, um die Low-Code-/No-Code-Welt mit der KI und der professionellen Programmierung zu verbinden.
19 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige