smplx.
Shopify Architektur

Technische Schulden in Shopify vermeiden: Architektur-Prinzipien [2026]

Claudio Gerlich··12 min

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

  1. Time Pressure: "Wir brauchen das Feature bis Freitag!" → Quick & Dirty Lösung → Morgen ein Bug → Patch darauf → Nach 6 Monaten: Unmaintainbar

  2. 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

  3. 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

  4. Outdated Themes: "Lass uns das alte Theme behalten" → Alte Theme-Version → Neue Features nicht möglich → Security-Updates verpassen → Nach 2 Jahren: Breakage

  5. 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.