32
loading...
This website collects cookies to deliver better user experience
Code = Deisgn = Model = Documents
is whether the domain expert can read the code. So the easy to learn, expressive and intuitive programming language will have strong benefits in the process of creating domain models.string
, bool
, number
, etc.type
to compose larger types:type Name = {
firstName: string
middleName: string
lastName: string
}
type
has other usages, which is not a trivial feature. It can help you record the domain knowledge into domain models, for example:const timeToFly = 10
type Second = number
const timeToFly: Second = 10
|
:type Pet = Fish | Bird
Pet
is in type Fish
or Bird
. In general, functional programming languages have strong pattern match capability to process this kind of type. But the sad thing is TypeScript has limited pattern match capability so you can often see some string literals present in the types to distinguish different types.&
:type ABC = A & B & C
type
:type Add = (a: number) => (b: number) => number
Add
is a function who accepts 2 numbers as arguments and returns a number.type CreditCard = {
cardNo: string
firstName: string
middleName: string
lastName: string
contactEmail: Email
contactPhone: Phone
}
CreditCard
payment method. Also please notice we don't use class
here.middle name
be empty?middle name
can be null.strictNullChecks
to enforece the null check), but in functional programming, you can only use Optional type to express nullable type.middle name
can exists, or be empty. Plese notice the word "or", indicate that we can use Union Type to model for the nullable type:type Optional<T> = T | null
type CreditCard = {
cardNo: string
firstName: string
middleName: Option<string>
lastName: string
contactEmail: Email
contactPhone: Phone
}
cardNo
with string
? If so can it be any string? Is firstName
an arbitrary length string? Obviously you can't answer these questions as this model doesn't contain relative domain knowledge.string
type for cardNo
during programming, but in domain model, string
can't express the domain knowledge of cardNo
.cardNo
is a 19-length string starts with 200
, name
is a string whose length is less than or equal to 50. As such, the domain information can be implemented by type alias
:type CardNo = string
type Name50 = string
cardNo
business rules inside domain models by defining function.type GetCardNo = (cardNo: string) => CardNo
GetCardNo
return? null? or exception thrown? Actually functionaly programming has more elegant way such as Either Monad or Railway oriented programming to handle errors. At least we can present the function's signature by Optional:type GetCardNo = (cardNo: string) => Optional<CardNo>
type CreditCard = {
cardNo: Optional<CardNo>
firstName: Name50
middleName: Optional<string>
lastName: Name50
contactEmail: Email
contactPhone: Phone
}
middle name
only? If not how can we encapsulate the knowledge of atomicity change into the domain model?Name
and Contact
types and compose them:type Name = {
firstName: Name50
middleName: Option<string>
lastName: Name50
}
type Contact = {
contactEmail: Email
contactPhone: Phone
}
type CreditCard3 = {
cardNo: Optional<CardNo>
name: Name
contact: Contact
}
type Contact = {
contactEmail: Option<Email>
contactPhone: Option<Phone>
}
type OnlyContactEmail = Email
type OnlyContactPhone = Phone
type BothContactEmailAndPhone = Email & Phone
type Contact =
| OnlyContactEmail
| OnlyContactPhone
| BothContactEmailAndPhone
abstract
and bean
, etc.AbstractContactBase
, you increased the complexity of the system without any help on domain models sharing.npm install --global tplant
cd your-typescript-project-folder
tplant --input src/**/*.ts --output output.svg
open output.svg