2025-07-30 11:15:04 +02:00
2025-07-30 11:15:04 +02:00

DHBW 2025: Web Engineering Prüfungsleistung

Maximale Basispunktzahl: 100 Punkte + bis zu 15 Bonuspunkte


1. Grundanforderungen (30 Punkte)

Projektgrundlagen (15 Punkte)

  • Funktionsfähige Anwendung (8 Punkte)
    • Webapp oder Backend-Anwendung läuft fehlerfrei
    • Kernfunktionalitäten sind in der Projektdokumentation beschrieben und testbar
  • Repository (4 Punkte)
    • GitHub/GitLab/CodeBerg Repository ist (öffentlich) zugänglich
    • Commit-Historie zeigt kontinuierliche Entwicklung
  • Projektdokumentation (3 Punkte)
    • Aussagekräftiger Projekttitel und Beschreibung
    • README.md mit Installation, Verwendung und Technologie-Stack
    • Kurze Erklärung der Hauptfunktionen am Anfang relevanter Dateien

Präsentation (15 Punkte)

  • Elevator Pitch (5 Punkte)

    • Maximal 1 Minute
    • Welches Problem wird gelöst und warum wurde es vorher noch nicht gelöst?
    • Zielgruppe definiert
  • Technische Präsentation (5 Punkte)

    • PowerPoint/Folien mit Technologie-Stack
    • Live-Demo der Anwendung
  • Projektevolution (5 Punkte) Jedes Projekt verläuft unterschiedlich. Sofern es zutrifft, beschreibt die unterschiedlichen Phasen des Projekts. Wie weit seid ihr gekommen? Wo waren die Stolpersteine? Wie könnte sich eure Anwendung bei fortgesetzter Arbeit entwickeln?

    1. (Paper) Prototype
    2. Make it work (PoC)
    3. Make it right (MvP)
    4. Make it fast (Production)

2. Clean Code Prinzipien (25 Punkte)

Projektstruktur (10 Punkte)

  • Ordnerstruktur (5 Punkte)

    projekt/
    ├── src/
    │   ├── components/     # React Components / UI
    │   ├── config/         # Konfigurationen, Hard-coded Strings etc.
    │   ├── services/       # Separitiere für-sich-stehende Funktionen Klassen, Clients etc.
    │   ├── utils/          # Hilfsfunktionen
    │   ├── main.css        # Haupteinstieg in CSS Klassen, Variablen, Imports etc.
    │   ├── main.js         # Die eigentliche Appliktion
    │   └── index.js        # Haupteinstieg in die gesamte Applikation
    ├── public/             # Statische Assets, Ressourcen, Bilder etc.
    ├── tests/              # Test-Dateien
    ├── .gitignore
    ├── package.json
    └── README.md
    
    • Logische Trennung von Funktionalitäten
    • Konsistente Benennung
  • Datei-Organisation (5 Punkte)

    • Ein Konzept pro Datei (Single Responsibility)
    • Konsistente Namenskonventionen: kebab-case für Dateien, camelCase für Variablen, PascalCase für Komponenten/Klassen

Code-Qualität (10 Punkte)

KISS Prinzip (3 Punkte)

Nicht so einfach:

const processData = (d) => d.filter(x => x.status === 'active').map(x => ({...x, processed: true})).reduce((acc, curr) => acc + curr.value, 0);

Einfach:

function calculateActiveTotal(data) {
  const activeItems = data.filter(item => item.status === 'active');
  const processedItems = activeItems.map(item => ({
    ...item,
    processed: true
  }));
  return processedItems.reduce((total, item) => total + item.value, 0);
}

Beschreibende Namen (3 Punkte)

Schlecht:

let isActive = true;
let data = [];
function calc(x, y) { return x * y; }

Gut:

let isMenuVisible = true;
let userProfiles = [];
function calculateTotalPrice(price, taxRate) { return price * taxRate; }

Funktionsverantwortlichkeiten (4 Punkte)

Zu viele Verantwortlichkeiten:

function handleUser(userData) {
  // Validiert Daten
  if (!userData.email) return false;
  // Speichert in DB
  database.save(userData);
  // Sendet Email
  sendWelcomeEmail(userData.email);
  // Updated UI
  updateUserList();
  return true;
}

Eine klare Verantwortlichkeit pro Funktion:

function validateUserData(userData) {
  return userData.email && userData.name;
}

function saveUser(userData) {
  return database.save(userData);
}

function sendWelcomeEmail(email) {
  return emailService.send(email, 'welcome');
}

Kommentierung & Dokumentation (5 Punkte)

JSDoc ist optional und der beste Code muss nicht kommentiert werden.

Über-/Unterkommentiert:

// Erhöht i um 1
i++;
// Checked ob user existiert
if (user) {
  // Macht irgendwas
  doSomething();
}

Sinnvoll kommentiert:

/**
 * Handles user authentication and session management
 * 
 * OR
 * 
 * This file manages JWT tokens and user permissions
 */

