Slide 1

Slide 1 text

#VJMEJOHUIFMBZFSFETFSWFSBQQMJDBUJPO
 BDIJFWFECZ*OWFSTJGZ+4 %FD +4$POG+1 !PLVOPLFOUBSP

Slide 2

Slide 2 text

+4$POG+1 ˙ ,FOԞ໺ݡଠ࿠
 !PLVOPLFOUBSP ˙ $MJFOUTJEF4FSWFSTJEFEFWFMPQFS ˙ "OHVMBS+BQBO6TFS(SPVQ

Slide 3

Slide 3 text

+4$POG+1 "HFOEB ˙ .ZBQQMJDBUJPOBSDIJUFDUVSF ˙ 8IBUJTUJHIUDPVQMJOH 8IZEPXFOFFE%*1 ˙ %FWFMPQJOHXJUI
 5ZQF4DSJQU &YQSFTT *OWFSTJGZ+4 ,OFYKT

Slide 4

Slide 4 text

8IBUUPEFWFMPQ

Slide 5

Slide 5 text

+4$POG+1 8IBUUPEFWFMPQ ˙ 5IFOFX4BB4UIBUDIBOHFTUIFXBZZPVMJTUFOUP NVTJD

Slide 6

Slide 6 text

+4$POG+1 )VNCMFQSPCMFNT ˙ *UTIPVMEIBWFCFFOSFMFBTFEOPX
 XIFO*BQQMJFEGPS$'1 ˙ %FWFMPQNFOUQFOEJOH ˙ 8JMMUBMLBCPVUEFWFMPQJOHBUFTUWFSTJPO

Slide 7

Slide 7 text

4ZTUFNBSDIJUFDUVSF

Slide 8

Slide 8 text

