<?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>argumentum GmbH</title>
	<atom:link href="https://argumentum.de/feed/" rel="self" type="application/rss+xml" />
	<link>https://argumentum.de/</link>
	<description>Experten für Softwareentwicklungsprozesse</description>
	<lastBuildDate>Thu, 19 Jun 2025 14:51:24 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://argumentum.de/wp-content/uploads/2023/12/cropped-small_logo-32x32.png</url>
	<title>argumentum GmbH</title>
	<link>https://argumentum.de/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Ports und Adapters in fünf Minuten</title>
		<link>https://argumentum.de/2025/05/ports-und-adapters-in-fuenf-minuten/</link>
		
		<dc:creator><![CDATA[Hendrik Wagner]]></dc:creator>
		<pubDate>Thu, 22 May 2025 20:16:21 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[hexagonale architektur]]></category>
		<category><![CDATA[onion-architektur]]></category>
		<category><![CDATA[ports and adapters]]></category>
		<guid isPermaLink="false">https://argumentum.de/?p=2244</guid>

					<description><![CDATA[In modernen Softwareentwicklungsprojekten wird mit Prinzipien und Architekturmodellen gearbeitet, um Software wartbarer, nachvollziehbarer und erweiterbar zu gestalten. Ein mögliches – und durchaus sinnvolles – Architekturmodell sind die Ports und Adapters, auch als Hexagonale Architektur oder Onion-Architektur bekannt.]]></description>
										<content:encoded><![CDATA[
<p>In modernen Softwareentwicklungsprojekten wird mit Prinzipien und Architekturmodellen gearbeitet, um Software wartbarer, nachvollziehbarer und erweiterbar zu gestalten. Ein mögliches – und durchaus sinnvolles – Architekturmodell sind die Ports und Adapters, auch als <a href="https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)">Hexagonale Architektur</a> oder Onion-Architektur bekannt (auf die Unterschiede gehen wir später kurz ein).</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><strong>Das Konzept</strong></h2>



<p>Mithilfe von Adaptern werden die entstehende Anwendung und Komponenten, mit denen kommuniziert werden, logisch abgetrennt. Der Anwendungskern wird von den Schnittstellen entfernt und ist von diesen nicht abhängig &#8211; dadurch werden sie einfach austauschbar. Fangen wir mit der einfacheren Seite an &#8211; eine Schnittstelle ruft die Anwendung auf. Dies kann zum Beispiel über eine Oberfläche passieren:</p>


<div class="wp-block-image">
<figure class="aligncenter is-resized"><img fetchpriority="high" decoding="async" width="581" height="242" src="https://argumentum.de/wp-content/uploads/2025/05/hexagon2.drawio.png" alt="Ports and Adapters - Kommunikation der Anwendung mit einem User-Interface" class="wp-image-2246" style="width:804px;height:auto" srcset="https://argumentum.de/wp-content/uploads/2025/05/hexagon2.drawio.png 581w, https://argumentum.de/wp-content/uploads/2025/05/hexagon2.drawio-300x125.png 300w" sizes="(max-width: 581px) 100vw, 581px" /><figcaption class="wp-element-caption"><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-contrast-2-color">In dieser Grafik wird die Anwendung von einer Webanwendung aus gesteuert. Die Kommunikation zwischen Frontend und Anwendung kann zum Beispiel mittels REST-API erfolgen – dann empfängt der Adapter die Aufrufe und kommuniziert mittels UI-Port die gewünschte Interaktion mit der Anwendung. In der Regel folgt darauf eine Antwort in Richtung der Webanwendung.</mark></figcaption></figure>
</div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p>In der Umsetzung kann man sich dies einfach vorstellen. Nehmen wir hierzu ein Java-Projekt mit Maven, welches eine Chatanwendung umsetzten soll. Angenommen, es gibt ein <strong>chat-core</strong> Modul. In diesem liegt unser Anwendungskern. Ein weiteres <strong>chat-ui</strong> Modul enthält die Webanwendung. Im Kern gibt es die Klasse <strong>UiPort</strong>, welche eine Methode <strong>sendMessage(String message)</strong> implementiert. Diese Methode kann nun vom Web-Adapter, welcher in dem UI-Modul liegt, aufgerufen werden. Damit ist der Adapter von dem Anwendungskern abhängig. Bei dieser Art von Schnittstelle spricht man von einem <em>Primary Component</em> (dt. primäre Komponente).</p>



<p>Sehen wir uns das ganze mal anhand einem Java EE-Beispiel an:</p>



<div class="wp-block-kevinbatdorf-code-block-pro padding-bottom-disabled cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>/* Diese Klasse ist im chat-core Modul */ 
@ApplicationScoped 
public class UiPort { 
  public void sendMessage(String message) { 
    // Aufruf der Kernlogik zum Nachrichtenversand &#8230; 
  } 
}

/* Diese Klasse ist im chat-ui Modul */ 
@ApplicationScoped 
public class WebAdapter { 
  @Inject UiPort uiPort; // zur Laufzeit wird hier eine Instanz des UiPort eingefügt 
  
  public void enterPressed(String textField) { 
    uiPort.sendmessage(textField); 
  } 
}</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/* Diese Klasse ist im chat-core Modul */</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">@</span><span style="color: #4EC9B0">ApplicationScoped</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UiPort</span><span style="color: #D4D4D4"> { </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sendMessage</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">message</span><span style="color: #D4D4D4">) { </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Aufruf der Kernlogik zum Nachrichtenversand ... </span></span>
<span class="line"><span style="color: #D4D4D4">  } </span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/* Diese Klasse ist im chat-ui Modul */</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">@</span><span style="color: #4EC9B0">ApplicationScoped</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">WebAdapter</span><span style="color: #D4D4D4"> { </span></span>
<span class="line"><span style="color: #D4D4D4">  @</span><span style="color: #4EC9B0">Inject</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UiPort</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">uiPort</span><span style="color: #D4D4D4">; </span><span style="color: #6A9955">// zur Laufzeit wird hier eine Instanz des UiPort eingefügt </span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">enterPressed</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">textField</span><span style="color: #D4D4D4">) { </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">uiPort</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">sendmessage</span><span style="color: #D4D4D4">(textField); </span></span>
<span class="line"><span style="color: #D4D4D4">  } </span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre><span style="display:flex;align-items:flex-end;padding:10px;width:100%;justify-content:flex-end;background-color:#1E1E1E;color:#c7c7c7;font-size:12px;line-height:1;position:relative">Java</span></div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p>In die andere Richtung wird es etwas spannender. Wir führen ein weiteres Modul <strong>chat-db </strong>ein, welches unsere Chatnachrichten verwalten soll. Würden wir hier wie eben vorgehen, hätte das zur Folge, dass unsere Anwendung von der Datenbank bzw. dessen Adapter abhängig wäre. Gemäß dem <a href="https://en.wikipedia.org/wiki/SOLID">SOLID</a> Prinzip <em>Dependency-Inversion</em> darf die Anwendung aber nicht von einer Komponente abhängig sein, selbst wenn diese die Komponente steuert (<em>Inversion of Control</em>).</p>



<p>Die Lösung: die Anwendung enthält den <strong>PersistencePort</strong>, ein Interface, welches von dem Anwendungskern aufgerufen wird. Dieser enthält die Methode <strong>storeMessage(String message)</strong>. Die Implementierung dieses Interfaces legen wir nun in den Adapter. Diese wird zur Laufzeit bereitgestellt &#8211; die Abhängigkeit besteht nun hier auch vom DB-Modul auf den Anwendungskern, da dort das zu implementierende Interface liegt. Der Adapter kommuniziert direkt mit der externen Schnittstelle, z.B. Hibernate mit MariaDB. In diesem Falle würde der Adapter auch für die Umwandlung der Anwendungsobjekten in Entitäten verantwortlich sein.</p>


