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.