A configuration-driven, event-driven computation engine that models computation as an explicit Directed Acyclic Graph (DAG) of Topics and Agents.
The project explores how strong architectural constraints (DAG enforcement, explicit dataflow, isolated execution units, and separation of concerns) can significantly improve reasoning, debuggability, and correctness in event-driven systems.
- ☕ Java 17+ (or compatible JDK)
- 📦 Maven 3.6+
-
Clone the repository
git clone <repository-url> cd Design_MVC
-
Build and start the application
mvn spring-boot:run
-
Open the UI in your browser
http://localhost:8080/ -
Use the application
- Click Load Config to load the demo computation graph
- Enter a topic name (e.g.
A) and a value (e.g.5), then click Publish - Watch the graph highlight in real time as events propagate through the DAG
- View the Event Log panel for a live stream of all system events
- Click Clear on any topic to reset its value and observe downstream effects
Event-driven systems often become difficult to reason about due to:
- ❌ Implicit mutable state hidden inside callbacks
- 🔁 Cyclic dependencies and uncontrolled feedback loops
- 🔗 Tight coupling between computation, orchestration, and presentation
- ⏱ Execution behavior depending on timing and scheduling rather than structure
This project explores an alternative design philosophy:
🧠 Make the computation graph an explicit, validated, first-class architectural artifact.
Instead of relying on conventions or discipline, the system enforces structural constraints up-front and pushes complexity to configuration validation time, not runtime.
- 🌳 Graph topology derived from configuration
- 🔍 Validated using DFS-based cycle detection
- 🚫 Cyclic graphs rejected before execution begins
This guarantees:
- ✅ Termination
- 🛑 No feedback loops
- 📐 Structural correctness by construction
- 🧠 Agents implement a narrow computation interface
- 📥 Inputs and 📤 outputs are explicit via Topics
- 🔗 No implicit coupling between Agents
ℹ️ Some agents maintain explicit, local input state (e.g., fan-in agents).
State is visible, bounded, and intentional — never global or hidden.
- 📡 Fan-out: Topics broadcast events to multiple downstream Agents
- 🧮 Fan-in: Agents wait for multiple required inputs before publishing
- 🏛 Dependencies are structural, not temporal
- 🗂 Graph structure defined declaratively at runtime
- 🔌 Wiring fully decoupled from Agent implementation
- 🏭 Agents instantiated dynamically via reflection
- 🧩 Model — Topics, Agents, Graph, execution semantics
- 🎛 Controller — REST API for config loading & event publishing
- 🖥 View — Cytoscape.js visualization via SSE
The domain model is completely unaware of HTTP, JSON, or UI concerns.
- Named, stateless pub/sub channels
- 📢 Fan-out events synchronously to subscribed Agents
- 🧼 No message history persistence
- 🗃 Managed centrally via TopicManager
- Reactive computation units
- 📥 Subscribe to input Topics
- 📤 Publish to output Topics
- 🔄 Driven purely by events (no direct invocation)
- 🆔 Uniquely identified per configuration
- 🔐 Immutable payloads
- ⚡ Delivered synchronously at Topic level
- 🔒 Cascading execution structurally bounded by DAG
- 📂 Load textual configuration
- 🏗 Instantiate Agents via reflection
- 🔌 Wire Agents and Topics into a bipartite graph
- 🔍 Validate acyclicity (fail-fast)
- 🧵 Wrap Agents with execution decorator
- 🌐 Publish input events via REST
- ⚡ Event-driven cascade across graph
- 🛑 Guaranteed termination due to DAG constraint
- Each Agent wrapped using Active Object–style decorator
- 🧵 Dedicated worker thread + bounded queue per Agent
- 🔐 Serialized execution per Agent
Provides:
- 🛡 Isolation between Agents
- 📏 Predictable per-Agent execution semantics
- 🚦 Backpressure via bounded queues
Important clarification:
⚠️ No globally deterministic execution order across Agents.
Determinism is structural (termination, DAG correctness) and per-Agent, not system-wide scheduling.
This trade-off is deliberate and explicit.
This project composes patterns to enforce architectural constraints, not to showcase patterns superficially.
- 📢 Publish–Subscribe — Topics notify Agents without coupling
- 🎯 Strategy — Agents encapsulate computation logic
- 🧵 Decorator + Active Object — Separate execution from logic
- 🏭 Factory (Reflection-Based) — Dynamic Agent instantiation
- 🗂 Singleton — TopicManager enforces namespace consistency
- 🪶 Flyweight (Partial) — Shared Topics preserve identity
- 🧱 Facade — REST controller simplifies orchestration
configs.PlusAgent
A,B
S
configs.IncAgent
S
S1
- 🏛 Architectural constraint design
- 📊 Explicit dataflow modeling
- 🛑 Fail-fast validation
- 🔐 Isolated execution units
- 🧱 Clean MVC separation
- 📡 Live operational visibility (SSE + graph visualization)
- 🚫 No feedback loops (by design)
- 🔀 No global execution ordering guarantees
- 🖥 Single-process JVM runtime
- 💾 No persistence or event replay
- 📬 At-most-once delivery semantics
These trade-offs prioritize:
- 🧠 Structural correctness
- 🔎 Debuggability
- 📐 Predictability
over maximal expressiveness or distributed throughput.
- 🧮 Deterministic schedulers / topological execution
- 🌍 Distributed Topics (Kafka / Redis Streams)
- 🧠 Stateful Agents with lifecycle management
- 🔁 Retry policies + dead-letter Topics
- 📊 Metrics, tracing, and critical-path analysis
- 🧾 Static configuration linting
- 🎓 Engineers learning event-driven & dataflow architectures
- 💼 Portfolio reviewers evaluating system-level thinking
- 🧱 Developers building workflow/orchestration engines
Constraining a system correctly often matters more than making it more powerful.
Explicit structure and validation dramatically simplify reasoning about complex event-driven behavior.
🚀 Designed & Implemented by
Shaked Arazi
Architectural design, concurrency model, validation engine, and execution semantics crafted with a strong emphasis on structural correctness and explicit dataflow thinking.