<div class="wp-block-image">
<figure class="aligncenter is-resized"><img decoding="async" width="501" height="242" src="https://argumentum.de/wp-content/uploads/2025/05/hexagon.drawio.png" alt="Ports and Adapters - Kommunikation der Anwendung mit einer Datenbank" class="wp-image-2245" style="width:739px;height:auto" srcset="https://argumentum.de/wp-content/uploads/2025/05/hexagon.drawio.png 501w, https://argumentum.de/wp-content/uploads/2025/05/hexagon.drawio-300x145.png 300w" sizes="(max-width: 501px) 100vw, 501px" /><figcaption class="wp-element-caption"><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-contrast-2-color">In dieser Grafik kommuniziert die Anwendung mit einer Datenbank. Die Anwendung reicht dem Adapter über den Port die zu persistierenden Daten. Dieser ist für die Umwandlung in Datenbank-Entitäten und die Persistierung zuständig.</mark></figcaption></figure>
</div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Um die Implementierung des Adapters ohne eine Abhängigkeit ausgehend vom Anwendungskern verwenden zu können, muss man auf <em><a href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency-Injection</a></em> oder eine <em><a href="https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)">Factory</a></em> zurückgreifen. Im Java EE-Kontext kann man diese Injection wie folgt umsetzen:</p>



<div class="wp-block-kevinbatdorf-code-block-pro padding-bottom-disabled cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><textarea class="code-block-pro-copy-button-textarea" aria-hidden="true" readonly>/* Diese Klasse ist im chat-db Modul */ 
@ApplicationScoped 
public class PersistenceAdapter implements PersistencePort { 
  @Override 
  public void storeMessage(String message) { 
    // Logik für die Persistierung &#8230; 
  } 
} 

/* Dieses Interface ist im chat-core Modul */ 
public interface IPersistencePort { 
  public void storeMessage(String message); 
} 

/* Diese Klasse ist im chat-core Modul */ 
@ApplicationScoped 
public class ChatController { 
  @Inject IPersistencePort persistencePort; // zur Laufzeit wird hier eine Instanz des PersistenceAdapter eingefügt 
  
  // hier kann der Port aufgerufen werden, um Nachrichten zu persistieren 
}</textarea><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/* Diese Klasse ist im chat-db Modul */</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">@</span><span style="color: #4EC9B0">ApplicationScoped</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">PersistenceAdapter</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">implements</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">PersistencePort</span><span style="color: #D4D4D4"> { </span></span>
<span class="line"><span style="color: #D4D4D4">  @</span><span style="color: #4EC9B0">Override</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">storeMessage</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">message</span><span style="color: #D4D4D4">) { </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Logik für die Persistierung ... </span></span>
<span class="line"><span style="color: #D4D4D4">  } </span></span>
<span class="line"><span style="color: #D4D4D4">} </span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/* Dieses Interface ist im chat-core Modul */</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">interface</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">IPersistencePort</span><span style="color: #D4D4D4"> { </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">storeMessage</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">String</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">message</span><span style="color: #D4D4D4">); </span></span>
<span class="line"><span style="color: #D4D4D4">} </span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/* Diese Klasse ist im chat-core Modul */</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">@</span><span style="color: #4EC9B0">ApplicationScoped</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ChatController</span><span style="color: #D4D4D4"> { </span></span>
<span class="line"><span style="color: #D4D4D4">  @</span><span style="color: #4EC9B0">Inject</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">IPersistencePort</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">persistencePort</span><span style="color: #D4D4D4">; </span><span style="color: #6A9955">// zur Laufzeit wird hier eine Instanz des PersistenceAdapter eingefügt </span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955">// hier kann der Port aufgerufen werden, um Nachrichten zu persistieren </span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre><span style="display:flex;align-items:flex-end;padding:10px;width:100%;justify-content:flex-end;background-color:#1E1E1E;color:#c7c7c7;font-size:12px;line-height:1;position:relative">Java</span></div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><strong>Wieso das Ganze?</strong></h2>



<p>Die beschriebene Trennung zwischen Anwendung und Komponenten bringt einige Vorteile mit sich:</p>



<ul class="wp-block-list">
<li>Komponenten außerhalb der Anwendung sind vollständig austauschbar. Welche Datenbank verwendet wird, und wie mit dieser kommuniziert wird, ist für die Anwendung nicht relevant.</li>



<li>Im Falle von Komponenten, die die Anwendung aufrufen (sog. <em>Driving</em> oder <em>Primary Components</em>), können an einem Port mehrere Adapter (und Komponenten) existieren – so kann der UI-Port sowohl über einen Adapter für eine Webanwendung als auch einen Adapter für eine Mobilanwendung angesprochen werden.</li>



<li>Änderungen an Adaptern beeinflussen die Anwendung nicht, und Änderungen an der Anwendung die Adapter nicht. Nur, wenn die Ports angepasst werden, sind beidseitig Änderungen notwendig.</li>



<li>Die Anwendung sowie die einzelnen Adapter sind leichter testbar – Testframeworks können einfach einen Adapter oder die Anwendung simulieren, um jeweils das Gegenstück in einer Testumgebung zu testen</li>
</ul>



<p>Das ist auch schon alles – zumindest in sehr grundlegender Ausführung. Der wahre Umsetzungsaufwand der hexagonalen Architektur entsteht durch das Mapping und dem Erstellen von guten(!) Ports.</p>



<p>Die Adapter benötigen die Daten oft in einem anderen Format, als es von der Anwendung bereitgestellt wird – Objekte müssen für die Datenbank in Entitäten umgewandelt werden, welche in Tabellen persistiert werden können. Eine REST-API arbeitet mit JSON-Objekten, welche zunächst in für die Anwendung verwendbare Objekte umgewandelt werden müssen, und in der Regel ebenfalls eine Umwandlung in die andere Richtung für Antworten der Anwendung.</p>



<p>Geben die Ports den Adaptern zu sehr die Umsetzung vor, kann es wesentlich schneller notwendig sein, diese anzupassen, sobald sich ein Adapter oder die Anwendung verändert. Die Kunst liegt darin, enge Kopplung zu vermeiden, und zukunftsfähige Ports zu entwerfen.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><strong>Die Variante der Onion-Architektur</strong></h2>



<p>Nun sind Dir die Grundlagen der Ports und Adapters bzw. Hexagonalen Architektur bekannt. Zugleich hast Du nun aber auch fast alle Bausteine der <a href="https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/">Onion-Architektur</a> gelernt – diese baut nämlich effektiv auf die hier beschriebene Architektur auf, nur dass sie außerdem noch in den Anwendungskern selbst blickt:</p>



<p>Auch hier wird nur die Regel der nach innen zeigenden Dependencies angewandt: Kern-Komponenten (die Domain – grundlegende Elemente wie ein Kunde oder Artikel) der Anwendung haben keine Abhängigkeiten auf die Domain-Services (Logik mit mehreren Objekten aus der Domain – beispielsweise Bestellungen). Diese wiederum haben keine Abhängigkeiten auf die Services der Anwendung, welche <em>Use Cases</em> umsetzen und mit unseren Ports sprechen können.</p>



<p>Die Verknüpfung von Architekturkonzepten kann weitergesponnen werden, indem weitere Konzepte zugezogen werden. Hierzu eine Leseempfehlung: <a href="https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/">DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together</a> von Herberto Graça – praktisch ein All-Inclusive Modell.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><strong>Schlusswort</strong></h2>



