layer-groupDependency Management

In line with Happen's philosophy of simplicity, our approach to dependencies emphasizes direct runtime access with minimal framework abstractions.

Core Principles

Happen's dependency management follows three key principles:

  1. Runtime Transparency: Your code has direct access to the runtime environment

  2. Minimal System Dependencies: Only essential framework dependencies (primarily NATS) are injected at initialization

  3. Event-Based Communication: Nodes interact through events, not traditional dependency injection

System-Level Dependencies

System dependencies are configured once during framework initialization:

// Initialize Happen with system-level dependencies
const happen = initializeHappen({
  // NATS configuration as the primary dependency
  nats: {
    // Direct NATS client for server environments
    server: {
      servers: ['nats://localhost:4222'],
      jetstream: true
    },
    // WebSocket client for browser environments
    browser: {
      servers: ['wss://localhost:8443'],
      jetstream: true
    }
  },
  
  // Optional: Override crypto implementation
  crypto: cryptoImplementation
});

// The initialized framework provides the node creation function
const { createNode } = happen;

These system dependencies represent the minimal set required for Happen to function across different runtime environments. By injecting them at initialization, we maintain runtime agnosticism while ensuring consistent behavior.

Direct Runtime Access

Rather than exposing a subset of features through abstraction layers, Happen encourages direct access to the runtime:

This approach provides several benefits:

  • Zero overhead: No performance penalty for accessing runtime features

  • Full capabilities: Access to everything the runtime offers, not just what the framework exposes

  • Runtime evolution: Immediate access to new runtime features without framework updates

  • Ecosystem compatibility: Works seamlessly with the broader ecosystem

Framework Agnosticism for Third-Party Libraries

When you need external libraries, import and use them directly:

Dependency Injection Through Closures

Use closures to create handlers with access to dependencies:

Flow State Through Closures

Although Happen provides a common object to share data across each flow you can also use closures to manage both dependencies and flow state, with explicit control over the flow through function returns:

How Flow Control Works With Closures

In this pattern, the flow is controlled through a clear mechanism:

  1. Each flow step returns a function: When a handler wants to continue the flow, it returns a function that becomes the next handler.

  2. Flow continues while functions are returned: The framework executes each returned function in sequence, as long as functions are being returned.

  3. Flow ends when a non-function is returned: When a handler returns anything other than a function (like an object), the flow completes with that value as the result.

  4. Dependencies and state flow through function parameters: Each step receives dependencies and state through its parameters, not through context.

  5. Each step creates the next step with updated state: Functions create and return the next function in the chain, passing updated state and dependencies.

Benefits of Closure-Based Dependency Management

This closure-based approach offers several advantages:

  1. Pure Functions: Flow handlers become pure functions with explicit dependencies

  2. Clear Data Flow: Dependencies and state are explicitly passed between functions

  3. Testability: Each flow step can be easily tested in isolation with mocked dependencies

  4. Immutability: Encourages immutable state updates through function parameters

  5. Separation of Concerns: Clearly separates framework concerns from application logic

NATS as the Primary Dependency

In the Happen framework, NATS serves as the primary dependency, providing core messaging, persistence, and coordination capabilities. This focused approach means:

  1. Single Core Dependency: NATS is the primary external dependency you need to understand

  2. Mature Ecosystem: NATS has clients for all major languages and platforms

  3. Unified Capability Set: One system provides messaging, persistence, and coordination

  4. Direct NATS Access: Your code can access NATS capabilities directly when needed

Dependency Management Philosophy

Happen's approach to dependencies reflects its broader philosophy: provide just enough framework to enable powerful capabilities, while getting out of the way and letting your code work directly with the runtime.

By limiting injected dependencies to only essential system needs (primarily NATS) and embracing direct runtime access and closure-based dependency management, Happen reduces complexity while maximizing flexibility.

There's no complex dependency injection system because, in most cases, you simply use JavaScript's natural closure mechanism to capture and pass dependencies where needed.

Last updated