Skip to content

abitofhelp/hybrid_lib_ada

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

122 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Hybrid DDD/Clean/Hexagonal library starter for Ada 2022

License Ada SPARK

Version: 2.0.0
Date: December 10, 2025
SPDX-License-Identifier: BSD-3-Clause License File: See the LICENSE file in the project root Copyright: Β© 2025 Michael Gardner, A Bit of Help, Inc.
Status: Released

Overview

Hybrid_Lib_Ada is a professional Ada 2022 library demonstrating hybrid DDD/Clean/Hexagonal architecture with functional error handling.

Key Capabilities:

  • 4-layer hexagonal architecture (Domain, Application, Infrastructure, API)
  • Functional error handling via Result monad (no exceptions)
  • Three-package API pattern for flexible dependency injection
  • Generic I/O plugin pattern for platform portability
  • Embedded-safe design (no heap allocation, bounded types)
  • SPARK-compatible for formal verification
  • Cross-platform: Linux, macOS, Windows, Embedded

SPARK Formal Verification

Status SPARK Proved
Scope API.Operations generic package (SPARK_Mode On)
Mode gnatprove --mode=prove --level=2
Results See CHANGELOG for current proof statistics

Verification Commands

make spark-check    # Run SPARK legality verification
make spark-prove    # Run full SPARK proof verification

Features

  • βœ… 4-layer hexagonal architecture
  • βœ… Result monad error handling (no exceptions across boundaries)
  • βœ… Static dependency injection via generics (zero runtime overhead)
  • βœ… Three-package API pattern (Operations + Desktop + facade)
  • βœ… Generic I/O plugin pattern for platform portability
  • βœ… Embedded safety restrictions (no heap allocation)
  • βœ… SPARK-compatible design (see SPARK section above)
  • βœ… Comprehensive documentation with UML diagrams
  • βœ… Test framework (see CHANGELOG)
  • βœ… Example programs (basic_greeting, error_handling)
  • βœ… Windows CI with GitHub Actions
  • βœ… 6 build profiles (standard, concurrent, embedded, baremetal, STM32)

Architecture

4-Layer Hexagonal Architecture

        Consumer Application
                ↓
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚              API LAYER (Public Facade)        β”‚
        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
        β”‚  β”‚ API + Operationsβ”‚    API.Desktop         β”‚ β”‚
        β”‚  β”‚ (facade)        β”‚  (composition root)    β”‚ β”‚
        β”‚  β”‚                 β”‚  Wires Infrastructure  β”‚ β”‚
        β”‚  β”‚ Depends on:     β”‚  Depends on:           β”‚ β”‚
        β”‚  β”‚ App + Domain    β”‚  ALL layers            β”‚ β”‚
        β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚              INFRASTRUCTURE LAYER             β”‚
        β”‚  Adapters: Console_Writer                     β”‚
        β”‚  Depends on: Application + Domain             β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚               APPLICATION LAYER               β”‚
        β”‚  Use Cases: Greet | Commands | Ports          β”‚
        β”‚  Depends on: Domain only                      β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚                 DOMAIN LAYER                  β”‚
        β”‚  Value Objects: Person | Error: Result monad  β”‚
        β”‚  Depends on: NOTHING (zero dependencies)      β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Design Principles:

  • Dependencies flow inward (toward Domain)
  • Domain layer has zero external dependencies
  • Infrastructure implements ports defined in Application
  • API facade depends on Application + Domain ONLY (no Infrastructure)
  • API.Desktop is a composition root that wires Infrastructure
  • Generic I/O plugin pattern enables platform portability
  • Static dispatch via generics (zero runtime overhead)

Project Structure

