Draft Specification · v0.1.0 · BSD-3-Clause

Object-Oriented Modelling Language

A JSON-based schema language that applies object-oriented concepts — namespacing, multi-inheritance, type safety — and a software-distribution versioning model to the world of data modelling. No query language. No storage engine. Just the model.

See ExamplesRead the Spec
Overview

A shared language for data, at any scale

Data modelling today is fragmented. Every tool — ERDs, JSON Schema, Avro, Protobuf, OpenAPI, custom wikis — speaks a different dialect. OOML proposes a single, human-readable format expressive enough for engineers yet accessible enough for product owners and analysts.

Business & Tech Agnostic

OOML describes the shape of data — not how it is stored, queried, or serialised. The same model can govern a relational schema, a document store, an API contract, or a data catalogue.

OOP-Inspired Semantics

Classes, multi-inheritance, type hierarchies, attributes, and controlled renaming/overriding give teams the vocabulary to model complex domains without ambiguity — familiar to any software engineer.

Class-Level Versioning

Each class carries its own semantic version. There is no collective package to version. Dependency edges are direct class-to-class relationships — precise, traversable, and meaningful.

Plain JSON

The canonical format is UTF-8 JSON. No proprietary tooling is required to read or write a model. Every artefact is self-describing — its identity is carried within the document itself.

OOML defines
  • A vocabulary and JSON encoding for classes, attributes, and their relationships
  • A versioning contract with clear semantics for breaking and non-breaking changes
  • A namespace and identity system enabling global, unambiguous class references
  • An inheritance mechanism for attribute reuse and type hierarchy
  • A class-to-class dependency model forming a directed acyclic graph (DAG)
  • A metadata model for structured, typed, versioned annotations
OOML does not define
  • A query language
  • A storage engine or persistence format
  • A serialisation format for data instances
  • A protocol for data exchange
  • A versioned package or bundle concept
  • A registry service, its wire protocol, or its governance model

"The central insight of OOML is that the class, not a collection of classes, is the correct unit of versioning for data models. This keeps the dependency graph simple and its edges meaningful: every edge represents an actual structural relationship between two classes."

— OOML Specification, §1

Core Concepts

The building blocks of OOML

Thirteen concepts form the complete vocabulary of OOML. Understanding them is sufficient to read, write, and reason about any valid model.

class

Class

The central construct of OOML. A versioned, named, uniquely identifiable collection of attributes. Each class is an independent artefact with its own FQN and semantic version.

Classes may be abstract (cannot be instantiated, only extended) or final (cannot be extended). A class is self-describing: its identity is carried within its own JSON document. The class — not any grouping layer — is the unit of versioning.

fqn

Fully Qualified Name

The globally unique identity of a class or global attribute. Format: namespace/ClassName@version, e.g. com.example.hr/Employee@1.2.0.

The namespace follows reverse-domain convention (all lowercase). The class name is PascalCase. The version is an exact semver. Owned attributes extend the class FQN with a # fragment: com.example.hr/Employee@1.2.0#employeeNumber. A sub-attribute nested inside a nested attribute uses a dotted path, e.g. #homeAddress.streetName — a positional address, not an independent identity.

namespace

Namespace

A reverse-domain organisational scope that groups related classes and governs who may publish names within it, e.g. com.example.hr or io.mycompany.platform.

All namespace segments are lowercase. A class name must be unique within its namespace. There is no package or module layer between the namespace and individual class artefacts.

attribute

Attribute

A named, typed position within a class. Every attribute has a kind that classifies its structural role: primitive, object, class, enum, list, set, map, attribute (reference to a global attribute), or nested.

Attributes may be required, nullable, static, local, or final. The attribute identifier (camelCase JSON key) is distinct from the human-readable name property. Inherited attributes cannot be overridden — only extended by adding new attributes in a subclass. object references an instance by identity; class references a class itself (a type-tag, not a record); nested embeds an ad hoc structure inline with no identity of its own.

globalattr

Global Attribute

A first-class, independently versioned reusable semantic contract for a typed attribute — independent of any class. Use for domain concepts that are genuinely global, such as monetaryAmount or geoCoordinate.

A global attribute has its own FQN, version, kind, and type constraints, and is named in camelCase — deliberately distinct from a class's PascalCase, since it is never instantiated or extended. A class references one using "kind": "attribute". The attribute identifier within the class is the local accessor; the global attribute FQN is the semantic identity. Both are independent.