<p>Ports und Adapters und ihre Verwandten präsentieren einen seriösen Ansatz, wie eine Anwendung sauber aufgebaut werden kann. Das Ganze ist jedoch mit Vorsicht zu genießen: mit der Architektur entsteht signifikanter Umsetzungsaufwand, und kommt nur in mittelgroßen bis großen Anwendungen infrage – wobei letztere möglicherweise mehr von einer dem Anwendungsfall angepassten Variante profitieren. Und wenn die Anwendung mit diesem Konzept umgesetzt werden soll, dann bitte richtig. Nehmt Euch die Zeit, sinnvolle Schnittstellen zu entwerfen, denn das ist eine ganz eigene <a href="https://anchor.fm/dominikusherzberg/episodes/Das-Gesprch-Holger-van-den-Boom----Design-als-Mittel-der-Erschlieung-von-Welt-e111nuj">Philosophie</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Nightwatch.js: Ein Test-Framework für alle Anforderungen</title>
		<link>https://argumentum.de/2023/12/nightwatch-js/</link>
		
		<dc:creator><![CDATA[Vanessa Nagy]]></dc:creator>
		<pubDate>Fri, 01 Dec 2023 12:32:12 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[Nightwatch.js]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://argumentum.de/?p=1886</guid>

					<description><![CDATA[In der Webentwicklung ist es von entscheidender Bedeutung, Anwendungen robust und zuverlässig zu gestalten. Nightwatch.js stellt sich dabei als ein Framework heraus, das eine Vielzahl von Anforderungen erfüllt, um Webanwendungen zu testen. Erhalten Sie einen Einblick in die umfangreichen Fähigkeiten dieses Frameworks!]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-boldblocks-group cbb-block is-layout-flow wp-block-boldblocks-group-is-layout-flow cbb-g-3 sm-cbb-padding-top sm-cbb-padding-right sm-cbb-padding-bottom sm-cbb-padding-left" style="padding-top:0;padding-right:0;padding-bottom:0;padding-left:0">
<p>Um die Qualität von Software zu gewährleisten, ist <strong>ausgiebiges Testen</strong> unabdingbar. Idealerweise sollte dazu das Testen bereits von Anfang an in den Entwicklungsprozess integriert werden, um bereits früh Fehler zu identifizieren. Zum Testen von Software gibt es <strong>eine Reihe an Möglichkeiten</strong>, angefangen bei Unit-Tests zum Testen kleinster Einheiten, über Component und Integration Tests bis hin zum Testen einer Anwendung als Einheit durch End-To-End-Tests (E2E). In der Testlandschaft hat sich dabei ein Framework positioniert, das durch seine Vielseitigkeit überzeugt: <strong><a href="https://nightwatchjs.org/">Nightwatch.js</a></strong>.</p>



<h2 class="wp-block-heading" style="font-size:30px">Was ist Nightwatch.js?</h2>



<p><strong>Nightwatch.js</strong> ist ein Open-Source Projekt, das seit 2014 existiert. Es handelt sich dabei um ein Framework für <strong>automatisiertes E2E-Testing</strong>, das auf Node.js basiert. Allerdings bietet dieses ebenfalls die Möglichkeit, Unit-, Component- oder Integrationstests zu schreiben.</p>



<p>Mit Nightwatch lassen sich Webanwendungen, Webseiten sowie mobile Applikationen unter Android und iOS testen. Für letztere bedient sich Nightwatch dem Framework <a href="http://appium.io">Appium</a>, welches ebenfalls der Automatisierung von Tests dient.</p>



<p>Tests lassen sich <strong>in allen gängigen Browsern</strong> (Chrome, Firefox, Safari und Edge) durchführen. Dazu folgt Nightwatch der WebDriver-Spezifikation des World Wide Web Consortium (W3C), welche einen Standard für das Automatisieren von Browsern darstellt und auf HTTP basiert. Mittels WebDrivern erfolgt die Kommunikation zur Interaktion mit dem Browser, um Tests durchzuführen.</p>



<h2 class="wp-block-heading" style="font-size:30px">Was bietet Nightwatch alles?</h2>



<p><strong>Test-Runner:</strong> Mit dem <a href="https://www.notion.so/Nightwatch-js-Testing-Framework-8102b3ded1624ffb920396460725265b?pvs=21">Test-Runner für die Kommandozeile</a> bietet Nightwatch eine einfache Möglichkeit, um Tests auszuführen. Gleichzeitig ermöglicht dies die reibungslose Integration in <strong>automatisierte Build- und Deploy-Prozesse</strong>.</p>



<p><strong>Parallelisierung: </strong>Bei einer Vielzahl an Tests kann es dauern, bis diese sequentiell ausgeführt werden. Dies ist besonders mühsam, wenn eine Anwendung oder Webseite in verschiedenen Browsern getestet wird. Um dieses Problem zu umgehen, bietet Nightwatch <strong>Parallelisierung</strong> mittels der Integration von <a href="https://www.selenium.dev/documentation/grid/">Selenium Grid</a> an.</p>



<p><strong>Cloud-Umgebungen:</strong> Ein weiterer Punkt ist die Ausführungsumgebung. Nightwatch ermöglicht die Verwendung von Cloud-basierten Testplattformen wie <a href="https://www.browserstack.com/">BrowserStack</a> oder <a href="https://saucelabs.com/">SauceLabs</a>. Dadurch kann die zu testende Anwendung oder Webseite in Browserinstanzen in der Cloud getestet werden, sodass <strong>lokal keine Testumgebungen</strong> erforderlich sind.</p>



<p><strong>Weitere Testarten:</strong> Wie bereits erwähnt ermöglicht Nightwatch von E2E bis Unit alle Arten von Testmöglichkeiten. Darüber hinaus  bietet das Framework ebenfalls Funktionalität für die folgenden spezifischen Testmöglichkeiten:</p>



<div class="wp-block-boldblocks-group cbb-block is-layout-flow wp-block-boldblocks-group-is-layout-flow cbb-g-1 sm-cbb-padding-right sm-cbb-padding-left">
<p><strong>1. Accessibility-Tests<br></strong>Nightwatch integriert mit der Accessibility Test Engine <a href="https://www.npmjs.com/package/axe-core">Axe</a> vordefinierte Tests, mit denen sich Webseiten und HTML-basierte Benutzeroberflächen auf Barrierefreiheit testen lassen. Die Tests prüfen die in den <strong>Web Content Accessibility Guidelines (WCAG) </strong>definierten Richtlinien in verschiedenen Stufen sowie gängige Best-Practices zum Sicherstellen von Barrierefreiheit im Web.</p>



<p><strong>2. Visuelle Tests<br></strong>Visuelle Tests, häufig unter Visual Regression Testing bekannt, dienen dem Testen des Verhaltens einer Anwendung mittels Screenshots. Dazu wird vor und nach Ausführen einer Aktion ein Screenshot gemacht, sodass die <strong>Auswirkungen der Aktion</strong> auf Korrektheit überprüft werden können. Nightwatch integriert diese Art des Testens, indem es sich <a href="https://www.npmjs.com/package/jimp">JIMP</a> bedient, einer JavaScript-Bibliothek zur Bildverarbeitung.</p>



<p><strong>3. API-Tests<br></strong>Die <strong>Kommunikation zwischen Client und Server</strong> spielt eine wichtige Rolle bei interaktiven Anwendungen und Webseiten. Um sicherzustellen, dass die API sich wie gewollt verhält, sind API-Tests unverzichtlich. Nightwatch bietet dazu das Plugin <a href="https://github.com/nightwatchjs/nightwatch-plugin-apitesting">apitesting</a>. Damit lassen sich Requests senden und festlegen, welche Daten in der Server-Response erwartet werden (beispielsweise Statuscode, Content-Type oder der Content im Body). Zusätzlich bietet Nightwatch die Möglichkeit, Mock-Server zu programmieren.</p>
</div>



<h2 class="wp-block-heading" style="font-size:30px">Wie ist Nightwatch zu verwenden?</h2>



<p>Bei der Verwendung von Nightwatch.js spielt die präzise Auswahl von Elementen eine entscheidende Rolle, um diese Testen zu können. <strong>Selektoren</strong> ermöglichen es, spezifische HTML-Elemente auf Webseites und in Anwendungen zu identifizieren und mit diesen zu interagieren. Nightwatch.js unterstützt verschiedene Arten von Selektoren, darunter:</p>



<ul class="wp-block-list">
<li><strong>HTML/CSS-Selektoren</strong> ermöglichen das Selektieren über Klassen, IDs, HTML-Tags sowie Verschachtelungen beziehungsweise Vater-Kind-Beziehungen</li>



<li><strong>XPath-Selektoren</strong> ermöglichen das Selektieren von Nodes aus XML-Dokumenten</li>



<li><strong>textbasierte Selektoren</strong> ermöglichen die Suche nach Texten für verschiedene UI-Elemente wie beispielsweise Labels, Bilder oder Formularfelder</li>
</ul>



<p>Selektierte Elemente können auf verschiedenste Arten <strong>manipuliert</strong> werden, wie beispielsweise das Klicken von Buttons oder das Eintragen von Texten in Formularfeldern. Damit sind mit Nightwatch <strong>unzählige Tests denkbar</strong>.<br>Falls die von Nightwatch vorgegebenen Kommandos nicht ausreichen sollten, bietet das Framework zusätzlich die Möglichkeit, <a href="https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-commands.html">eigene Kommandos</a> zu definieren.</p>



<p>Um sicherzustellen, dass die Funktionalitäten der Anwendung wie beabsichtigt funktionieren, kann mittels <strong>Assertions</strong> festgelegt werden, welche Ergebnisse/Zustände zu erwarten sind. Dazu integriert Nightwatch das Assertion Framework <a href="https://www.chaijs.com/">chai.js</a>, womit die Keywords <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color">expect</mark></code>, <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"><code>should</code></mark> und <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"><code>assert</code></mark> zur Verfügung stehen. Gleichzeitig bietet chai.js einen sogenannten BDD-Codestil¹, welcher durch seine Verkettung von Füllwörtern nah an <strong>menschenlesbare Sprache</strong> herankommt und somit die <strong>Lesbarkeit und Verständlichkeit</strong> verbessert: <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color">browser.expect.element('#main').to.be.present;</mark></code></p>



<p class="has-small-font-size">¹ BDD steht für Behavior Driven Development und stellt einen Ansatz in der agilen Softwareentwicklung dar, der u.a. das Verwenden von menschenlesbaren Beschreibungen von Softwareanforderungen beinhält. Für mehr Informationen siehe <a href="https://www.chaijs.com/api/bdd/">https://www.chaijs.com/api/bdd/</a></p>



<h2 class="wp-block-heading" style="font-size:30px">Der Nightwatch-Inspektor</h2>



<p>Ein einzigartiges Feature von Nightwatch stellt der <a href="https://nightwatchjs.org/guide/writing-tests/nightwatch-inspector.html">Nightwatch-Inspektor</a> dar. Mit diesem lassen sich die einzelnen Elemente von Webseiten untersuchen, ähnlich wie mit <strong>Entwicklertools von Browsern</strong>. Im sogenannten <strong>Explore Mode</strong> kann ein spezifisches Element angeklickt werden. Zu dem ausgewählten Element wird daraufhin im Inspektor ein Selektor angezeigt, der das Element identifiziert. Dies erleichtert es dem Entwickler, das gewünschte, zu testende Element zu benennen. Zudem besitzt der Inspektor ein <strong>Konsolenfeld mit Autocompletion</strong>, in dem sich Kommandos ausführen lassen. Mit dem zuvor ermittelten Selektor eines Elements lassen sich so entweder Informationen zu dem gewünschten Element abrufen oder das Element direkt manipulieren. Das Ergebnis der Manipulation wird dem Nutzer angezeigt. Der Inspektor von Nightwatch stellt somit eine <strong>Einstiegshilfe dar und bietet Zeitersparnis</strong>, was besonders für Anfänger attraktiv sein dürfte.</p>



<h2 class="wp-block-heading" style="font-size:30px">Setup von Nightwatch</h2>



<p>Die Voraussetzung, um Nightwatch zu verwenden, ist eine aktuelle Version von <a href="https://nodejs.org/">Node</a>. Wenn dies gegeben ist, sehen die Schritte zum Aufsetzen eines Nightwatch-Projekts wie folgt aus:</p>



<div class="wp-block-boldblocks-group cbb-block is-layout-flow wp-block-boldblocks-group-is-layout-flow cbb-g-2 sm-cbb-padding-right sm-cbb-padding-left lg-cbb-padding-top lg-cbb-padding-bottom" style="padding-top:var(--wp--preset--spacing--20);padding-right:0;padding-bottom:var(--wp--preset--spacing--20);padding-left:0">
<p><strong>1. Installieren des Nightwatch-Pakets via npm</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm init nightwatch &lt;dir&gt;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">npm init nightwatch &lt;dir&gt;</span></span></code></pre></div>



<div style="height:1em" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>2. Beantworten verschiedener Fragen, um Nightwatch zu konfigurieren (hier ein einfaches Beispiel)</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#d4d4d433" stroke="#d4d4d44d" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="? Select testing type to setup for your project: End-to-End testing
? Select language + test runner variant: TypeScript / default
? Select target browsers: Chrome, Firefox, Edge
? Enter source folder where test files are stored: testfiles
? Enter the base_url of the project: http://localhost
? Select where to run Nightwatch tests: On localhost" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">? Select testing type to setup for your project: End-to-End testing</span></span>
<span class="line"><span style="color: #D4D4D4">? Select language + test runner variant: TypeScript / default</span></span>
<span class="line"><span style="color: #D4D4D4">? Select target browsers: Chrome, Firefox, Edge</span></span>
<span class="line"><span style="color: #D4D4D4">? Enter source folder where test files are stored: testfiles</span></span>
<span class="line"><span style="color: #D4D4D4">? Enter the base_url of the project: http://localhost</span></span>
<span class="line"><span style="color: #D4D4D4">? Select where to run Nightwatch tests: On localhost</span></span></code></pre></div>
</div>



<p>Daraufhin werden lediglich alle benötigten packages installiert sowie Dateien angelegt, bevor das Setup abgeschlossen ist. Darunter befinden sich auch <strong>Beispieltests</strong>, welche direkt im Anschluss ausgeführt werden können. Die Testergebnisse werden grafisch aufbereitet in der Konsole dargestellt.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img decoding="async" width="1024" height="706" src="https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231122_103337-1024x706.png" alt="Ein Beispiel, wie Testergebnisse in der Konsole ausgegeben werden." class="wp-image-1899" style="width:1123px;height:auto" srcset="https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231122_103337-1024x706.png 1024w, https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231122_103337-300x207.png 300w, https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231122_103337-768x530.png 768w, https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231122_103337.png 1250w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Ein Beispiel für die Konsolenausgaben der ausgeführten Beispieltests für <a href="http://duckduckgo.com">duckduckgo.com</a> und <a href="http://google.com">google.com</a>.</figcaption></figure>
</div>


<h2 class="wp-block-heading" style="font-size:30px">Selenium</h2>



<p>Selenium stellt zunächst ein Framework zur Automatisierung von Browsern dar. Den häufigsten Anwendungsfall stellt dabei die Automatisierung für Testzwecke dar. Selenium entstand 2004 und ist wie Nightwatch ebenfalls Open Source.</p>



<p>Initial geschrieben für JavaScript, unterstützt Selenium heute viele Sprachen, darunter Java und Python. Der Entwickler hat mit Selenium also die Freiheit, sich eine Sprache auszusuchen, mit der er gut zurecht kommt.</p>



<p>Was einst als TestRunner für JavaScript begann, hat sich zu einem umfassenden Ökosystem entwickelt. Mit der Weiterentwicklung entstanden neben der Test-API (<strong>Selenium Core</strong>) weitere Projekte wie das Browser Add-on <strong>Selenium IDE</strong> zum Aufnehmen von Tests, <strong>Selenium Server/Grid </strong>für verteilte, parallelisierte Tests oder auch der <strong>Selenium WebDriver</strong>, der für alle gängigen Browser funktioniert. Das macht Selenium zu einem starken Tool, welches sich in der Praxis bewiesen hat. <em>Doch wie kommt Nightwatch hier ins Spiel?</em></p>



<p>Wichtig zu verstehen ist, dass Selenium kein Testframework ist, es ermöglicht lediglich die Automatisierung von Browsern. Aus diesem Grund listet Selenium auf seiner offiziellen Webseite <a href="https://www.selenium.dev/ecosystem/">eine Reihe an Testframeworks</a> auf, die mit Selenium verwendet werden können, dazu gehört auch Nightwatch.js.</p>



<h2 class="wp-block-heading" style="font-size:30px">Fazit</h2>



<p>Nightwatch zeichnet sich durch seine Benutzerfreundlichkeit und Vielseitigkeit aus. Es ermöglicht das Durchführen einer breiten Palette von Tests, angefangen bei End-to-End-Tests bis hin zu Unit-Tests, und das in unterschiedlichen Umgebungen, sei es mobil oder im Web. Zusätzlich ermöglicht Nightwatch verschiedene Testmöglichkeiten, darunter Accessibility-Tests, visuelle sowie API-Tests.<br>Außerdem besonders hervorzuheben ist der Nightwatch-Inspektor, der das Identifizieren und Manipulieren von Testelementen im Web erheblich erleichtert.<br>Darüber hinaus punktet Nightwatch durch die Integration von Selenium Grid für Parallelisierung sowie die Möglichkeit, das Framework mit Cloud-basierten Testplattformen wie BrowserStack und SauceLabs zu verwenden.</p>



<p>Insgesamt präsentiert sich Nightwatch als ein robustes Test-Framework, das umfassende Testmöglichkeiten bietet und sowohl für erfahrene Entwickler als auch für Anfänger attraktiv ist. Nightwatch bietet seine eigene Implementierung des WebDrivers, kann aber durchaus mit Selenium verwendet werden, um Anwendungen und Webseiten automatisiert zu testen.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Inklusives Webdesign leicht gemacht? Die KoliBri Bibliothek</title>
		<link>https://argumentum.de/2023/11/die-kolibri-bibliothek/</link>
		
		<dc:creator><![CDATA[Vanessa Nagy]]></dc:creator>
		<pubDate>Fri, 17 Nov 2023 16:17:07 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Accessibility]]></category>
		<category><![CDATA[Barrierefreiheit]]></category>
		<category><![CDATA[Bibliothek]]></category>
		<category><![CDATA[KoliBri]]></category>
		<category><![CDATA[Komponenten]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://argumentum.de/?p=1791</guid>

					<description><![CDATA[Vor dem Hintergrund der rechtlichen Verpflichtungen öffentlicher Stellen in der EU, ihre digitalen Angebote barrierefrei zu gestalten,  wurde vom Informationstechnikzentrum Bund (ITZBund) die KoliBri-Bibliothek entwickelt. Aber wie genau unterstützt diese Bibliothek den barrierefreien Zugang zu Informationen? Erfahren Sie mehr über die Funktionen der Bibliothek sowie die zugrundeliegende Implementierung, die dies ermöglicht.]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-boldblocks-group cbb-block is-layout-flow wp-block-boldblocks-group-is-layout-flow cbb-g-7 sm-cbb-padding-top sm-cbb-padding-right sm-cbb-padding-bottom sm-cbb-padding-left" style="padding-top:0;padding-right:0;padding-bottom:0;padding-left:0">
<p>Mit der zunehmenden Digitalisierung werden Webseiten und Anwendungen zu den zentralen Vermittlern von Informationen. Dabei bieten die Sprachen HTML und CSS, die als Grundbaustein für den Aufbau von Webseiten dienen, großen Spielraum für Gestaltung. Diese Freiheit ermöglicht es allerdings, <strong>unsemantische Layouts</strong> zu erzeugen, die vor allem eine Herausforderung für Menschen darstellen, die auf assistive Technologien, sei es in Form von Soft- oder Hardware, angewiesen sind. Sofern beim Gestalten von Webinhalten diese Problematik nicht berücksichtigt wird, wird mit hoher Wahrscheinlichkeit die Navigation und Interpretation dieser erschwert und schlussendlich <strong>Nutzern der Zugang zu Informationen behindert</strong>.<br>So sind öffentliche Stellen in der EU heute rechtlich verpflichtet, ihre Webseiten und digitalen Anwendungen barrierefrei zu gestalten. In Deutschland dienen das Gesetz zur Gleichstellung von Menschen mit Behinderungen (BGG) sowie die Verordnung zur Schaffung barrierefreier Informationstechnik nach dem Behindertengleichstellungsgesetz (BITV) als rechtliche Grundlagen.</p>



<p>Barrierefreiheit in der Informationstechnik ist allerdings <strong>kein rein inklusives Anliegen</strong>. Das Berücksichtigen von Aspekten wie semantischer Korrektheit oder auch hinreichender Farbkontraste gewährleistet den Zugang zu Informationen unabhängig von den individuellen Möglichkeiten der einzelnen Person.</p>



<p>In dieser Hinsicht stellt <strong><a href="https://public-ui.github.io/">die Bibliothek KoliBri</a></strong>, die vom Informationstechnikzentrum Bund (ITZBund) entwickelt wurde, einen Lösungsansatz für das beschriebene Problem dar. <em>Doch <strong>wie genau trägt KoliBri zur Problemlösung bei</strong>? Wie l</em>ässt sich <em>die Bibliothek implementier</em>en<em>?</em> <em>Wie barrierefrei sind die Komponenten der Bibliothek?</em></p>



<h2 class="wp-block-heading" style="font-size:30px"><br>Was ist KoliBri?</h2>



<p>Das Akronym <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color">KoliBri</mark> steht für &#8222;Komponentenbibliothek für die Barrierefreiheit”. Die Bibliothek wurde unter Verwendung von TypeScript entwickelt und <strong>basiert auf</strong> den Leitlinien des World Wide Web Consortium (W3C), den <strong>Web Content Accessibility Guidelines (WCAG)</strong>. Diese Richtlinien sind unabhängig von konkreten Implementierungen und Frameworks und bilden die Grundlage für die Umsetzung von Barrierefreiheit im Web. Zudem hat die Bibliothek den <strong>BITV-Test </strong>in einer an die Besonderheiten von Web-Komponenten angepassten Form implementiert, um die Barrierefreiheit dieser zu gewährleisten.</p>



<p>KoliBri verfolgt das Ziel, <strong>Web-Komponenten bereitzustellen</strong>, die ohne große Anpassungen von Grund auf barrierefrei sind.</p>



<p>Die <strong>Kompatibilität</strong> der Bibliothek ist dabei eines der primären Ziele. So ist sie kompatibel mit gängigen Geräten, Betriebssystemen und Browsern und kann in verschiedenen Umgebungen und Architekturen eingesetzt werden. Ob es sich um statische oder dynamische Webseiten mit oder ohne Frameworks handelt, spielt keine Rolle. Ebenfalls kann KoliBri unabhängig davon eingesetzt werden, ob das Rendern der Webseite vorab (Pre-Rendering), server- (SSR) oder clientseitig (CSR) erfolgt.</p>



<h2 class="wp-block-heading" style="font-size:30px"><br>Wie funktioniert KoliBri?</h2>



<p>KoliBri bietet eine Auswahl an Web-Komponenten, die <strong>atomare und wiederverwendbare HTML-Kompositionen</strong> darstellen und einfach in Webseiten und Anwendungen integriert werden können. Es handelt sich dabei um gängige UI-Elemente wie Buttons, Eingabefelder oder Dropdown-Menüs. Komponenten haben jeweils einen Namen, Attribute und eine Beschreibung. Sie folgen also einem klaren Muster, um <strong>Einheitlichkeit</strong> sowie <strong>Verständlichkeit</strong> zu garantieren. Jede Komponente ist nach der PascalCase-Konvention <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color">KolNameDerKomponente</mark></code> (oder alternativ nach KebabCase<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"> <code>kol-name-der-komponente</code></mark>) benannt und wird wie ein gewöhnlicher HTML-Tag im Code verwendet. Mittels der Attribute lassen sich Komponenten individuell anpassen. Attribute besitzen stets die Form <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color">_attributName</mark></code> und können Werte zugewiesen bekommen (<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color">_attributName=”Wert”</mark></code>), um <strong>Inhalt</strong>, <strong>Form</strong> sowie (besonders relevant für interaktive Elemente) das <strong>Verhalten</strong> einer Komponente zu steuern.</p>



