Codierungsstandards & Best Practices
Basis-Codierungskonventionen, die projektübergreifend gelten.
Dieser Skill ist die gemeinsame Grundlage, nicht das detaillierte Framework-Handbuch.
- Verwenden Sie
frontend-patternsfür React, State, Formulare, Rendering und UI-Architektur. - Verwenden Sie
backend-patternsoderapi-designfür Repository/Service-Schichten, Endpunkt-Design, Validierung und serverseitige Anliegen. - Verwenden Sie
rules/common/coding-style.md, wenn Sie die kürzeste wiederverwendbare Regel-Ebene anstelle eines vollständigen Skill-Durchlaufs benötigen.
Wann zu aktivieren
- Start eines neuen Projekts oder Moduls
- Überprüfung von Code auf Qualität und Wartbarkeit
- Refactoring von vorhandenem Code, um Konventionen zu befolgen
- Durchsetzung von Namens-, Formatierungs- oder struktureller Konsistenz
- Einrichtung von Linting-, Formatierungs- oder Typprüfungsregeln
- Onboarding neuer Mitwirkender zu Codierungskonventionen
Abgrenzung des Umfangs
Aktivieren Sie diesen Skill für:
- beschreibende Namensgebung
- Unveränderlichkeit als Standard
- Lesbarkeit, KISS, DRY und YAGNI-Durchsetzung
- Erwartungen an die Fehlerbehandlung und Code-Smell-Überprüfung
Verwenden Sie diesen Skill NICHT als primäre Quelle für:
- React-Komposition, Hooks oder Rendering-Muster
- Backend-Architektur, API-Design oder Datenbankschichten
- domänenspezifische Framework-Anleitungen, wenn ein spezifischerer ECC-Skill bereits existiert
Grundsätze der Codequalität
1. Lesbarkeit zuerst
- Code wird öfter gelesen als geschrieben
- Klare Variablen- und Funktionsnamen
- Selbstdokumentierender Code wird Kommentaren vorgezogen
- Einheitliche Formatierung
2. KISS (Halte es einfach, dumm)
- Die einfachste funktionierende Lösung
- Vermeide Überengineering
- Keine vorzeitige Optimierung
- Leicht verständlich > cleverer Code
3. DRY (Wiederhole dich nicht)
- Extrahiere gemeinsame Logik in Funktionen
- Erstelle wiederverwendbare Komponenten
- Teile Hilfsprogramme über Module hinweg
- Vermeide Kopieren-und-Einfügen-Programmierung
4. YAGNI (Du wirst es nicht brauchen)
- Baue keine Funktionen, bevor sie benötigt werden
- Vermeide spekulative Allgemeinheit
- Füge Komplexität nur bei Bedarf hinzu
- Starte einfach, refaktoriere bei Bedarf
TypeScript/JavaScript-Standards
Variablenbenennung
// BESTANDEN: GUT: Beschreibende Namen
const marketSearchQuery = 'election'
const isUserAuthenticated = true
const totalRevenue = 1000
// NICHT BESTANDEN: SCHLECHT: Unklare Namen
const q = 'election'
const flag = true
const x = 1000
Funktionsbenennung
// BESTANDEN: GUT: Verb-Nomen-Muster
async function fetchMarketData(marketId: string) { }
function calculateSimilarity(a: number[], b: number[]) { }
function isValidEmail(email: string): boolean { }
// NICHT BESTANDEN: SCHLECHT: Unklar oder nur Nomen
async function market(id: string) { }
function similarity(a, b) { }
function email(e) { }
Unveränderlichkeitsmuster (KRITISCH)
// BESTANDEN: IMMER Spread-Operator verwenden
const updatedUser = {
...user,
name: 'New Name'
}
const updatedArray = [...items, newItem]
// NICHT BESTANDEN: NIEMALS direkt mutieren
user.name = 'New Name' // SCHLECHT
items.push(newItem) // SCHLECHT
Fehlerbehandlung
// BESTANDEN: GUT: Umfassende Fehlerbehandlung
async function fetchData(url: string) {
try {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
return await response.json()
} catch (error) {
console.error('Fetch failed:', error)
throw new Error('Fehler beim Abrufen der Daten')
}
}
// NICHT BESTANDEN: SCHLECHT: Keine Fehlerbehandlung
async function fetchData(url) {
const response = await fetch(url)
return response.json()
}
Async/Await Best Practices
// BESTANDEN: GUT: Parallele Ausführung wenn möglich
const [users, markets, stats] = await Promise.all([
fetchUsers(),
fetchMarkets(),
fetchStats()
])
// NICHT BESTANDEN: SCHLECHT: Sequentiell wenn unnötig
const users = await fetchUsers()
const markets = await fetchMarkets()
const stats = await fetchStats()
Typsicherheit
// BESTANDEN: GUT: Korrekte Typen
interface Market {
id: string
name: string
status: 'active' | 'resolved' | 'closed'
created_at: Date
}
function getMarket(id: string): Promise<Market> {
// Implementierung
}
// NICHT BESTANDEN: SCHLECHT: Verwendung von 'any'
function getMarket(id: any): Promise<any> {
// Implementierung
}
React Best Practices
Komponentenstruktur
// BESTANDEN: GUT: Funktionale Komponente mit Typen
interface ButtonProps {
children: React.ReactNode
onClick: () => void
disabled?: boolean
variant?: 'primary' | 'secondary'
}
export function Button({
children,
onClick,
disabled = false,
variant = 'primary'
}: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant}`}
>
{children}
</button>
)
}
// NICHT BESTANDEN: SCHLECHT: Keine Typen, unklare Struktur
export function Button(props) {
return <button onClick={props.onClick}>{props.children}</button>
}
Benutzerdefinierte Hooks
// BESTANDEN: GUT: Wiederverwendbarer benutzerdefinierter Hook
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value)
}, delay)
return () => clearTimeout(handler)
}, [value, delay])
return debouncedValue
}
// Verwendung
const debouncedQuery = useDebounce(searchQuery, 500)
State Management
// BESTANDEN: GUT: Korrekte Zustandsaktualisierungen
const [count, setCount] = useState(0)
// Funktionale Aktualisierung für Zustand basierend auf vorherigem Zustand
setCount(prev => prev + 1)
// NICHT BESTANDEN: SCHLECHT: Direkter Zustandsverweis
setCount(count + 1) // Kann in asynchronen Szenarien veraltet sein
Bedingtes Rendern
// BESTANDEN: GUT: Klares bedingtes Rendern
{isLoading && <Spinner />}
{error && <ErrorMessage error={error} />}
{data && <DataDisplay data={data} />}
// NICHT BESTANDEN: SCHLECHT: Ternary-Hölle
{isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}
API-Design-Standards
REST-API-Konventionen
GET /api/markets # Alle Märkte auflisten
GET /api/markets/:id # Bestimmten Markt abrufen
POST /api/markets # Neuen Markt erstellen
PUT /api/markets/:id # Markt aktualisieren (vollständig)
PATCH /api/markets/:id # Markt aktualisieren (teilweise)
DELETE /api/markets/:id # Markt löschen
# Abfrageparameter zum Filtern
GET /api/markets?status=active&limit=10&offset=0
Antwortformat
// BESTANDEN: GUT: Einheitliche Antwortstruktur
interface ApiResponse<T> {
success: boolean
data?: T
error?: string
meta?: {
total: number
page: number
limit: number
}
}
// Erfolgsantwort
return NextResponse.json({
success: true,
data: markets,
meta: { total: 100, page: 1, limit: 10 }
})
// Fehlerantwort
return NextResponse.json({
success: false,
error: 'Ungültige Anfrage'
}, { status: 400 })
Eingabevalidierung
import { z } from 'zod'
// BESTANDEN: GUT: Schema-Validierung
const CreateMarketSchema = z.object({
name: z.string().min(1).max(200),
description: z.string().min(1).max(2000),
endDate: z.string().datetime(),
categories: z.array(z.string()).min(1)
})
export async function POST(request: Request) {
const body = await request.json()
try {
const validated = CreateMarketSchema.parse(body)
// Mit validierten Daten fortfahren
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json({
success: false,
error: 'Validierung fehlgeschlagen',
details: error.issues
}, { status: 400 })
}
}
}
Dateiorganisation
Projektstruktur
src/
├── app/ # Next.js App Router
│ ├── api/ # API-Routen
│ ├── markets/ # Marktseiten
│ └── (auth)/ # Auth-Seiten (Routengruppen)
├── components/ # React-Komponenten
│ ├── ui/ # Generische UI-Komponenten
│ ├── forms/ # Formularkomponenten
│ └── layouts/ # Layout-Komponenten
├── hooks/ # Benutzerdefinierte React-Hooks
├── lib/ # Hilfsprogramme und Konfigurationen
│ ├── api/ # API-Clients
│ ├── utils/ # Hilfsfunktionen
│ └── constants/ # Konstanten
├── types/ # TypeScript-Typen
└── styles/ # Globale Styles
Dateibenennung
components/Button.tsx # PascalCase für Komponenten
hooks/useAuth.ts # camelCase mit 'use'-Präfix
lib/formatDate.ts # camelCase für Hilfsprogramme
types/market.types.ts # camelCase mit .types-Suffix
Kommentare & Dokumentation
Wann kommentieren
// BESTANDEN: GUT: Erklären Sie WARUM, nicht WAS
// Exponentielle Backoff verwenden, um die API bei Ausfällen nicht zu überlasten
const delay = Math.min(1000 * Math.pow(2, retryCount), 30000)
// Mutation wird hier bewusst aus Leistungsgründen bei großen Arrays verwendet
items.push(newItem)
// NICHT BESTANDEN: SCHLECHT: Das Offensichtliche ausdrücken
// Zähler um 1 erhöhen
count++
// Name auf den Benutzernamen setzen
name = user.name
JSDoc für öffentliche APIs
/**
* Durchsucht Märkte mittels semantischer Ähnlichkeit.
*
* @param query - Suchanfrage in natürlicher Sprache
* @param limit - Maximale Anzahl der Ergebnisse (Standard: 10)
* @returns Array von Märkten, sortiert nach Ähnlichkeitswert
* @throws {Error} Wenn die OpenAI-API fehlschlägt oder Redis nicht verfügbar ist
*
* @example
* ```typescript
* const results = await searchMarkets('Wahl', 5)
* console.log(results[0].name) // "Trump vs. Biden"
* ```
*/
export async function searchMarkets(
query: string,
limit: number = 10
): Promise<Market[]> {
// Implementierung
}
Performance Best Practices
Memoisierung
import { useMemo, useCallback } from 'react'
// BESTANDEN: GUT: Teure Berechnungen memoisieren
// Vor dem Sortieren kopieren - Array.prototype.sort mutiert direkt
const sortedMarkets = useMemo(() => {
return [...markets].sort((a, b) => b.volume - a.volume)
}, [markets])
// BESTANDEN: GUT: Callbacks memoisieren
const handleSearch = useCallback((query: string) => {
setSearchQuery(query)
}, [])
Lazy Loading
import { lazy, Suspense } from 'react'
// BESTANDEN: GUT: Schwere Komponenten lazy laden
const HeavyChart = lazy(() => import('./HeavyChart'))
export function Dashboard() {
return (
<Suspense fallback={<Spinner />}>
<HeavyChart />
</Suspense>
)
}
Datenbankabfragen
// BESTANDEN: GUT: Nur benötigte Spalten auswählen
const { data } = await supabase
.from('markets')
.select('id, name, status')
.limit(10)
// NICHT BESTANDEN: SCHLECHT: Alles auswählen
const { data } = await supabase
.from('markets')
.select('*')
Teststandards
Teststruktur (AAA-Muster)
test('berechnet Ähnlichkeit korrekt', () => {
// Arrange (Anordnen)
const vector1 = [1, 0, 0]
const vector2 = [0, 1, 0]
// Act (Handeln)
const similarity = calculateCosineSimilarity(vector1, vector2)
// Assert (Überprüfen)
expect(similarity).toBe(0)
})
Testbenennung
// BESTANDEN: GUT: Beschreibende Testnamen
test('gibt leeres Array zurück, wenn kein Markt der Abfrage entspricht', () => { })
test('wirft Fehler, wenn OpenAI-API-Schlüssel fehlt', () => { })
test('fällt auf Teilstring-Suche zurück, wenn Redis nicht verfügbar ist', () => { })
// NICHT BESTANDEN: SCHLECHT: Vage Testnamen
test('funktioniert', () => { })
test('teste Suche', () => { })
Erkennung von Code Smells
Achten Sie auf diese Anti-Patterns:
1. Lange Funktionen
// NICHT BESTANDEN: SCHLECHT: Funktion > 50 Zeilen
function processMarketData() {
// 100 Zeilen Code
}
// BESTANDEN: GUT: In kleinere Funktionen aufteilen
function processMarketData() {
const validated = validateData()
const transformed = transformData(validated)
return saveData(transformed)
}
2. Tiefe Verschachtelung
// NICHT BESTANDEN: SCHLECHT: 5+ Verschachtelungsebenen
if (user) {
if (user.isAdmin) {
if (market) {
if (market.isActive) {
if (hasPermission) {
// Etwas tun
}
}
}
}
}
// BESTANDEN: GUT: Frühe Rückgaben
if (!user) return
if (!user.isAdmin) return
if (!market) return
if (!market.isActive) return
if (!hasPermission) return
// Etwas tun
3. Magische Zahlen
// NICHT BESTANDEN: SCHLECHT: Unerklärte Zahlen
if (retryCount > 3) { }
setTimeout(callback, 500)
// BESTANDEN: GUT: Benannte Konstanten
const MAX_RETRIES = 3
const DEBOUNCE_DELAY_MS = 500
if (retryCount > MAX_RETRIES) { }
setTimeout(callback, DEBOUNCE_DELAY_MS)
Denken Sie daran: Codequalität ist nicht verhandelbar. Klarer, wartbarer Code ermöglicht schnelle Entwicklung und sicheres Refactoring.