# 2. Architecture Principles
Adopt a mORMot
This framework implements established "best-practice" patterns:
The mORMot 2 architecture follows a layered design:
┌────────────────────────────────────────────────────────────────────┐
│ mORMot 2 Architecture │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ ┌───────────────┐ │
│ │ Web Clients │ │ REST Clients │ │
│ │ (AJAX/Mobile) │ │(Delphi/FPC/…) │ │
│ └───────┬───────┘ └───────┬───────┘ │
│ │ │ │
│ └───────────────┬───────────────────────┘ │
│ │ RESTful JSON │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ TRestServer │ │
│ │ ┌────────────┐ ┌───────────┐ ┌───────────────────────┐ │ │
│ │ │ Auth │ │ MVC/MVVM │ │ Services │ │ │
│ │ │ (Sessions) │ │ WebServer │ │ (Interface-based SOA) │ │ │
│ │ └────────────┘ └───────────┘ └───────────────────────┘ │ │
│ │ │ │ │
│ │ ┌────────┴────────┐ │ │
│ │ │ IRestOrm │ │ │
│ │ │ ORM Layer │ │ │
│ │ └────────┬────────┘ │ │
│ └─────────────────────────┼────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────┴────────────────────────────────────┐ │
│ │ Storage Backends │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────────────┐ │ │
│ │ │ SQLite3 │ │External │ │ MongoDB │ │ In-Memory/File │ │ │
│ │ │ (native)│ │ SQL │ │ (NoSQL) │ │ (JSON/Binary) │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ Cross-Cutting Features: │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Compression │ Security │ Crypto │ Logging │ Testing │ JSON │ │
│ └──────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
Key concepts of mORMot 2:
Architecture should be driven by actual application needs, not by theoretical patterns. There is no "one architecture fits all" solution. Architecture is about how you build your software.
┌─────────────────────────────────────────────────────────────────┐
│ Iterative Architecture Process │
│ │
│ Customer ──► BackLog ──► Design ──► Dev ──► Software │
│ │ │ │ │ │ │
│ │ │ │ │ │ │
│ Use Cases Requirements Architecture Tasks Definition │
│ │ of Done │
│ │ │
│ Risk Assessment │
│ Technology & Models │
└─────────────────────────────────────────────────────────────────┘
Common pitfalls to avoid:
The Model-View-Controller (MVC) pattern isolates domain logic from user interface, permitting independent development, testing, and maintenance.
┌───────────────────────────────────────────────────────────┐
│ MVC Pattern │
│ │
│ ┌──────────┐ Uses ┌──────────┐ │
│ │Controller│ ──────────► │ Model │ │
│ └──────────┘ └──────────┘ │
│ │ │ │
│ │ Command │ Notify Updates │
│ ▼ ▼ │
│ ┌──────────┐ Refresh ┌──────────┐ │
│ │ View │ ◄────────── │ Model │ │
│ └──────────┘ └──────────┘ │
└───────────────────────────────────────────────────────────┘
Model: Manages behavior and data of the application domain. Responds to requests for information about its state and instructions to change state. In mORMot, implemented via TOrmModel class which centralizes all TOrm-inherited classes.
View: Renders the model into a form suitable for interaction:
TOrm classes or RESTful Services.
Multi-tier architecture separates presentation, application processing, and data management into logically separate processes.
┌─────────────────────────────────────────────────────────┐
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Application Tier │ │ Data Tier │ │
│ │ (UI + Logic mixed) │───►│ (Database) │ │
│ └─────────────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Presentation │ │ Logic Tier │ │ Data Tier │ │
│ │ Tier │─►│ (ORM + SOA) │─►│ (Database) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────────┐
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Presentation │ │ Application │ │Business Logic│ │ Data │ │
│ │ Tier │─►│ Tier │─►│ Tier │─►│ Tier │ │
│ │(Delphi/AJAX) │ │(JSON Server) │ │ (Domain) │ │(Storage) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │
└───────────────────────────────────────────────────────────────────────┘
In mORMot 2:
SOA is a design approach where functionality is packaged as inter-operable services that can be used across multiple systems and business domains.
┌──────────────────────────────────────────────────────────────────┐
│ SOA Architecture │
│ │
│ Consumers Service Bus Publishers │
│ ───────── ─────────── ────────── │
│ ┌─────────┐ ┌───────────┐ ┌───────────┐ │
│ │Client A │◄───────────►│ │◄──────────►│Publisher 1│ │
│ └─────────┘ │ │ └───────────┘ │
│ ┌─────────┐ │ Service │ ┌───────────┐ │
│ │Client B │◄───────────►│ Bus │◄──────────►│Publisher 2│ │
│ └─────────┘ │ │ └───────────┘ │
│ ┌─────────┐ │ │ ┌───────────┐ │
│ │Client C │◄───────────►│ │◄──────────►│Publisher 3│ │
│ └─────────┘ └───────────┘ └───────────┘ │
└──────────────────────────────────────────────────────────────────┘
A software service is a logical representation of a repeatable activity that produces a precise result. Services are:
| Dependency | Desired Decoupling | Technique |
|---|---|---|
| Platform | Hardware/Framework/OS should not constrain choices | Standard protocols (REST/JSON) |
| Location | Consumers unaffected by hosting changes | Routing and proxies |
| Availability | Maintenance transparent to clients | Server-side support |
| Versions | New services without client upgrades | Contract marshalling |
ORM and SOA complement each other:
ORM provides methods to persist high-level objects into a relational database.
┌───────────────────────────────────────────────────────────────┐
│ ORM Process │
│ │
│ ┌──────────────┐ ┌─────────────┐ ┌──────────────────┐ │
│ │ Object │───►│ ORM │───►│ RDBMS │ │
│ │ Instance │ │ (CRUD) │ │ (Database) │ │
│ └──────────────┘ └─────────────┘ └──────────────────┘ │
│ │ │
│ SQL Mapping │
└───────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Class Type │ │ Data Model │ │
│ │ (via RTTI) │────────►│ (Database) │ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │ │
│ └───────────┬───────────────┘ │
│ │ │
│ ┌────┴────┐ │
│ │ ORM │ │
│ └─────────┘ │
└────────────────────────────────────────────────────────────────┘
| Scheme | Pros | Cons |
|---|---|---|
| RAD DB Components | SQL is powerful; RAD approach | Business logic limited; SQL binds to engine; Poor multi-tier |
| Manual SQL Mapping | Elaborated business logic | SQL must be hand-coded; Duplication; Engine-specific |
| Database ORM | SQL generated by ORM; Engine-agnostic | More abstraction needed; May retrieve excess data |
| Client-Server ORM | All ORM benefits; Services for precise data; Full multi-tier | More abstraction needed |
SQL (Relational):
1. Graph-oriented: Store data by relations (e.g., Neo4j) 2. Aggregate-oriented: - Document-based (MongoDB, CouchDB) - Key/Value (Redis, Riak) - Column family (Cassandra, HBase)
SQL stores data per table (requires JOINs):
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Users │ │ Contacts │ │ Access │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ ID | UserName │ │ UserID | Phone │ │ UserID | Level │
└─────────────────┘ └─────────────────┘ └─────────────────┘
NoSQL stores as documents (embedded):
{
"ID": 1234,
"UserName": "John Smith",
"Contact": {
"Phone": "123-456-789",
"Email": "xyz@abc.com"
},
"Access": {
"Level": 5,
"Group": "dev"
}
}
| SQL | NoSQL |
|---|---|
| Ubiquitous SQL language | Maps OOP and complex types natively |
| Easy vertical scaling | Horizontal scaling (sharding) |
| Data normalization | Schema-less evolution |
| Data consistency (single source) | Version management |
| Complex ACID transactions | Graph/Document native storage |
| Aggregation functions | Map/Reduce support |
From domaindrivendesign.org:
"The premise of domain-driven design is two-fold:
mORMot enables DDD through:
TOrm descendants representing persistent domain objectsIRestOrm interface for data access┌─────────────────────────────────────────────────────────────────────────┐
│ DDD with mORMot 2 │
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Domain Layer (Pure Pascal) │ │
│ │ · TOrm entities with business logic │ │
│ │ · Value Objects as records │ │
│ │ · Aggregates with clear boundaries │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────────┴───────────────────────────────────┐ │
│ │ Application Layer (Services) │ │
│ │ · IInvokable interfaces (mormot.soa.*) │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────────┴───────────────────────────────────┐ │
│ │ Infrastructure Layer │ │
│ │ · IRestOrm repositories (mormot.orm.*) │ │
│ │ · TSqlDBConnection (mormot.db.*) │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────────┴───────────────────────────────────┐ │
│ │ Presentation Layer │ │
│ │ · TRestHttpServer (mormot.rest.*) │ │
│ │ · MVC views (mormot.core.mvc) │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
mORMot 2 embraces SOLID principles:
mormot.core.json handles JSON, mormot.core.rtti handles RTTITOrm descendants can substitute the base classIRestOrm vs IRestOrmClient vs IRestOrmServerIRestOrm), not implementationsTInjectableObjectRestmORMot 1 used inheritance:
TSQLRestServer = class(TSQLRest)
// ORM methods directly in class
function Add(...): TID;
mORMot 2 uses composition:
TRest = class
property Orm: IRestOrm; // ORM via interface
property Services: TServiceContainer; // SOA via container
end;
// Access ORM through .Orm property
Server.Orm.Add(Customer);
This change improves:
Next Chapter: Meet mORMot 2 - New Units and Structure
| Previous | Index | Next |
|---|---|---|
| Chapter 1: mORMot 2 Overview | Index | Chapter 3: Meet mORMot 2 |