← Back to Documentation

Feature Sets

Feature sets are the primary organizational unit in ARO. They group related statements that work together to accomplish a business goal.

Defining Feature Sets

A feature set consists of a name, business activity, and body:

(Feature Name: Business Activity) {
    (* statements *)
}

Naming Guidelines

Feature Set Name - Describes what the feature does:

Business Activity - Describes the domain context:

Feature Set Categories

Application Lifecycle

These special feature sets manage the application lifecycle:

(* Entry point - exactly one per application *)
(Application-Start: My Application) {
    <Log> "Starting..." to the <console>.
    <Start> the <http-server> on port 8080.
    <Return> an <OK: status> for the <startup>.
}

(* Called on graceful shutdown - optional *)
(Application-End: Success) {
    <Stop> the <http-server>.
    <Return> an <OK: status> for the <shutdown>.
}

HTTP Route Handlers (Contract-First)

Feature sets named after OpenAPI operationId values handle HTTP requests:

(* Feature sets named after operationIds in openapi.yaml *)
(listUsers: User API) {
    <Retrieve> the <users> from the <user-repository>.
    <Return> an <OK: status> with <users>.
}

(createUser: User API) {
    <Extract> the <user-data> from the <request: body>.
    <Create> the <user> with <user-data>.
    <Store> the <user> into the <user-repository>.
    <Return> a <Created: status> with <user>.
}

(getUser: User API) {
    <Extract> the <user-id> from the <pathParameters: id>.
    <Retrieve> the <user> from the <user-repository> where id = <user-id>.
    <Return> an <OK: status> with <user>.
}

Event Handlers

Feature sets with "Handler" in the business activity respond to events:

(* Handle domain events *)
(Send Welcome Email: UserCreated Handler) {
    <Extract> the <user> from the <event: user>.
    <Extract> the <email> from the <user: email>.
    <Send> the <welcome-email> to the <email>.
    <Return> an <OK: status> for the <notification>.
}

(* Handle file system events *)
(Process Upload: FileCreated Handler) {
    <Extract> the <path> from the <event: path>.
    <Read> the <content> from the <file: path>.
    <Transform> the <processed> from the <content>.
    <Return> an <OK: status> for the <processing>.
}

Feature Set Execution

Triggering

Feature sets are never called directly. They're triggered by:

  1. Application start: Application-Start runs once at startup
  2. HTTP requests: Route handlers match incoming requests via OpenAPI operationId
  3. Events: Event handlers respond to emitted events
  4. Application shutdown: Application-End runs during shutdown

Execution Flow

Within a feature set, statements execute sequentially:

(Process Order: Order Management) {
    (* 1. Extract data *)
    <Extract> the <order-data> from the <request: body>.

    (* 2. Validate *)
    <Validate> the <order-data> for the <order-schema>.

    (* 3. Create order *)
    <Create> the <order> with <order-data>.

    (* 4. Store *)
    <Store> the <order> into the <order-repository>.

    (* 5. Emit event *)
    <Emit> an <OrderCreated: event> with <order>.

    (* 6. Return response *)
    <Return> a <Created: status> with <order>.
}

Early Returns

Use control flow to return early:

(getUser: User API) {
    <Extract> the <user-id> from the <pathParameters: id>.
    <Retrieve> the <user> from the <user-repository> where id = <user-id>.

    if <user> is empty then {
        <Return> a <NotFound: status> for the <missing: user>.
    }

    <Return> an <OK: status> with <user>.
}

Organizing Feature Sets

By File

Organize related feature sets in files:

MyApp/
├── openapi.yaml       # Required for HTTP server
├── main.aro           # Application lifecycle
├── users.aro          # User CRUD operations
├── orders.aro         # Order management
├── payments.aro       # Payment processing
├── notifications.aro  # Email/SMS handlers
└── events.aro         # Domain event handlers

Cross-File Communication

Publishing Variables

Make variables available to other feature sets:

(* In config.aro *)
(Load Configuration: Initialization) {
    <Read> the <config: JSON> from the <file: "./config.json">.
    <Publish> as <app-config> <config>.
    <Return> an <OK: status> for the <loading>.
}

(* In any other file *)
(getSettings: Settings API) {
    <Extract> the <timeout> from the <app-config: timeout>.
    <Return> an <OK: status> with <timeout>.
}

Emitting Events

Trigger other feature sets via events:

(* In orders.aro *)
(createOrder: Order API) {
    <Create> the <order> with <order-data>.
    <Store> the <order> into the <order-repository>.
    <Emit> an <OrderCreated: event> with <order>.
    <Return> a <Created: status> with <order>.
}

(* In notifications.aro - automatically triggered *)
(Send Confirmation: OrderCreated Handler) {
    <Extract> the <order> from the <event: order>.
    <Send> the <confirmation-email> to the <order: customerEmail>.
    <Return> an <OK: status> for the <notification>.
}

Best Practices

Single Responsibility

Each feature set should do one thing well:

(* Good - focused on one task *)
(Validate Email Format: Validation) {
    <Extract> the <email> from the <input: email>.
    <Validate> the <email> for the <email-pattern>.
    <Return> an <OK: status> for the <validation>.
}

(* Avoid - too many responsibilities *)
(Handle User: User Management) {
    (* Don't mix validation, creation, notification, and logging *)
}

Consistent Structure

Follow a consistent pattern:

(Feature Name: Domain) {
    (* 1. Extract/validate inputs *)
    <Extract> the <input> from the <source>.
    <Validate> the <input> for the <schema>.

    (* 2. Business logic *)
    <Create> the <result> with <input>.
    <Transform> the <output> from the <result>.

    (* 3. Side effects *)
    <Store> the <output> into the <repository>.
    <Emit> an <Event: type> with <output>.

    (* 4. Return *)
    <Return> an <OK: status> with <output>.
}

Next Steps

Actions - Understanding and using actions
Application Lifecycle - Startup and shutdown