<p>Darüber hinaus sind diese Komponenten um gewöhnliche HTML-Tags wie <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color">&lt;div&gt;</mark></code> ergänzbar, welche durch zusätzliche Attribute wie <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color">slot=footer</mark></code> ihre Semantik erhalten. Ebenfalls lassen sich die bekannten ARIA-Attribute mit den gleichnamigen, durch einen Unterstrich versehenen KoliBri-Attribute (beispielsweise <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"><code>_ariaExpanded</code></mark> aus KoliBri für <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"><code>aria-expanded</code></mark> aus ARIA) weiterhin verwenden, sofern diese in der Bibliothek implementiert wurden.</p>



<p><strong>Das folgende Code-Snippet</strong> demonstriert die Funktionsweise von Komponenten am Beispiel der Komponente <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"><code>KolAlert</code></mark>, deren Zweck die Darstellung von Hinweisen ist.</p>



<div class="wp-block-boldblocks-group cbb-block is-layout-flow wp-block-boldblocks-group-is-layout-flow cbb-g-4 sm-cbb-padding-right sm-cbb-padding-left" style="padding-top:var(--wp--preset--spacing--20);padding-right:0;padding-bottom:var(--wp--preset--spacing--20);padding-left:0">
<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers cbp-highlight-hover" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(131, 148, 240, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1b1e28"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import React from 'react';
import { KolAlert } from &quot;@public-ui/react&quot;;

