Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
IT Security NachrichtenICYMI: August 2026 @AWS Security(24.09.2026 um 01:31 Uhr)
IT Security NachrichtenMaintenance Company in Dubai: What to Check Before You Sign(24.09.2026 um 01:33 Uhr)
IT Security DownloadsGitHub Release: ollama/ollama v0.34.4-rc1 (24.09.2026)(24.09.2026 um 01:36 Uhr)
IT Security DownloadsGitHub Release: google-gemini/gemini-cli v0.61.0 (24.09.2026)(24.09.2026 um 01:59 Uhr)
IT Security NachrichtenICYMI: August 2026 @AWS Security(24.09.2026 um 01:31 Uhr)
IT Security NachrichtenMaintenance Company in Dubai: What to Check Before You Sign(24.09.2026 um 01:33 Uhr)
IT Security DownloadsGitHub Release: ollama/ollama v0.34.4-rc1 (24.09.2026)(24.09.2026 um 01:36 Uhr)
IT Security DownloadsGitHub Release: google-gemini/gemini-cli v0.61.0 (24.09.2026)(24.09.2026 um 01:59 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Design Patterns in a Real-World Tkinter Application: From Lateral Coupling to Clean Architecture

What you can build with Python's standard library Beyond "Hello World" Python, Tkinter, SQLite. The "batteries included" stack. Most tutorials stop at a contact list or a todo app. But this stack can do much more — p…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

What you can build with Python's standard library









Beyond "Hello World"



Python, Tkinter, SQLite. The "batteries included" stack.



Most tutorials stop at a contact list or a todo app. But this stack can do much more — production applications solving real problems, with clean architecture and proper design patterns.



This article shows how. No external GUI frameworks, no ORMs, no heavyweight dependencies. Just the standard library, good patterns, and real-world requirements.



I'll walk you through Inventarium, a laboratory inventory management system running in production at a hospital. Along the way, we'll cover:





  • Singleton (two different implementations!)


  • Observer (decoupled view communication)


  • Registry (Toplevel window management)

  • Template Method

  • Mixin Architecture



All with real code, real problems, and real solutions.









The Problem: Lateral Coupling



Picture this: You have a Warehouse window showing stock levels. You have a Delivery window where you record incoming goods. When a delivery is saved, the warehouse view needs to refresh.



The naive solution:




# In delivery.py
def on_save(self):
self.save_to_database()

# Lateral coupling: Delivery KNOWS about Warehouse
if "warehouse" in self.engine.dict_instances:
warehouse = self.engine.dict_instances["warehouse"]
warehouse.refresh_batches()






This works. But now add:





  • Expiring view (shows batches about to expire)


  • Stocks view (shows stock levels)


  • Requests view (shows pending orders)



Suddenly, Delivery needs to know about all of them:




# This is getting ugly...
def on_save(self):
self.save_to_database()

if "warehouse" in self.engine.dict_instances:
self.engine.dict_instances["warehouse"].refresh_batches()
if "expiring" in self.engine.dict_instances:
self.engine.dict_instances["expiring"].refresh()
if "stocks" in self.engine.dict_instances:
self.engine.dict_instances["stocks"].refresh()
# And on and on...






This is lateral coupling — modules that should be independent are now tangled together. Adding a new view means modifying every module that might affect it.









Solution: The Observer Pattern



The fix is elegant: instead of "push" (delivery tells everyone), use "pull" (interested parties subscribe).






The Subject (Engine)






class Engine(DBMS, Controller, Tools, Launcher, metaclass=_EngineMeta):
"""Main orchestrator with event system."""

def __init__(self, database: str, autocommit: bool = True):
super().__init__(database=database, autocommit=autocommit)

# Event system: event_name -> [callbacks]
self._subscribers = {}

def subscribe(self, event: str, callback) -> None:
"""Register a callback for an event."""
if event not in self._subscribers:
self._subscribers[event] = []
if callback not in self._subscribers[event]:
self._subscribers[event].append(callback)

def unsubscribe(self, event: str, callback) -> None:
"""Remove a callback from an event."""
if event in self._subscribers:
try:
self._subscribers[event].remove(callback)
except ValueError:
pass

def notify(self, event: str, data=None) -> None:
"""Notify all subscribers of an event."""
for callback in self._subscribers.get(event, []):
try:
callback(data)
except Exception:
pass # Subscriber might be dead, ignore









The Publisher (Delivery)






# In delivery.py - clean and simple
def on_save(self):
self.save_to_database()

# Delivery doesn't know WHO listens, just WHAT happened
self.engine.notify("stock_changed")









The Subscribers (Warehouse, Expiring, etc.)






# In warehouse.py
class UI(ParentView):
def __init__(self, parent):
super().__init__(parent, name="warehouse")
if self._reusing:
return

# Subscribe to events we care about
self.engine.subscribe("stock_changed", self.on_stock_changed)
self.engine.subscribe("batch_cancelled", self.on_stock_changed)

self.init_ui()
self.show()

def on_stock_changed(self, data=None):
"""React to stock changes from any source."""
self.refresh_batches()

def on_cancel(self, evt=None):
# Clean up subscriptions before closing
self.engine.unsubscribe("stock_changed", self.on_stock_changed)
self.engine.unsubscribe("batch_cancelled", self.on_stock_changed)
super().on_cancel()









The Events



Inventarium uses these events:






































Event Fired by Subscribers
stock_changed Delivery Warehouse, Stocks
batch_cancelled Expiring Warehouse
category_changed Category Warehouse, Products
package_changed Package Warehouse
request_changed Requests Delivery


Now adding a new view is trivial — just subscribe to the events you care about. No existing code needs to change.









Singleton: Three Ways



Tkinter has a classic problem: users double-click menu items and create duplicate windows. Here are three approaches I use:






1. Singleton via __new__ (ParentView)



For main windows (Warehouse, Products, Suppliers), I use __new__ to intercept instance creation:




class ParentView(tk.Toplevel):
"""Base class for main views with singleton behavior."""

_instance = None

def __new__(cls, parent, *args, **kwargs):
# If instance exists and is alive, reuse it
if cls._instance is not None:
try:
if cls._instance.winfo_exists():
cls._instance.lift()
cls._instance.focus_set()
return cls._instance
except Exception:
pass

# Create new instance
obj = super().__new__(cls)
cls._instance = obj
return obj

def __init__(self, parent, name=None):
# Guard against re-initialization
self._reusing = getattr(self, "_is_init", False)
if self._reusing:
return

super().__init__(name=name)
self._is_init = True

# Anti-flash: hide during construction
self.attributes("-alpha", 0.0)

self.parent = parent
self.engine = self.nametowidget(".").engine

def show(self):
"""Show window after construction."""
self.deiconify()
self.attributes("-alpha", 1.0)

def on_cancel(self, evt=None):
"""Clean up singleton reference."""
type(self)._instance = None
self._is_init = False
self.destroy()






Usage is clean:




class UI(ParentView):
def __init__(self, parent):
super().__init__(parent, name="warehouse")

if self._reusing:
return # Window already exists, nothing to do

# ... setup UI ...
self.show()









2. Registry Pattern (ChildView)



For dialogs (edit forms, detail views), I use a registry to prevent duplicate windows — we want one instance per dialog type, and if the user tries to open another, we close the existing one first:




class ChildView(tk.Toplevel):
"""Base class for CRUD dialogs with registry."""

def __init__(self, parent, name=None):
super().__init__(name=name)

self.parent = parent
self.engine = self.nametowidget(".").engine
self._dialog_name = name

# Register in global registry to track open windows
if name:
self.engine.dict_instances[name] = self

def on_cancel(self, evt=None):
# Unregister on close
if self._dialog_name:
self.engine.dict_instances.pop(self._dialog_name, None)
self.destroy()






The caller checks the registry before opening:




def on_edit(self):
# Close existing dialog if open
self.engine.close_instance("product")

# Open new one
obj = product.UI(self, index=product_id)
obj.on_open(selected)









3. Metaclass Singleton (Engine)



For the Engine class (the application's brain), I use a metaclass — the "proper" Python way:




class _EngineMeta(type):
"""Metaclass ensuring single Engine instance."""

_instance = None

def __call__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__call__(*args, **kwargs)
return cls._instance


class Engine(DBMS, Controller, Tools, Launcher, metaclass=_EngineMeta):
"""Main orchestrator - singleton via metaclass."""
pass






This intercepts creation before __new__ and __init__ — the cleanest possible Singleton.




Note: The metaclass is "educational" in Inventarium since Engine is only instantiated once in App. But it demonstrates the pattern and protects against accidents.










Template Method: ParentView and ChildView



Both base classes implement the Template Method pattern — they define the skeleton, subclasses fill in the details:




┌─────────────────────────────────────────┐
│ ParentView │
├─────────────────────────────────────────┤
│ __new__() → Singleton logic │
│ __init__() → Anti-flash setup │
│ show() → Display window │
│ on_cancel() → Cleanup + destroy │
├─────────────────────────────────────────┤
│ Subclass provides: │
│ • init_ui() → Build the interface │
│ • Event handlers │
└─────────────────────────────────────────┘






Every window follows the same lifecycle:




class UI(ParentView):
def __init__(self, parent):
super().__init__(parent, name="myview")
if self._reusing:
return

self.protocol("WM_DELETE_WINDOW", self.on_cancel)
self.init_ui() # Subclass builds UI
self.engine.center_window(self)
self.show() # Template method

def init_ui(self):
# Subclass-specific UI code
pass

def on_cancel(self, evt=None):
# Subclass cleanup...
super().on_cancel() # Template method












Mixin Architecture: The Engine



Engine combines four specialized mixins via multiple inheritance:




class Engine(DBMS, Controller, Tools, Launcher, metaclass=_EngineMeta):
"""
Mixin Architecture (in MRO order):
1. DBMS: Database connection and queries
2. Controller: SQL builders and domain logic
3. Tools: Shared utilities
4. Launcher: Cross-platform file opener
"""
pass






Each mixin has a single responsibility:




























Mixin Responsibility
DBMS
read(), write(), execute()
Controller
get_stock(), build_sql(), domain queries
Tools
center_window(), set_icon(), validation
Launcher
launch() — open files with default app


Views access everything through one interface:




# In any view
self.engine.read(True, sql, params) # From DBMS
self.engine.get_stock() # From Controller
self.engine.center_window(self) # From Tools
self.engine.launch(filepath) # From Launcher












Key Takeaways




  1. Observer eliminates lateral coupling — publishers don't know subscribers, subscribers don't know publishers. Just events.


  2. Singleton has multiple valid implementations__new__ for simplicity, metaclass for purity, registry for context-sensitive uniqueness.


  3. Template Method creates consistency — every window follows the same lifecycle, reducing cognitive load.


  4. Mixins compose behavior — instead of deep inheritance hierarchies, combine focused capabilities.


  5. Real code teaches better than tutorials — patterns emerge from solving actual problems, not from contrived examples.










Try It Yourself



The full source is on GitHub: github.com/1966bc/inventarium



It's a working application managing real laboratory inventory — proof that Python's "batteries included" philosophy extends beyond tutorials to real-world, maintainable software.



Browse the code, steal the patterns, file issues if you find bugs.



Python + Tkinter + SQLite + Design Patterns = Production-ready applications.






Giuseppe Costanzi (@1966bc) is a biomedical laboratory technician at Sant'Andrea University Hospital, Mass Spectrometry Lab, in Rome. Inventarium is his solution for managing IVD product inventory.



This project was developed in collaboration with Claude (Anthropic). The AI pair-programming approach allowed focusing on architecture and functionality rather than getting bogged down in boilerplate code and syntax details — a workflow that proved transformative for development productivity.

CTI Threat Relationship Graph2 Knoten / 1 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
IR-PLAYBOOK-RCE
HIGH
SOC Incident Playbook: Remote Code Execution (RCE) Defense
1-Click Detection Engineering: Sigma & YARA Rules
SOC Ready
title: Detect Exploitation - Design Patterns in a Real-World Tkinter Application: From Lateral Coupling to Clean Architecture
id: 87d82ad7-53fb-40a0-8faa-4cdc0bb2568b
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "Design Patterns in a Real-Worl" ascii wide
    condition:
        any of them
}
Infrastructure Blast Radius & Exposure
CATASTROPHIC
Perimeter & External Ingress
GEFÄHRDET (85%)
Lateral Movement & Pivot
GEFÄHRDET (90%)
Data Stores & Crown Jewels
GEFÄHRDET (95%)
Supply Chain & Cascading Reach
GEFÄHRDET (100%)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Design Patterns in a Real-World Tkinter Application: From Lateral Coupling to Clean Architecture

Thematisch verwandte Begriffe: Design, Patterns, RealWorld, Tkinter · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-96676 | A vulnerability was identified in Fast FAC1900R 20190827_2.0.2. The impa…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick