Why hexagonal architecture doesn't suit me. My DDD implementation is a layered block architecture







* In this article, examples will be in TypeScript







Brief preface



DDD (Domain Driven Design) , ( ) — , , , . , , , , ( 1).







.







, DDD.







— DDD.







.







, , .







(.1):







.1







, ?







, , .







, , .







, .







, .







, DDD .







:







  • . , .
  • , , , . :

    1. , , , ..
    2. .
    3. — , .


, , :







  • , , , .


.







.







, , , , , ..?







(.2):







.2







, , , , , , — , , , .







, , .









.







(.2), , , — .







:







  1. — , . , . .
  2. — , . .
  3. — , . , . .
  4. — , . , . .
  5. — , , . . , .








, , :







  1. .

    , . , , — , . . 2 — .
  2. . . .
  3. , .
  4. , .
  5. , ( data-transfer-object- DTO-).
  6. unit . (DI) , → .


,



  1. , , .
  2. , ().
  3. — , . , ORM, , , ORM . API, , , 2 : , .
  4. , .




CRM, , ORM TypeORM, — PostgresSQL.







, ,

.







:







.3







:







@clients = src/domains/clients
@clientsEnities = src/adapters/typeorm/entities/clients
@adapters = src/adapters
      
      





:









, , .







, . 2 :







domains/clients/models/Client.ts


import { Contact } from './Contact';

export interface Client {
  id: number;
  title: string;
  contacts?: Contact[];
}
      
      





domains/clients/models/Contact.ts


import { Client } from './Client';

export enum ContactType {
  PHONE = 'phone',
  EMAIL = 'email',
}

export interface Contact {
  client?: Client;
  type: ContactType;
  value: string;
}
      
      





TypeORM enitity







adapters/typeorm/entities/clients/Client.ts


import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { Client as ClientModel } from '@clients/models/Client';
import { Contact } from './Contact';

@Entity({ name: 'clients' })
export class Client implements ClientModel {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @OneToMany((_type) => Contact, (contact) => contact.client)
  contacts?: Contact[];
}
      
      





adapters/typeorm/entities/clients/Contact.ts


import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Contact as ContactModel, ContactType } from '@clients/models/Contact';
import { Client } from './Client';

@Entity({ name: 'contacts' })
export class Contact implements ContactModel {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'string' })
  type: ContactType;

  @Column()
  value: string;

  @ManyToOne((_type) => Client, (client) => client.contacts, { nullable: false })
  client?: Client;
}
      
      





: .. , . , - — .







.







domains/clients/methods/createClient.ts


import { Repository } from 'typeorm';
import { Client as ClientModel } from '@clients/models/Client';
import { Client } from '@clientsEnities/Client';

export async function  createClient(repo: Repository<Client>, clientData: ClientModel) {
  const client = await repo.save(clientData);

  return client;
}
      
      





domains/clients/index.ts


import { Connection } from 'typeorm';
import { Client } from '@clientsEnities/Client';
import { Client as ClientModel } from '@clients/models/Client';
import { createClient } from './methods/createClient';

export class Clients {
  protected _connection: Connection;

  constructor(connection: Connection) {
    if (!connection) {
      throw new Error('No connection!');
    }
    this._connection = connection;
  }

  protected getRepository<T>(Entity: any) {
    return this._connection.getRepository<T>(Entity);
  }

  protected getTreeRepository<T>(Entity: any) {
    return this._connection.getTreeRepository<T>(Entity);
  }

  public async createClient(clientData: ClientModel) {
    const repo = this.getRepository<Client>(Client);

    const client = await createClient(repo, clientData);

    return client;
  }
}
      
      





.. TypeORM , ( DI) , connection, .







.







businessProcesses/createClient.ts


import { Client as ClientModel } from '@clients/models/Client';
import { Clients } from '@clients';
import { db } from '@adapters/typeorm'; //   TypeORM    db

export function createClient(clientData: ClientModel) {
  const clients = new ClientService(db.connection)

  const client = await clients.createClient(clientData)

  return  client
}
      
      





, , . .







?



  1. .
  2. . . . — , .
  3. . , — ( , ), , .
  4. . . DTO , , , , . — , .
  5. . , . , notifications



    notifications.notifyClient({ client: client.id, type:’SUCCESS_REGISTRATION’ })





, , !








All Articles