function calculateCompoundInterest(principal, rate, time) {
  // Using compound interest formula: A = P(1 + r/n)^(nt)
  return principal * Math.pow((1 + rate), time);
}

3. Accessibility & UX (25 Punkte)

Web Accessibility (15 Punkte)

Semantisches HTML (5 Punkte)

Nicht semantisch:

<div class="header">
  <div class="nav">
    <div class="nav-item">Home</div>
    <div class="nav-item">About</div>
  </div>
</div>
<div class="content">
  <div class="title">Welcome</div>
  <div class="text">Description...</div>
</div>

Semantisch korrekt:

<header>
  <nav aria-label="Hauptnavigation">
    <ul>
      <li><a href="#home">Home</a></li>
      <li><a href="#about">About</a></li>
    </ul>
  </nav>
</header>
<main>
  <section>
    <h1>Welcome</h1>
    <p>Description...</p>
  </section>
</main>

ARIA Labels & Alt-Texte (5 Punkte)

Schlecht:

<img src="chart.png" alt="chart">
<button onclick="closeMenu()">×</button>
<input type="email" required>
<div>We don't send spam</div>

Gut:

<img src="chart.png" alt="Verkaufszahlen 2024: 40% Steigerung gegenüber Vorjahr">
<button aria-label="Menü schließen" onclick="closeMenu()">×</button>
<input type="email" aria-describedby="email-help" required>
<div id="email-help">Wir versenden keine Spam-Mails</div>

Tastaturnavigation (5 Punkte)

  • Alle interaktiven Elemente per Tab erreichbar
  • Sichtbarer Focus-Indikator
  • Logische Tab-Reihenfolge

Nicht tastaturzugänglich:

<div class="clickable">🍔</div>
div.clickable {
  cursor: pointer;
}

Tastaturzugänglich:

div.clickable:focus {
  outline: 2px solid #007acc;
}
<div class="clickable" tabindex="0" aria-label="Menü öffnen">🍔</div>

Responsive Design (10 Punkte)

Mobile First Approach (5 Punkte - mindestens 1 Breakpoint)

/* Mobile First */
.container {
  width: 100%;
  padding: 1rem;
}

/* Desktop */
@media (min-width: 768px) {
  .container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 2rem;
  }
}

Flexbox/Grid Layout (5 Punkte)

Veraltete Layouts:

.container {
  float: left;
  width: 33.33%;
}
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

Moderne Layouts:

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1.5rem;
}
.navigation {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

4. Technische Umsetzung (20 Punkte)

Plattformunabhängigkeit (5 Punkte)

  • Funktioniert auf macOS, Windows, GNU/Linux
  • Browser-Kompatibilität (Chrome, Firefox, Safari, Edge)

Plattformspezifisch:

// Nur Chrome
navigator.clipboard.writeText(text);

Plattformunabhängig:

In aller Regel sind solche sog. Polyfills kaum noch eigenhändig zu implementieren. Nichtsdestotrotz gilt es die Plattformunabhängig zu prüfen und ggf. Alternativen für die Implementierung zu finden wie im folgenden Beispiel für die Zwischenablage:

// Fallback für ältere Browser
function copyToClipboard(text) {
  if (navigator.clipboard) {
    return navigator.clipboard.writeText(text);
  } else {
    const textArea = document.createElement('textarea');
    textArea.value = text;
    document.body.appendChild(textArea);
    textArea.select();
    document.execCommand('copy');
    document.body.removeChild(textArea);
  }
}

Package Management (5 Punkte)

Sämtliche nodeJS/JavaScript Projekte sollten eine package.json beinhalten. npm init und ein Dialog öffnet sich.

{
  "name": "my-project",
  "scripts": {
    "start": "vite",
    "build": "vite build",
    "test": "jest",
    "lint": "eslint src/"
  },
  "dependencies": {
    "react": "^18.0.0"
  },
  "devDependencies": {
    "vite": "^4.0.0",
    "jest": "^29.0.0"
  }
}

Build Tools & Optimierung (5 Punkte)

  • Vite, Webpack, oder ähnliche Tools
  • Optimierte Produktions-Builds
    • Debugger und unnötige console.log()'s entfernen
    • Code-Splitting
    • Nur Teile statt gesamte Bibliotheken importieren
    • Bspw. PostCSS für Entfernung von überschüssigem CSS

Entwicklungs-Build:

// Unminified, alle Dependencies geladen
import * as _ from 'lodash';
// Debugging
console.log('Debug info:', data);
debugger;

Produktions-Build:

// Minified, nur benötigte Funktionen
import { debounce } from 'lodash';

// Debug-Code entfernt in Production

Live-Demo (5 Punkte)

  • Anwendung läuft während der Präsentation stabil
  • Alle Kernfunktionen werden erfolgreich vorgeführt
  • Ungefähr 5 Minuten Demo-Zeit

5. Bonusfeatures (max. 15 Zusatzpunkte)

Wähle mindestens 2 Bereiche für Bonuspunkte:

API Integration (5 Bonuspunkte)

Ohne Error Handling:

async function getUser(id) {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}

Mit Error Handling:

async function fetchUserData(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    return await response.json();
  } catch (error) {
    console.error('Fehler beim Laden der Benutzerdaten:', error);
    throw new Error('Benutzerdaten konnten nicht geladen werden');
  }
}