export default function App() {
    return (
        &lt;KolAlert _label=&quot;Hinweis&quot; _type=&quot;info&quot; _variant=&quot;card&quot;&gt;
            &lt;p className=&quot;m-0&quot;&gt;
                Am Freitag, den 15.12.2024 steht die Anwendung von 06:00 bis 12:00 Uhr nicht zur Verfügung.
            &lt;/p&gt;
        &lt;/KolAlert&gt;
    );
};" style="color:#a6accd;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki poimandres" style="background-color: #1b1e28" tabindex="0"><code><span class="line"><span style="color: #5DE4C7">import </span><span style="color: #ADD7FF">React</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">react</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"><span style="color: #5DE4C7">import </span><span style="color: #A6ACCD">{</span><span style="color: #5DE4C7"> </span><span style="color: #ADD7FF">KolAlert</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">}</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&quot;</span><span style="color: #5DE4C7">@public-ui/react</span><span style="color: #A6ACCD">&quot;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #5DE4C7">export default </span><span style="color: #91B4D5">function</span><span style="color: #5DE4C7"> </span><span style="color: #ADD7FF">App</span><span style="color: #A6ACCD">()</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">{</span></span>
<span class="line"><span style="color: #5DE4C7">    </span><span style="color: #5DE4C7C0">return</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">(</span></span>
<span class="line"><span style="color: #5DE4C7">        </span><span style="color: #E4F0FB">&lt;</span><span style="color: #5DE4C7">KolAlert</span><span style="color: #E4F0FB"> </span><span style="color: #91B4D5; font-style: italic">_label</span><span style="color: #91B4D5">=</span><span style="color: #A6ACCD">&quot;</span><span style="color: #5DE4C7">Hinweis</span><span style="color: #A6ACCD">&quot;</span><span style="color: #E4F0FB"> </span><span style="color: #91B4D5; font-style: italic">_type</span><span style="color: #91B4D5">=</span><span style="color: #A6ACCD">&quot;</span><span style="color: #5DE4C7">info</span><span style="color: #A6ACCD">&quot;</span><span style="color: #E4F0FB"> </span><span style="color: #91B4D5; font-style: italic">_variant</span><span style="color: #91B4D5">=</span><span style="color: #A6ACCD">&quot;</span><span style="color: #5DE4C7">card</span><span style="color: #A6ACCD">&quot;</span><span style="color: #E4F0FB">&gt;</span></span>
<span class="line"><span style="color: #E4F0FB">            &lt;</span><span style="color: #5DE4C7">p</span><span style="color: #E4F0FB"> </span><span style="color: #91B4D5; font-style: italic">className</span><span style="color: #91B4D5">=</span><span style="color: #A6ACCD">&quot;</span><span style="color: #5DE4C7">m-0</span><span style="color: #A6ACCD">&quot;</span><span style="color: #E4F0FB">&gt;</span></span>
<span class="line"><span style="color: #E4F0FB">                Am Freitag, den 15.12.2024 steht die Anwendung von 06:00 bis 12:00 Uhr nicht zur Verfügung.</span></span>
<span class="line"><span style="color: #E4F0FB">            &lt;/</span><span style="color: #5DE4C7">p</span><span style="color: #E4F0FB">&gt;</span></span>
<span class="line"><span style="color: #E4F0FB">        &lt;/</span><span style="color: #5DE4C7">KolAlert</span><span style="color: #E4F0FB">&gt;</span></span>
<span class="line"><span style="color: #5DE4C7">    </span><span style="color: #A6ACCD">);</span></span>
<span class="line"><span style="color: #A6ACCD">};</span></span></code></pre></div>



