<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Software Engineering &amp; Programming Archives - Creatronix</title>
	<atom:link href="https://creatronix.de/category/software-engineering/feed/" rel="self" type="application/rss+xml" />
	<link>https://creatronix.de/category/software-engineering/</link>
	<description>My adventures in code &#38; business</description>
	<lastBuildDate>Thu, 16 Jul 2026 12:42:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>
	<item>
		<title>Qualitätsmetriken bei binärer Klassifikation</title>
		<link>https://creatronix.de/qualitaetsmetriken-bei-binarer-klassifikation/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Mon, 13 Jul 2026 06:44:34 +0000</pubDate>
				<category><![CDATA[Data Science & SQL]]></category>
		<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=8067</guid>

					<description><![CDATA[<p>Motivation Im Universum Bremen haben wir die Sonderausstellung KI besucht. Dort konnte man an einer Station prüfen, ob man Chihuahuas von Muffins unterscheiden kann. Die Kinder hatten einen Riesenspaß, da das Ganze auf Zeit ging und sie daraus einen Wettbewerb machen konnten. Wer schneller im Unterscheiden war, hatte gewonnen. Eine bessere Zeit zählt jedoch nicht,&#8230;</p>
<p>The post <a href="https://creatronix.de/qualitaetsmetriken-bei-binarer-klassifikation/">Qualitätsmetriken bei binärer Klassifikation</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Motivation</h2>
<p>Im <a href="https://universum-bremen.de" target="_blank" rel="noopener">Universum Bremen</a> haben wir die Sonderausstellung KI besucht. Dort konnte man an einer Station prüfen, ob man Chihuahuas von Muffins unterscheiden kann. Die Kinder hatten einen Riesenspaß, da das Ganze auf Zeit ging und sie daraus einen Wettbewerb machen konnten. Wer schneller im Unterscheiden war, hatte gewonnen. Eine bessere Zeit zählt jedoch nicht, wenn Karten dabei falsch zugeordnet wurden.</p>
<p>Um überprüfen zu können, wie gut eine Klassifizierung ist, können wir Metriken definieren. Vorher brauchen wir aber noch ein paar grundlegende Begriffe.</p>
<h2>Begriffe</h2>
<p><img fetchpriority="high" decoding="async" src="https://creatronix.de/wp-content/uploads/2026/07/termini-1024x683.png" alt="" width="1024" height="683" class="alignnone size-large wp-image-8062" srcset="https://creatronix.de/wp-content/uploads/2026/07/termini-1024x683.png 1024w, https://creatronix.de/wp-content/uploads/2026/07/termini-300x200.png 300w, https://creatronix.de/wp-content/uploads/2026/07/termini-768x512.png 768w, https://creatronix.de/wp-content/uploads/2026/07/termini.png 1536w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p>Die Unterscheidung zwischen Chihuahua und Muffin ist gar nicht so leicht. Grundsätzlich gibt es vier mögliche Ergebnisse: Ein Chihuahua kann korrekt als Chihuahua erkannt werden, oder er wird fälschlicherweise als Muffin eingeordnet. Umgekehrt kann ein Muffin korrekt als Muffin erkannt werden, oder er wird für einen Chihuahua gehalten. Das sind die vier Klassifikationsmöglichkeiten.</p>
<p>Die Klasse der Objekte, die man erkennen möchte, gilt als der positive Wert. In unserem Fall möchten wir Chihuahuas erkennen.</p>
<table>
<thead>
<tr>
<th>Wirklichkeit</th>
<th>Vorhersage</th>
<th>Ergebnis</th>
</tr>
</thead>
<tbody>
<tr>
<td>Chihuahua</td>
<td>Chihuahua</td>
<td><strong>True Positive</strong></td>
</tr>
<tr>
<td>Muffin</td>
<td>Chihuahua</td>
<td><strong>False Positive</strong></td>
</tr>
<tr>
<td>Chihuahua</td>
<td>Muffin</td>
<td><strong>False Negative</strong></td>
</tr>
<tr>
<td>Muffin</td>
<td>Muffin</td>
<td><strong>True Negative</strong></td>
</tr>
</tbody>
</table>
<p>Ein False Positive wird auch als Typ-1-Fehler bezeichnet, ein False Negative als Typ-2-Fehler.</p>
<h2>Beispiel</h2>
<h2><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/07/example-classification-1024x683.png" alt="" width="1024" height="683" class="alignnone size-large wp-image-8065" srcset="https://creatronix.de/wp-content/uploads/2026/07/example-classification-1024x683.png 1024w, https://creatronix.de/wp-content/uploads/2026/07/example-classification-300x200.png 300w, https://creatronix.de/wp-content/uploads/2026/07/example-classification-768x512.png 768w, https://creatronix.de/wp-content/uploads/2026/07/example-classification.png 1535w" sizes="(max-width: 1024px) 100vw, 1024px" /></h2>
<p>Wenn sich meine Tochter zwanzig Bilder von Muffins und Chihuahuas anschaut (8 Muffins und 12 Chihuahuas)<br />
und sie 10 davon als Chihuahuas klassifiziert, sich unter diesen zehn jedoch tatsächlich 2 Muffins befinden,<br />
ergibt sich folgendes Bild:</p>
<ul>
<li><strong>8 True Positives</strong> – korrekt als Chihuahua erkannt</li>
<li><strong>2 False Positives</strong> – Muffin fälschlicherweise als Chihuahua eingeordnet</li>
<li><strong>6 True Negatives</strong> – korrekt als Muffin erkannt</li>
<li><strong>4 False Negatives</strong> – Chihuahua fälschlicherweise als Muffin klassifiziert</li>
</ul>
<p>Mit diesen Werten berechnen wir im Folgenden die Metriken.</p>
<h2>Metriken</h2>
<p>Metriken dienen der Überprüfung der Qualität von Machine-Learning-Algorithmen. Sie funktionieren besonders gut bei Supervised-Learning-Algorithmen, da wir gelabelte Trainings- und Testdaten (Ground-Truth-Labels) vorliegen haben und somit überprüfen können, ob eine Klassifikation korrekt oder falsch erfolgte.</p>
<h3>Precision</h3>
<h3><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/07/recall-1024x1024.png" alt="" width="1024" height="1024" class="alignnone size-large wp-image-8061" srcset="https://creatronix.de/wp-content/uploads/2026/07/recall-1024x1024.png 1024w, https://creatronix.de/wp-content/uploads/2026/07/recall-300x300.png 300w, https://creatronix.de/wp-content/uploads/2026/07/recall-150x150.png 150w, https://creatronix.de/wp-content/uploads/2026/07/recall-768x769.png 768w, https://creatronix.de/wp-content/uploads/2026/07/recall.png 1027w" sizes="(max-width: 1024px) 100vw, 1024px" /></h3>
<p>Die Präzision – auch als <em>positive predictive value</em> bezeichnet – gibt den Anteil der korrekt als positiv klassifizierten Ergebnisse an der Gesamtheit der als positiv klassifizierten Ergebnisse an.</p>
<span class="katex-eq" data-katex-display="true"> Precision = True Positive / (True Positive + False Positive) </span>
<p>In unserem Beispiel beträgt die Präzision 8 / (8 + 2) = 4/5 oder 80 %.</p>
<h3><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/07/precision-1024x1024.png" alt="" width="1024" height="1024" class="alignnone size-large wp-image-8063" srcset="https://creatronix.de/wp-content/uploads/2026/07/precision-1024x1024.png 1024w, https://creatronix.de/wp-content/uploads/2026/07/precision-300x300.png 300w, https://creatronix.de/wp-content/uploads/2026/07/precision-150x150.png 150w, https://creatronix.de/wp-content/uploads/2026/07/precision-768x769.png 768w, https://creatronix.de/wp-content/uploads/2026/07/precision.png 1027w" sizes="(max-width: 1024px) 100vw, 1024px" /></h3>
<h3>Recall</h3>
<p>Der Recall – auch Sensitivität genannt – gibt die Wahrscheinlichkeit an, mit der ein positives Objekt korrekt als positiv klassifiziert wird.</p>
<span class="katex-eq" data-katex-display="true">Recall = True Positive / (True Positive + False Negative)</span>
<p>Da bekannt ist, dass es tatsächlich 12 Chihuahuas gibt und meine Tochter 4 davon übersieht (falsch-negative Ergebnisse), beträgtihre Trefferquote (Recall) 8 / (8 + 4) = 2/3 oder rund 67 %.</p>
<h3>Accuracy</h3>
<h3><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/07/accuracy-1024x1024.png" alt="" width="1024" height="1024" class="alignnone size-large wp-image-8060" srcset="https://creatronix.de/wp-content/uploads/2026/07/accuracy-1024x1024.png 1024w, https://creatronix.de/wp-content/uploads/2026/07/accuracy-300x300.png 300w, https://creatronix.de/wp-content/uploads/2026/07/accuracy-150x150.png 150w, https://creatronix.de/wp-content/uploads/2026/07/accuracy-768x769.png 768w, https://creatronix.de/wp-content/uploads/2026/07/accuracy.png 1027w" sizes="(max-width: 1024px) 100vw, 1024px" /></h3>
<p>Der Accuracy-Score berechnet sich aus dem Anteil aller korrekt klassifizierten Ergebnisse:</p>
<span class="katex-eq" data-katex-display="true"> Accuracy = (TP + TN) / (TP + FP + TN + FN) </span>
<p>In unserem Beispiel ergibt das:</p>
<p>(8 + 6) / 20 = 14/20 = 7/10 = 70 %</p>
<h3>F1-Score</h3>
<p>Der F1-Score ist das harmonische Mittel zwischen Precision und Recall und bietet sich besonders dann an, wenn beide Größen gleichermaßen wichtig sind.</p>
<span class="katex-eq" data-katex-display="true">f1 = 2/(1/Precision + 1/Recall)</span>
<p>Für unser Beispiel: 2 / (1 / (4/5) + 1 / (2/3)) = 2 / (5/4 + 3/2) = 2 / (11/4) = 2*(4/11) = 8/11 = 0,727</p>
<h2>Fazit</h2>
<p>Precision, Recall, Accuracy und F1-Score sind vier grundlegende Metriken, um die Qualität eines binären Klassifikationsmodells zu bewerten. Welche Metrik im Vordergrund steht, hängt dabei vom konkreten Anwendungsfall ab:</p>
<ul>
<li>Ist es besonders wichtig, keine positiven Fälle zu verpassen (z. B. bei medizinischen Diagnosen), rückt der Recall in den Fokus.</li>
<li>Soll hingegen vermieden werden, zu viele Fehlalarme zu produzieren, ist Precision die relevantere Größe.</li>
<li>Der F1-Score bietet sich an, wenn beide Aspekte gleich gewichtet werden sollen.</li>
</ul>
<p>Darüber hinaus gibt es weitere Metriken – etwa den ROC-AUC-Score oder die Konfusionsmatrix –, die ein noch detaillierteres Bild liefern können.</p>
<p>Beim Unsupervised Learning gelten zudem andere Regeln: Da keine Ground-Truth-Labels vorliegen, kommen dort eigene Verfahren wie der Silhouetten-Koeffizient oder der Davies-Bouldin-Index zum Einsatz – aber das ist Stoff für einen eigenen Artikel.</p>
<p>The post <a href="https://creatronix.de/qualitaetsmetriken-bei-binarer-klassifikation/">Qualitätsmetriken bei binärer Klassifikation</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Boost SML Tutorial</title>
		<link>https://creatronix.de/boost-sml/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Sun, 05 Jul 2026 10:18:14 +0000</pubDate>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=8045</guid>

					<description><![CDATA[<p>Motivation Wer mit Robotern arbeitet, wird früher oder später eine Zustandsmaschine programmieren müssen, da Roboter typischerweise verschiedene Betriebszustände einnehmen können. Was sind State Machines? Eine State Machine (deutsch: Zustandsautomat) ist ein Modell, das beschreibt, wie sich ein System abhängig von seinem aktuellen Zustand und einem Ereignis verhält. Statt viele verschachtelte if-Anweisungen zu verwenden, definiert man&#8230;</p>
<p>The post <a href="https://creatronix.de/boost-sml/">Boost SML Tutorial</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Motivation</h2>
<p>Wer mit Robotern arbeitet, wird früher oder später eine Zustandsmaschine programmieren müssen, da Roboter typischerweise verschiedene Betriebszustände einnehmen können.</p>
<h2>Was sind State Machines?</h2>
<p>Eine State Machine (deutsch: Zustandsautomat) ist ein Modell, das beschreibt, wie sich ein System abhängig von seinem aktuellen Zustand und einem Ereignis verhält. Statt viele verschachtelte if-Anweisungen zu verwenden, definiert man klar:</p>
<ul>
<li><strong>Zustände</strong> – z. B. „Aus&#8221;, „Ein&#8221;, „Pause&#8221;</li>
<li><strong>Ereignisse</strong> – z. B. Tastendruck oder Timer</li>
<li><strong>Übergänge</strong> – wann von einem Zustand in einen anderen gewechselt wird</li>
<li><strong>Aktionen</strong> – was beim Wechsel oder innerhalb eines Zustands passiert</li>
</ul>
<h2>Boost SML</h2>
<p>Boost State Machine Language wurde 2016 von Kris Jusiak entwickelt.</p>
<ul>
<li>Erste öffentliche Version auf GitHub: 2016</li>
<li>Anzahl der Contributors: ~50</li>
<li>Ein bis zwei Releases pro Jahr</li>
<li>Kein offizieller Teil von Boost</li>
</ul>
<p>Projektseite: <a href="https://github.com/boost-ext/sml">https://github.com/boost-ext/sml</a></p>
<h2>Installation</h2>
<h3>Variante 1 &#8211; Download Header</h3>
<p>Die erste Variante ist, eine flache Kopie des Headers direkt ins Projekt zu legen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>cd ~/robot_sml_demo
mkdir boost
wget https://raw.githubusercontent.com/boost-ext/sml/master/include/boost/sml.hpp</code></pre>
</div>
<p>Einbinden mit</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>#include "boost/sml.hpp"
</code></pre>
</div>
<h3>Variante 2 &#8211; Globale Verfügbarkeit</h3>
<p>Alternativ kann auch das Repo ins Home-Verzeichnis geklont werden:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>cd ~
git clone https://github.com/boost-ext/sml</code></pre>
</div>
<p>Erstellt dafür den Ordner sml im Home, dann kann man über CMake das Verzeichnis inkludieren</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>target_include_directories(robot_sml_tutorial PRIVATE
    $ENV{HOME}/sml/include
)</code></pre>
</div>
<p>Einbinden kann man nun mit</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>#include &lt;boost/sml.hpp&gt;</code></pre>
</div>
<h3>Variante 3 &#8211; git submodules</h3>
<p>Eine weitere Variante ist die Einbindung über git submodules.</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>mkdir external
git submodule add https://github.com/boost-ext/sml external/boost
git submodule update --init --recursive</code></pre>
</div>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>#include "../external/boost/include/boost/sml.hpp"</code></pre>
</div>
<h2>Einfache State Machine</h2>
<p>Im folgenden Implementieren wir eine einfache State Machine für einen Roboter. Hier sind die Zustände und Übergänge tabellarisch:</p>
<table>
<thead>
<tr>
<th>State</th>
<th>Event</th>
<th>New state</th>
</tr>
</thead>
<tbody>
<tr>
<td>Idle</td>
<td>Start</td>
<td>Driving</td>
</tr>
<tr>
<td>Idle</td>
<td>Error</td>
<td>Fault</td>
</tr>
<tr>
<td>Driving</td>
<td>Stop</td>
<td>Idle</td>
</tr>
<tr>
<td>Driving</td>
<td>Error</td>
<td>Fault</td>
</tr>
<tr>
<td>Fault</td>
<td>Reset</td>
<td>Idle</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>Ein Bild sagt aber mehr als 1000 Worte:</p>
<h2><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/07/simple-robot-states.png" alt="" width="600" height="459" class="alignnone size-full wp-image-8044" srcset="https://creatronix.de/wp-content/uploads/2026/07/simple-robot-states.png 600w, https://creatronix.de/wp-content/uploads/2026/07/simple-robot-states-300x230.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></h2>
<h2>Erste Implementierung</h2>
<p>Eine State Machine in SML benötigt drei Dinge:</p>
<ul>
<li>Zustände + Events</li>
<li>Transition Table</li>
<li>Transition durch die Zustände mit <code>process_event()</code></li>
</ul>
<h3>Modellierung der Zustände und Events</h3>
<p>In Boost.SML können Zustände und Events durch structs implementiert werden:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>// States
struct Idle {};
struct Driving {};
struct Fault{};

// Events
struct Start{};
struct Stop{};
struct Error{};
struct Reset{};
</code></pre>
</div>
<h3>Transition Table</h3>
<p>Die Transition Table ist das Herzstück der State Machine. Der Startzustand wird über <code>*</code> definiert, dann folgt die Modellierung der Zustandsübergänge nach dem Muster:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>src_state + event = dst_state</code></pre>
</div>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>struct Robot
{
    auto operator()() const
    {
        using namespace sml;
        return make_transition_table(

<idle><start><driving><driving><error><fault><driving><stop><idle><fault><reset><idle>            *state&lt;Idle&gt;+ event&lt;Start&gt; = state&lt;Driving&gt;,
            state&lt;Driving&gt; + event&lt;Error&gt; = state&lt;Fault&gt;,
            state&lt;Driving&gt; + event&lt;Stop&gt; = state&lt;Idle&gt;,
            state&lt;Fault&gt; + event&lt;Reset&gt; = state&lt;Idle&gt;
        );
    }
};

TEST(SimpleStateMachine, TestStartState) {
    const sml::sm<robot> robot{};

    robot.visit_current_states([](auto state) {
        EXPECT_STREQ(state.c_str(), "Idle");
    });
}
</robot></idle></reset></fault></idle></stop></driving></fault></error></driving></driving></start></idle></code></pre>
</div>
<p>Im Grunde ist Robot hier keine State Machine, sondern eine Konfigurationsklasse. Der operator()()-Ausdruck bedeutet, dass der Funktionsaufruf-Operator überladen wird. Klassen, die diesen Operator implementieren, erzeugen Objekte, die wie ganz normale Funktionen aufgerufen werden können. Solche Objekte nennt man auch Funktoren.</p>
<h3>Transition durch die Zustände</h3>
<p>Eine Transition von einem Zustand in einen anderen wird durch process_event ausgelöst:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>TEST(SimpleStateMachine, TestTransition) {
    sml::sm<robot> robot{};

    robot.process_event(Start{});

    robot.visit_current_states([](auto state) {
        EXPECT_STREQ(state.c_str(), "Driving");
    });
}
</robot></code></pre>
</div>
<h2>Actions</h2>
<p>Jedem Zustandübergang kann eine Aktion zugeordnet werden, hier im Beispiel mit Lambdas</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>src_state + event / action = dst_state</code></pre>
</div>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>struct Robot
{
    auto operator()() const
    {
        using namespace sml;
        return make_transition_table(
<idle><start><start><driving><driving><error><error><fault><driving><stop><stop><idle><fault><reset><reset>
            *state&lt;Idle&gt; + event&lt;Start&gt; / [] { std::cout &lt;&lt; "Received &lt;&lt;Start&gt;&gt; Event";} = state&lt;Driving&gt;,
            state&lt;Driving&gt; + event&lt;Error&gt; / [] { std::cout &lt;&lt; "Received &lt;&lt;Error&gt;&gt; Event";} = state&lt;Fault&gt;,
            state&lt;Driving&gt; + event&lt;Stop&gt; / [] { std::cout &lt;&lt; "Received &lt;&lt;Stop&gt;&gt; Event";} = state&lt;Idle&gt;,
            state&lt;Fault&gt; + event&lt;Reset&gt; / [] { std::cout &lt;&lt; "Received &lt;&lt;Reset&gt;&gt; Event";} = state&lt;Idle&gt;<idle>
        );
    }
};
</idle></reset></reset></fault></idle></stop></stop></driving></fault></error></error></driving></driving></start></start></idle></code></pre>
</div>
<h3>Actions als Function Objects / Funktoren</h3>
<p>Eleganter hingegen ist es, Actions ebenfalls als Funktor zu definieren, da das die Transition Table deutlich übersichtlicher macht:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>struct start_action {
    void operator()() const {
        std::cout &lt;&lt; "Start\n";
    }
};
struct stop_action {
    void operator()() const {
        std::cout &lt;&lt; "Stop\n";
    }
};
struct error_action {
    void operator()() const {
        std::cout &lt;&lt; "Error\n";
    }
};
struct reset_action {
    void operator()() const {
        std::cout &lt;&lt; "Reset\n";
    }
};

...
return make_transition_table(

<idle><start><driving><driving><error><fault><driving><stop><idle><fault><reset><idle>     *state&lt;Idle&gt;+ event&lt;Start&gt; / start_action{} = state&lt;Driving&gt;,
     state&lt;Driving&gt; + event&lt;Error&gt; / error_action{} = state&lt;Fault&gt;,
     state&lt;Driving&gt; + event&lt;Stop&gt; / stop_action{} = state&lt;Idle&gt;,
     state&lt;Fault&gt; + event&lt;Reset&gt; / reset_action{} = state&lt;Idle&gt;
 );
</idle></reset></fault></idle></stop></driving></fault></error></driving></driving></start></idle></code></pre>
</div>
<h2>Guards</h2>
<p>Ein Guard ist eine Bedingung, die entscheiden darf, ob ein Übergang stattfinden soll.</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>state + event [ guard ] = next_state;</code></pre>
</div>
<h2>Beispiel</h2>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>auto battery_ok = [] { return true; };

...
*state&lt;Idle&gt;+ event&lt;Start&gt;[battery_ok] = state&lt;Driving&gt;,</code></pre>
</div>
<h3>Mehrere Guards verknüpfen</h3>
<p>Das ist ein besonderes Feature von SML: Guards können mit &amp;&amp;, || und ! kombiniert werden.</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>state + event [ guard1 || guard2 ] / action = next_state;</code></pre>
</div>
<h3>Dependency Injection</h3>
<p>Eine weitere große Stärke von SML ist die Verwendung von Dependency Injection.</p>
<p>Hier injiziert SML das <code>RobotContext</code>-Objekt in den Guard:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>struct RobotContext {
    bool battery_ok = true;
};
...
*state&lt;Idle&gt;+ (StartEvent)[([](const RobotContext&amp; ctx) {return ctx.battery_ok;})] = state&lt;Driving&gt;,

...
RobotContext ctx;
sml::sm robot{ctx};
robot.process_event(StartEvent());</code></pre>
</div>
<h2>User-Defined Literals (UDLs)</h2>
<p>Zu Deutsch benutzerdefinierte Literale.</p>
<h3>States</h3>
<p>Für Zustände definiert SML das Literal <code>_s</code>, dadurch ist <code>"Idle"_s</code> ein gültiger Zustand.</p>
<h2>Events</h2>
<p>Für Events existiert das Literal <code>_e</code>:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>auto start_event = "Start"_e;
</code></pre>
</div>
<p>Die Transitiontabelle wird dadurch etwas besser lesbar:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>return make_transition_table(

    *"Idle"_s    + start_event  = "Driving"_s,
     "Driving"_s + stop_event  = "Idle"_s,
     "Driving"_s + error_event = "Fault"_s,
     "Fault"_s   + reset_event = "Idle"_s
    );
</code></pre>
</div>
<p>Im process_event muss es dann so aufgerufen werden:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-cpp" data-lang="C++"><code>robot.process_event(start_event());
</code></pre>
</div>
<h2>Fazit &amp; Ausblick</h2>
<p>SML ist eine kleine, schlanke Library für State Machines in C++. Sie überzeugt durch ihre ausdrucksstarke Syntax, Dependency Injection und die Möglichkeit, Guards flexibel zu kombinieren.</p>
<h2>Links</h2>
<p>Die Codebeispiele findest Du in diesem Repo:<br />
<a href="https://github.com/jboegeholz/boost_sml_tutorial">https://github.com/jboegeholz/boost_sml_tutorial</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The post <a href="https://creatronix.de/boost-sml/">Boost SML Tutorial</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Das Perzeptron</title>
		<link>https://creatronix.de/das-perzeptron/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Wed, 10 Jun 2026 18:27:21 +0000</pubDate>
				<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=8011</guid>

					<description><![CDATA[<p>Warum brauchen wir überhaupt KI? Der Mensch ist im Grunde kein faules Tier. Er ist nur sehr konsequent darin, unnötige Mühen als persönliche Beleidigung zu empfinden. Irgendwann stand also einer da, hatte zwei Arme voll Zeug und dachte: „Nee, komm, dat kann doch nich alles gewesen sein.“ Zack: Rad. Ein anderer kaute auf rohem Fleisch&#8230;</p>
<p>The post <a href="https://creatronix.de/das-perzeptron/">Das Perzeptron</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Warum brauchen wir überhaupt KI?</h2>
<p>Der Mensch ist im Grunde kein faules Tier. Er ist nur sehr konsequent darin, unnötige Mühen als persönliche Beleidigung zu empfinden.</p>
<p>Irgendwann stand also einer da, hatte zwei Arme voll Zeug und dachte: „Nee, komm, dat kann doch nich alles gewesen sein.“ Zack: Rad. Ein anderer kaute auf rohem Fleisch herum wie auf einem alten Fahrradmantel und kam zu dem Schluss, dass die Evolution ruhig mal einen Gang höher schalten könnte. Also Feuer.</p>
<p>Später saß jemand vor einem getippten Text und verschmierte Tipp-Ex. Daraus wurden dann Textverarbeitung, Backspace-Taste und dieses stille Glück, einen Fehler einfach verschwinden lassen zu können.</p>
<p>Im Kern geht es immer um dasselbe: Das Gehirn will nicht mehr Energie verbrauchen als unbedingt nötig. Es möchte rationale Entscheidungen treffen, Aufwand senken und den erwarteten Nutzen erhöhen. Klingt trocken, ist aber menschheitsgeschichtlich gesehen der rote Faden vom Faustkeil bis zur Tabellenkalkulation.</p>
<p>Und deshalb forscht der Mensch heute an KI: nicht nur, weil er bequem ist, sondern weil er verstehen will, wie Intelligenz funktioniert, wie man nützliche Aufgaben automatisiert und wie daraus Werkzeuge für Wissenschaft, Wirtschaft und Gesellschaft entstehen.</p>
<p>Kurz gesagt: Der Mensch denkt gern. Aber wenn eine Maschine das Vorsortieren übernehmen kann, sagt er auch nicht nein.</p>
<h2>Historie der KI</h2>
<p>&#8220;Ich baue ein Neuron so, dass es eine feste Regel ausführt.&#8221;</p>
<p>Die Sache mit der KI fing nicht erst an, als irgendein Start-up-Mensch mit Macha Latte in einem Co-Working-Space „disruptiv“ sagte.</p>
<p>Schon 1943 saßen Warren McCulloch und Walter Pitts da und dachten sich sinngemäß: „Wenn das Gehirn mit Neuronen arbeitet, kann man doch mal gucken, ob man sowas nicht auch in ordentlich nachbauen kann.“ Also beschrieben sie einfache Einheiten, die miteinander verknüpft werden – ein Netz, das grob an Nervenzellen im Gehirn erinnert. Das Paper hieß &#8220;A Logical Calculus of the Ideas Immanent in Nervous Activity&#8221;.</p>
<p>Das Neuron konnte als Boolesche Variable die Zustände wahr und falsch annehmen und „feuerte“ (= wahr), wenn die Summe der Eingangssignale einen Schwellenwert überschritt.</p>
<p>Und siehe da: Mit solchen künstlichen Neuronen ließen sich theoretisch so ziemlich jede logische oder arithmetische Funktion berechnen. Also alles, wofür normale Menschen später Taschenrechner, Computer und irgendwann Kaffee brauchten.</p>
<h2>Das Perzeptron</h2>
<p>&#8220;Ich gebe dem Neuron Beispiele, und es verändert seine Gewichte, bis es die Regel selbst gelernt hat.&#8221;</p>
<p>Dann kam das Perzeptron. Es wurde 1957 von Frank Rosenblatt vorgestellt und ist ein vereinfachtes künstliches neuronales Netz. Sein wichtigster Beitrag: die Anpassung der Gewichte erfolgte jetzt dynamisch. Die Ausgabe des Neurons blieb dank der Schwellwertfunktion aber digital 0 oder 1, auch wenn die Eingaben jetzt kontinuierliche Werte verarbeiten konnte.</p>
<h3>Einlagiges Perzeptron</h3>
<p>Nehmen wir ein Perzeptron mit 2 Eingaben und einer Ausgabe:</p>
<p><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/06/perceptron-1024x608.png" alt="" width="1024" height="608" class="alignnone size-large wp-image-8009" srcset="https://creatronix.de/wp-content/uploads/2026/06/perceptron-1024x608.png 1024w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-300x178.png 300w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-768x456.png 768w, https://creatronix.de/wp-content/uploads/2026/06/perceptron.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p>&nbsp;</p>
<p>Die Verbindung vom Neuron x1 zu Neuron z wird mit dem Gewicht w1 multipliziert, die von x2 mit w2.<br />
Zusätzlich wird noch ein unabhängiger Bias b addiert.<br />
So kommt die Formel</p>
<span class="katex-eq" data-katex-display="true"> z = w_1 x_1 + w_2 x_2 + b </span>
<p>zustande.</p>
<p>Jetzt Butter bei die Fische, wir rechnen jetzt mit konkreten Werten:</p>
<p><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/06/perceptron-with-values-1024x649.png" alt="" width="1024" height="649" class="alignnone size-large wp-image-8005" srcset="https://creatronix.de/wp-content/uploads/2026/06/perceptron-with-values-1024x649.png 1024w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-with-values-300x190.png 300w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-with-values-768x487.png 768w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-with-values.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p>Eingabewerte</p>
<span class="katex-eq" data-katex-display="true">

x_1 = 1 \\

x_2 = 1

</span>
<p>Gewichte</p>
<span class="katex-eq" data-katex-display="true">

w_1 = -0.2 \\

w_2 = -0.1 </span>
<p>Bias<br />
<span class="katex-eq" data-katex-display="true"> b = 0.1 </span></p>
<p>Damit ergibt sich:</p>
<span class="katex-eq" data-katex-display="true"> z = -0.2 * 1 + -0.1 * 1 + 0.1 = -0.2 </span>
<h3>Aktivierungsfunktion</h3>
<p>Jetzt kommt noch die Aktivierungsfunktion dazu.<br />
Bei einem klassischen Perceptron verwendet man häufig eine Schwellenfunktion, auch Heaviside-Funktion oder Step Function genannt.<br />
Das bedeutet: Liegt die gewichtete Summe über einem bestimmten Schwellwert, gibt das Neuron eine 1 aus. Liegt sie darunter, gibt es eine 0 aus.</p>
<span class="katex-eq" data-katex-display="true">

y = \begin{cases}

1, &amp; z \ge 0 \\

0, &amp; z \lt 0

\end{cases}

</span>
<p><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/06/step-function.png" alt="" width="567" height="455" class="alignnone size-full wp-image-8006" srcset="https://creatronix.de/wp-content/uploads/2026/06/step-function.png 567w, https://creatronix.de/wp-content/uploads/2026/06/step-function-300x241.png 300w" sizes="(max-width: 567px) 100vw, 567px" /></p>
<p>Da -0.2 kleiner als 0 ist, bleibt der Ausgang auch auf 0</p>
<span class="katex-eq" data-katex-display="true"> y = H(z) = H(-0.2) = 0 </span>
<h3>Error / Loss Function</h3>
<p>Der Fehler ist die Differenz zwischen dem berechneten Wert und dem erwarteten Wert.<br />
Beim Perceptron wird jetzt der Fehler berechnet, indem der Vorhersagewert vom echten Wert des Traininglabels abgezogen wird.</p>
<span class="katex-eq" data-katex-display="true"> error = y_{true} - y_{pred} </span>
<p>Für unser Beispiel erwarten wir eine 1 am Ausgang, bekommen aber eine 0, also ist der Fehler 1</p>
<span class="katex-eq" data-katex-display="true"> error = 1 - 0 = 1 </span>
<h3>Lernregeln und Lernrate</h3>
<p>Konfuzius soll gesagt haben: &#8220;Ein Fehler, den man nicht korrigiert, ist der eigentliche Fehler.&#8221;</p>
<p>Beim Perzeptron gilt:</p>
<ul>
<li>Stimmen Ausgabe und Zielwert überein, bleiben Gewichte und Bias unverändert.</li>
<li>Ist die Ausgabe 0, obwohl sie 1 sein sollte, werden die passenden Gewichte erhöht.</li>
<li>Ist die Ausgabe 1, obwohl eine 0 erwartet wurde, werden sie verringert.</li>
</ul>
<p>Mathematisch<br />
<span class="katex-eq" data-katex-display="true">

w_i&#039; = w + \Delta w \\

b&#039; = b + \Delta b

</span></p>
<p>Die Größe der Anpassung wird durch die Lernrate eta gesteuert:<br />
<span class="katex-eq" data-katex-display="true">

\Delta w = \eta (y_{soll} - y_{ist}) * x_i \\

\Delta b = \eta (y_{soll} - y_{ist})

</span></p>
<p>Nehmen wir eine Lernrate von:</p>
<span class="katex-eq" data-katex-display="true">

\eta=0,1

</span>
<p>Dann werden die Gewichte angepasst:</p>
<span class="katex-eq" data-katex-display="true">

w_1&#039; = -0.2 + 0.1 (1-0) * 1 = -0.1 \\

w_2&#039; = -0.1 + 0.1 (1-0) * 1 = 0.0

</span>
<p>Auch der Bias verändert sich:</p>
<span class="katex-eq" data-katex-display="true">

b&#039; = 0.1 + 0.1 (1-0) = 0.2

</span>
<p><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-0-1024x825.png" alt="" width="1024" height="825" class="alignnone size-large wp-image-8008" srcset="https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-0-1024x825.png 1024w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-0-300x242.png 300w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-0-768x619.png 768w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-0.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" />Mit den neuen Werten erhalten wir:</p>
<span class="katex-eq" data-katex-display="true">

z&#039; = -0.1 * 1 + 0.0 * 1 + 0.2 = 0.1

</span>
<p>Nach der Aktivierungsfunktion:</p>
<span class="katex-eq" data-katex-display="true">

y&#039; = H(z&#039;) = 1

</span>
<p><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-1-1024x649.png" alt="" width="1024" height="649" class="alignnone size-large wp-image-8007" srcset="https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-1-1024x649.png 1024w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-1-300x190.png 300w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-1-768x487.png 768w, https://creatronix.de/wp-content/uploads/2026/06/perceptron-epoch-1.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" />Nach nur einem Lernschritt liefert das Perzeptron den gewünschten Wert.</p>
<h3>Epoche</h3>
<p>In unserem Beispiel war bereits nach einer Anpassung das richtige Ergebnis erreicht. Das ist in der Praxis nicht immer so.</p>
<p>Häufig müssen sämtliche Trainingsbeispiele mehrfach verarbeitet werden, bis brauchbare Gewichte gefunden sind.</p>
<p>Einen vollständigen Durchlauf durch alle Trainingsdaten nennt man eine Epoche oder auf Englisch epoch.</p>
<p>Das klingt gewaltiger, als es ist. Im Grunde bedeutet es nur: einmal alles durchsehen und anschließend feststellen, dass man noch mal von vorne anfangen muss.</p>
<h2>Beispiel: Festival-Entscheider</h2>
<p>Schluss mit trockener Theorie, wir brauchen ein praktisches Anwendungsbeispiel!<br />
Ich war auf Rock im Park mit einem Kumpel und das Lineup war gut und wir haben Camping-Tickets bekommen. Das Jahr drauf hat mir das Lineup nicht zugesagt und es waren keine Camping-Tickets verfügbar, also bin ich nicht gegangen.</p>
<p>Daraus können wir ein sehr einfaches Entscheidungsmodell bauen. Unser erster Eingang x1 beschreibt, ob mir das Line-up gefällt. Unser zweiter Eingang x2 beschreibt, ob ein Camping-Ticket verfügbar ist.</p>
<p>Eine 1 bedeutet „ja“, eine 0 bedeutet „nein“. Der Ausgang y beschreibt meine Entscheidung: Fahre ich hin, ist der Ausgang 1. Bleibe ich zu Hause, ist er 0.</p>
<table>
<thead>
<tr>
<th style="text-align: right;">(x_1) Line-up</th>
<th style="text-align: right;">(x_2) Camping</th>
<th style="text-align: right;">(y) Entscheidung</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
<tr>
<td style="text-align: right;">0</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0</td>
</tr>
<tr>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
<tr>
<td style="text-align: right;">1</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">1</td>
</tr>
</tbody>
</table>
<p>Wir setzen das jetzt mit Python um. Ich verschone euch vorerst mit numpy, pytorch und Konsorten.<br />
Für das Perzeptron reicht Vanilla Python völlig aus.</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>X = [
[0, 0],
[0, 1],
[1, 0],
[1, 1]
]
y_train = [0, 0, 0, 1]</code></pre>
</div>
<p>Die Gewichte und den Bias initialisieren wir jeweils mit 0:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>weights = [0.0, 0.0]
bias = 0.0</code></pre>
</div>
<p>Als Lernrate nehmen wir wieder 0,1</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>eta = 0.1
number_of_epochs = 10</code></pre>
</div>
<p>Die Schwellenfunktion liefert 1, sobald z mindestens null ist:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>def step_function(z):
    return 1 if z &gt;= 0 else 0</code></pre>
</div>
<p>Nun folgt das Training:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>print(f"Start training: weights {weights}, bias {bias}")
for epoch in range(number_of_epochs):
    for x, y_true in zip(X, y_train):
        z = x[0] * weights[0] + x[1] * weights[1] + bias
        y_pred = step_function(z)

        error = y_true - y_pred

        weights[0] = weights[0] + eta * error * x[0]
        weights[1] = weights[1] + eta * error * x[1]
        bias = bias + eta * error

    print(f"Epoch {epoch} weights {weights}, bias {bias}")


print(f"Finished training: weights {weights}, bias {bias}")</code></pre>
</div>
<p>Das Programm geht alle Beispiele durch, berechnet eine Vorhersage und korrigiert bei Bedarf Gewichte und Bias.</p>
<h2>Grenzen des Perzeptrons</h2>
<p>Ein einzelnes Perzeptron kann nur Probleme lösen, die linear separierbar sind.</p>
<p>Das bedeutet: Die verschiedenen Klassen müssen sich durch eine gerade Linie, beziehungsweise in höheren Dimensionen durch eine Ebene, voneinander trennen lassen.</p>
<p>Unsere Festivalentscheidung funktioniert. Nur wenn sowohl Line-up als auch Camping stimmen, fahren wir hin. Diese Fälle lassen sich sauber trennen. Beim XOR-Gatter klappt das nicht. Für solche Probleme braucht man mehrere Schichten beziehungsweise komplexere neuronale Netze.</p>
<h2>Ausblick auf das ADALINE</h2>
<p>Das klassische Perzeptron lernt anhand der fertigen Entscheidung. Es sieht also nur die ausgegebene 0 oder 1.</p>
<p>ADALINE, kurz für Adaptive Linear Neuron, verwendet für das Lernen dagegen den linearen Rohwert vor der Schwellenfunktion.</p>
<p>Dadurch erkennt ADALINE nicht nur, ob eine Vorhersage falsch war, sondern auch, wie weit sie danebenlag.</p>
<h2>Paper</h2>
<p><a href="https://www.cs.cmu.edu/~epxing/Class/10715/reading/McCulloch.and.Pitts.pdf">https://www.cs.cmu.edu/~epxing/Class/10715/reading/McCulloch.and.Pitts.pdf</a><br />
<a href="https://bpb-us-e2.wpmucdn.com/websites.umass.edu/dist/a/27637/files/2016/03/rosenblatt-1957.pdf">https://bpb-us-e2.wpmucdn.com/websites.umass.edu/dist/a/27637/files/2016/03/rosenblatt-1957.pdf</a></p>
<h2>Links</h2>
<p><a href="https://neuralnetworksanddeeplearning.com/chap1.html">https://neuralnetworksanddeeplearning.com/chap1.html</a></p>
<blockquote class="wp-embedded-content" data-secret="60LlAiAxot"><p><a href="https://blog.hnf.de/frank-rosenblatt-und-das-perceptron/">Frank Rosenblatt und das Perceptron</a></p></blockquote>
<p><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="„Frank Rosenblatt und das Perceptron“ – HNF Blog" src="https://blog.hnf.de/frank-rosenblatt-und-das-perceptron/embed/#?secret=lbSfm73BQI#?secret=60LlAiAxot" data-secret="60LlAiAxot" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br />
https://www.nutsvolts.com/magazine/article/the_perceptron_circuit</p>
<h2>Videos</h2>
<p><a href="https://www.youtube.com/watch?v=l-9ALe3U-Fg">Hardware Perceptron </a><br />
<a href="https://www.youtube.com/watch?v=-KLnurhX-Pg">Perceptron Algorithm with Code Example</a><br />
<a href="https://www.youtube.com/watch?v=IEFRtz68m-8">Adaline</a><br />
<a href="https://youtu.be/cNxadbrN_aI">Perceptron Research </a></p>
<p>The post <a href="https://creatronix.de/das-perzeptron/">Das Perzeptron</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Das große Git-Tutorial</title>
		<link>https://creatronix.de/das-grosse-git-tutorial/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Thu, 26 Mar 2026 20:10:53 +0000</pubDate>
				<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=7965</guid>

					<description><![CDATA[<p>Motivation Jeder kennt und nutzt Git. Es gibt bis auf Ausnahmen (ich schaue dich an, Perforce) keine ernstzunehmenden Alternativen mehr. Ich lasse Azubis ab der ersten Woche schon mit Git arbeiten, allerdings zunächst im Kontext einer IDE, damit sie ihren Code entspannt versionieren können. Im zweiten Lehrjahr gibt es dann den Blick hinter die Kulissen,&#8230;</p>
<p>The post <a href="https://creatronix.de/das-grosse-git-tutorial/">Das große Git-Tutorial</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Motivation</h2>
<p>Jeder kennt und nutzt Git. Es gibt bis auf Ausnahmen (ich schaue dich an, Perforce) keine ernstzunehmenden Alternativen mehr.</p>
<p>Ich lasse Azubis ab der ersten Woche schon mit Git arbeiten, allerdings zunächst im Kontext einer IDE,<br />
damit sie ihren Code entspannt versionieren können.</p>
<p>Im zweiten Lehrjahr gibt es dann den Blick hinter die Kulissen, also auf die Kommandozeile.</p>
<h2>Inhalt</h2>
<ul>
<li>Basics: Installation, Konfiguration, Repository erstellen, Status &amp; Log, Commits, .gitignore, Remote, Fetch &amp; Pull</li>
<li>Intermediate: Branching, Merging, Merge-Konflikte, Stash, Diff, Tags</li>
<li>Advanced: Rebase, Squashen von Commits, Cherry-Pick, Reflog, Bisect</li>
</ul>
<h2>Voraussetzungen</h2>
<ul>
<li>Ein Terminal / eine Shell (bash, zsh, PowerShell, …)</li>
<li>Grundlegende Erfahrung mit der Kommandozeile (cd, mkdir, ls/dir)</li>
<li>Optional: ein GitHub- oder GitLab-Account für Remote-Repositories</li>
</ul>
<h2>Basics</h2>
<h3>Installation</h3>
<p>Damit etwas unter Versionskontrolle gestellt werden kann, muss Git zuerst installiert sein.</p>
<p><strong>Windows:</strong></p>
<p>Download von <a href="https://git-scm.com/download/win">https://git-scm.com/download/win</a> und Installer ausführen</p>
<p><strong>Linux (Debian/Ubuntu):</strong></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>sudo apt install git</code></pre>
</div>
<p><strong>macOS:</strong></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>brew install git</code></pre>
</div>
<p>Wir können nun testen, ob die Installation erfolgreich war:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git --version</code></pre>
</div>
<h3>Konfiguration</h3>
<p>Bevor wir loslegen, teilen wir Git unseren Namen und unsere E-Mail-Adresse mit.<br />
Diese Infos werden in jedem Commit gespeichert.</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git config --global user.name "Dein Name"
git config --global user.email "deine@email.de"</code></pre>
</div>
<p>Optional – Standardbranch auf <code>main</code> setzen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git config --global init.defaultBranch main</code></pre>
</div>
<h3>Repository erstellen (<code>init</code>)</h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>mkdir my_workspace
cd my_workspace
git init</code></pre>
</div>
<p>Damit haben wir ein leeres Git-Repository. Jetzt legen wir die ersten Dateien an:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>touch .gitignore
touch README.md
touch app.py</code></pre>
</div>
<h3>Status &amp; Log</h3>
<p>Zwei Befehle, die man ständig braucht sind:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git status # Zeigt den aktuellen Zustand des Repositories
git log # Zeigt die Commit-Historie
git log --oneline # Kompakte Einzeiler-Ansicht</code></pre>
</div>
<h3>Staging &amp; Commit</h3>
<p>Dateien müssen zunächst in die Staging Area und können dann committet werden:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git add . # Alle Änderungen stagen
git add README.md # Einzelne Datei stagen
git commit -m "initial commit" # Commit mit Nachricht</code></pre>
</div>
<p><strong>Tipp:</strong> Gute Commit-Messages beschreiben <em>was</em> und <em>warum</em>, nicht <em>wie</em>.</p>
<p>&nbsp;</p>
<h3><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/03/git-init-add-commit.png" alt="" width="1010" height="275" class="alignnone size-full wp-image-7962" srcset="https://creatronix.de/wp-content/uploads/2026/03/git-init-add-commit.png 1010w, https://creatronix.de/wp-content/uploads/2026/03/git-init-add-commit-300x82.png 300w, https://creatronix.de/wp-content/uploads/2026/03/git-init-add-commit-768x209.png 768w" sizes="(max-width: 1010px) 100vw, 1010px" /></h3>
<h3>.gitignore</h3>
<p>Die Datei <code>.gitignore</code> definiert, welche Dateien Git ignorieren soll (Build-Artefakte, IDE-Konfiguration, Secrets, …):</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-json" data-lang="JSON"><code># Beispiel .gitignore
pycache/
*.pyc
.idea/
.env
build/
</code></pre>
</div>
<h3>Remote hinzufügen und pushen</h3>
<p>Ein Remote-Repository (z. B. auf GitHub) wird so verknüpft:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git remote add origin https://github.com/user/repo.git
git push -u origin main</code></pre>
</div>
<p><code>-u</code> setzt das Upstream-Tracking, sodass <code>git push</code> danach ohne weitere Argumente funktioniert.</p>
<h3>Änderungen vom Remote holen</h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git fetch # Holt Änderungen, merged aber NICHT
git pull # Holt Änderungen UND merged in den aktuellen Branch</code></pre>
</div>
<p><strong>Faustregel:</strong> <code>fetch</code> ist sicher und unverbindlich, <code>pull</code> verändert den lokalen Branch.</p>
<h2>Intermediate</h2>
<h3>Remote-Repo clonen</h3>
<p>Statt ein Repository von Grund auf neu zu erstellen, kannst du ein bestehendes Remote-Repository mit <code>git clone</code> auf den eigenen Rechner kopieren.<br />
Dabei passiert automatisch einiges:</p>
<ol>
<li>Ein neuer Ordner mit dem Repository-Namen wird erstellt</li>
<li>Die gesamte Historie (alle Commits, Branches, Tags) wird heruntergeladen</li>
<li>Ein Remote namens <code>origin</code> wird angelegt, der auf die Quell-URL zeigt</li>
<li>Der Standard-Branch (z. B. <code>main</code>) wird ausgecheckt</li>
</ol>
<p><strong>Grundsyntax:</strong></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git clone https://github.com/user/repo.git</code></pre>
</div>
<p><strong>Einen bestimmten Branch clonen:</strong></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git clone -b develop https://github.com/user/repo.git</code></pre>
</div>
<p>Damit wird direkt der Branch <code>develop</code> ausgecheckt, nützlich, wenn du nicht auf <code>main</code> arbeiten möchtest.</p>
<p><strong>Tipp:</strong> Nach dem Clonen kannst du dir den eingerichteten Remote anzeigen lassen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>cd repo
git remote -v

#origin https://github.com/user/repo.git (fetch)
#origin https://github.com/user/repo.git (push)</code></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/03/git-workflow.png" alt="" width="842" height="202" class="alignnone size-full wp-image-7961" srcset="https://creatronix.de/wp-content/uploads/2026/03/git-workflow.png 842w, https://creatronix.de/wp-content/uploads/2026/03/git-workflow-300x72.png 300w, https://creatronix.de/wp-content/uploads/2026/03/git-workflow-768x184.png 768w" sizes="(max-width: 842px) 100vw, 842px" /></h3>
<h3>Branching</h3>
<p>Branches sind einer der größten Vorteile von Git. Sie erlauben paralleles Arbeiten an Features, Bugfixes usw.</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git branch # Alle lokalen Branches anzeigen
git branch feature/login # Neuen Branch erstellen
git checkout feature/login # In den Branch wechseln
git checkout -b feature/login # Erstellen + Wechseln in einem Schritt</code></pre>
</div>
<h3><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/03/git-remote-branch.png" alt="" width="911" height="290" class="alignnone size-full wp-image-7963" srcset="https://creatronix.de/wp-content/uploads/2026/03/git-remote-branch.png 911w, https://creatronix.de/wp-content/uploads/2026/03/git-remote-branch-300x95.png 300w, https://creatronix.de/wp-content/uploads/2026/03/git-remote-branch-768x244.png 768w" sizes="(max-width: 911px) 100vw, 911px" /></h3>
<h3>Merging</h3>
<p>Wenn ein Feature fertig ist, wird der Branch zurück in <code>main</code> gemerged:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git checkout main
git merge feature/login</code></pre>
</div>
<h3>Merge-Konflikte</h3>
<p>Wenn zwei Branches dieselbe Stelle in einer Datei geändert haben, entsteht ein Merge-Konflikt.<br />
Git markiert die betroffenen Stellen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
Deine Änderung
=======
Änderung aus dem anderen Branch
&gt;&gt;&gt;&gt;&gt;&gt;&gt; feature/login</code></pre>
</div>
<p>Lösung: Datei manuell bereinigen, dann:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git add &lt;datei&gt;
git commit</code></pre>
</div>
<h3>Stash</h3>
<p>Unfertige Änderungen kann man zwischenspeichern, ohne zu committen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git stash # Änderungen wegstashen
git stash list # Alle Stashes anzeigen
git stash pop # Letzten Stash wiederherstellen und entfernen
git stash apply # Letzten Stash wiederherstellen, aber behalten</code></pre>
</div>
<h3>Diff</h3>
<p>Änderungen anzeigen lassen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git diff # Unstaged-Änderungen
git diff --staged # Staged-Änderungen (vor dem Commit)
git diff main..feature # Unterschied zwischen zwei Branches</code></pre>
</div>
<h3>Tags</h3>
<p>Releases oder Meilensteine markieren:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git tag v1.0.0
git tag -a v1.0.0 -m "Erstes Release"
git push origin v1.0.0</code></pre>
</div>
<h2>Advanced</h2>
<h3>Rebase</h3>
<p>Rebase schreibt die Commit-Historie um und setzt Commits auf eine neue Basis.<br />
Nützlich, um einen sauberen, linearen Verlauf zu erzeugen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git checkout feature/login
git rebase main</code></pre>
</div>
<p>&nbsp;</p>
<p><strong><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/03/git-rebase.png" alt="" width="685" height="202" class="alignnone size-full wp-image-7964" srcset="https://creatronix.de/wp-content/uploads/2026/03/git-rebase.png 685w, https://creatronix.de/wp-content/uploads/2026/03/git-rebase-300x88.png 300w" sizes="(max-width: 685px) 100vw, 685px" /></strong></p>
<p><strong>Achtung:</strong> Rebase verändert die Historie. Deshalb nicht auf bereits gepushten, geteilten Branches verwenden.</p>
<h3>Squashen von Commits</h3>
<p>Mehrere Commits zu einem zusammenfassen (z. B. vor einem Merge Request):</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git rebase -i HEAD~3 # Die letzten 3 Commits interaktiv bearbeiten</code></pre>
</div>
<p>Im Editor dann <code>pick</code> für die gewünschten Commits durch <code>squash</code> (oder <code>s</code>) ersetzen.</p>
<h3>Cherry-Pick</h3>
<p>Einen einzelnen Commit aus einem anderen Branch übernehmen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git cherry-pick &lt;commit-hash&gt;</code></pre>
</div>
<h3>Reflog</h3>
<p>Das Sicherheitsnetz: Zeigt <em>alle</em> Aktionen, auch nach einem versehentlichen Reset:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>git reflog
git checkout &lt;hash&gt; # Verlorenen Stand wiederherstellen</code></pre>
</div>
<h2>Fazit</h2>
<p>Git ist ein mächtiges Werkzeug. Die Basics reichen für den Alltag, aber wer Rebase, Squash und Bisect beherrscht,<br />
kann auch in komplexen Projekten souverän arbeiten.</p>
<p><strong>Weiterführende Ressourcen:</strong></p>
<ul>
<li><a href="https://learngitbranching.js.org/?locale=de_DE">Git Branching interaktiv lernen</a></li>
<li><a href="https://git-scm.com/book/de/v2">Pro Git Book (kostenlos)</a></li>
<li><a href="https://education.github.com/git-cheat-sheet-education.pdf">Git Cheat Sheet</a></li>
<li><code>git help &lt;befehl&gt;</code>: Die eingebaute Hilfe ist besser, als man denkt</li>
</ul>
<p>The post <a href="https://creatronix.de/das-grosse-git-tutorial/">Das große Git-Tutorial</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Lerne neue Programmiersprachen schneller mit diesen Coding Challenges</title>
		<link>https://creatronix.de/lerne-neue-programmiersprachen-schneller-mit-diesen-coding-challenges/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Sun, 22 Mar 2026 07:20:50 +0000</pubDate>
				<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=7954</guid>

					<description><![CDATA[<p>Motivation Motivation Das Erlernen einer Programmiersprache kann herausfordernd sein. Es gibt zwar unzählige Artikel und Tutorials, doch echtes Verständnis entsteht vor allem durch regelmäßige Wiederholung und praktische Anwendung. Wer Konzepte immer wieder in kleinen Übungen, Katas und realen Problemen einsetzt, entwickelt mit der Zeit eine Art Muscle Memory fürs Programmieren. Genau diese Routine hilft dabei,&#8230;</p>
<p>The post <a href="https://creatronix.de/lerne-neue-programmiersprachen-schneller-mit-diesen-coding-challenges/">Lerne neue Programmiersprachen schneller mit diesen Coding Challenges</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Motivation</h2>
<h2>Motivation</h2>
<p>Das Erlernen einer Programmiersprache kann herausfordernd sein. Es gibt zwar unzählige Artikel und Tutorials, doch echtes Verständnis entsteht vor allem durch regelmäßige Wiederholung und praktische Anwendung.</p>
<p>Wer Konzepte immer wieder in kleinen Übungen, Katas und realen Problemen einsetzt, entwickelt mit der Zeit eine Art Muscle Memory fürs Programmieren. Genau diese Routine hilft dabei, Syntax, Denkweisen und Lösungsstrategien nachhaltig zu verinnerlichen.</p>
<h2>Die Herausforderungen</h2>
<p>Die Programmieraufgaben sind sprachunabhängig, sodass du jede moderne Sprache verwenden kannst, die das Schreiben von Konsolenanwendungen unterstützt.</p>
<h2>🟢 Level 1 – Grundlagen (Syntax &amp; einfache Logik)</h2>
<ol>
<li>Schreibe das berühmte / berüchtigte „Hello World“</li>
<li>Schreibe ein Skript, das alle Zahlen von 1 bis 365 in die Konsole ausgibt</li>
<li>Schreibe ein Skript, das 10 Zufallszahlen zwischen 1 und 10 ausgibt</li>
<li>Schreibe ein Skript, das alle Buchstaben des Alphabets (großgeschrieben) mit ihrer jeweiligen Position ausgibt, z. B. 1: A, 2: B</li>
<li>Schreibe deinen ersten Unit-Test für eine Funktion <code>is_even(num)</code>, die <code>true</code> zurückgibt, wenn die Zahl gerade ist</li>
</ol>
<h2>🟡 Level 2 – Einfache Funktionen &amp; Kontrolle</h2>
<ol>
<li>Schreibe eine Funktion <code>to_upper</code>, die einen String von lower_case nach upper_case umwandelt</li>
<li>Die Funktion <code>compare(num1, num2)</code> soll
<ol>
<li>-1 zurückgeben, wenn <code>num1</code> kleiner als <code>num2</code> ist</li>
<li>ansonsten 1 zurückgeben</li>
<li>wenn beide Werte gleich sind, 0 zurückgeben</li>
</ol>
</li>
<li>Die Funktion <code>simple_sum(num)</code> soll alle Zahlen von 1 bis <code>num</code> aufsummieren
<ol>
<li>Beispiel: Bei Eingabe 4 soll das Ergebnis 10 sein</li>
<li>Für Testfälle liegt <code>num</code> zwischen 1 und 1000</li>
</ol>
</li>
<li>Die Funktion <code>time_convert(minutes)</code> soll Minuten in Stunden und Minuten umwandeln (z. B. 63 → 1:03)</li>
<li>Die Funktion <code>first_reverse(input)</code> soll den String umdrehen</li>
</ol>
<h2>🟠 Level 3 – Strings &amp; Arrays</h2>
<ol>
<li>Die Funktion <code>alphabet_soup(input)</code> soll den String alphabetisch sortieren</li>
<li>Die Funktion <code>longest_word(sentence)</code> soll das längste Wort zurückgeben</li>
<li>Die Funktion <code>letter_changes(input)</code> soll Buchstaben ersetzen und Vokale kapitalisieren</li>
</ol>
<h2>🔵 Level 4 – Mathematische Grundlagen</h2>
<ol>
<li>Die Funktion <code>factorial(num)</code> soll die Fakultät berechnen</li>
<li>Schreibe eine Funktion, die Fibonacci-Zahlen erzeugt (inkl. Memoization)</li>
<li>Schreibe eine Funktion, die die Collatz-Sequenz als Liste zurückgibt</li>
<li>Schreibe eine Funktion, die den Mittelwert (Mean) eines Integer-Arrays berechnet</li>
<li>Schreibe eine Funktion, die den Median eines Integer-Arrays berechnet</li>
</ol>
<h2>🟣 Level 5 – Klassische Algorithmen</h2>
<ol>
<li>Schreibe eine Funktion, die ein Integer-Array mit Bubble Sort sortiert</li>
<li>Schreibe eine Funktion, die eine Liste von Primzahlen mithilfe des Siebs des Eratosthenes zurückgibt</li>
<li>Schreibe eine Funktion, die den größten gemeinsamen Teiler mithilfe des euklidischen Algorithmus berechnet</li>
</ol>
<h2>🔴 Level 6 – Anspruchsvoll / Interview-Level</h2>
<ol>
<li>Schreibe eine Funktion, die römische Zahlen in Dezimalzahlen konvertiert</li>
<li>Schreibe eine Funktion, die Dezimalzahlen in römische Zahlen konvertiert</li>
<li>Die Funktion <code>kaprekars_constant(num)</code> berechnet die Anzahl der Schritte bis 6174 erreicht wird</li>
</ol>
<h2>🧪 Hinweis</h2>
<p>Ab der Funktion <code>simple_sum</code> sollte nach dem TDD-Prinzip gearbeitet werden (Test → Implementierung → Refactoring).</p>
<p>The post <a href="https://creatronix.de/lerne-neue-programmiersprachen-schneller-mit-diesen-coding-challenges/">Lerne neue Programmiersprachen schneller mit diesen Coding Challenges</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Was ist Software Engineering? Eine verständliche Einführung</title>
		<link>https://creatronix.de/was-ist-software-engineering-eine-verstaendliche-einfuehrung/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Sat, 21 Mar 2026 12:41:56 +0000</pubDate>
				<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=7932</guid>

					<description><![CDATA[<p>Software Engineering ist die systematische Entwicklung von Software: von der Idee über die Umsetzung bis zum Betrieb. Programmieren gehört natürlich dazu, ist aber interessanterweise oft nur ein kleiner Teil des Ganzen. Disclaimer Die folgende Unterteilung in Programmierung, Entwicklung und Engineering ist ein Versuch einer Einordnung von Prozessen, Methoden und Tools. Ich habe dieses Modell entwickelt,&#8230;</p>
<p>The post <a href="https://creatronix.de/was-ist-software-engineering-eine-verstaendliche-einfuehrung/">Was ist Software Engineering? Eine verständliche Einführung</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Software Engineering ist die systematische Entwicklung von Software: von der Idee über die Umsetzung bis zum Betrieb. Programmieren gehört natürlich dazu, ist aber interessanterweise oft nur ein kleiner Teil des Ganzen.</p>
<h2>Disclaimer</h2>
<p>Die folgende Unterteilung in Programmierung, Entwicklung und Engineering ist ein Versuch einer Einordnung von Prozessen, Methoden und Tools. Ich habe dieses Modell entwickelt, um unseren Auszubildenden und Praktikanten, die oft keine Vorkenntnisse hatten, Software-Engineering beizubringen.</p>
<p>Daher enthält es einige persönliche Ansichten und möglicherweise keine präzisen Definitionen. Es spiegelt meine fast 20-jährige Erfahrung in der Softwarebranche als Entwickler, Tester, QA-Mitarbeiter und Teamleiter wider.</p>
<h2><img decoding="async" src="https://creatronix.de/wp-content/uploads/2023/01/mental-model.png" alt="" width="391" height="392" class="alignnone size-full wp-image-6606" srcset="https://creatronix.de/wp-content/uploads/2023/01/mental-model.png 391w, https://creatronix.de/wp-content/uploads/2023/01/mental-model-300x300.png 300w, https://creatronix.de/wp-content/uploads/2023/01/mental-model-150x150.png 150w" sizes="(max-width: 391px) 100vw, 391px" /></h2>
<h2>Programmierung: der Kern</h2>
<p>Ein bekannter Spruch lautet:</p>
<blockquote><p>A programmer is an organism that turns coffee and pizza into code.</p></blockquote>
<p>Programmieren bedeutet, Anforderungen des Kunden in ausführbare Anweisungen, die ein Computer versteht, zu übersetzen. Das kann eine einzelne Person — ein Programmierer — tun.</p>
<h3>Programmiersprachen</h3>
<p>Ein Programmierer braucht eine oder mehrere Programmiersprachen um <strong>Quellcode</strong> zu erstellen. Quellcode oder oft nur <strong>Code</strong> ist Text in einer Sprache wie C, <a href="https://creatronix.de/modernes-c-plus-plus/">C++</a>, Java oder <a href="https://creatronix.de/python-tips-tricks-for-junior-developers/">Python</a>. Jede Sprache definiert klare Regeln für Syntax und Semantik.</p>
<h3>Vom Quelltext zum Programm</h3>
<ol>
<li>Quelltext schreiben (Editor oder IDE)</li>
<li>Kompilieren (z. B. C/C++)</li>
<li>Linken und ausführbare Datei erzeugen</li>
</ol>
<p>Beispiel in C:</p>
<div>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-c" data-lang="C"><code>#include &lt;stdio.h&gt;

int main(void) {
    printf("Hello world\n");
    return 0;
}</code></pre>
</div>
</div>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>gcc -Wall -g -c hello.c
gcc -o hello hello.o -lm</code></pre>
</div>
<p>&nbsp;</p>
<p><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/03/compiler_linker-1024x150.png" alt="" width="1024" height="150" class="alignnone size-large wp-image-7929" srcset="https://creatronix.de/wp-content/uploads/2026/03/compiler_linker-1024x150.png 1024w, https://creatronix.de/wp-content/uploads/2026/03/compiler_linker-300x44.png 300w, https://creatronix.de/wp-content/uploads/2026/03/compiler_linker-768x112.png 768w, https://creatronix.de/wp-content/uploads/2026/03/compiler_linker.png 1031w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p>Das reicht schon, damit wurde bereits ein Programm erstellt. Für echte Projekte oder Produkte reicht das reine<br />
Programmieren aber noch nicht aus.</p>
<h2>Softwareentwicklung: vom Code zum Produkt</h2>
<p>Sobald mehrere Personen beteiligt sind oder Kundennutzen im Fokus steht, kommen Prozesse, Rollen und Werkzeuge hinzu.</p>
<h3>Requirements Tracking &#8211; Anforderungen erfassen und klären</h3>
<p>Damit ein Team von Programmierern das Richtige baut, müssen Anforderungen des Kunden klar beschrieben werden. Eine Anforderung, die in Textform niedergeschrieben wurde, nennt man auch <strong>Requirement</strong>. Für die Formulierung haben sich zwei Formate etabliert:</p>
<ul>
<li>User Story: Als <strong>Rolle</strong> möchte ich <strong>Funktion</strong>, damit <strong>Nutzen</strong>.</li>
<li>Use Case: strukturierte Beschreibung einer Interaktion zwischen Nutzer und System</li>
</ul>
<p>Anforderungen erhalten IDs, Status und Verweise auf Implementierung und Tests. So bleibt über den gesamten Lebenszyklus nachvollziehbar, was umgesetzt, geändert oder verworfen wurde.</p>
<p>Auch die guten alten Lastenhefte (Was der Kunde will) und Pflichtenhefte (Was wir verstanden haben und auch umsetzen werden) haben oft noch ihre Daseinsberechtigung.</p>
<h3>Neue Rollen</h3>
<p>Dedizierte Tester entlasten ein Team von Programmierern und erhöhen die Produktqualität, weil sie Programme systematisch aus Nutzer- und Risikoperspektive prüfen.</p>
<p>Typische Aufgaben für Tester sind:</p>
<ul>
<li>Testfälle aus den Anforderungen ableiten</li>
<li>Teststrategie und Testdaten definieren</li>
<li>Manuelle und automatisierte Tests durchführen</li>
<li>Fehler sauber dokumentieren und priorisieren</li>
<li>Regressionsrisiken vor Releases bewerten</li>
</ul>
<p>Wichtig: Tester &#8220;testen nicht nur am Ende&#8221;, sondern arbeiten <a href="https://creatronix.de/wie-baue-ich-eine-entwicklungsbegleitende-software-qualitatssicherung-auf/">früh</a> mit den Programmierern zusammen. So werden Qualitätsprobleme früher sichtbar und deutlich günstiger behoben.</p>
<h3>Dokumentation</h3>
<p>Gute <strong>Dokumentation</strong> entlastet Teams im Alltag und reduziert Wissensinseln.</p>
<ul>
<li>Produktdokumentation: Was kann das System aus Nutzersicht?</li>
<li>Technische Dokumentation: Architektur, Schnittstellen, Betriebswissen</li>
<li>Entscheidungsdokumentation: Warum wurde etwas so gebaut?</li>
</ul>
<p>Wichtig ist nicht &#8220;möglichst viel Text&#8221;, sondern aktuelle, auffindbare und wartbare Dokumentation.</p>
<h3>Versionsverwaltung nutzen</h3>
<p>Werkzeuge wie <a href="https://creatronix.de/das-grose-git-tutorial/">Git</a> speichern den kompletten zeitlichen Verlauf einer Codebasis. Sie ermöglichen damit:</p>
<ul>
<li>Zusammenarbeit im Team</li>
<li>Nachvollziehbare Änderungen</li>
<li>Rückkehr zu früheren Ständen</li>
</ul>
<p>Hinweis: Git ersetzt kein vollständiges Backup-Konzept.</p>
<h3><img decoding="async" src="https://creatronix.de/wp-content/uploads/2026/03/branching-1024x391.png" alt="" width="1024" height="391" class="alignnone wp-image-7931 size-large" srcset="https://creatronix.de/wp-content/uploads/2026/03/branching-1024x391.png 1024w, https://creatronix.de/wp-content/uploads/2026/03/branching-300x115.png 300w, https://creatronix.de/wp-content/uploads/2026/03/branching-768x293.png 768w, https://creatronix.de/wp-content/uploads/2026/03/branching.png 1194w" sizes="(max-width: 1024px) 100vw, 1024px" /></h3>
<h3>Builds automatisieren &amp; Abhängigkeiten verwalten</h3>
<p>Moderne Anwendungen nutzen viele oft externe Bibliotheken. Package Manager wie <code>cargo</code>, <code>npm</code> oder <code>gradle</code> helfen bei einheitlichen Builds und reproduzierbaren Versionen. Ziel: Alle können jederzeit denselben Build erzeugen.</p>
<p>Zusätzlich braucht es klare <strong>Build Tools</strong> und ein belastbares <strong>Build System</strong>:</p>
<ul>
<li><a href="https://creatronix.de/compiler-optionen-fur-sauberes-c/">standardisierte Build-Kommandos</a> lokal und in CI</li>
<li>reproduzierbare Artefakte über Umgebungen hinweg</li>
<li>schnelle, stabile Pipelines mit klarer Fehlerdiagnose</li>
</ul>
<h3>IDE</h3>
<p>Während beim reinen Programmieren ein einfacher Texteditor ausreichen kann, verwenden Softwareentwickler in der Praxis meist leistungsfähige IDEs.</p>
<p>Eine IDE bündelt zentrale Entwicklungsaufgaben in einem Werkzeug:</p>
<ul>
<li>Code schreiben mit Syntaxprüfung und Autovervollständigung</li>
<li>Navigation durch große Codebasen (z. B. &#8220;Gehe zu Definition&#8221;)</li>
<li>Refactoring mit geringem Fehlerrisiko</li>
<li>Debugging mit Breakpoints und Variableninspektion</li>
<li>Direkte Integration von Tests, Linter und Build-Prozessen</li>
<li>Anbindung an Versionsverwaltung wie Git</li>
</ul>
<p>Der eigentliche Nutzen liegt in der Produktivität und Qualität: Teams arbeiten schneller, konsistenter und machen weniger vermeidbare Fehler.</p>
<h3>Issue Tracking &#8211; Arbeit transparent machen</h3>
<p>Issues, Bugs und Aufgaben werden in einem Tracking-System verwaltet (z. B. Jira, YouTrack, GitHub Issues). So bleiben Prioritäten, Zuständigkeiten und Fortschritt nachvollziehbar.</p>
<h3>Projektorganisation mit Scrum oder Kanban</h3>
<p>Damit Teamarbeit planbar und transparent bleibt, wird Arbeit in kleine, priorisierte Einheiten aufgeteilt und sichtbar gemacht.</p>
<p>Bei <strong>Scrum</strong> erfolgt die Planung meist in festen Iterationen (Sprints), z. B. alle ein bis zwei Wochen:</p>
<ul>
<li>Ziele für den Sprint festlegen</li>
<li>Aufgaben gemeinsam schätzen und zuschneiden</li>
<li>Fortschritt täglich abstimmen</li>
<li>Ergebnisse am Sprint-Ende überprüfen und verbessern</li>
</ul>
<p>Bei <strong>Kanban</strong> steht der kontinuierliche Fluss im Vordergrund:</p>
<ul>
<li>Aufgaben visualisieren (z. B. To-do, In Arbeit, Erledigt)</li>
<li>Parallelarbeit mit WIP-Limits begrenzen</li>
<li>Engpässe früh erkennen und aktiv beseitigen</li>
</ul>
<p>Beide Ansätze helfen, Lieferfähigkeit und Qualität im Alltag stabil zu halten.</p>
<h3>Qualität absichern</h3>
<p>Qualität entsteht nicht zufällig, sondern durch disziplinierte Routinen:</p>
<ul>
<li>Tests (Unit, Integration, End-to-End)</li>
<li><a href="https://creatronix.de/wie-tdd-die-welt-rettet-und-deine-nerven-schont/">TDD</a> (Test-Driven Development)</li>
<li>Debugging</li>
<li><a href="https://creatronix.de/logging-in-python-cheat-sheet/">Logging</a></li>
<li>Linting und statische Codeanalyse</li>
<li>Code Reviews</li>
</ul>
<h4>TDD sinnvoll einsetzen</h4>
<p>Bei TDD schreibst du zuerst einen fehlschlagenden Test, implementierst dann den minimal nötigen Code und verbesserst anschließend die Struktur (Red-Green-Refactor).</p>
<p>TDD ist besonders hilfreich bei:</p>
<ul>
<li>Geschäftslogik mit klaren Regeln</li>
<li>APIs und Modulen mit stabilen Schnittstellen</li>
<li>Codebereichen, die häufig geändert werden</li>
</ul>
<p>So entsteht oft besser testbarer, klarer strukturierter Code und Regressionen werden früher erkannt.</p>
<h3>Struktur schaffen mit Design Patterns</h3>
<p>Design Patterns werden benötigt, weil in Softwareprojekten viele Probleme immer wieder auftreten. Statt jedes Mal eine neue, ungeprüfte Lösung zu bauen, nutzt du bewährte Strukturen.</p>
<p>Sie helfen konkret bei:</p>
<ul>
<li>Verständlichkeit: Andere Entwickler erkennen schneller, wie dein Code aufgebaut ist.</li>
<li>Wartbarkeit: Änderungen sind einfacher, weil Verantwortlichkeiten klarer getrennt sind.</li>
<li>Erweiterbarkeit: Neue Features lassen sich oft mit weniger Umbau integrieren.</li>
<li>Teamkommunikation: Begriffe wie Factory, Observer oder Strategy sind eine gemeinsame Sprache.</li>
<li>Risikoreduktion: Patterns sind praxiserprobt und vermeiden typische Architekturfehler.</li>
</ul>
<p>Kurz: Design Patterns machen Code nicht &#8220;magisch besser&#8221;, aber sie machen komplexe Systeme robuster und für Teams beherrschbarer.</p>
<h2>Software-Engineering &#8211; erfolgreich Großprojekte umsetzen</h2>
<p>Sobald mehrere Teams parallel an einem Produkt arbeiten, reicht reine Softwareentwicklung nicht mehr aus. Spätestens bei Teamgrößen von etwa 8 bis 12 Personen (oder mehreren unabhängigen Feature-Teams) steigen Koordinationsaufwand, Integrationsrisiken und Betriebsverantwortung deutlich.</p>
<p>Dann geht es nicht nur um &#8220;Features bauen&#8221;, sondern auch um:</p>
<ul>
<li>einheitliche technische Leitplanken</li>
<li>verlässliche Release- und Betriebsprozesse</li>
<li>klare Verantwortlichkeiten zwischen Entwicklung, Produkt und Betrieb</li>
<li>skalierbare Qualitätssicherung über Teamgrenzen hinweg</li>
</ul>
<p>Genau hier beginnt der eigentliche Mehrwert von Software Engineering.</p>
<h3>Neue Rollen</h3>
<p>Mit wachsender Produkt- und Teamgröße entstehen zusätzliche Rollen, die Entwicklung strukturieren und skalierbar machen.</p>
<p><strong>Projektleiter</strong> koordinieren Zeit, Budget, Abhängigkeiten und Risiken.<br />
Sie sorgen dafür, dass Entscheidungen transparent sind und Teams in die gleiche Richtung arbeiten.</p>
<p><strong>Requirements Engineers</strong> präzisieren Anforderungen und übersetzen fachliche Ziele in umsetzbare Spezifikationen.<br />
Dadurch sinken Missverständnisse zwischen Fachseite, Produktmanagement und Entwicklung.</p>
<p><strong>DevOps-Teams</strong> bauen die Brücke zwischen Entwicklung und Betrieb.<br />
Sie verantworten u. a. CI/CD-Pipelines, Deployment-Prozesse, Monitoring und stabile Betriebsabläufe.</p>
<p>Wichtig ist das Zusammenspiel: Diese Rollen ersetzen nicht die Entwicklung, sondern schaffen den Rahmen, in dem Entwicklung zuverlässig liefern kann.</p>
<h3>Architektur definieren</h3>
<p>Architektur beschreibt die grobe Struktur und die Kommunikationswege eines Systems, z. B.:</p>
<ul>
<li>Frontend &#8211; Backend &#8211; Datenbank</li>
<li>Schichtenarchitektur</li>
<li>Event-basierte Systeme (Pub/Sub)</li>
<li>Dependency-Injection-Frameworks</li>
</ul>
<p>Sie legt die Leitplanken fest, nicht jedes Implementierungsdetail.</p>
<h3>Software betreiben und ausliefern</h3>
<p>Zum Engineering gehört auch der Betrieb:</p>
<ul>
<li>CI/CD (Continuous Integration / Continuous Deployment) für automatisches Bauen, Testen und Ausrollen</li>
<li>Staging-Umgebungen vor Produktion</li>
<li><a href="https://learngitbranching.js.org/?locale=de_DE">Branching-Strategie</a> (z. B. Trunk-Based oder Gitflow)</li>
<li>Containerisierung mit Docker/Kubernetes</li>
<li>Monitoring und Qualitätsmetriken</li>
<li>Release Notes pro Version oder Deployment</li>
<li>Artifact Mirror/Artifact Repository für kontrollierte Abhängigkeiten und Build-Artefakte</li>
</ul>
<h3>Quality Dashboards nutzen</h3>
<p><strong>Quality Dashboards</strong> machen Qualität messbar statt gefühlt. Typische Kennzahlen sind:</p>
<ul>
<li>Testabdeckung und Fehlerraten</li>
<li>Build- und Deployment-Stabilität</li>
<li>Laufzeitmetriken wie Latenz, Fehlerquote und Verfügbarkeit</li>
<li>technische Schulden (z. B. statische Analyse, Duplikate, Komplexität)</li>
</ul>
<p>Nicht jede Metrik passt für jedes Team. Entscheidend ist, wenige Kennzahlen konsequent zu nutzen und Trends zu beobachten.</p>
<h3>Blindspots im Alltag</h3>
<p>Einige Themen fehlen in vielen Teams anfangs, sind aber zentral für professionelles Software Engineering:</p>
<ul>
<li>Security by Design: Threat Modeling, Dependency-Scans, Secret-Management, Sicherheitsupdates</li>
<li>Reliability Engineering: SLOs, Alerting, Runbooks, Incident- und Postmortem-Prozesse</li>
<li>Wartbarkeit: technischer Schuldenabbau, regelmäßige Refactorings, klare Ownership</li>
<li>Wissensverteilung: Onboarding, Pairing, Reviews und Dokumentation statt &#8220;Single Points of Failure&#8221;</li>
</ul>
<h2>Fazit</h2>
<p>Software Engineering ist mehr als Programmieren. Es verbindet Technik, Prozesse und Zusammenarbeit, damit Software langfristig zuverlässig, wartbar und nutzbar bleibt.</p>
<p>Wie ich eingangs erwähnte: Dies ist ein gedankliches Modell. Die Grenzen zwischen den Bereichen sind fließend: Man kann natürlich von Anfang an Versionskontrolle einsetzen und ein CI/CD-System für ein einfaches „Hello World“-Programm einrichten. Mein Hauptanliegen ist es, das Bewusstsein dafür zu schärfen, dass Softwareentwicklung eine Vielzahl von Werkzeugen und Praktiken umfasst, deren Lernkurve steil ist, wenn man versucht, alles auf einmal zu beherrschen. Durch die Unterteilung des Fachgebiets in drei Ebenen lassen sich die Konzepte möglicherweise leichter schrittweise erfassen und die Fähigkeiten von innen nach außen entwickeln.</p>
<h2>Links</h2>
<p><a href="https://creatronix.de/die-junior-und-die-senior-rolle/">Die Junior und die Senior-Rolle</a></p>
<p><a href="https://creatronix.de/wie-baue-ich-eine-entwicklungsbegleitende-software-qualitatssicherung-auf/">Wie baue ich eine entwicklungsbegleitende Software-Qualitätssicherung auf?</a></p>
<p><a href="https://creatronix.de/wie-tdd-die-welt-rettet-und-deine-nerven-schont/">Wie TDD die Welt rettet und deine Nerven schont</a></p>
<p><a href="https://creatronix.de/pytest-tutorial/">Pytest Tutorial</a></p>
<p><a href="https://creatronix.de/so-verwendest-du-google-test-in-deinem-cpp-projekt/">So verwendest du Google Test in deinem C++-Projekt</a></p>
<p><a href="https://creatronix.de/alles-was-du-ueber-scrum-wissen-musst/">Alles was du über Scrum wissen musst</a></p>
<p><a href="https://creatronix.de/writing-as-complementary-skill-for-your-sw-engineering-career/">Writing as a complementary skill for your SW engineering career</a></p>
<h2>Literatur</h2>
<p><a href="https://amzn.to/40E6sBJ">The Software Engineer&#8217;s Guidebook</a></p>
<p><a href="https://frankwestphal.de/ftp/Westphal_Testgetriebene_Entwicklung.pdf">Mein erster Kontakt mit TDD (old but gold) </a></p>
<p>The post <a href="https://creatronix.de/was-ist-software-engineering-eine-verstaendliche-einfuehrung/">Was ist Software Engineering? Eine verständliche Einführung</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>So verwaltest du deine Roboter mit Ansible</title>
		<link>https://creatronix.de/so-verwaltest-du-deine-roboter-mit-ansible/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Wed, 11 Mar 2026 19:43:10 +0000</pubDate>
				<category><![CDATA[Robotics]]></category>
		<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=7893</guid>

					<description><![CDATA[<p>Motivation Eine einzelne Ubuntu-Maschine zu warten, ist noch überschaubar. Man loggt sich per SSH ein, installiert ein paar Pakete, macht ein Update – und dann läuft die Kiste wieder. In der Robotik bleibt es aber selten bei einer Maschine. Sobald mehrere Roboter im Einsatz sind, sitzt man plötzlich vor einem kleinen Zoo aus Linux-Systemen. Dann&#8230;</p>
<p>The post <a href="https://creatronix.de/so-verwaltest-du-deine-roboter-mit-ansible/">So verwaltest du deine Roboter mit Ansible</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Motivation</h2>
<p>Eine einzelne Ubuntu-Maschine zu warten, ist noch überschaubar. Man loggt sich per SSH ein, installiert ein paar Pakete, macht ein Update – und dann läuft die Kiste wieder.</p>
<p>In der Robotik bleibt es aber selten bei einer Maschine. Sobald mehrere Roboter im Einsatz sind, sitzt man plötzlich vor einem kleinen Zoo aus Linux-Systemen.</p>
<p>Dann beginnt die klassische Runde:<br />
SSH auf Rechner eins, Updates einspielen.<br />
SSH auf Rechner zwei, dieselben Updates einspielen.<br />
SSH auf Rechner drei – na, Du ahnst es schon.</p>
<p>Spätestens nach dem fünften Roboter merkt man: Das ist weniger Systemadministration und mehr Fleißarbeit mit Copy-Paste.</p>
<p>Genau hier kommt Ansible ins Spiel. Mit sogenannten Playbooks beschreibt man einfach den gewünschten Zustand der Systeme – welche Pakete installiert sein sollen, welche Konfigurationen gelten, welche Updates eingespielt werden. Ansible kümmert sich dann darum, diese Zustände automatisch auf allen Zielrechnern umzusetzen.</p>
<p>Gerade in Robotik-Umgebungen mit vielen verteilten Rechnern sorgt dieser Ansatz dafür, dass Wartung nicht mehr Handarbeit ist – sondern planbar, reproduzierbar und vor allem deutlich entspannter.</p>
<h2>Ansible</h2>
<p>Ansible wurde 2012 von Michael DeHaan entwickelt und als Open-Source-Projekt veröffentlicht. 2015 wurde das Unternehmen Ansible, Inc. von Red Hat übernommen, das wiederum seit 2019 zu IBM gehört.</p>
<p>Es ist ein agentenloses Automatisierungstool – das heißt, auf den Zielrechnern muss keine zusätzliche Software installiert werden. Ansible verbindet sich einfach per SSH und führt die gewünschten Aufgaben aus.</p>
<h2>Setup</h2>
<p>Für dieses Tutorial brauchst Du einen Ubuntu-PC und einen Raspberry Pi mit einem installierten Ubuntu. Auf deinem Control-Rechner (also deinem PC) läuft Ansible und der SSH Client, auf dem Raspberry (also dem Remote-Rechner) muss der SSH-Server aktiviert sein.</p>
<h2>Installation</h2>
<p>Auf deinem Control-Rechner installierst du Ansible wie folgt:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>sudo apt update
sudo apt install ansible
sudo apt install sshpass</code></pre>
</div>
<p>Jetzt kannst Du testen, ob die Installation geklappt hat:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>ansible --version</code></pre>
</div>
<h2>SSH aktivieren</h2>
<p>Damit Ansible funktioniert, muss auf dem Raspberry aka Remote-Rechner SSH eingerichtet sein.<br />
Probier mal im Terminal deines Control-Rechners aus, dich mit dem Raspberry zu verbinden:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>ssh pi@192.168.178.50</code></pre>
</div>
<p>Falls das nicht klappt, musst du SSH auf dem Raspberry aktivieren. Das geht ganz einfach über die raspi-config:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>sudo raspi-config</code></pre>
</div>
<p>Dann navigierst du zu &#8220;Interfacing Options&#8221; -&gt; &#8220;SSH&#8221; und aktivierst den SSH-Server.</p>
<h2>Projektordner</h2>
<p>Auf deinem Control-Rechner legst du dir z.B. einen Projektordner an:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>mkdir ~/ansible
cd ansible
touch hosts
touch ansible.cfg
touch update_pi.yml</code></pre>
</div>
<p>Die Ordnerstruktur soll nachher so aussehen:</p>
<p>ansible/<br />
├── hosts<br />
├── update_pi.yml<br />
└── ansible.cfg</p>
<h2>hosts-Datei anlegen</h2>
<p>In der hosts-Datei stehen die Rechner und ihre IP-Adressen bzw. ihre A-Records.</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-json" data-lang="JSON"><code>[raspberry]
pi1 ansible_host=192.168.178.66 ansible_user=&lt;username&gt;</code></pre>
</div>
<h2>ansible.cfg</h2>
<p>Die ansible.cfg Datei ist die Konfigurationsdatei für Ansible.<br />
Hier kannst du verschiedene Einstellungen vornehmen, z.B. den Pfad zu deiner hosts-Datei.<br />
Ein einfaches Beispiel sieht so aus</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-json" data-lang="JSON"><code>[defaults]
inventory = hosts</code></pre>
</div>
<h2>Playbooks</h2>
<p>Playbooks sind die Ansible-Äquivalente zu Skripten, sie beschreiben die gewünschten Zustände der Zielrechner.<br />
Ein einfaches Playbook für die Updates des Raspberrys könnte so aussehen:</p>
<h3>update_pi.yml</h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-json" data-lang="JSON"><code>---
- name: Update Raspberry Pi
  hosts: raspberry
  become: yes

  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes

    - name: Upgrade all packages
      apt:
        upgrade: dist</code></pre>
</div>
<h3>Im Detail</h3>
<table>
<thead>
<tr>
<th>Ansible</th>
<th>Bash</th>
</tr>
</thead>
<tbody>
<tr>
<td>become: yes</td>
<td>sudo</td>
</tr>
<tr>
<td>apt: update_cache: yes</td>
<td>apt update</td>
</tr>
<tr>
<td>upgrade: dist</td>
<td>apt upgrade</td>
</tr>
<tr>
<td>autoremove: yes</td>
<td>apt autoremove</td>
</tr>
</tbody>
</table>
<h2>Ansible starten</h2>
<p>Wenn du diese drei Dateien anegelegt hast, kann es auch schon losgehen</p>
<h3>ping</h3>
<p>Der ping-Befehl ist ein Testmodul von Ansible, das überprüft, ob der Host erreichbar und ausführbar ist.<br />
Wenn du Passwort-Login benutzt musst du Ansible sagen, dass es nach einem SSH-Passwort fragen soll:<br />
Das -k steht für &#8211;ask-pass</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>ansible -i hosts raspberry -m ping -k
SSH password:</code></pre>
</div>
<p>Wenn alles funktioniert, solltest du folgenden Output sehen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>pi1 | SUCCESS =&gt; {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}</code></pre>
</div>
<h3>Playbook starten</h3>
<p>Jetzt zum eigentlichen Task:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>ansible-playbook -i hosts update_pi.yml -k -K</code></pre>
</div>
<p>Da wir sudu apt update / upgrade machen wollen, müssen wir auch das root-PW übergeben. Das machen wir mit dem Flag -K.<br />
-K steht für &#8211;ask-become-pass, damit wird Ansible nach dem sudo-Passwort fragen.</p>
<h2>Zertifikat-Login</h2>
<p>Da wir aber nicht permanent die<br />
Ansible unterstützt auch die Authentifizierung mit Zertifikaten, was sicherer ist als die Passwort-Authentifizierung.<br />
Dazu musst du auf deinem Control-Rechner ein SSH-Schlüsselpaar generieren und den öffentlichen Schlüssel auf den<br />
Zielrechner kopieren.</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>ssh-keygen -t rsa -b 4096 -C "@ansible-controller"
ssh-copy-id @192.168.178.66</code></pre>
</div>
<p>Danach kannst du Ansible ohne Passwort verwenden, indem du einfach den Hostnamen angibst:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>ansible-playbook -i hosts update_pi.yml -K</code></pre>
</div>
<h2>Weitere Beispiele</h2>
<h3>Ubuntu-Pakete installieren</h3>
<p>Man kann natürlich auch andere Pakete installieren, z.B. git:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-json" data-lang="JSON"><code>tasks: 
- name: Install git 
  apt: 
    name: git 
    state: present 
    update_cache: yes</code></pre>
</div>
<h3>Git Repository klonen</h3>
<p>Auch das Klonen eines Git-Repositories ist mit Ansible kein Problem:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-json" data-lang="JSON"><code>tasks: 
- name: Clone Git repo 
    git:
      repo: https://github.com/user/meinprojekt.git 
      dest: /home/pi/meinprojekt 
      version: main</code></pre>
</div>
<h2>Fazit</h2>
<p>Ansible ist ein mächtiges Werkzeug, um die Wartung von Robotern zu automatisieren. Es ermöglicht dir, den Zustand deiner<br />
Systeme zu beschreiben und automatisch umzusetzen, ohne dich manuell auf jedem Rechner einzuloggen. Gerade in Umgebungen<br />
mit vielen verteilten Rechnern spart das enorm viel Zeit und Nerven.</p>
<p>The post <a href="https://creatronix.de/so-verwaltest-du-deine-roboter-mit-ansible/">So verwaltest du deine Roboter mit Ansible</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Alles, was Du über SCRUM wissen musst</title>
		<link>https://creatronix.de/alles-was-du-ueber-scrum-wissen-musst/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Tue, 10 Mar 2026 18:45:41 +0000</pubDate>
				<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=7886</guid>

					<description><![CDATA[<p>Motivation SCRUM wurde von Ken Schwaber und Jeff Sutherland entwickelt und ist ein agiles Framework für die Softwareentwicklung. Es hilft Teams, komplexe Projekte zu managen und schnell auf Veränderungen zu reagieren. SCRUM fördert die Zusammenarbeit, Transparenz und kontinuierliche Verbesserung. Werte Commitment, Focus, Openness, Respect, and Courage Vorgehensmodell Interativ &#38; Inkrementell Entwicklungszeitraum wird in Sprints unterteilt&#8230;</p>
<p>The post <a href="https://creatronix.de/alles-was-du-ueber-scrum-wissen-musst/">Alles, was Du über SCRUM wissen musst</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Motivation</h2>
<p>SCRUM wurde von Ken Schwaber und Jeff Sutherland entwickelt und ist ein agiles Framework für die Softwareentwicklung.<br />
Es hilft Teams, komplexe Projekte zu managen und schnell auf Veränderungen zu reagieren.<br />
SCRUM fördert die Zusammenarbeit, Transparenz und kontinuierliche Verbesserung.</p>
<h2>Werte</h2>
<p>Commitment, Focus, Openness, Respect, and Courage</p>
<h2>Vorgehensmodell</h2>
<h3>Interativ &amp; Inkrementell</h3>
<p>Entwicklungszeitraum wird in Sprints unterteilt</p>
<h3>Sprints</h3>
<p>Dauer: 2-4 Wochen<br />
Ziel: funktionierende Software nach jedem Sprint mit neuen Features die den Geschäftswert des Produkte maximieren</p>
<h3>Messen der Velocity</h3>
<ul>
<li>Velocity = Anzahl der Story Points, die in einem Sprint abgeschlossen wurden</li>
<li>hilft bei der Planung zukünftiger Sprints</li>
</ul>
<h2>Rollen</h2>
<h3>Product Owner</h3>
<p>Stellvertreter des Kunden und der Stakeholder<br />
Der Product Owner ist verantwortlich für:</p>
<ul>
<li>Produktvision und Strategie</li>
<li>Product Backlog erstellen und priorisieren</li>
<li>Anforderungen verstehen, übersetzen und priorisieren</li>
<li>Wert für das Produkt maximieren</li>
<li>Stakeholder koordinieren</li>
</ul>
<p>Er ist die zentrale Entscheidungsinstanz für das Produkt.</p>
<h3>Scrum Master</h3>
<ul>
<li>coacht Teammitglieder und Organisation</li>
<li>verwaltet impediment backlog</li>
<li>löst impediments auf</li>
<li>moderiert Meetings mit dem Ziel, die Effizienz des Teams zu verbessern</li>
<li>schützt das Team vor äußeren Störungen</li>
<li>fördert die Einhaltung von Scrum-Prinzipien und -Praktiken</li>
</ul>
<h3>Scrum Team</h3>
<ul>
<li>schätzt User Stories</li>
<li>setzt Stories um</li>
<li>arbeitet selbstorganisiert</li>
<li>cross-funktional (Entwickler, Tester, Designer etc.)</li>
<li>verantwortlich für die Lieferung von Inkrementen am Ende jedes Sprints</li>
</ul>
<h2>Artefakte</h2>
<h3>Inkrement</h3>
<p>Neue Software, die am Ende eines Sprints fertiggestellt und potenziell auslieferbar ist.</p>
<h3>Product-Backlog</h3>
<ul>
<li>enthält User Stories mit Definition of Done (DoD) und Akzeptanzkriterien</li>
<li>priorisiert nach Business Value</li>
<li>dynamisch, wird während des Projekts angepasst</li>
</ul>
<h3>Sprint-Backlog</h3>
<ul>
<li>alle Items für den Sprint, inkl. DoD und Akzeptanzkriterien</li>
<li>Burndown / Burnup Chart für Fortschrittsverfolgung</li>
</ul>
<h3>Impediment-Backlog</h3>
<p>Für Hindernisse, die das Team daran hindern, die Sprint-Ziele zu erreichen<br />
Beispiele:</p>
<ul>
<li>CI Pipeline funktioniert nicht</li>
<li>Zugang zu Testdaten fehlt</li>
<li>API Dokumentation unvollständig</li>
<li>Fehlende Hardware für Tests</li>
</ul>
<h2>Termine</h2>
<h3>Backlog Refinement (früher Backlog Grooming)</h3>
<p>Zeitpunkt: 1-2 mal pro Sprint, oft in der Mitte des Sprints<br />
Dauer: 1-2 Stunden<br />
Ziel: User Stories mit DoD, Akzeptanzkriterien und Story Points versehen, damit sie für die Sprintplanung bereit sind</p>
<p><strong>Planning Poker</strong></p>
<p>Wie geschätzt wird, lässt Scrum offen, aber Planning Poker ist beliebt.<br />
Jeder Teilnehmer erhält Karten mit Zahlen (z.B. Fibonacci-Folge: 1, 2, 3, 5, 8, 13)</p>
<p>Die Zahlen stehen für die Komplexität der Aufgabe von 1 &#8211; sehr simpel bis 13 sehr komplex.<br />
Der Product Owner liest eine User Story vor, und die Teilnehmer schätzen gleichzeitig, indem sie eine Karte mit ihrer Schätzung hochhalten<br />
Nach der Schätzung diskutieren die Teilnehmer, um ein gemeinsames Verständnis zu erreichen.</p>
<h3>Sprint Planning</h3>
<p>Zeitpunkt: Am Anfang eines Sprints<br />
Dauer: 4-8 Stunden (je nach Sprintlänge)<br />
Ziel: Sprint-Ziele festlegen, User Stories auswählen, die im Sprint bearbeitet werden sollen, und Aufgaben planen</p>
<h3>Daily Standup</h3>
<p>Zeitpunkt: Täglich, meist morgens<br />
Dauer: 15 Minuten<br />
Ziel: Mini-Retro: Awareness für erledigte und aktuelle Tätigkeiten, Impediments an Scrum Master kommunizieren</p>
<h3>Sprint Retro</h3>
<p>Zeitpunkt: Am Sprint-Ende<br />
Dauer: 1-2 Stunden<br />
Ziel: Reflexion über den vergangenen Sprint, Identifikation von Verbesserungsmöglichkeiten, Maßnahmen für den nächsten Sprint planen</p>
<p>&nbsp;</p>
<h2>Scrum but &#8211; Antipatterns</h2>
<p>Wenn Scrum nicht richtig umgesetzt wird, können verschiedene Probleme auftreten, z.B.:</p>
<ul>
<li>Scrum Master ist nur ein Titel, aber keine echte Rolle im Team</li>
<li>Product Owner ist nicht verfügbar oder hat keine Entscheidungsbefugnis</li>
<li>Team arbeitet nicht selbstorganisiert, sondern wird von außen gesteuert</li>
<li>Sprints werden nicht eingehalten, sondern ständig verlängert oder verkürzt</li>
<li>Meetings werden nicht effektiv genutzt, sondern sind reine Zeitverschwendung</li>
<li>Keine klare Definition of Done, was zu unklaren Anforderungen und Qualitätsproblemen führt</li>
<li>Keine regelmäßige Retrospektive, was zu fehlender kontinuierlicher Verbesserung führt</li>
<li>Keine klare Priorisierung im Product Backlog, was zu ineffizienter Arbeit und fehlendem Fokus führt</li>
</ul>
<h2>Quellen</h2>
<p><a href="https://scrumguides.org/scrum-guide.html">https://scrumguides.org/scrum-guide.html</a></p>
<p>The post <a href="https://creatronix.de/alles-was-du-ueber-scrum-wissen-musst/">Alles, was Du über SCRUM wissen musst</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Linux Shell Kommandos Cheatsheet</title>
		<link>https://creatronix.de/linux-shell-kommandos-cheatsheet/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Wed, 04 Mar 2026 11:54:04 +0000</pubDate>
				<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=7878</guid>

					<description><![CDATA[<p>Motivation In Robotik-Projekten wird in den meisten Fällen mit einer Linux-Distribution wie Ubuntu gearbeitet, deswegen ist es von Vorteil, sich auch auf der Linux-Konsole aka shell auszukennen. Die Standard-Shell ist meistens Bash (Bourne Again Shell). Viele ROS-Tools erwarten explizit Bash: source /opt/ros/humble/setup.bash Informationen über Kommandos Mit dem Kommando man kann man sich Infos zu den&#8230;</p>
<p>The post <a href="https://creatronix.de/linux-shell-kommandos-cheatsheet/">Linux Shell Kommandos Cheatsheet</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Motivation</h2>
<p>In Robotik-Projekten wird in den meisten Fällen mit einer Linux-Distribution wie Ubuntu gearbeitet, deswegen ist es von Vorteil, sich auch auf der Linux-Konsole aka shell auszukennen.</p>
<p>Die Standard-Shell ist meistens Bash (Bourne Again Shell). Viele ROS-Tools erwarten explizit Bash:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>source /opt/ros/humble/setup.bash</code></pre>
</div>
<h2>Informationen über Kommandos</h2>
<p>Mit dem Kommando man kann man sich Infos zu den Kommandos geben lassen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash">man ls</pre>
</div>
<p>Eine moderne Alternative ist tldr:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>tldr ls</code></pre>
</div>
<p>Du kannst es unter Ubuntu mit</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>sudo snap install tldr</code></pre>
</div>
<p>installieren.</p>
<h2>Datei-Handling</h2>
<table>
<thead>
<tr>
<th>Befehl</th>
<th>Bedeutung</th>
<th>Nützliche Optionen</th>
</tr>
</thead>
<tbody>
<tr>
<td>ls</td>
<td>Verzeichnisinhalt anzeigen</td>
<td>-a verstecdkte Dateien<br />
-h human readable<br />
-l detaillierte List</td>
</tr>
<tr>
<td>cd</td>
<td>Verzeichnis wechseln</td>
<td>.. eine Ebene höher / ~ home Verzeichnis</td>
</tr>
<tr>
<td>pwd</td>
<td>aktuelles Verzeichnis anzeigen</td>
<td></td>
</tr>
<tr>
<td>mkdir</td>
<td>make directory: Verzeichnis erstellen</td>
<td></td>
</tr>
<tr>
<td>touch</td>
<td>Datei erstellen / Timestamp ändern</td>
<td></td>
</tr>
<tr>
<td>rm</td>
<td>Datei / Ordner löschen</td>
<td>-r rekursiv / -f force</td>
</tr>
<tr>
<td>cp</td>
<td>Datei kopieren</td>
<td>-r rekursiv</td>
</tr>
<tr>
<td>mv</td>
<td>Datei verschieben oder umbenennen</td>
<td></td>
</tr>
<tr>
<td>ln</td>
<td>Link erstellen</td>
<td>-s symbolischer Link</td>
</tr>
<tr>
<td>du</td>
<td>Speicherverbrauch anzeigen</td>
<td>-h human readable</td>
</tr>
<tr>
<td>df</td>
<td>freien Speicher anzeigen</td>
<td>-h human readable</td>
</tr>
<tr>
<td>which</td>
<td>Pfad eines Programms anzeigen</td>
<td>-a alle Treffer</td>
</tr>
<tr>
<td>tar</td>
<td>Archive packen/entpacken</td>
<td>-xvf entpacken</td>
</tr>
<tr>
<td>find</td>
<td>Dateien suchen</td>
<td>-name, -type</td>
</tr>
<tr>
<td>grep</td>
<td>Text in Dateien suchen</td>
<td>-r rekursiv</td>
</tr>
</tbody>
</table>
<h2>Benutzer &amp; Rechte</h2>
<table>
<thead>
<tr>
<th>Befehl</th>
<th>Bedeutung</th>
<th>Nützliche Optionen</th>
</tr>
</thead>
<tbody>
<tr>
<td>whoami</td>
<td>aktuellen Benutzer anzeigen</td>
<td></td>
</tr>
<tr>
<td>id</td>
<td>Benutzer- und Gruppeninformationen</td>
<td></td>
</tr>
<tr>
<td>sudo</td>
<td>Befehl als root ausführen</td>
<td></td>
</tr>
<tr>
<td>chmod</td>
<td>Dateirechte ändern</td>
<td>chmod +x script.sh</td>
</tr>
<tr>
<td>chown</td>
<td>Eigentümer ändern</td>
<td>sudo chown user:file</td>
</tr>
</tbody>
</table>
<h2>Linux-Pakete &amp; Versionsinformationen</h2>
<table>
<thead>
<tr>
<th>Befehl</th>
<th>Bedeutung</th>
<th>Nützliche Optionen</th>
</tr>
</thead>
<tbody>
<tr>
<td>apt</td>
<td>Paketmanager</td>
<td>install <package_name>, update, upgrade</package_name></td>
</tr>
<tr>
<td>dpkg</td>
<td>lokale .deb installieren</td>
<td>dpkg -i file.deb</td>
</tr>
<tr>
<td>lsb_release -a</td>
<td>Distribution anzeigen</td>
<td></td>
</tr>
<tr>
<td>uname -a</td>
<td>Kernelinformationen</td>
<td></td>
</tr>
</tbody>
</table>
<h2>Prozesse</h2>
<table>
<thead>
<tr>
<th>Befehl</th>
<th>Bedeutung</th>
<th>Nützliche Optionen</th>
</tr>
</thead>
<tbody>
<tr>
<td>ps</td>
<td>Prozesse anzeigen</td>
<td>ps aux</td>
</tr>
<tr>
<td>top</td>
<td>Systemmonitor</td>
<td></td>
</tr>
<tr>
<td>htop</td>
<td>CPU und RAM Verbrauch anzeigen</td>
<td></td>
</tr>
<tr>
<td>kill</td>
<td>Prozess per PID beenden</td>
<td></td>
</tr>
<tr>
<td>pkill</td>
<td>Prozess per Name beenden</td>
<td></td>
</tr>
<tr>
<td>jobs</td>
<td>Hintergrundjobs anzeigenn</td>
<td></td>
</tr>
</tbody>
</table>
<h2>Netzwerke</h2>
<table>
<thead>
<tr>
<th>Befehl</th>
<th>Bedeutung</th>
<th>Nützliche Optionen</th>
</tr>
</thead>
<tbody>
<tr>
<td>ip a</td>
<td>Netzwerkschnittstellen anzeigen</td>
<td></td>
</tr>
<tr>
<td>ping</td>
<td>Verbindung testen</td>
<td>ping heise.de</td>
</tr>
<tr>
<td>ss</td>
<td>offene Ports anzeigen</td>
<td>-tulpen</td>
</tr>
<tr>
<td>curl</td>
<td>HTTP Requests</td>
<td></td>
</tr>
<tr>
<td>ssh</td>
<td>Remote Login</td>
<td></td>
</tr>
</tbody>
</table>
<h2>USB</h2>
<table>
<thead>
<tr>
<th>Befehl</th>
<th>Bedeutung</th>
</tr>
</thead>
<tbody>
<tr>
<td>lsusb</td>
<td>USB-Geräte anzeigen</td>
</tr>
<tr>
<td>dmesg</td>
<td>Kernel-Logs (z. B. beim Einstecken)</td>
</tr>
</tbody>
</table>
<p>The post <a href="https://creatronix.de/linux-shell-kommandos-cheatsheet/">Linux Shell Kommandos Cheatsheet</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Pytest Tutorial</title>
		<link>https://creatronix.de/pytest-tutorial/</link>
		
		<dc:creator><![CDATA[Jörn]]></dc:creator>
		<pubDate>Fri, 06 Feb 2026 20:00:23 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Software Engineering & Programming]]></category>
		<guid isPermaLink="false">https://creatronix.de/?p=7846</guid>

					<description><![CDATA[<p>Motivation Tests sind ein zentraler Bestandteil moderner Entwicklung. Das Framework pytest macht das Schreiben, Organisieren und Ausführen von Tests einfach, flexibel und leistungsfähig. Tests schreiben und ausführen Installation Zuerst installierst du pytest mit: pip install pytest pytest ist kompatibel mit unittest-Tests und erfordert keine Testklassen. Namenskonventionen Damit pytest Tests automatisch findet, müssen Dateien und Funktionen&#8230;</p>
<p>The post <a href="https://creatronix.de/pytest-tutorial/">Pytest Tutorial</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Motivation</h2>
<p>Tests sind ein zentraler Bestandteil moderner Entwicklung. Das Framework pytest macht das Schreiben, Organisieren und Ausführen von Tests einfach, flexibel und leistungsfähig.</p>
<h2>Tests schreiben und ausführen</h2>
<h3>Installation</h3>
<p>Zuerst installierst du pytest mit:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>pip install pytest</code></pre>
</div>
<p>pytest ist kompatibel mit unittest-Tests und erfordert keine Testklassen.</p>
<h3>Namenskonventionen</h3>
<p>Damit pytest Tests automatisch findet, müssen Dateien und Funktionen bestimmte Namen haben:</p>
<ul>
<li>Dateinamen haben test im Namen</li>
<li>Funktionsnamen beginnen mit test_</li>
</ul>
<p>Beispiel:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>def test_example():
    x = 5
    assert x == 5</code></pre>
</div>
<p>Mit pytest im Terminal führt pytest alle passenden Tests aus.</p>
<h3>Testauswahl</h3>
<p>Du kannst gezielt Tests ausführen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>pytest test_module.py::test_function
pytest -k "keyword"</code></pre>
</div>
<p>Optionen wie -v (verbose), -x (bei Fehler abbrechen) oder -s (print-Ausgaben anzeigen) sind sehr praktisch.</p>
<p>Um Optionen nicht immer per Hand eingeben zu müssen, können diese auch in einer pytest.ini angegeben werden:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang="Plain Text"><code>[pytest]
pythonpath = .
addopts = -x --durations=0 -vv</code></pre>
</div>
<h2>Fortgeschrittene pytest-Techniken</h2>
<h3>Fixtures</h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>import pytest

@pytest.fixture(scope="function")
def simple_fixture():
    return 42

def test_function(simple_fixture):
    assert simple_fixture == 42</code></pre>
</div>
<h3>Fixture scopes</h3>
<p>pytest-Fixtures haben einen Scope, der bestimmt, wie oft eine Fixture erzeugt und wiederverwendet wird.<br />
Der Standard-Scope ist function, d. h. die Fixture wird für jeden Test neu ausgeführt.</p>
<p>Weitere Scopes sind:</p>
<ul>
<li>class &#8211; einmal pro Testklasse</li>
<li>module &#8211; einmal pro Datei</li>
<li>package &#8211; einmal pro Paket</li>
<li>session &#8211; einmal pro gesamtem Testlauf</li>
</ul>
<p>Größere Scopes verbessern die Performance, bergen aber das Risiko von geteiltem Zustand zwischen Tests.<br />
Daher gilt: so klein wie möglich, so groß wie nötig.</p>
<h3>Setup and teardown</h3>
<p>Mit pytest können wir klassische setup / teardown Methoden mit fixtures nachbauen</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>import pytest

def test_setup_and_teardown():
    assert True

@pytest.fixture(autouse=True, scope="function")
def setup_and_teardown():
    print("SetUp")
    # setup code goes here
    yield
    print("TearDown")
    # teardown code goes here</code></pre>
</div>
<h3>Parametrisierung</h3>
<p>Mit Parametrisierung lässt sich derselbe Test mit verschiedenen Daten ausführen. So umgehst du Duplikate:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>import pytest

@pytest.mark.parametrize("data, expected", [
    ([1], 1),
    ([1, 2], 1.5),
    ([1, 2, 3], 2),
])
def test_calculate_mean(data, expected_mean):
    mean = calculate_mean(data)
    assert mean == expected_mean

def calculate_mean(data):
    return sum(data) / len(data)</code></pre>
</div>
<p>&nbsp;</p>
<p>Das definiert mehrere Testinstanzen automatisch.</p>
<h3>Marker</h3>
<p>Marker helfen, Gruppen von Tests zu steuern.<br />
Marker eignen sich z. B. zur Gruppierung nach Plattform, Kategorie oder Dauer.</p>
<p>Es gibt drei eingebaute Marker:</p>
<ul>
<li>skip</li>
<li>skipif</li>
<li>xfail</li>
</ul>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>import pytest
import sys

@pytest.mark.skip(reason="Feature not yet implemented")
def test_future():
    pass

@pytest.mark.skipif(sys.platform == "win32", reason="Linux only")
def test_linux_only():
    pass

@pytest.mark.xfail(reason="Bug #123")
def test_known_bug():
    pass</code></pre>
</div>
<h3>Eigene Marker</h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>import pytest

@pytest.mark.slow
def test_slow():
    pass</code></pre>
</div>
<p>In pytest.ini:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang="Plain Text"><code>[pytest]
...
markers =
    slow: mark slow tests</code></pre>
</div>
<p>Dann kannst du testen mit:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>pytest -m slow</code></pre>
</div>
<p>Oder alle nicht langsamen Tests laufen lassen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>pytest -m "not slow"</code></pre>
</div>
<h3>Nahezu gleiche Vergleiche</h3>
<p>Für Fließkommazahlen ist ein exakter Vergleich oft ungeeignet. pytest bietet das approx-Feature:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>assert 2.2 == pytest.approx(2.3, 0.1)</code></pre>
</div>
<p>Erlaubt eine Toleranz statt exakter Übereinstimmung.</p>
<h3>Exceptions testen</h3>
<p>Mit pytest kannst du das Auftreten von Ausnahmen elegant testen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>def test_zero_division():
    with pytest.raises(ZeroDivisionError):
        1 / 0</code></pre>
</div>
<p>Das prüft, ob ein Fehler erwartet korrekt geworfen wird.</p>
<h2>Test-Reporting &amp; Coverage</h2>
<p>Testabdeckung mit pytest-cov</p>
<p>Mit dem Plugin pytest-cov lässt sich messen, wie viel deines Codes getestet wird:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>pip install pytest-cov

pytest --cov=my_app 10_app_test</code></pre>
</div>
<p>Ergebnis: Coverage-Statistiken zeigen an, wie viele Zeilen getestet wurden.</p>
<h3>HTML-Reports</h3>
<p>Du kannst mit demselben Plugin HTML-Berichte erzeugen:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>pytest --cov=my_app --cov-report=html</code></pre>
</div>
<p>Eine visuelle Übersicht über die Abdeckung hilft bei der Analyse.</p>
<h3>Integration mit Werkzeugen</h3>
<p>Coverage-Daten lassen sich in Tools wie SonarQube einbinden:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>pytest --cov-report=xml:coverage.xml</code></pre>
</div>
<p>Dadurch kannst du Metriken in CI/CD-Pipelines oder Dashboards verwenden.</p>
<h2>Assertions mit Hamcrest (optional, aber mächtig)</h2>
<p>Neben den eingebauten assert-Anweisungen von pytest kann man auch Hamcrest verwenden.<br />
Hamcrest ist eine Matcher-Bibliothek, die Tests lesbarer und ausdrucksstärker machen kann – besonders bei komplexen Datenstrukturen.</p>
<h3>Installation</h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>pip install pyhamcrest</code></pre>
</div>
<p>Import in Tests:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>from hamcrest import assert_that, equal_to</code></pre>
</div>
<h3>Warum Hamcrest?</h3>
<p>Vergleich:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>def test_hamcrest_assert():
    result = 42
    assert_that(result, equal_to(42))</code></pre>
</div>
<p>Der Vorteil zeigt sich bei komplexeren Assertions:</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>def test_hamcrest_start_with():
    name = "Max Mustermann"
    assert_that(name, starts_with("Max"))

def test_hamcrest_has_length():
    items: Sized = ['apple', 'banana', 'cherry']
    assert_that(items, has_length(3))</code></pre>
</div>
<p>Tests lesen sich mehr wie Spezifikationen.</p>
<h3>Listen &amp; Collections</h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-python" data-lang="Python"><code>from hamcrest import assert_that, has_items
from collections.abc import Sequence

def test_compare_list_of_items():
    actual_list_of_items: Sequence[str] = ['apple', 'banana', 'cherry']
    assert_that(actual_list_of_items, has_items("apple", "banana"))</code></pre>
</div>
<h2>Fazit</h2>
<p>pytest ist ein einfaches, doch mächtiges Framework zur Testautomatisierung in Python. Es kombiniert:</p>
<ul>
<li>geringe Einstiegshürde – einfache Tests schnell geschrieben</li>
<li>hohe Flexibilität – Marker, Parameter, Coverage</li>
<li>gute Tools-Integration – HTML-Reports oder CI-Coverage</li>
</ul>
<p>Damit eignet es sich sowohl für Einsteiger als auch für professionelle Test-Pipelines.</p>
<h2>Code</h2>
<p><a href="https://github.com/jboegeholz/pytest_tutorial">https://github.com/jboegeholz/pytest_tutorial</a></p>
<p>The post <a href="https://creatronix.de/pytest-tutorial/">Pytest Tutorial</a> appeared first on <a href="https://creatronix.de">Creatronix</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
