Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Building the layered server application achieve...
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
OKUNOKENTARO
December 01, 2019
Technology
4.2k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Building the layered server application achieved by InversifyJS
The slide that used when I talked in JSConf JP.
OKUNOKENTARO
December 01, 2019
More Decks by OKUNOKENTARO
See All by OKUNOKENTARO
トレタO/X アーキテクチャ移行記 Next.js App Router化への道のり / TORETA TECH UPDATE 1
okunokentaro
5
12k
Podcastを継続する技術 / refactoradio-240119
okunokentaro
1
220
Webアプリケーション設計の第一歩は ディレクトリの整理から / Encraft 1
okunokentaro
33
10k
JSONとJSON Schemaを改めて理解する / tokyo_study
okunokentaro
9
2.5k
それでもどうしてRecoilを使うのか / Harajuku.ts Meetup Recoil
okunokentaro
19
5.7k
TypeScriptは10年でこんなに進化しました / TechFeed Experts Night 11
okunokentaro
6
1.8k
Hasura.io RDBをサクサク作る方法はARやO/RMだけじゃなくなりました/hasura-io
okunokentaro
5
730
コードには型アノテーションよりも要件アノテーションを増やせ!/harajukuts2
okunokentaro
14
6.6k
10年と3ヶ月でWebサービスを作った話 / Piyogrammer Conference 2021
okunokentaro
2
1.1k
Other Decks in Technology
See All in Technology
AI時代のキョウソウ戦略
ystk
2
110
ClaudeCodeでセキュリティ監視業務を半自動化_1年の運用でわかったAIに任せる設計の5つのポイント
kintotechdev
4
1k
Jetpack Compose で挑む新聞紙面UI ─ 複合ジェスチャー・ポリゴン記事領域・適応的ページ構成という3つの壁/droidkaigi2026
nikkei_engineer_recruiting
0
110
LLMアプリ、 雰囲気で運用してませんか? 〜LLMOpsの現在地〜
taka_aki
1
650
20260903 Tokyo Jazug Night #62 | Azure エンジニアよ、 その環境は本当にセキュアか?
olivia_0707
0
200
Master Dataグループ紹介資料
sansan33
PRO
1
4.9k
Bet AI Day 2026丨バクラク Autopilot、業務システムの再設計
layerx
PRO
1
740
Introduction to Bill One Development Engineer
sansan33
PRO
0
480
「面白い!」を信じ抜け。激動の時代を貫く、オンリーワン・エンジニアの条件
kizawa2020
2
610
Guerilla InnerSource in enterprises, during the AI hype
onenashev
PRO
0
130
Point Cloud as a Foreign Language for Multi-modal Large Language Model
takmin
0
350
Bet AI Day 2026丨Agentは、「金融」という巨大産業の何を変えられるのか
layerx
PRO
0
480
Featured
See All Featured
Why Our Code Smells
bkeepers
PRO
340
58k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
400
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
400
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
300
Code Reviewing Like a Champion
maltzj
528
40k
Navigating Team Friction
lara
192
16k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.6k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3k
Transcript
#VJMEJOHUIFMBZFSFETFSWFSBQQMJDBUJPO BDIJFWFECZ*OWFSTJGZ+4 %FD +4$POG+1 !PLVOPLFOUBSP
+4$POG+1 ˙ ,FOԞݡଠ !PLVOPLFOUBSP ˙ $MJFOUTJEF4FSWFSTJEFEFWFMPQFS ˙ "OHVMBS+BQBO6TFS(SPVQ
+4$POG+1 "HFOEB ˙ .ZBQQMJDBUJPOBSDIJUFDUVSF ˙ 8IBUJTUJHIUDPVQMJOH 8IZEPXFOFFE%*1 ˙ %FWFMPQJOHXJUI
5ZQF4DSJQU &YQSFTT *OWFSTJGZ+4 ,OFYKT
8IBUUPEFWFMPQ
+4$POG+1 8IBUUPEFWFMPQ ˙ 5IFOFX4BB4UIBUDIBOHFTUIFXBZZPVMJTUFOUP NVTJD
+4$POG+1 )VNCMFQSPCMFNT ˙ *UTIPVMEIBWFCFFOSFMFBTFEOPX XIFO*BQQMJFEGPS$'1 ˙ %FWFMPQNFOUQFOEJOH ˙ 8JMMUBMLBCPVUEFWFMPQJOHBUFTUWFSTJPO
4ZTUFNBSDIJUFDUVSF
+4$POG+1 ˙ (PPHMF$MPVE1MBUGPSN ˙ $MPVE42- ˙ "QQ&OHJOF 4UBOEBSEFOWJSPONFOU XJUI/PEFKT
˙ $MPVE4UPSBHF
"QQMJDBUJPOBSDIJUFDUVSF
+4$POG+1 ˙ 5ZQF4DSJQU ˙ 4FSWFS&YQSFTT ˙ $MJFOU"OHVMBS
8IBUJTUJHIUDPVQMJOH
+4$POG+1 5JHIUDPVQMJOH ˙ %JGpDVMUTJUVBUJPOUPEFUFSNJOFXIJDIDPEFDIBOHFT XJMMBGGFDUXIFSF ˙ *OUSJDBUFMZJOUFSUXJOFE ˙ 4DIFNB FYUFSOBMTFSWJDFT
CVTJOFTTSVMFT TUSVDUVSFPG3&45"1* (6*FMFNFOUT
'PSFYBNQMF
+4$POG+1 ˙ $SFBUFEB3&45"1*XJUIBEBUBTUSVDUVSFTJNJMBSUP UFYUpFMETPOUIFTDSFFO ˙ 1FSTJTUFEUIF+40/BTJUJTJOUIFEBUBCBTF
+4$POG+1 ˙ 0VUCSFBLPGSFEFTJHO ˙ 5FYUpFMETXFSFTQMJUJOUPNVMUJQMFTFDUJPOT XIFOUIFDMJFOUBQQXBTSFEFTJHOFE ˙ "EEFETDSFFOUSBOTJUJPO
+4$POG+1 ˙ %BUBCBTFTDIFNBXBTTUSPOHMZEFQFOEFOU POUIFTDSFFOCFGPSFSFEFTJHO ˙ $POTJTUFODZIBTCFFOMPTU
+4$POG+1 8IZ Screen before redesigned Schema before redesigned Redesigned screen
Schema before redesigned
+4$POG+1 8IBUTIPVMEXFEP Redesigned screen Schema unaffected by a screen design
Abstract interface
+4$POG+1 -BZFSJOH
-BZFSFEBSDIJUFDUVSF
+4$POG+1 4PMJUBSZCBUUMF ˙ 8IFOTFSWFSBOEDMJFOUBSFJNQMFNFOUFEBMPOF XFDPVMEXSJUFDPEFTXJUIQFSGFDUGSFFEPN ˙ 5IBUJT
%JTUVSCFEBSFB
PS
+4$POG+1 Render and handle event Persist
+4$POG+1 Render and handle event Persist Client Server
+4$POG+1 Render and handle event Persist Usecases Abstract storages Mediator
Repository HTTP
+4$POG+1 Render and handle event Persist Usecases Abstract storages Mediator
Repository HTTP -BZFSFEDMJFOU -BZFSFETFSWFS
+4$POG+1 #SJOHPSEFS ˙ 3FHBSEMFTTPGUIFOVNCFSPGEFWFMPQFST BMXBZTCFBXBSFPGEJTDJQMJOFEDPEFEJWJTJPOT ˙ -PPLTMJLFBOPSHBOJ[FETIFMG ˙ "CMFUPEJWJEFMBCPS
4PNFEBZ
+4$POG+1 ˙ %%%%PNBJO%SJWFO%FTJHO ˙ 5PVHIUPUBLF%%%QFSGFDUMZ ˙ ,OPXUIFDPODFQUBOECPSSPXJU ˙ .%%.PEFM%SJWFO%FWFMPQNFOU ˙
3FQPTJUPSZ%BUBQFSTJTUFODFBCTUSBDUJPO
3FQPTJUPSZQBUUFSO
+4$POG+1 ˙ %BUBCBTFJTBMNPTUBMXBZTOPSNBMJ[FE ˙ .VMUJQMFUBCMFT ˙ .VMUJQMFSFBETBOEXSJUFT ˙ .BOZ+0*/ ˙
.BOZUSBOTBDUJPOT
+4$POG+1 $IBPTEVSJOHNJHSBUJPO ˙ *UTQBJOGVMUPpYUIFXIPMFBQQMJDBUJPO XJUIFBDI%#NJHSBUJPOT ˙ 7JPMBUFT0JO40-*%QSJODJQMFT ˙ 0$1&OUJUJFTTIPVMECFPQFOGPSFYUFOTJPO
CVUDMPTFEGPSNPEJpDBUJPO
+4$POG+1 3FQPTJUPSZ ˙ %BUBCBTFBCTUSBDUJPO ˙ %FDPVQMFTEBUBCBTFNBQQJOHGSPN UIFEPNBJONPEFMJUTFMG ˙ 4USFOHUIFOTQFDJpDBUJPODIBOHFT
+4$POG+1 %#DPOOFDUJPO ˙ .BOZDSFEFOUJBMTBSFUSFBUFEBTFOWJSPONFOU WBSJBCMFT ˙ %BUBCBTFOBNFT VTFST QBTTXPSET ˙
.PTUPGUIFNNBZCFTQFDJpFEJOEJWJEVBMMZ GPSQSPEVDUBOEEFWFMPQNFOU
+4$POG+1 %JGpDVMUUPUFTU ˙ *GZPVDPOOFDUUP%#GPSQSPEVDUJPO FWFSZUJNFZPVUFTU ZPVDBOUUFTUPGqJOF ˙ 8IFOQSFQBSJOHBpYUVSF%#GPSUFTUJOH ZPVDBOUEPJUFWFOJGZPVXBOUUPTQMJUJU
)PX
%FQFOEFODZ*OWFSTJPO1SJODJQMF
+4$POG+1 ˙ %*1 ˙ %JO40-*%QSJODJQMFT
+4$POG+1 ˙ )JHIMFWFMNPEVMFTTIPVMEOPUEFQFOEPOMPXMFWFM NPEVMFT ˙ #PUITIPVMEEFQFOEPOBCTUSBDUJPOT ˙ "CTUSBDUJPOTTIPVMEOPUEFQFOEPOEFUBJMT ˙ %FUBJMTTIPVMEEFQFOEPOBCTUSBDUJPOT
3JHIU
.PSFGBNJMJBSFYBNQMFT☝
class UserId { readonly value: string; constructor() { this.value =
uuid(); } } /PUHPPE
function makeUserId(): UserId { return new UserId(uuid()); } function makeUserIdMock(mockValue:
string): UserId { return new UserId(mockValue); } class UserId { constructor(readonly value: string) {} } #FUUFS
class UsersRepository { private readonly db: Knex; constructor() { this.db
= knex(config); } } /PUHPPE
class UsersRepository { constructor( private readonly db: DatabaseProvider ) {}
} #FUUFS
class UsersGetMediator { async handle(req: Request, res: Response) { const
repo = new UsersRepository( new DatabaseProvider(), ); const users = await repo.getAll(); // Processing to send response } } )NNN
class Application { private router: Router; constructor() { this.router =
new Router( new UsersGetMediator( new UsersRepository( new DatabaseProvider(), ) ) ) } } :PVLOPX
class Application { private router: Router; constructor() { this.router =
new Router( new UsersGetMediator( new UsersRepository( new DatabaseProvider(), ) ) ) } } )!%0,&/
*TUIJTPLBZ
-FUTVTF%*DPOUBJOFS
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
@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(); } }
+4$POG+1 *OWFSTJGZ+4 ˙ "CMFUPIBOEMF"constructor injection" ˙ *OUFSGBDFTJNJMBSUP"OHVMBS ˙ IUUQTHJUIVCDPNJOWFSTJGZ*OWFSTJGZ+4
I was going to introduce the trick here...
But I have found it...
+4$POG+1 54ZSJOHF ˙ .BEFCZ.JDSPTPGU ˙ *OUFSGBDFTJNJMBSUP*OWFSTJGZ+4 *OPUIFSXPSET TJNJMBSUP"OHVMBS ˙ /POFFEGPSNZUSJDLTGPS*OWFSTJGZ+4
˙ IUUQTHJUIVCDPNNJDSPTPGUUTZSJOHF
%FWFMPQJOHXJUI 5ZQF4DSJQU &YQSFTT *OWFSTJGZ+4 ,OFYKT
+4$POG+1 Express Http Handler (Router) Google Cloud SQL Mediator Repository
Database Provider Reader Writer
+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)
+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)
+4$POG+1 ˙ *OUSPEVDF"value object"CZ%%% ˙ "WPJEVTJOHQSJNJUJWFUZQFTBTNVDIBTQPTTJCMF MJLFstring number ˙ 'PSFYBNQMF
UserId UserName AccessToken Email
+4$POG+1 ˙ /PUVTFBWBMJEBUPSGVODUJPOBOEBOifTUBUFNFOU ˙ 7FSJGZCZUISPXJOHBOFYDFQUJPOCZUIFDPOTUSVDUPS ˙ *GJOTUBOUJBUJPOJTTVDDFTTGVM BMXBZTWBMJEBUFEBOEDPNQJMFTBGF
+4$POG+1 8IZEPOU*VTF/FTU+4 ˙ IUUQTOFTUKTDPN ˙ /FTU+4IBTEFQFOEFODZJOKFDUJPO ˙ *QSFGFS"OHVMBSCVU*MJLFUPDPNCJOF UIFNJOJNVNSFRVJSFEGFBUVSFTPOUIFTFSWFSTJEF ˙
5BTUFTEJGGFS
-FUTTUBZPSHBOJ[FE XJUI%*$POUBJOFS
5IBOLZPV