<p class="has-small-font-size"></p>
</div>



<h2 class="wp-block-heading" style="font-size:30px"><br>Wie können Komponenten visuell gestaltet werden?</h2>



<p>Das obige Beispiel zur Komponente <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"><code>KolAlert</code></mark> demonstriert, wie eine Komponente durch ihre Attribute <strong>manipuliert</strong> werden kann. Dazu stellt sich die Frage, inwiefern Komponenten visuell gestaltet werden können. Nur selten besitzen Komponenten Attribute, die eine visuelle Gestaltung dieser ermöglichen. <em>Aber die visuelle Gestaltung von Webseiten spielt doch eine wesentliche Rolle bei der Benutzererfahrung?</em> <br>Um die Probleme zu umgehen, die durch die mit CSS gegebenen Freiheiten entstehen können, bietet KoliBri den sogenannten <a href="https://public-ui.github.io/designer/">KoliBri-Designer</a> an. Dieses Tool ermöglicht es, <strong>beliebige Styleguides und Designs umzusetzen</strong>, ohne dabei Layouts zu erzeugen, die sich nicht mit der durch HTML vorgegebenen Semantik decken. So wird ermöglicht, dass mithilfe von assistiven Technologien die Nutzererfahrung sich nicht erheblich von der Erfahrung ohne solche unterscheidet.</p>



<div class="wp-block-boldblocks-group cbb-block is-layout-flow wp-block-boldblocks-group-is-layout-flow cbb-g-5 sm-cbb-padding-right sm-cbb-padding-left" style="padding-top:var(--wp--preset--spacing--20);padding-right:0;padding-bottom:var(--wp--preset--spacing--20);padding-left:0">
<figure class="wp-block-image size-large is-resized is-style-default"><img loading="lazy" decoding="async" width="1024" height="574" src="https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231106_155921-1024x574.png" alt="Ein Bild des KoliBri-Designers" class="wp-image-1792" style="aspect-ratio:1.78397212543554;width:1112px;height:auto" srcset="https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231106_155921-1024x574.png 1024w, https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231106_155921-1536x861.png 1536w, https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231106_155921-2048x1147.png 2048w, https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231106_155921-300x168.png 300w, https://argumentum.de/wp-content/uploads/2023/11/Screenshot_20231106_155921-768x430.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Der <a href="https://public-ui.github.io/designer/">KoliBri-Designer</a> im Einsatz.</figcaption></figure>
</div>



