Domain Driven Design
The Goal
We are going to discuss how the our code should be a reflection of the business domain that we are operating in.
We also want to highlight the importance of having clear boundaries between distinct contexts within our conceptual understanding as well as in our code.
These boundaries allow us to start to develop and converge on a set of unambiguous semantics that developers and non-technical stakeholders can use to describe the core domain and sub-domains.
Another super important concept is the need to establish a data contract so that the frontend and the backend are decoupled as they can both program to the same interfaces.
Our goal is to define the domain model and data contract for our application.
The Domains
Users
The user domain is responsible for registering users and setting user roles.
The users domain will also be responsible for authenticating users. This may need to be broken out into a separate domain.
Challenges
The challenges domain is where challenges can be created and grouped in a series for users to complete.
Flashcards
The flashcards domain is where flashcards can be created and iterated through much like Anki.
Notes
The notes domain allows for users to create and save snippets much like GitHub Gist.
The Apps
Portal The portal is a registery for microfrontends (MFEs) which is used to expose MFEs, control access, andd perform health checks.
We may consider allowing the register API endpoints as well.
Dashboard
The dashboard is the client facing application which queries the portal after authenticating and loads available MFEs.
Mobile
The mobile application is a read-only mobile variation which will illustrate the power of creating reusuable libraries.
The Stack
Portal | Dashboard | Mobile | Users | Challenges | Flashcards | Notes | |
---|---|---|---|---|---|---|---|
APP | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
API | ✅ | ❎ | ❎ | ✅ | ✅ | ✅ | ✅ |
DOCKER | ✅ | ✅ | ❎ | ✅ | ✅ | ✅ | ✅ |
DB | ✅ | ❎ | ❎ | ✅ | ✅ | ✅ | ✅ |
The Data Contract
Users
export interface BaseEntity {
id?: string | null;
}
export interface User extends BaseEntity {
firstName: string;
lastName: string;
email: string;
password: string;
role: UserRoleEnum;
company_id: string;
}
export enum UserRoleEnum {
ADMIN = 'admin',
MENTOR = 'mentor',
APPRENTICE = 'apprentice',
}
export interface Company extends BaseEntity {
name: string;
description: string;
}
Challenges
export interface Challenge extends BaseEntity {
slug: string;
title: string;
description: string;
completed: boolean;
repo_url: string;
comment: string;
user_id: string;
}
Notes
export interface Note extends BaseEntity {
title: string;
content: string;
type: NoteTypeEnum;
user_id: string;
}
export enum NoteTypeEnum {
TEXT = 'text',
IMAGE = 'image',
VIDEO = 'video',
LINK = 'link',
}
Flashcards
export interface Flashcard extends BaseEntity {
title: string;
description: string;
question: string;
answer: string;
user_id: string;
}
The Portal
export interface Feature extends BaseEntity {
title: string;
description: string;
slug: string;
remote_uri: string;
api_uri: string;
healthy: boolean;
}
The Commands
Create the workspace with a portal
application.
npx create-nx-workspace@18.0.8 workshop \
--appName=portal \
--preset=angular-monorepo \
--workspaceType=integrated \
--bundler=esbuild \
--e2eTestRunner=cypress \
--style=scss \
--ci=skip \
--ssr=false
Create a library to hold the interfaces for the entire root domain and sub-domains.
npx nx g @nx/js:lib api-interfaces --directory=libs --unitTestRunner=none --minimal --no-interactive
Challenges
Choose and define an entity that we can use to build a feature slice around.
Resources
The Core of Domain-Driven Design
Modern Architectures with Angular – Part 1: Strategic Design with Sheriff and Standalone Components