Im Shopify-Architektur-Ratgeber sprechen wir über gute Architektur. Heute: Die Kehrseite. Technische Schulden.
Bei smplx. haben wir Shops gesehen, die nach 3 Jahren nicht mehr zu verändern waren. Nicht wegen der Technologie. Wegen der Schulden, die aufgehäuft wurden.
Die gute Nachricht: Es ist vermeidbar. Und wenn du schon Schulden hast – sie sind abbaubar.
Was sind Technische Schulden?
Definition: Code/Architektur, die schnell gebaut wurde aber schwer zu ändern ist.
Metapher: Du machst einen Schnellkredit bei der Bank. Jetzt zahlst du Zinsen. Für einen Shopify-Shop sind die "Zinsen" jede Feature, die schwerer wird.
Wie Schulden entstehen
Time Pressure: "Wir brauchen das Feature bis Freitag!" → Quick & Dirty Lösung → Morgen ein Bug → Patch darauf → Nach 6 Monaten: Unmaintainbar
App Sprawl: "Lass uns eine App für das installieren" → Erste App für Rabatte → Zweite App für Bundling → Dritte App für Variants → Fünfte App später: Du hast 5 Apps, keiner weiß wie sie zusammenhängen
Undocumented Code: "Ich weiß, wie es funktioniert" → Developer verlässt Firma → Neuer Developer: "Warum macht dich dieser Code das?" → Kann nicht sicher ändern → Keine neuen Features
Outdated Themes: "Lass uns das alte Theme behalten" → Alte Theme-Version → Neue Features nicht möglich → Security-Updates verpassen → Nach 2 Jahren: Breakage
Liquid Spaghetti-Code
<!-- ❌ FALSCH: Dieser Code existiert wirklich -->
{% if product.handle == "special-product-1" %}
<div class="special-styling-1">
{% if customer.email == "vip@customer.com" %}
<span class="vip-text">VIP Only!</span>
{% else %}
<!-- Old code from 2019 -->
{% for item in cart.items %}
{% if item.product.handle == "special-product-1" %}
<!-- Recursive logic - code smell! -->
{% endif %}
{% endfor %}
{% endif %}
</div>
{% elsif product.handle == "special-product-2" %}
<!-- 200 Lines of duplicate code -->
{% elsif product.handle == "special-product-3" %}
<!-- 200 Lines of duplicate code -->
{% endif %}
<!-- This repeats 50 times! -->
Real-World: Bekateq Story
Bekateq hatte eine Situation, die viele kennen:
Ausgangslage (Before):
- 5 verschiedene Custom Apps
- 30+ Theme-Snippets mit Spaghetti-Logic
- Keine Tests
- Schwer zu verstehen
- Neue Features dauerten Wochen
- Bug-Fixes brachten neue Bugs
Die Kosten:
- Monatlich: 2 Entwickler
- Monatlich: 1-2 Bugs pro Week
- Monatlich: Features dauern 3x länger
Die Lösung: One App to Rule Them All
Bekateq schrieb eine einzige Custom App mit 4400 Zeilen Code und Zero External Dependencies (außer Shopify SDK).
Das Resultat (After):
- 1 App statt 5
- Verständlich + dokumentiert
- Tests möglich
- Neue Features: 5 Tage statt 15
- Bugs: Fast null
Die Investment:
- 8 Wochen Refactoring
- Kosten: €50-80k
- ROI: 6 Monate (schneller Entwicklung)
Lernpunkt: Die Zeit, die du sparst, bezahlt sich aus.
Zeichen, dass du Schulden hast
Zeichen 1: "Keine, ich kann das nicht ändern"
Developer sagt: "Das Feature kann ich nicht bauen,
weil ich diese Code-Stelle nicht anfassen kann."
Das ist Schuld. Dein Code blockiert dich selbst.
Zeichen 2: Änderungen dauern länger und länger
Metrik: Velocity sinkt
Monat 1: 10 Features
Monat 3: 8 Features
Monat 6: 5 Features
Monat 12: 2 Features
Das ist Schuld-Zins. Je älter der Code, desto mehr "Zinsen".
Zeichen 3: Tests sind unmöglich
"Diesen Code kann ich nicht testen, weil..."
- "...alles global ist"
- "...zu viele Dependencies"
- "...tausend if-Statements"
Wenn Code nicht testbar ist, ist er Schuld.
Zeichen 4: Kleine Änderungen, große Bugs
Changed: Button Text
Result: Cart funktioniert nicht mehr
Das ist Schuld. Tight Coupling.
Zeichen 5: 5+ Apps für einfache Dinge
- App 1: Discounts
- App 2: Variants
- App 3: Bundling
- App 4: Reviews
- App 5: Inventory
- App 6: Analytics
Jede App hat:
- Eigene API-Limits
- Eigene Webhooks
- Eigene Rate-Limits
- Potenzielle Konflikte
Das ist Schuld der "App Sprawl".
Wie du Schulden vermeidest (Architecture-First)
Prinzip 1: Entscheide früh – "Build vs. Buy"
Frage: Brauchen wir eine Custom App dafür?
Entscheidungsbaum:
Feature X nötig?
├─ Kann man mit Standard Shopify machen?
│ └─ JA → Use Standard (keine Schuld!)
│
├─ Braucht man Custom Code?
│ └─ JA → Native (Theme) oder App?
│ ├─ Theme? (Simple UI-Logik)
│ │ └─ Ja → Liquid (schnell, kein Overhead)
│ │
│ └─ App? (Complex Logic, Admin API)
│ └─ Eine App mit klarem Purpose
│
└─ Kann man mit Existing App machen?
└─ JA → Use App (nicht custom!)
Beispiel: Rabatt-System
❌ Früher: 3 verschiedene Apps
- Discount App A
- Discount App B
- Custom Discount App
✅ Besser: Shopify's eigenes Discount-System
(Kein Custom Code nötig!)
✅ Wenn Custom nötig: 1 App, klarer Purpose
Prinzip 2: Schreibe Code für andere
Annahme: Dein Code wird in 6 Monaten von jemand anderem verwaltet.
Konkrekt:
// ❌ FALSCH: Nur du verstehst es
const x = arr.map(a => a.p * (1 - d)).filter(b => b > 0);
// ✅ RICHTIG: Jeder versteht es
const applyDiscount = (price, discountPercent) => {
return price * (1 - discountPercent / 100);
};
const filteredPrices = prices
.map(price => applyDiscount(price, discount))
.filter(price => price > 0);
Im Shopify-Context (Liquid):
<!-- ❌ FALSCH: Magic Numbers -->
{% if product.price > 10000 %}
<span class="premium">Premium</span>
{% endif %}
<!-- ✅ RICHTIG: Dokumentiert -->
{% comment %}
Premium products are those with price > $100 (10000 cents)
They get special treatment in search and collections
{% endcomment %}
{% assign premium_price_threshold = 10000 %}
{% if product.price > premium_price_threshold %}
<span class="premium">Premium</span>
{% endif %}
Prinzip 3: One Responsibility per App/Component
The Single Responsibility Principle (SRP)
Falsch:
MyAwesomeApp handles:
- Discounts
- Bundling
- Inventory
- Analytics
- Custom Checkout
Jede Änderung affect alles!
Richtig:
DiscountApp handles:
- Creating discounts
- Applying discounts
- Reporting on discounts
(Nur das!)
Prinzip 4: Dokumentiere Entscheidungen
# Decision Log
## Why do we use Metafields for Product Bundles?
**Date:** 2025-01-15
**Decision:** Use Metaobjects instead of separate App
**Alternatives considered:**
1. Custom App - Too heavyweight for this feature
2. Liquid only - Can't handle admin experience well
**Why Metaobjects?**
- Native Shopify (no external dependencies)
- Queryable in GraphQL (good DX)
- Admin UI auto-generated
- Can be related to Products
**Trade-offs:**
- Requires Shopify Plus (but we have it)
- Limited by Metaobject rate limits (ok for our use case)
**Who decided?** Claudio + Team Lead
**Status?** Implemented ✅
Dieser Log hilft neuen Entwicklern: "Warum nicht anders?"
Prinzip 5: Tests schreiben (früh!)
Nicht am Ende. Von Anfang an.
// test-discount-logic.js
import { applyDiscount, validateCoupon } from './discount.js';
describe('Discount Logic', () => {
it('should apply 10% discount correctly', () => {
expect(applyDiscount(100, 10)).toBe(90);
});
it('should not allow negative discounts', () => {
expect(() => applyDiscount(100, -10)).toThrow();
});
it('should validate coupon expiry', () => {
const expiredCoupon = { code: 'OLD', expiresAt: '2024-01-01' };
expect(validateCoupon(expiredCoupon)).toBe(false);
});
});
Wenn Tests existieren, kannst du sicher refactorn.
Existing Schulden abbauen
Schritt 1: Audit (Hole die Fakten)
# Code Komplexität messen
npm install complexity-report
complexity-report --format markdown . > complexity.md
# Unused Code finden
npm install unused-exports
unused-exports
# Dependencies checken
npm audit
# Test Coverage
npm test -- --coverage
Output:
- Welche Files sind am meisten Schuld?
- Welche Functions sind zu komplex?
- Welche Dependencies sind veraltet?
Schritt 2: Priorisieren (Was behindert dich am meisten?)
Frage: Wenn du einen File refactorn könntest – welcher würde Features am schnellsten machen?
Beispiel: Bekateq
Priorisiert nach: Impact on Velocity
1. Discount Logic (20% komplexer als gedacht)
2. Variant Handling (10 verschiedene Patterns)
3. Inventory Sync (5 verschiedene Quellen)
Schritt 3: Refactor mit Sicherheit
Nicht einfach rewrite!
// SICHER refactorn:
// Step 1: Write Tests (für alten Code!)
// Step 2: Refactor (mit Tests grün)
// Step 3: Deploy (Tests schützen dich)
// Step 4: Monitore (es funktioniert noch?)
// Step 5: Delete alt Code (wenn alles ok)
Beispiel: Discount Logic refactor
Before:
├─ discount.liquid (200 Zeilen Spaghetti)
├─ discount.js (300 Zeilen)
└─ discount.scss (100 Zeilen)
Process:
├─ Step 1: Write Tests für alten Code
├─ Step 2: Extract in Functions
├─ Step 3: Deploy (Tests schützen)
├─ Step 4: Weitere Extracts
├─ Step 5: Deploy
├─ Step 6: Delete alt Code
After:
├─ discount-logic.js (100 Zeilen, testbar)
├─ discount-component.jsx (50 Zeilen)
└─ discount.scss (50 Zeilen)
Kosten-Nutzen:
Refactoring: 2 Wochen
Savings: 1 Tag pro neuer Feature (für immer)
ROI: Break-even nach 3 Monaten
Schritt 4: Monitoring (Du wirst wieder Schuld machen)
Metriken für Code-Gesundheit:
- Code Coverage > 80%
- Complexity Score < 10 pro Function
- No outdated Dependencies
- Zero Security Vulnerabilities
Best Practices von smplx.
1. Architecture Review (vor jedem großen Feature)
Checkliste:
- Passt das zu unserer bestehenden Architektur?
- Brauchen wir eine neue App oder Liquid?
- Welche sind die Risiken?
- Wie testen wir das?
- Wer maintaint das?
2. Code Review (vor jedem Deploy)
## Review Checklist
- [ ] Tests grün?
- [ ] Keine Linting-Fehler?
- [ ] Performance impact ok?
- [ ] Security review?
- [ ] Dokumentation updated?
- [ ] Alte Code entfernt?
3. Quarterly Debt Assessment
# Q1 2026 Technical Debt Report
## Schuld: High
- Theme ist 2 Jahre alt (Shopify 11 → 12 notwendig)
- Discount Logic zu komplex (20+ Patterns)
- Keine Tests für Admin API Integration
## Investitionen notwendig:
1. Theme-Upgrade (2 Wochen)
2. Refactor Discount (3 Wochen)
3. Tests schreiben (2 Wochen)
## Cost-Benefit:
- Investition: 150 Dev-Hours
- Savings: ~10 Hours pro Monat (neue Features)
- ROI: 15 Monate
Die Realität: Schuld ist ok
Wichtig: Du musst nicht schuldenfrei sein!
Schuld ist ok wenn:
- Es ist bewusst (du weißt davon)
- Es ist zeitlich begrenzt (plan für Abbau)
- Es blockiert dich nicht (die Features funktionieren)
Schuld ist kritisch wenn:
- Es ist versteckt (keiner kennt den Code)
- Es hat keine Exit-Strategie
- Es blockiert neue Features
- Es verursacht ständig Bugs
Checkliste: Schuld-Vermeidung
- Entscheidungen dokumentiert
- One App = One Purpose
- Tests vorhanden
- Code ist lesbar
- Keine 5+ Apps für einfache Dinge
- Theme ist aktuell (< 1 Jahr alt)
- Dependencies aktuell
- Code Review vor Deploy
- Quarterly Debt Assessment
- Clear Refactoring Plan
Über den Autor
Claudio Gerlich ist Technical Architect bei smplx. und seit 2020 spezialisiert auf Shopify-Architektur. Mit Bekateq haben wir bewiesen: Schulden sind abbaubar, und es lohnt sich.
Technische Schulden sind keine Features-Versprechen. Sie sind deine Zukunft bestsellen.
smplx. ist Shopify Technical Partner (seit 2020) mit Sitz in Coesfeld, NRW.