<p><br>Zudem sind in KoliBri bereits Mechanismen integriert, die <strong>unzureichende Farbkontraste </strong>vermeiden. So kann beispielsweise der Komponente <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"><code>Badge</code></mark> eine Hintergrundfarbe, allerdings keine Textfarbe zugewiesen werden. Die Textfarbe wird basierend auf der spezifizierten Hintergrundfarbe <strong>automatisch berechnet und gesetzt</strong>, um einen hinreichenden Farbkontrast zu gewährleisten. Dieses Merkmal, dass Komponenten nur begrenzt manipulierbar sind, um deren Barrierefreiheit zu gewährleisten, stellt ein <strong>Kernprinzip</strong> der Bibliothek dar. </p>



<p>KoliBri löst also die Probleme hinsichtlich der Barrierefreiheit, <strong>ohne Kompromisse</strong> bei der Gestaltungsfreiheit zu machen.</p>



<h2 class="wp-block-heading" style="font-size:30px"><br>Wie kann man mit KoliBri entwickeln?</h2>



<p>Besonders gut eignet sich KoliBri für JSX/TSX-basierte Frameworks wie <strong>React </strong>oder <strong>Solid</strong>, da hier die maximalen Möglichkeiten der Typ-Unterstützung und Autovervollständigung möglich sind. Für Frameworks mit eigenen Template-Sprachen wie Angular und Vue variiert die Unterstützung bei der Entwicklung.</p>



<p>Je nach Anwendungsgebiet und vorliegender Architektur sehen die Schritte zur Integration ein wenig anders aus. Für das Web-Framework React sind<strong> die folgenden Schritte</strong> notwendig:</p>



<div class="wp-block-boldblocks-group cbb-block is-layout-flow wp-block-boldblocks-group-is-layout-flow cbb-g-6 sm-cbb-padding-right sm-cbb-padding-left" style="padding-top:var(--wp--preset--spacing--20);padding-right:0;padding-bottom:var(--wp--preset--spacing--20);padding-left:0">
<p><strong>1. Installieren der KoliBri-Bibliotheken mittels Paketmanager der Wahl (hier beispielhaft mit npm)</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1b1e28"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm i @public-ui/components @public-ui/themes @public-ui/react" style="color:#a6accd;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki poimandres" style="background-color: #1b1e28" tabindex="0"><code><span class="line"><span style="color: #91B4D5">npm</span><span style="color: #A6ACCD"> </span><span style="color: #ADD7FF">i</span><span style="color: #A6ACCD"> </span><span style="color: #ADD7FF">@public-ui/components</span><span style="color: #A6ACCD"> </span><span style="color: #ADD7FF">@public-ui/themes</span><span style="color: #A6ACCD"> </span><span style="color: #ADD7FF">@public-ui/react</span></span></code></pre></div>



<p class="has-small-font-size"></p>



<p><br><strong>2. Integration der Bibliothek</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1b1e28"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import React from 'react';
import ReactDOM from 'react-dom';

import { AppComponent } from './components/app/component';

import { register } from '@public-ui/core';
import { defineCustomElements } from '@public-ui/components/dist/loader';
import { DEFAULT } from '@public-ui/themes';

register(DEFAULT, defineCustomElements)
    .then(() =&gt; {
        const htmlDivElement: HTMLDivElement | null = document.querySelector&lt;HTMLDivElement&gt;('div#app');
        if (htmlDivElement instanceof HTMLDivElement) {
            const root = createRoot(htmlDivElement);
            root.render(&lt;AppComponent /&gt;);
        }
    })
    .catch(console.warn);" style="color:#a6accd;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki poimandres" style="background-color: #1b1e28" tabindex="0"><code><span class="line"><span style="color: #5DE4C7">import </span><span style="color: #ADD7FF">React</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">react</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"><span style="color: #5DE4C7">import </span><span style="color: #ADD7FF">ReactDOM</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">react-dom</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #5DE4C7">import </span><span style="color: #A6ACCD">{</span><span style="color: #5DE4C7"> </span><span style="color: #ADD7FF">AppComponent</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">}</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">./components/app/component</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #5DE4C7">import </span><span style="color: #A6ACCD">{</span><span style="color: #5DE4C7"> </span><span style="color: #ADD7FF">register</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">}</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">@public-ui/core</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"><span style="color: #5DE4C7">import </span><span style="color: #A6ACCD">{</span><span style="color: #5DE4C7"> </span><span style="color: #ADD7FF">defineCustomElements</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">}</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">@public-ui/components/dist/loader</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"><span style="color: #5DE4C7">import </span><span style="color: #A6ACCD">{</span><span style="color: #5DE4C7"> </span><span style="color: #ADD7FF">DEFAULT</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">}</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">@public-ui/themes</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #E4F0FBD0">register</span><span style="color: #A6ACCD">(</span><span style="color: #E4F0FB">DEFAULT</span><span style="color: #A6ACCD">, </span><span style="color: #E4F0FB">defineCustomElements</span><span style="color: #A6ACCD">)</span></span>
<span class="line"><span style="color: #A6ACCD">    .</span><span style="color: #E4F0FBD0">then</span><span style="color: #A6ACCD">(() </span><span style="color: #91B4D5">=&gt;</span><span style="color: #A6ACCD"> {</span></span>
<span class="line"><span style="color: #A6ACCD">        </span><span style="color: #91B4D5">const</span><span style="color: #A6ACCD"> </span><span style="color: #E4F0FB">htmlDivElement</span><span style="color: #91B4D5">:</span><span style="color: #A6ACCD"> </span><span style="color: #A6ACCDC0">HTMLDivElement</span><span style="color: #A6ACCD"> </span><span style="color: #91B4D5">|</span><span style="color: #A6ACCD"> </span><span style="color: #A6ACCDC0">null</span><span style="color: #A6ACCD"> </span><span style="color: #91B4D5">=</span><span style="color: #A6ACCD"> </span><span style="color: #E4F0FB">document</span><span style="color: #A6ACCD">.</span><span style="color: #E4F0FBD0">querySelector</span><span style="color: #A6ACCD">&lt;</span><span style="color: #A6ACCDC0">HTMLDivElement</span><span style="color: #A6ACCD">&gt;(</span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">div#app</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">);</span></span>
<span class="line"><span style="color: #A6ACCD">        if (</span><span style="color: #E4F0FB">htmlDivElement</span><span style="color: #A6ACCD"> </span><span style="color: #91B4D5">instanceof</span><span style="color: #A6ACCD"> </span><span style="color: #A6ACCDC0">HTMLDivElement</span><span style="color: #A6ACCD">) {</span></span>
<span class="line"><span style="color: #A6ACCD">            </span><span style="color: #91B4D5">const</span><span style="color: #A6ACCD"> </span><span style="color: #E4F0FB">root</span><span style="color: #A6ACCD"> </span><span style="color: #91B4D5">=</span><span style="color: #A6ACCD"> </span><span style="color: #E4F0FBD0">createRoot</span><span style="color: #A6ACCD">(</span><span style="color: #E4F0FB">htmlDivElement</span><span style="color: #A6ACCD">);</span></span>
<span class="line"><span style="color: #A6ACCD">            </span><span style="color: #E4F0FB">root</span><span style="color: #A6ACCD">.</span><span style="color: #E4F0FBD0">render</span><span style="color: #A6ACCD">(</span><span style="color: #E4F0FB">&lt;</span><span style="color: #5DE4C7">AppComponent</span><span style="color: #E4F0FB"> /&gt;</span><span style="color: #A6ACCD">);</span></span>
<span class="line"><span style="color: #A6ACCD">        }</span></span>
<span class="line"><span style="color: #A6ACCD">    })</span></span>
<span class="line"><span style="color: #A6ACCD">    .</span><span style="color: #E4F0FBD0">catch</span><span style="color: #A6ACCD">(</span><span style="color: #E4F0FB">console</span><span style="color: #A6ACCD">.</span><span style="color: #E4F0FB">warn</span><span style="color: #A6ACCD">);</span></span></code></pre></div>