+4$POG+1 ˙ (PPHMF$MPVE1MBUGPSN ˙ $MPVE42- ˙ "QQ&OHJOF 4UBOEBSEFOWJSPONFOU 
 XJUI/PEFKT ˙ $MPVE4UPSBHF

Slide 9

Slide 9 text

"QQMJDBUJPOBSDIJUFDUVSF

Slide 10

Slide 10 text

+4$POG+1 ˙ 5ZQF4DSJQU ˙ 4FSWFS&YQSFTT ˙ $MJFOU"OHVMBS

Slide 11

Slide 11 text

8IBUJTUJHIUDPVQMJOH

Slide 12

Slide 12 text

+4$POG+1 5JHIUDPVQMJOH ˙ %JGpDVMUTJUVBUJPOUPEFUFSNJOFXIJDIDPEFDIBOHFT XJMMBGGFDUXIFSF ˙ *OUSJDBUFMZJOUFSUXJOFE ˙ 4DIFNB FYUFSOBMTFSWJDFT CVTJOFTTSVMFT 
 TUSVDUVSFPG3&45"1* (6*FMFNFOUT

Slide 13

Slide 13 text

'PSFYBNQMF

Slide 14

Slide 14 text

+4$POG+1 ˙ $SFBUFEB3&45"1*XJUIBEBUBTUSVDUVSFTJNJMBSUP
 UFYUpFMETPOUIFTDSFFO ˙ 1FSTJTUFEUIF+40/BTJUJTJOUIFEBUBCBTF

Slide 15

Slide 15 text

+4$POG+1 ˙ 0VUCSFBLPGSFEFTJHO ˙ 5FYUpFMETXFSFTQMJUJOUPNVMUJQMFTFDUJPOT
 XIFOUIFDMJFOUBQQXBTSFEFTJHOFE ˙ "EEFETDSFFOUSBOTJUJPO

Slide 16

Slide 16 text

+4$POG+1 ˙ %BUBCBTFTDIFNBXBTTUSPOHMZEFQFOEFOU
 POUIFTDSFFOCFGPSFSFEFTJHO ˙ $POTJTUFODZIBTCFFOMPTU

Slide 17

Slide 17 text

+4$POG+1 8IZ Screen before redesigned Schema before redesigned Redesigned screen Schema before redesigned

Slide 18

Slide 18 text

+4$POG+1 8IBUTIPVMEXFEP Redesigned screen Schema unaffected by a screen design Abstract interface

Slide 19

Slide 19 text

+4$POG+1 -BZFSJOH

Slide 20

Slide 20 text

-BZFSFEBSDIJUFDUVSF

Slide 21

Slide 21 text

+4$POG+1 4PMJUBSZCBUUMF ˙ 8IFOTFSWFSBOEDMJFOUBSFJNQMFNFOUFEBMPOF 
 XFDPVMEXSJUFDPEFTXJUIQFSGFDUGSFFEPN ˙ 5IBUJT

Slide 22

Slide 22 text

%JTUVSCFEBSFB

Slide 23

Slide 23 text

PS

Slide 24

Slide 24 text

+4$POG+1 Render and
 handle event Persist

Slide 25

Slide 25 text

+4$POG+1 Render and
 handle event Persist Client Server

Slide 26

Slide 26 text

+4$POG+1 Render and
 handle event Persist Usecases Abstract storages Mediator Repository HTTP

Slide 27

Slide 27 text

+4$POG+1 Render and
 handle event Persist Usecases Abstract storages Mediator Repository HTTP -BZFSFEDMJFOU -BZFSFETFSWFS

Slide 28

Slide 28 text

+4$POG+1 #SJOHPSEFS ˙ 3FHBSEMFTTPGUIFOVNCFSPGEFWFMPQFST 
 BMXBZTCFBXBSFPGEJTDJQMJOFEDPEFEJWJTJPOT ˙ -PPLTMJLFBOPSHBOJ[FETIFMG ˙ "CMFUPEJWJEFMBCPS 4PNFEBZ

Slide 29

Slide 29 text

+4$POG+1 ˙ %%%%PNBJO%SJWFO%FTJHO ˙ 5PVHIUPUBLF%%%QFSGFDUMZ ˙ ,OPXUIFDPODFQUBOECPSSPXJU ˙ .%%.PEFM%SJWFO%FWFMPQNFOU ˙ 3FQPTJUPSZ%BUBQFSTJTUFODFBCTUSBDUJPO

Slide 30

Slide 30 text

3FQPTJUPSZQBUUFSO

Slide 31

Slide 31 text

+4$POG+1 ˙ %BUBCBTFJTBMNPTUBMXBZTOPSNBMJ[FE ˙ .VMUJQMFUBCMFT ˙ .VMUJQMFSFBETBOEXSJUFT ˙ .BOZ+0*/ ˙ .BOZUSBOTBDUJPOT

Slide 32

Slide 32 text

+4$POG+1 $IBPTEVSJOHNJHSBUJPO ˙ *UTQBJOGVMUPpYUIFXIPMFBQQMJDBUJPO
 XJUIFBDI%#NJHSBUJPOT ˙ 7JPMBUFT0JO40-*%QSJODJQMFT ˙ 0$1&OUJUJFTTIPVMECFPQFOGPSFYUFOTJPO 
 CVUDMPTFEGPSNPEJpDBUJPO

Slide 33

Slide 33 text

+4$POG+1 3FQPTJUPSZ ˙ %BUBCBTFBCTUSBDUJPO ˙ %FDPVQMFTEBUBCBTFNBQQJOHGSPN
 UIFEPNBJONPEFMJUTFMG ˙ 4USFOHUIFOTQFDJpDBUJPODIBOHFT

Slide 34

Slide 34 text

+4$POG+1 %#DPOOFDUJPO ˙ .BOZDSFEFOUJBMTBSFUSFBUFEBTFOWJSPONFOU WBSJBCMFT ˙ %BUBCBTFOBNFT VTFST QBTTXPSET ˙ .PTUPGUIFNNBZCFTQFDJpFEJOEJWJEVBMMZ
 GPSQSPEVDUBOEEFWFMPQNFOU

Slide 35

Slide 35 text

+4$POG+1 %JGpDVMUUPUFTU ˙ *GZPVDPOOFDUUP%#GPSQSPEVDUJPO
 FWFSZUJNFZPVUFTU ZPVDBOUUFTUPGqJOF ˙ 8IFOQSFQBSJOHBpYUVSF%#GPSUFTUJOH 
 ZPVDBOUEPJUFWFOJGZPVXBOUUPTQMJUJU

Slide 36

Slide 36 text

)PX

Slide 37

Slide 37 text

%FQFOEFODZ*OWFSTJPO1SJODJQMF

Slide 38

Slide 38 text

+4$POG+1 ˙ %*1 ˙ %JO40-*%QSJODJQMFT

Slide 39

Slide 39 text

+4$POG+1 ˙ )JHIMFWFMNPEVMFTTIPVMEOPUEFQFOEPOMPXMFWFM NPEVMFT ˙ #PUITIPVMEEFQFOEPOBCTUSBDUJPOT ˙ "CTUSBDUJPOTTIPVMEOPUEFQFOEPOEFUBJMT ˙ %FUBJMTTIPVMEEFQFOEPOBCTUSBDUJPOT

Slide 40

Slide 40 text

3JHIU

Slide 41

Slide 41 text

.PSFGBNJMJBSFYBNQMFT☝

Slide 42

Slide 42 text

class UserId { readonly value: string; constructor() { this.value = uuid(); } } /PUHPPE

Slide 43

Slide 43 text

function makeUserId(): UserId { return new UserId(uuid()); } function makeUserIdMock(mockValue: string): UserId { return new UserId(mockValue); } class UserId { constructor(readonly value: string) {} } #FUUFS

Slide 44

Slide 44 text

class UsersRepository { private readonly db: Knex; constructor() { this.db = knex(config); } } /PUHPPE

Slide 45

Slide 45 text

class UsersRepository { constructor( private readonly db: DatabaseProvider ) {} } #FUUFS

Slide 46

Slide 46 text

class UsersGetMediator { async handle(req: Request, res: Response) { const repo = new UsersRepository( new DatabaseProvider(), ); const users = await repo.getAll(); // Processing to send response } } )NNN

Slide 47

Slide 47 text

class Application { private router: Router; constructor() { this.router = new Router( new UsersGetMediator( new UsersRepository( new DatabaseProvider(), ) ) ) } } :PVLOPX

Slide 48

Slide 48 text

class Application { private router: Router; constructor() { this.router = new Router( new UsersGetMediator( new UsersRepository( new DatabaseProvider(), ) ) ) } } )!%0,&/

Slide 49

Slide 49 text

*TUIJTPLBZ

Slide 50

Slide 50 text

-FUTVTF%*DPOUBJOFS

Slide 51

Slide 51 text

import { injectable } from 'inversify'; @injectable() export class Application { constructor( private readonly auth: AuthService, private readonly router: Router, private readonly express: ExpressProvider, ) {} main() { this.auth.prepare(); this.router.prepare(); this.express.listen(); } } *OKFDUBCMFEFDPSBUPS

Slide 52

Slide 52 text

@injectable() export class UsersGetMediator { constructor( private readonly auth: AuthService, private readonly permissionVerifier: PermissionVerifier, private readonly errorHandler: ErrorHandler, private readonly usersRepo: UsersRepository, ) {} async handle(req: Request, res: Response) { if (!(await this.auth.isAuthenticated(req))) { return this.errorHandler.unauthorized(res); } if (!(await this.permissionVerifier.canReadUsers(req.user.id))) { return this.errorHandler.forbidden(res); } const users = await this.usersRepo.getAll(); const body: UsersGetResponse = { users: users.serialize(), }; res.send(body).end(); } }

Slide 53

Slide 53 text

+4$POG+1 *OWFSTJGZ+4 ˙ "CMFUPIBOEMF"constructor injection" ˙ *OUFSGBDFTJNJMBSUP"OHVMBS ˙ IUUQTHJUIVCDPNJOWFSTJGZ*OWFSTJGZ+4

Slide 54

Slide 54 text

I was going to introduce the trick here...

Slide 55

Slide 55 text

But I have found it...

Slide 56

Slide 56 text

+4$POG+1 54ZSJOHF ˙ .BEFCZ.JDSPTPGU ˙ *OUFSGBDFTJNJMBSUP*OWFSTJGZ+4
 *OPUIFSXPSET TJNJMBSUP"OHVMBS ˙ /POFFEGPSNZUSJDLTGPS*OWFSTJGZ+4 ˙ IUUQTHJUIVCDPNNJDSPTPGUUTZSJOHF

Slide 57

Slide 57 text

%FWFMPQJOHXJUI
 5ZQF4DSJQU &YQSFTT *OWFSTJGZ+4 ,OFYKT

Slide 58

Slide 58 text

+4$POG+1 Express Http Handler (Router) Google Cloud SQL Mediator Repository Database Provider Reader Writer

Slide 59

Slide 59 text

+4$POG+1 Express Http Handler (Router) Google Cloud SQL Mediator Repository Database Provider Reader Writer Http Request (Not TS) Domain model Data access object Knex.js ORM Raw SQL Query (Not TS)

Slide 60

Slide 60 text

+4$POG+1 Express Http Handler (Router) Google Cloud SQL Mediator Repository Database Provider Reader Writer Serialized JSON (Not TS) Domain model Data transfer object Results as JSON (Not TS)

Slide 61

Slide 61 text

+4$POG+1 ˙ *OUSPEVDF"value object"CZ%%% ˙ "WPJEVTJOHQSJNJUJWFUZQFTBTNVDIBTQPTTJCMF
 MJLFstring number ˙ 'PSFYBNQMF
 UserId UserName AccessToken Email

Slide 62

Slide 62 text

+4$POG+1 ˙ /PUVTFBWBMJEBUPSGVODUJPOBOEBOifTUBUFNFOU ˙ 7FSJGZCZUISPXJOHBOFYDFQUJPOCZUIFDPOTUSVDUPS ˙ *GJOTUBOUJBUJPOJTTVDDFTTGVM 
 BMXBZTWBMJEBUFEBOEDPNQJMFTBGF

Slide 63

Slide 63 text

+4$POG+1 8IZEPOU*VTF/FTU+4 ˙ IUUQTOFTUKTDPN ˙ /FTU+4IBTEFQFOEFODZJOKFDUJPO ˙ *QSFGFS"OHVMBSCVU*MJLFUPDPNCJOF
 UIFNJOJNVNSFRVJSFEGFBUVSFTPOUIFTFSWFSTJEF ˙ 5BTUFTEJGGFS

Slide 64

Slide 64 text

-FUTTUBZPSHBOJ[FE XJUI%*$POUBJOFS

Slide 65

Slide 65 text

5IBOLZPV