Hybrid_Lib_Ada/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ api/                        # Public Interface
β”‚   β”‚   β”œβ”€β”€ hybrid_lib_ada-api.ads  # Facade: re-exports + Greet operation
β”‚   β”‚   β”œβ”€β”€ operations/             # Generic operations (DI pattern)
β”‚   β”‚   └── desktop/                # Desktop composition root
β”‚   β”‚
β”‚   β”œβ”€β”€ application/                # Use Cases & Ports
β”‚   β”‚   β”œβ”€β”€ command/                # Input DTOs (Greet_Command)
β”‚   β”‚   β”œβ”€β”€ port/                   # Port interfaces (in/out)
β”‚   β”‚   └── usecase/                # Use case orchestration (Greet)
β”‚   β”‚
β”‚   β”œβ”€β”€ infrastructure/             # Adapters
β”‚   β”‚   └── adapter/                # Console_Writer implementation
β”‚   β”‚
β”‚   β”œβ”€β”€ domain/                     # Pure Business Logic
β”‚   β”‚   β”œβ”€β”€ error/                  # Error types & Result monad
β”‚   β”‚   └── value_object/           # Person value object
β”‚   β”‚
β”‚   └── hybrid_lib_ada.ads          # Root package
β”‚
β”œβ”€β”€ examples/                       # Example Programs
β”‚   β”œβ”€β”€ basic_greeting.adb          # Simple greeting example
β”‚   └── error_handling.adb          # Result monad error handling
β”‚
β”œβ”€β”€ test/                           # Test Suite
β”‚   β”œβ”€β”€ unit/                       # 99 unit tests
β”‚   └── integration/                # 10 integration tests
β”‚
β”œβ”€β”€ docs/                           # Documentation (submodule)
β”‚   β”œβ”€β”€ formal/                     # SRS, SDS, STG
β”‚   β”œβ”€β”€ guides/                     # Developer guides
β”‚   └── diagrams/                   # UML diagrams
β”‚
β”œβ”€β”€ config/profiles/                # Build profiles
β”‚   β”œβ”€β”€ standard/                   # Desktop/server (default)
β”‚   β”œβ”€β”€ concurrent/                 # Multi-threaded server
β”‚   β”œβ”€β”€ embedded/                   # Ravenscar embedded
β”‚   β”œβ”€β”€ baremetal/                  # Zero footprint (ZFP)
β”‚   β”œβ”€β”€ stm32h7s78/                 # STM32H7S78-DK
β”‚   └── stm32mp135_linux/           # STM32MP135F-DK (Linux MPU)
β”‚
β”œβ”€β”€ hybrid_lib_ada.gpr              # Main library project
β”œβ”€β”€ hybrid_lib_ada_internal.gpr     # Internal project (tests + examples)
β”œβ”€β”€ alire.toml                      # Alire manifest
└── Makefile                        # Build automation

Three-Package API Pattern

-- 1. API.Operations - Generic operations (SPARK-safe, no Infrastructure)
generic
   with function Writer (Message : String) return Unit_Result.Result;
package Hybrid_Lib_Ada.API.Operations is
   function Greet (Cmd : Greet_Command) return Unit_Result.Result;
end Hybrid_Lib_Ada.API.Operations;

-- 2. API.Desktop - Desktop composition root (wires Console_Writer)
package Hybrid_Lib_Ada.API.Desktop is
   function Greet (Cmd : Greet_Command) return Unit_Result.Result;
end Hybrid_Lib_Ada.API.Desktop;

-- 3. API - Public facade (convenience wrapper)
package Hybrid_Lib_Ada.API is
   function Greet (Cmd : Greet_Command) return Unit_Result.Result;
   -- Delegates to API.Desktop.Greet
end Hybrid_Lib_Ada.API;

Benefits:

  • Library users get simple API facade by default
  • Advanced users can inject custom I/O adapters via API.Operations
  • Zero runtime overhead (compile-time polymorphism)
  • SPARK-compatible (API.Operations has SPARK_Mode On)

Platform Support

Platform Status Notes
Linux βœ… Full Fully supported
macOS βœ… Full Primary development platform
BSD βœ… Full Fully supported
Windows βœ… Full Windows 11+ (CI tested)
Embedded πŸ”§ Stub Custom adapter required

Quick Start

Using Alire (Recommended)

# Add to your project
alr with hybrid_lib_ada

# Or get standalone
alr get hybrid_lib_ada
cd hybrid_lib_ada_*
alr build

Manual Installation

git clone --recurse-submodules https://github.com/abitofhelp/hybrid_lib_ada.git
cd hybrid_lib_ada
alr build

Prerequisites

  • Alire 2.0+ (Ada package manager)
  • GNAT 13+ (via Alire toolchain)
  • Make (for convenience targets)

Usage

Basic Greeting

with Ada.Text_IO;
with Hybrid_Lib_Ada.API;

procedure My_First_Greeting is
   use Ada.Text_IO;
   use Hybrid_Lib_Ada.API;

   Cmd    : constant Greet_Command := Create_Greet_Command ("Alice");
   Result : constant Unit_Result.Result := Greet (Cmd);
begin
   if Unit_Result.Is_Ok (Result) then
      Put_Line ("Greeting succeeded!");
   else
      declare
         Err : constant Error_Type := Unit_Result.Error_Info (Result);
      begin
         Put_Line ("Error: " & Error_Strings.To_String (Err.Message));
      end;
   end if;
end My_First_Greeting;

Output:

Hello, Alice!
Greeting succeeded!

Error Handling with Result Monad