<div style="height:1em" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-small-font-size">Quelle: <a href="https://public-ui.github.io/docs/get-started/first-steps">https://public-ui.github.io/docs/get-started/first-steps</a> (zuletzt abgerufen am 06.11.2023)</p>



<p><br><strong>3. Beispiel zur Verwendung einer KoliBri-Komponente (hier <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-accent-hover-color"><code>KolSpin</code></mark>)</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1b1e28"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#a6accd33" stroke="#a6accd4d" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import React from 'react';
import { KolSpin } from '@public-ui/react';

export default function Spinner({show}: {show: boolean}) {
    return (
        &lt;KolSpin _show={show} /&gt;
    );
};" style="color:#a6accd;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki poimandres" style="background-color: #1b1e28" tabindex="0"><code><span class="line"><span style="color: #5DE4C7">import </span><span style="color: #ADD7FF">React</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">react</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"><span style="color: #5DE4C7">import </span><span style="color: #A6ACCD">{</span><span style="color: #5DE4C7"> </span><span style="color: #ADD7FF">KolSpin</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">}</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">from</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">&#39;</span><span style="color: #5DE4C7">@public-ui/react</span><span style="color: #A6ACCD">&#39;</span><span style="color: #A6ACCD">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #5DE4C7">export default </span><span style="color: #91B4D5">function</span><span style="color: #5DE4C7"> </span><span style="color: #ADD7FF">Spinner</span><span style="color: #A6ACCD">({</span><span style="color: #E4F0FB">show</span><span style="color: #A6ACCD">}</span><span style="color: #91B4D5">:</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">{</span><span style="color: #5DE4C7">show</span><span style="color: #91B4D5">:</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCDC0">boolean</span><span style="color: #A6ACCD">})</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">{</span></span>
<span class="line"><span style="color: #5DE4C7">    </span><span style="color: #5DE4C7C0">return</span><span style="color: #5DE4C7"> </span><span style="color: #A6ACCD">(</span></span>
<span class="line"><span style="color: #5DE4C7">        </span><span style="color: #E4F0FB">&lt;</span><span style="color: #5DE4C7">KolSpin</span><span style="color: #E4F0FB"> </span><span style="color: #91B4D5; font-style: italic">_show</span><span style="color: #91B4D5">=</span><span style="color: #E4F0FB">{show} /&gt;</span></span>
<span class="line"><span style="color: #5DE4C7">    </span><span style="color: #A6ACCD">);</span></span>
<span class="line"><span style="color: #A6ACCD">};</span></span></code></pre></div>



<p class="has-small-font-size"></p>
</div>



<p>Für Informationen zu einzelnen Komponenten bietet KoliBri eine umfassende <a href="https://public-ui.github.io/docs/components">Dokumentation aller verfügbaren Komponenten</a>. Hierdurch erhält der Entwickler Einblicke in:</p>



<ul class="wp-block-list">
<li>den Zweck jeder Komponente</li>



<li>eine Erklärung zur Funktionsweise</li>



<li>die Dokumentation aller Attribute</li>



<li>die visuelle Darstellung</li>



<li>die Abhängigkeiten zu anderen Komponenten</li>
</ul>



<p></p>



<h2 class="wp-block-heading" style="font-size:30px"><br>Testen der Komponenten</h2>



<p>Das ITZBund-interne Barrierefreiheitstestteam prüft die Barrierefreiheit von Komponenten durch verschiedene Testmethoden. Dazu gehören unter anderem <strong>Unit-Tests, Snapshot-Tests und visuelle Screenshot-Tests</strong>. Das Testvorgehen basiert dabei auf einer angepassten Form des BIK BITV-Tests.</p>



<p>So sind Komponenten in der Regel bereits getestet, allerdings kann es vorkommen, dass Tests noch ausstehen.<br>Die Dokumentation der Komponenten enthält teilweise Informationen darüber, ob einzelne Komponenten nach den Anforderungen des Testvorgehens als vollständig barrierefrei gelten beziehungsweise falls nicht, welche Mängel sie aufweisen. Zudem gibt es eine <a href="https://public-ui.github.io/docs/test-results#bitv-test">Liste mit Testergebnissen</a>.<br><br>Es ist also davon auszugehen, dass die Komponenten der KoliBri-Bibliothek hinreichend barrierefrei sind. Um die Barrierefreiheit jedoch selbstständig sicherzustellen, bieten sich für Entwickler verschiedene Möglichkeiten. <br>Neben (meist kostenpflichtigen) Drittanbieter-Services stehen Entwicklern vermehrt <strong>kostenlose Tools</strong> wie <a href="https://wave.webaim.org">WAVE</a> zur Verfügung, um Barrieren auf Webseiten <strong>automatisiert zu erkennen</strong> und zu kategorisieren. Im Vergleich zum manuellen Testen mit Checklisten und assistiven Technologien überzeugen automatisierte Tests durch den erheblich verringerten Arbeitsaufwand, um Mängel in der Barrierefreiheit zu ermitteln, wenngleich sie gegebenenfalls nicht so gründlich sind.</p>



<p>Auf Anregung von Janis von Bleichert von experte.de möchten wir zudem den deutschsprachigen <a href="http://experte.de/barrierefreiheit">Barrierefreiheits-Test von experte.de</a> erwähnen. Der Test überzeugt durch eingebautes Crawling, wodurch sich eine Webseite <strong>in nur einem Schritt</strong> vollständig auf Barrierefreiheit prüfen lässt. <br>Zuletzt sei zu erwähnen, dass sich ein Blick auf <a href="https://www.w3.org/WAI/ER/tools/">die Liste der Web Accessibility Initiative</a> lohnt, um einen Überblick über verschiedenste Test-Tools zu gewinnen und eine geeignete Wahl zu treffen.¹</p>



<p class="has-small-font-size">¹Die W3C arbeitet aktuell an einer Aktualisierung der Liste. (Stand November 2023)</p>



<h3 class="wp-block-heading" style="font-size:30px"><br>Fazit</h3>



<p>Die Webseite von React bietet einen <a href="https://legacy.reactjs.org/docs/accessibility.html">Guide für den Umgang mit Barrierefreiheit in React-Projekten</a> an. Obwohl keine aktuelle Version des Artikels gefunden werden konnte, beschreibt der Leitfaden viele Praktiken, die nicht spezifisch für das Framework sind, sondern allgemeine Empfehlungen zur Gewährleistung der Barrierefreiheit von Webseiten darstellen. So verweist der Artikel zu Beginn auf die Bedeutung der WCAG, der ARIA-Attribute als Ergänzung zu HTML sowie die Verwendung von semantischem HTML.</p>



<p><em>Wie l</em>ässt sich<em> Barrierefreiheit im Web umsetzen?</em> Dies kann aufgrund der Vielzahl von Problemen und Ansätzen <strong>nicht so konkret definiert werden</strong>. KoliBri nimmt einem die Notwendigkeit ab, den Überblick über all diese verschiedenen Punkte zu behalten. Die Bibliothek <strong>unterstützt den Entwickler</strong>, indem sie diesem Komponenten vorgibt. Durch die Typisierung von Attributen oder Vorgaben, welche Attribute verpflichtend mit Werten zu befüllen sind, stellt KoliBri die Funktionalität und Barrierefreiheit der Komponenten sicher.</p>



<p>Angesichts der Tatsache, dass KoliBri vom ITZBund, dem IT-Dienstleister der deutschen Bundesverwaltung, entwickelt wurde, kann angenommen werden, dass die Bibliothek die <strong>Anforderungen an Barrierefreiheit von Webseiten in hohem Maße erfüllt</strong>. Dies ist in der gesetzlichen Verpflichtung begründet, die öffentliche Stellen haben, ihre Webseiten barrierefrei zu gestalten.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
