Naming Conventions in Datenprojekten: Klein, aber teuer
Es gibt diesen Moment, den wohl jeder kennt, der länger als ein paar Monate in einem Datenprojekt gearbeitet hat. Du öffnest ein SQL-Query, das du selbst geschrieben hast, vor sechs Monaten. Und da steht: SELECT t1.val, t2.amt FROM tbl1 t1 JOIN tbl2 t2 ON t1.id = t2.ref.
Was ist val? Was ist amt? Welche Tabelle ist tbl1? Ist ref ein Foreign Key oder irgendein interner Referenzcode?
Keine Ahnung. Du musst erstmal graben. Die Datenbank befragen. Alte Jira-Tickets durchsuchen. Jemanden fragen, der vielleicht noch weiß, was damals gemeint war.
Das ist nicht ein Problem von schlechtem Code, das ist ein Problem von schlechten Namen.
Warum Namen so viel ausmachen
Namen sind Kommunikation. Jedes Mal, wenn du eine Spalte dt statt transaction_date nennst, oder eine Tabelle tmp statt orders_staging, triffst du eine Entscheidung: Du sparst ein paar Sekunden beim Tippen und kostest deinen zukünftigen Kollegen (oder dich selbst) Minuten oder Stunden beim Verstehen.
Das klingt dramatisch. Aber addier mal die Minuten, die du pro Woche damit verbringst, Abkürzungen aufzulösen, Spaltennamen nachzuschlagen oder ein Datenmodell zu reverse-engineeren, weil die Namen nichts verraten.
Und dann das Onboarding. Jemand Neues kommt ins Team. Du gibst ihm Zugang zum Data Warehouse. Die erste Frage, die er nach zehn Minuten stellt: “Was bedeutet eigentlich cust_ref_ext_id?”
Der erste Grundsatz: Sei beschreibend, nicht kurz
Abkürzungen sind verlockend. amt, qty, dt, desc. Klingt effizient. Ist es aber nicht.
Das Problem: Abkürzungen sind nicht universell. In einem Team bedeutet desc vielleicht description. Im nächsten descending. Und amt, ist das amount? In welcher Einheit? Euro? Cent? Tausend Euro?
Wenn du order_amount_eur schreibst, ist das klar. Wenn du amt schreibst, öffnest du eine Interpretationslücke.
Das gilt besonders für Datumsfelder. dt, ts, created: all das ist zu vage. Besser:
created_atfür den Erstellungszeitpunkt (mit Uhrzeit)order_datefür ein Datum ohne Uhrzeitprocessed_atfür den Verarbeitungszeitpunkt
Wer diese Felder sieht, muss nicht nachdenken.
Snake Case für alles
Das ist eigentlich keine Diskussion wert, aber ich führe sie trotzdem, weil man immer wieder auf camelCase oder PascalCase in SQL trifft.
Verwende snake_case. Überall. Für Tabellennamen, Spaltennamen, Schemata, Views.
Warum? Weil SQL case-insensitiv ist, viele Datenbanken aber case-sensitiv bei Identifier-Handling werden, sobald du Anführungszeichen verwendest. CustomerID und customerid können in PostgreSQL zwei verschiedene Dinge sein. customer_id ist immer customer_id.
Und mal ehrlich: customer_lifetime_value liest sich schöner als CustomerLifetimeValue in einem SQL-Kontext.
Konsistente Suffixe für Typen
Eine Convention, die ich für sehr wertvoll halte: Typ-Suffixe für Datums- und Zeitfelder.
_at→ Timestamp mit Zeitzone (created_at,updated_at,shipped_at)_date→ reines Datum ohne Uhrzeit (birth_date,invoice_date)_ts→ wenn du wirklich einen Unix-Timestamp meinst (selten nötig, aber dann klar)
Wer das konsequent durchzieht, erkennt sofort, welche Felder ein Datum liefern und welche einen vollständigen Zeitstempel. Das macht Joins, Filterungen und Aggregationen intuitiver.
Ähnlich nützlich: Suffixe für IDs.
_id→ interner Primärschlüssel (user_id,order_id)_key→ natürlicher Business-Schlüssel (product_key,customer_key)_ref→ externe Referenznummer (payment_ref,tracking_ref)
Das ist keine starre Regel. Aber wenn du und dein Team euch einmal einigt, sparst du euch viele “Was ist das jetzt eigentlich?”-Gespräche.
Tabellen: Plural, Layer, Domäne
Tabellennamen erzählen, was in der Tabelle steckt und wo sie im Datenfluss sitzt.
Ein einfaches Schema, das ich empfehle:
<layer>_<domain>_<entity>
Beispiele:
raw_ecommerce_orders: Rohdaten aus dem E-Commerce-Systemstg_ecommerce_orders: gestagete, gereinigte Versiondim_customers: Dimension-Tabelle für Kundenfct_orders: Faktentabelle für Bestellungenmart_revenue_monthly: fertige Kennzahlen für den Revenue-Bericht
Das klingt zunächst nach Overhead. Aber sobald du dreißig Tabellen im Warehouse hast, ist dieses Naming der Unterschied zwischen “Ich sehe sofort, was wo sitzt” und “Ich brauche zwanzig Minuten, um den Datenfluss nachzuvollziehen”.
Konsistenz schlägt Perfektion
Die perfekte Convention zu suchen ist die falsche Priorität. Eine wählen und durchhalten reicht.
customer_id oder cust_id, beides ist vertretbar. Aber wenn du in einer Tabelle customer_id hast und im nächsten Join auf cust_id joinen musst, verlierst du den Faden. Einer muss sich ändern, oder du baust explizite Aliase ein. Beides kostet.
Schreib die Conventions auf. Eine halbe Seite in deinem Team-Wiki reicht. Nicht um Bürokratie zu schaffen, sondern um neuen Leuten und deinem Zukunfts-Ich eine Orientierung zu geben.
Wann umbenennen und wann nicht
Manchmal übernimmst du ein Datenprojekt und stellst fest: Die Namen sind… suboptimal. Tabellen heißen tbl_A und tbl_B. Spalten heißen f1, f2, val.
Umbenennen?
Meine Einschätzung: Wenn das Projekt jung ist und die Namen wirklich opak, dann ja. Leg einen Migrationssprint ein, taufe alles vernünftig um, dokumentiere die Änderungen und mach weiter.
Wenn das Projekt aber schon groß ist und die Namen tief in Dashboards, Reports und externen Systemen stecken, dann sei vorsichtig. Ein großes Rename kann mehr kaputtmachen als es bringt. Manchmal ist der vernünftigere Weg, eine saubere View-Schicht mit guten Namen draufzulegen und die alten Tabellen für Kompatibilität stehen zu lassen.
Namen ändern sich nicht von selbst. Aber mit einer halben Stunde Nachdenken und ein paar Zeilen im Wiki kannst du dafür sorgen, dass dein Datenprojekt auch in einem Jahr noch lesbar ist.