with Hybrid_Lib_Ada.API;

procedure Error_Example is
   use Hybrid_Lib_Ada.API;

   -- Empty name triggers validation error
   Result : constant Unit_Result.Result :=
     Greet (Create_Greet_Command (""));
begin
   if Unit_Result.Is_Error (Result) then
      declare
         Err : constant Error_Type := Unit_Result.Error_Info (Result);
      begin
         -- Err.Kind = Validation_Error
         -- Err.Message = "Name cannot be empty"
      end;
   end if;
end Error_Example;

Custom I/O Adapter (Advanced)

with Hybrid_Lib_Ada.API.Operations;
with My_Custom_Writer;

procedure Custom_Output is
   package My_Ops is new Hybrid_Lib_Ada.API.Operations
     (Writer => My_Custom_Writer.Write);

   use Hybrid_Lib_Ada.API;
   Cmd    : constant Greet_Command := Create_Greet_Command ("Bob");
   Result : Unit_Result.Result;
begin
   Result := My_Ops.Greet (Cmd);
end Custom_Output;

Testing

Test Type Count Location Purpose
Unit 99 test/unit/ Domain & Application logic
Integration 10 test/integration/ Cross-layer interactions
Total 109 100% passing
# Run all tests
make test-all

# Run specific test level
make test-unit
make test-integration

# Code quality
make check-arch          # Validate architecture boundaries

Examples

# Build examples
alr exec -- gprbuild -P examples/examples.gpr

# Run basic greeting
./examples/bin/basic_greeting

# Run error handling demonstration
./examples/bin/error_handling

Build Profiles

Profile Target Platform RAM String Limits Contracts Debug
standard Desktop/Server 1+ GB 128/256/512 Yes Yes
concurrent Multi-threaded Server 1+ GB 128/256/512 Yes Yes
stm32mp135_linux STM32MP135F-DK (Linux MPU) 512 MB 128/256/512 Yes Yes
embedded Ravenscar Embedded 512KB-1MB 64/128/256 Yes No
stm32h7s78 STM32H7S78-DK 620KB+32MB 64/128/256 Yes Yes
baremetal Zero Footprint (ZFP) 128KB-256KB 32/64/128 No No
# Build with specific profile
alr build -- -XHYBRID_LIB_PROFILE=embedded

Documentation

Diagrams

  • docs/diagrams/library_architecture.svg - 4-layer architecture overview
  • docs/diagrams/ada/api_reexport_pattern_ada.svg - Three-package API pattern
  • docs/diagrams/ada/package_structure_ada.svg - Package structure
  • docs/diagrams/ada/error_handling_flow_ada.svg - Error propagation
  • docs/diagrams/ada/static_dispatch_ada.svg - Static DI with generics
  • docs/diagrams/ada/three_package_api_ada.svg - API composition pattern

Dependencies

Dependency Version Purpose
functional ^3.0.0 Result monad and Option types

Submodule Management

This project uses git submodules for shared tooling:

  • docs - Shared documentation templates and guides
  • scripts/python - Build, release, and architecture scripts
  • test/python - Shared test fixtures and configuration

Commands

# After fresh clone
make submodule-init

# Pull latest from submodule repos
make submodule-update

# Check current submodule commits
make submodule-status

Code Standards

This project follows:

  • Ada Agent (~/.claude/agents/ada.md) - Ada 2022 standards
  • Architecture Agent (~/.claude/agents/architecture.md) - DDD/Clean/Hexagonal
  • Functional Agent (~/.claude/agents/functional.md) - Result/Option patterns
  • SPARK Agent (~/.claude/agents/spark.md) - Formal verification patterns

Contributing

This project is not open to external contributions at this time.

AI Assistance & Authorship

This project β€” including its source code, tests, documentation, and other deliverables β€” is designed, implemented, and maintained by human developers, with Michael Gardner as the Principal Software Engineer and project lead.

We use AI coding assistants (such as OpenAI GPT models and Anthropic Claude Code) as part of the development workflow to help with:

  • drafting and refactoring code and tests,
  • exploring design and implementation alternatives,
  • generating or refining documentation and examples,
  • and performing tedious and error-prone chores.

AI systems are treated as tools, not authors. All changes are reviewed, adapted, and integrated by the human maintainers, who remain fully responsible for the architecture, correctness, and licensing of this project.

License

Copyright Β© 2025 Michael Gardner, A Bit of Help, Inc.

Licensed under the BSD-3-Clause License. See LICENSE for details.

Author

Michael Gardner A Bit of Help, Inc. https://github.com/abitofhelp

Sponsor this project

 

Packages

 
 
 

Contributors