Skip to main content

Architecture Overview

Layer model

DAF follows a layered architecture. Six of its modules split their contracts into an Abstractions companion package, so app code can depend on interfaces alone:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Your Application             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Application  β”‚  Hosting  β”‚  MediatR    β”‚  ← Composition
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Logging β”‚   Config  β”‚   DI    β”‚ NNLog  β”‚  ← Services
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚         Commons Β· Rtti Β· Threading      β”‚  ← Foundation
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Abstractions pattern

Configuration, DependencyInjection, Hosting, Logging, MediatR and SQLCute ship as a pair:

Package Role
Daf.X.Abstractions Interfaces only β€” no implementation
Daf.X Concrete implementation + registration helpers

Your app code depends only on Abstractions. Implementations are swappable at composition root.

Dependency flow

Application
  └── Hosting
        β”œβ”€β”€ DependencyInjection
        β”œβ”€β”€ Configuration
        └── Logging
              └── NNLog (provider)

Testing with MiniSpec

MiniSpec is independent of the rest of the stack. It can test any Delphi code using Gherkin-style specs:

Feature('Calculator')
  .UseWorld<TCalculatorWorld>
  .Scenario('Add two numbers')
    .Given('I have a calculator', procedure(World: TCalculatorWorld)
      begin
        World.Calculator := TCalculator.Create;
      end)
    .When('I add 2 and 3', procedure(World: TCalculatorWorld)
      begin
        World.Calculator.Add(2, 3);
      end)
    .&Then('the result is 5', procedure(World: TCalculatorWorld)
      begin
        Expect(World.Calculator.Result).ToEqual(5);
      end);

&Then carries the ampersand because then is a Delphi keyword, and UseWorld<T> comes first because it is what gives every step its World. The runnable version is src/MiniSpec/samples/CalculatorSpecs.

See the MiniSpec module for the full guide.