inheritance

Inheritance

A class declares one or more superclasses via extends. It inherits all non-local attributes from all ancestors. OOML supports multiple inheritance.

Attribute resolution follows a depth-first, left-to-right MRO (C3 linearisation). Inherited attributes cannot be re-declared or overridden. The diamond problem does not arise because attributes are identified by FQN, not by local name — two ancestors sharing a local name hold distinct attributes.

enumroot

Enum Root

An ordinary class whose subtypes (excluding itself) define the valid values of an enum attribute. Enum members are real classes — they can carry attributes and be independently versioned.

An attribute with "kind": "enum" accepts a reference to any class that is a subtype of the named root, excluding the root itself. Adding a new subclass to the root is a non-breaking MINOR change; removing one is a MAJOR breaking change.

use

Renaming & Overriding (use)

A class adjusts an inherited attribute — without redeclaring it, which is disallowed — via the use property. Each entry may rename the attribute (as) and/or narrow a limited set of its properties (override).

use replaces aliasing entirely: renaming is non-additive — the old name becomes unreachable, not aliased alongside the new one. Keys are either a bare attribute identifier (when unambiguous) or an FQN range (to pick one attribute out from under a name collision). Only a fixed list of properties are override-eligible, and narrowing rules apply.

metadata

Metadata

Structured, typed, versioned annotations on any OOML artefact. Metadata schemas are ordinary OOML classes — the language uses itself as the metadata modelling language.

The metadata object on a class maps a metadata schema FQN range to a set of typed attribute values. Metadata entries support cascade (propagate to subclasses), final (cannot be overridden), and local (scoped to the declaring artefact only).

depgraph

Dependency Graph

A directed acyclic graph (DAG) of class-to-class and class-to-global-attribute edges. There is no separate dependencies property — every edge is derived directly from a class's own body.

Edge types include: extends (inheritance), object (instance reference), class (class-itself reference), enum (enum root), attribute-import, and metadata. use introduces no edge of its own — it only adjusts an attribute already reachable via an existing extends or attribute-import edge. Self-referential object, class, and enum edges are exempt from cycle detection — only extends, attribute-import, and metadata create structural cycles. "What depends on this class?" is a direct graph-edge lookup — no scan, no declared manifest.

nested

Nested Attribute

An ad hoc, locally-scoped structure with no independent identity, described inline by its own attributes property. Use "kind": "nested" instead of defining a separate class for a shape that only ever appears in one place.

A nested attribute has no type — its shape is entirely defined by sub-attributes, which may themselves be nested to any depth. Sub-attributes have no FQN of their own; dependencies they introduce attach to the nearest containing class or global attribute. A collection (list, set, map) may hold nested values via valueKind: "nested", with valueType carrying the inline sub-attribute map.

versioning

Versioning

Every class and global attribute carries a semantic version (MAJOR.MINOR.TRIVIAL). Artefact versions are treated as immutable once distributed.

MAJOR: breaking changes (removing/renaming attributes, narrowing types). MINOR: non-breaking additions (new optional attributes, widening types, new enum subtypes). TRIVIAL: documentation and metadata edits only. Version ranges follow npm-compatible semver syntax (^, ~, >=).

self

The self Reference

An authoring token used in a type position to mean "the class in which this attribute is declared". Expanded to the class's own FQN range before distribution.

self solves the chicken-and-egg problem of a class needing to reference itself before its version is known. It resolves to the declaring class, not the inheriting class — keeping the dependency graph acyclic and attribute types unambiguous across the hierarchy.

Examples

OOML in plain JSON

Seven annotated examples drawn directly from the specification — from standalone global attributes to derived dependency graph queries.

Global attributes are first-class, independently versioned artefacts. They define a reusable semantic contract for a typed attribute — independent of any class. Note the camelCase name: global attributes are never instantiated or extended, so they take camelCase rather than a class's PascalCase. Here, salary is published as a standalone artefact usable by any class that imports it.

{
  "ooml": "0.1.0",
  "fqn": "com.example.finance/salary@1.0.0",
  "name": "Annual Salary",
  "description": "An annual gross salary in the organisation's base currency.",
  "kind": "primitive",
  "type": "decimal",
  "precision": 14,
  "scale": 2,
  "minimum": 0
}
Glossary