Local Storage / State Management (5 Bonuspunkte)

Ohne Error Handling:

function saveData(data) {
  localStorage.setItem('data', JSON.stringify(data));
}
function loadData() {
  return JSON.parse(localStorage.getItem('data'));
}

Mit Error Handling:

function saveUserPreferences(prefs) {
  try {
    localStorage.setItem('userPrefs', JSON.stringify(prefs));
    return true;
  } catch (error) {
    console.warn('Local Storage nicht verfügbar:', error);
    return false;
  }
}

function loadUserPreferences() {
  try {
    const data = localStorage.getItem('userPrefs');
    return data ? JSON.parse(data) : getDefaultPreferences();
  } catch (error) {
    console.warn('Fehler beim Laden der Einstellungen:', error);
    return getDefaultPreferences();
  }
}

Progressive Web App Features (5 Bonuspunkte)

  • Service Worker für Offline-Funktionalität
  • Manifest.json für App-Installation
  • Caching-Strategien

Ohne PWA:

<!-- Nur normale Website -->

Mit PWA Features:

<!-- manifest.json -->
<link rel="manifest" href="/manifest.json">
<!-- Service Worker -->
<script>
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}
</script>

Testing (5 Bonuspunkte)

Von Vornherein mitgedachte Tests helfen beim Code-Splitting. Um beim Testen jene Funktionen eindeutig referenzieren zu können, hilft es sie in einzelne Dateien zu verteilen und Ordnern zu gruppieren.

Ohne Tests:

// Keine Tests vorhanden
function calculateTotal(price, tax) {
  return price + (price * tax);
}

Mit Tests:

// calculate.js
export function calculateTotal(price, tax) {
  if (typeof price !== 'number' || typeof tax !== 'number') {
    throw new Error('Price and tax must be numbers');
  }
  return price + (price * tax);
}

// calculate.test.js
import { calculateTotal } from './calculate.js';

test('calculateTotal should return correct sum', () => {
  expect(calculateTotal(100, 0.19)).toBeCloseTo(119);
});

test('calculateTotal should throw error for invalid input', () => {
  expect(() => calculateTotal('100', 0.19)).toThrow();
});

Erweiterte Responsive Features (5 Bonuspunkte - 3+ Breakpoints)

/* Mobile */
.grid { display: block; }

/* Tablet */
@media (min-width: 768px) {
  .grid { 
    display: grid; 
    grid-template-columns: 1fr 1fr; 
  }
}

/* Desktop */
@media (min-width: 1024px) {
  .grid { 
    grid-template-columns: repeat(3, 1fr); 
  }
}

/* Large Desktop */
@media (min-width: 1440px) {
  .grid { 
    grid-template-columns: repeat(4, 1fr); 
  }
}

Security Features (5 Bonuspunkte)

Unsicher:

// XSS anfällig
element.innerHTML = userInput;
// Unvalidierte Eingabe
function search(query) {
  return database.query(`SELECT * FROM users WHERE name = '${query}'`);
}

Sicher:

// XSS-sicher durch HTML-Escaping
function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}
element.innerHTML = escapeHtml(userInput);

// SQL-Injection sicher
function search(query) {
  const sanitizedQuery = query.replace(/[^\w\s]/gi, '');
  return database.query('SELECT * FROM users WHERE name = ?', [sanitizedQuery]);
}

Punkteverteilung im Überblick

Basispunkte (100 Punkte):

  • Grundanforderungen: 30 Punkte
  • Clean Code Prinzipien: 25 Punkte
  • Accessibility & UX: 25 Punkte
  • Technische Umsetzung: 20 Punkte

Bonuspunkte (max. 15 Punkte):

  • Bis zu 3 Bonusfeatures à 5 Punkte wählbar
  • Gesamtmögliche Punktzahl: 115 Punkte

Abgabe

  • Deadline: 27.07.2025
  • Format: GitHub/GitLab Repository Link + Live-Demo URL (falls gehostet)
  • Präsentation: 18.07.2025 - 10-15 Minuten pro Gruppe + ~5 Minuten Demo

Tipps

  1. Beginnt früh mit der Eingrenzung des Funktionsumfangs
  2. Testet eure Anwendung auf verschiedenen Geräten, Betriebssystemen und Browsern
  3. Fragt bei Unklarheiten rechtzeitig nach
  4. Fokussiert euch auf Qualität statt Quantität
  5. Behaltet Barrieren im Blick und vermeidet sie rechtzeitig
  6. Verwendet gute Struktur um eure Code-Beispiele zu organisieren
Description
No description provided
Readme 54 KiB