Terminology reference

abstract
A class property. When true, the class cannot be instantiated directly — it may only be extended. Abstract classes may still define attributes and be the target of object and class attributes.
as
The renaming key within a use entry. Replaces an inherited attribute's exposed name for this class and every subclass beneath it — non-additive: the old name becomes unreachable, not aliased alongside the new one. Always a MAJOR (breaking) change.
Attribute
A named, typed position within a class. Every attribute has a kind — primitive, object, class, enum, list, set, map, or attribute (a reference to a global attribute) — and associated type constraints. The JSON key in the attributes object is the attribute identifier (camelCase), distinct from the human-readable name property.
Attribute Identifier
The camelCase JSON key used within a class's attributes object, e.g. employeeNumber. Locally scoped to the declaring class. Distinct from the human-readable name property and from any global attribute FQN the attribute may reference.
cascade
A metadata entry control property. When true, the entry value propagates to subclasses that do not set their own value for that entry. Subclasses may override a cascaded value unless final: true is also set. Incompatible with local: true.
Class
The central construct of OOML. A versioned, named, uniquely identifiable collection of attributes. Each class is an independent artefact with its own FQN and semantic version. The class — not any grouping layer — is the unit of versioning in OOML. Class names are PascalCase.
class (kind)
An attribute whose value is a reference to a class itself — the named class or any of its subtypes — a type-tag, not a record. Contrast with object (instance reference). Self-referential class-kind edges are exempt from cycle detection.
Dependency Graph
A directed acyclic graph (DAG) where nodes are individual versioned class and global attribute artefacts. There is no declared dependencies property — every edge is derived directly from a class's own body: extends, attribute type properties, valueType/keyType, and metadata keys. use introduces no edge of its own — it only adjusts an attribute already reachable via an existing edge. Acyclicity is only required across extends, attribute-import, and metadata edges — self-referential object, class, and enum edges are exempt, since they record identity, not structural embedding.
Enum Root
An ordinary class whose subtypes (excluding itself) serve as the valid values of an enum attribute. Enum members are real OOML classes — they can carry attributes and be independently versioned. There is no dedicated enum artefact type.
enum (kind)
An attribute whose value is a reference to a class that is a strict subtype of the named root class — the root class itself is not a valid value. This is the enumerative selection pattern in OOML.
extends
A class property declaring one or more superclasses. Accepts a single FQN range string or an array of them. OOML supports multiple inheritance. Order is significant: determines MRO (depth-first, left-to-right, C3 linearisation).
final
On a class: cannot be extended. On an attribute or metadata entry: subclasses cannot shadow or further constrain it, and override.value does not apply. Renaming via use.as is still permitted — it does not change the attribute's structural contract. Combined with static: true and value, the closest OOML equivalent to a traditional constant.
FQN (Fully Qualified Name)
The globally unique identity of a class or global attribute. Format: namespace/Name@version, e.g. com.example.hr/Employee@1.2.0 (class, PascalCase) or com.example.finance/salary@1.0.0 (global attribute, camelCase). Owned attributes extend the class FQN: com.example.hr/Employee@1.2.0#employeeNumber.
Global Attribute
A first-class, independently versioned OOML artefact defining a reusable typed semantic contract for an attribute, independent of any class. Named in camelCase — deliberately distinct from a class's PascalCase, since it is never instantiated or extended. Appropriate for domain concepts that are genuinely global, such as monetaryAmount or geoCoordinate.
local
A control property on attributes and metadata entries. When true, the attribute or entry is scoped to the declaring class and is not inherited by subclasses. It remains fully visible to consumers of the declaring class.
Metadata
Structured, typed, versioned annotations attached to a class or global attribute. Metadata schemas are ordinary OOML classes. Each entry in the metadata object maps a metadata schema FQN range to a typed value object with optional control properties (cascade, final, local). Each metadata key also contributes an edge to the dependency graph.
MRO (Method Resolution Order)
The deterministic linearisation of a class's ancestor list used to compute its full attribute set. OOML uses a depth-first, left-to-right traversal consistent with C3 linearisation. Earlier positions in the MRO take precedence for local-name access.
Namespace
A reverse-domain organisational scope in dot notation, e.g. com.example.hr. All segments are lowercase. Governs who may publish class and global attribute names within it. There is no versioning at the namespace level — versioning applies to individual classes and global attributes.
nullable
An attribute property. When true, the value of this attribute MAY be JSON null when present. Defaults to false. Must not be combined with static: true.
nested (kind)
An ad hoc, locally-scoped structure with no independent identity, described inline via its own attributes property rather than a type reference. Sub-attributes may nest to any depth. Introduces no edge of its own in the dependency graph — dependencies from its sub-attributes attach to the nearest containing class or global attribute.
object (kind)
An attribute whose value is a reference to an instance of a named class — or an instance of any of its subtypes — identified by that instance's own identity. Contrast with class (reference to the class itself). Self-referential object-kind edges are exempt from cycle detection, since they record identity, not structural embedding.
OOML
Object-Oriented Modelling Language. A JSON-based schema-definition language for describing data models that borrows object-oriented abstractions — classes, inheritance, namespacing, type safety — and applies a class-level versioning and distribution model borrowed from modern software ecosystems.
override
The overriding key within a use entry. Adjusts a limited, fixed set of properties on an inherited attribute (name, description, and narrowing-only bounds like maxLength, pattern, required, or a static, non-final attribute's value) without changing its kind or type. Every override except name/description is a MAJOR change.
primitive (kind)
An attribute holding a scalar value of one of OOML's built-in primitive types. Supports constraints including minLength, maxLength, pattern, minimum, maximum, precision, and scale, depending on the type.
Primitive Types
OOML's built-in scalar types: boolean; int8, int16, int32, int64; uint8, uint16, uint32, uint64; float32, float64; decimal; string; date; time; datetime; duration; uuid; uri; binary; any. Implementations must support all of them.
Rename
Replacing an inherited attribute's exposed name via use.as. Non-additive: the old name is no longer reachable from this class or its subclasses, distinguishing it from the aliasing OOML previously had, where the old name stayed available alongside the new one.
required
An attribute property. When true, instances of the class must carry a non-null value for this attribute. Defaults to false. Must not be combined with static: true.
self
A reserved authoring token used in a type position to mean "the class in which this attribute is declared". Expanded to the class's own FQN range before distribution. Resolves to the declaring class, not the inheriting class.
Semantic Versioning
OOML versions use MAJOR.MINOR.TRIVIAL (semver). MAJOR: breaking changes. MINOR: non-breaking data- or query-significant additions. TRIVIAL: documentation and metadata edits only. MAJOR=0 indicates initial development; any change may be breaking.
static
An attribute property. When true, the value belongs to the class itself, not to instances. A static + final + value combination is the closest OOML equivalent to a constant. Cannot be combined with required: true or nullable: true.
Sub-attribute
An attribute declared within the attributes property of a nested-kind attribute. Has no identity of its own beyond its position within its containing artefact — no FQN, no independent dependency-graph node. May be addressed for documentation purposes via a dotted path, e.g. #homeAddress.streetName.
Subclass
A class that names one or more classes in its extends array, thereby inheriting their attributes transitively. A subclass cannot re-declare or override inherited non-local attributes.
Subtype
A class that has one or more ancestor classes anywhere in the inheritance chain (transitive closure of extends). Subtypes are substitutable wherever their supertypes are expected (Liskov Substitution Principle).
Superclass
A class whose attributes and type identity are inherited by another class (its subclass) via extends. OOML supports multiple superclasses per class.
Supertype
A class that appears anywhere in the MRO of another class (excluding the class itself). Because OOML supports multi-inheritance, the type hierarchy is a DAG rather than a tree.
use
A class property replacing OOML's earlier aliasing mechanism. Maps a bare attribute identifier (when unambiguous) or an FQN range (to disambiguate a name collision) to an entry containing as (rename), override (narrow eligible properties), or both. At any point in the hierarchy, an attribute has exactly one current name — never several.
Version Range
A semver-compatible constraint used wherever an FQN range appears: extends, attribute type/valueType/keyType, use FQN-range keys, and metadata keys. Syntax follows npm conventions: exact (1.2.3), caret (^1.2.3 — same major), tilde (~1.2.3 — same major.minor), comparison range (>=1.0.0 <2.0.0), or wildcard (*).

37 of 37 terms shown