@k2works/claude-code-booster 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +42 -42
- package/bin/claude-code-booster +90 -90
- package/lib/assets/.claude/README.md +239 -239
- package/lib/assets/.claude/scripts/generate-inception-deck.mjs +911 -911
- package/lib/assets/.claude/settings.json +11 -11
- package/lib/assets/.claude/skills/ai-agent-guidelines/SKILL.md +111 -111
- package/lib/assets/.claude/skills/analyzing-architecture/SKILL.md +83 -83
- package/lib/assets/.claude/skills/analyzing-business/SKILL.md +95 -95
- package/lib/assets/.claude/skills/analyzing-data-model/SKILL.md +77 -77
- package/lib/assets/.claude/skills/analyzing-domain-model/SKILL.md +117 -88
- package/lib/assets/.claude/skills/analyzing-inception-deck/SKILL.md +84 -84
- package/lib/assets/.claude/skills/analyzing-non-functional/SKILL.md +95 -95
- package/lib/assets/.claude/skills/analyzing-operation/SKILL.md +95 -95
- package/lib/assets/.claude/skills/analyzing-requirements/SKILL.md +91 -91
- package/lib/assets/.claude/skills/analyzing-tech-stack/SKILL.md +101 -101
- package/lib/assets/.claude/skills/analyzing-test-strategy/SKILL.md +89 -89
- package/lib/assets/.claude/skills/analyzing-ui-design/SKILL.md +80 -80
- package/lib/assets/.claude/skills/analyzing-usecases/SKILL.md +72 -72
- package/lib/assets/.claude/skills/creating-adr/SKILL.md +113 -113
- package/lib/assets/.claude/skills/developing-backend/SKILL.md +100 -100
- package/lib/assets/.claude/skills/developing-frontend/SKILL.md +93 -93
- package/lib/assets/.claude/skills/developing-release/SKILL.md +120 -120
- package/lib/assets/.claude/skills/generating-slides/SKILL.md +94 -94
- package/lib/assets/.claude/skills/git-commit/SKILL.md +81 -81
- package/lib/assets/.claude/skills/killing-processes/SKILL.md +44 -44
- package/lib/assets/.claude/skills/operating-backup/SKILL.md +59 -59
- package/lib/assets/.claude/skills/operating-cicd/SKILL.md +54 -54
- package/lib/assets/.claude/skills/operating-deploy/SKILL.md +67 -67
- package/lib/assets/.claude/skills/operating-docs/SKILL.md +219 -219
- package/lib/assets/.claude/skills/operating-provision/SKILL.md +77 -77
- package/lib/assets/.claude/skills/operating-setup/SKILL.md +63 -63
- package/lib/assets/.claude/skills/orchestrating-analysis/SKILL.md +104 -104
- package/lib/assets/.claude/skills/orchestrating-development/SKILL.md +162 -161
- package/lib/assets/.claude/skills/orchestrating-operation/SKILL.md +158 -158
- package/lib/assets/.claude/skills/orchestrating-project/SKILL.md +144 -144
- package/lib/assets/.claude/skills/planning-releases/SKILL.md +119 -119
- package/lib/assets/.claude/skills/syncing-github-project/SKILL.md +151 -151
- package/lib/assets/.claude/skills/tracking-progress/SKILL.md +91 -91
- package/lib/assets/.claude/skills/validating-iteration-plan/SKILL.md +215 -215
- package/lib/assets/.devcontainer/devcontainer.json +34 -34
- package/lib/assets/.env.example +17 -17
- package/lib/assets/.gitattributes +4 -4
- package/lib/assets/.github/workflows/docker-publish.yml +77 -77
- package/lib/assets/.github/workflows/mkdocs.yml +39 -39
- package/lib/assets/AGENTS.md +94 -94
- package/lib/assets/CLAUDE.md +183 -183
- package/lib/assets/README.md +254 -254
- package/lib/assets/docker-compose.yml +33 -33
- package/lib/assets/docs/adr/index.md +10 -10
- package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +475 -475
- package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +519 -519
- package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +537 -537
- package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +300 -300
- package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +320 -320
- package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +498 -498
- package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +298 -298
- package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +291 -291
- package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +336 -336
- package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +303 -303
- package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +286 -286
- package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +322 -322
- package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +319 -319
- package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +365 -365
- package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +156 -156
- package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +178 -178
- package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +312 -312
- package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +287 -287
- package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +286 -286
- package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +274 -274
- package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +294 -294
- package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +337 -337
- package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +388 -388
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +273 -273
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +380 -380
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +384 -384
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +350 -350
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +352 -352
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +383 -383
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +529 -529
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +395 -395
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +399 -399
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +485 -485
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +566 -566
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +567 -567
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +475 -475
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +462 -462
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +325 -325
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +401 -401
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +450 -450
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +475 -475
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +739 -739
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +567 -567
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +518 -518
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +532 -532
- package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +241 -241
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +383 -383
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +374 -374
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +375 -375
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +195 -195
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +268 -268
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +294 -294
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +164 -164
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +168 -168
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +254 -254
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +269 -269
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +148 -148
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +176 -176
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +604 -604
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +729 -729
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +291 -291
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +420 -420
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +319 -319
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +466 -466
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +523 -523
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +287 -287
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +340 -340
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +395 -395
- package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +248 -248
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +384 -384
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +452 -452
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +495 -495
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +416 -416
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +382 -382
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +687 -687
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +442 -442
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +479 -479
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +479 -479
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +427 -427
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +428 -428
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +339 -339
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +309 -309
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +596 -596
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +355 -355
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +350 -350
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +414 -414
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +367 -367
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +403 -403
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +291 -291
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +324 -324
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +332 -332
- package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +274 -274
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +298 -298
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +304 -304
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +362 -362
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +257 -257
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +254 -254
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +283 -283
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +395 -395
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +319 -319
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +382 -382
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +287 -287
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +303 -303
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +326 -326
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +332 -332
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +379 -379
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +177 -177
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +219 -219
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +244 -244
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +363 -363
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +438 -438
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +325 -325
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +403 -403
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +469 -469
- package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +174 -174
- package/lib/assets/docs/article/functional-desgin-ppp/index.md +90 -90
- package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +450 -450
- package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +463 -463
- package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +425 -425
- package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +273 -273
- package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +247 -247
- package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +841 -841
- package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +384 -384
- package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +383 -383
- package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +339 -339
- package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +331 -331
- package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +356 -356
- package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +379 -379
- package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +361 -361
- package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +392 -392
- package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +300 -300
- package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +297 -297
- package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +304 -304
- package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +315 -315
- package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +311 -311
- package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +304 -304
- package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +336 -336
- package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +349 -349
- package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +243 -243
- package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +328 -328
- package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +348 -348
- package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +357 -357
- package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +364 -364
- package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +515 -515
- package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +557 -557
- package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +363 -363
- package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +327 -327
- package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +517 -517
- package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +441 -441
- package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +407 -407
- package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +379 -379
- package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +398 -398
- package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +476 -476
- package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +391 -391
- package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +342 -342
- package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +324 -324
- package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +730 -730
- package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +624 -624
- package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +512 -512
- package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +433 -433
- package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +688 -688
- package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +243 -243
- package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +166 -166
- package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +162 -162
- package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +135 -135
- package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +88 -88
- package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +299 -299
- package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +241 -241
- package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +131 -131
- package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +130 -130
- package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +127 -127
- package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +114 -114
- package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +138 -138
- package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +161 -161
- package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +65 -65
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +232 -232
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +244 -244
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +202 -202
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +92 -92
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +256 -256
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +195 -195
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +214 -214
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +249 -249
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +174 -174
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +166 -166
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +192 -192
- package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +211 -211
- package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +83 -83
- package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +87 -87
- package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +95 -95
- package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +109 -109
- package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +96 -96
- package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +88 -88
- package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +71 -71
- package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +110 -110
- package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +108 -108
- package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +104 -104
- package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +178 -178
- package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +142 -142
- package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +145 -145
- package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +35 -35
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +202 -202
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +246 -246
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +218 -218
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +179 -179
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +267 -267
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +190 -190
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +161 -161
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +175 -175
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +222 -222
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +189 -189
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +212 -212
- package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +215 -215
- package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +71 -71
- package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +213 -213
- package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +302 -302
- package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +339 -339
- package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +112 -112
- package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +272 -272
- package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +233 -233
- package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +394 -394
- package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +422 -422
- package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +400 -400
- package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +226 -226
- package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +296 -296
- package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +411 -411
- package/lib/assets/docs/article/getting-start-tdd/go/index.md +83 -83
- package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +279 -279
- package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +337 -337
- package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +257 -257
- package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +182 -182
- package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +313 -313
- package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +309 -309
- package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +412 -412
- package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +390 -390
- package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +461 -461
- package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +434 -434
- package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +392 -392
- package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +631 -631
- package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +49 -49
- package/lib/assets/docs/article/getting-start-tdd/index.md +93 -93
- package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +375 -375
- package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +349 -349
- package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +445 -445
- package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +409 -409
- package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +330 -330
- package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +290 -290
- package/lib/assets/docs/article/getting-start-tdd/integration/index.md +69 -69
- package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +234 -234
- package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +261 -261
- package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +185 -185
- package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +115 -115
- package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +382 -382
- package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +272 -272
- package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +626 -626
- package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +393 -393
- package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +310 -310
- package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +188 -188
- package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +167 -167
- package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +205 -205
- package/lib/assets/docs/article/getting-start-tdd/java/index.md +61 -61
- package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +244 -244
- package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +262 -262
- package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +169 -169
- package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +112 -112
- package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +314 -314
- package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +235 -235
- package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +327 -327
- package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +322 -322
- package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +285 -285
- package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +199 -199
- package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +207 -207
- package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +295 -295
- package/lib/assets/docs/article/getting-start-tdd/node/index.md +56 -56
- package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +259 -259
- package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +200 -200
- package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +248 -248
- package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +141 -141
- package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +410 -410
- package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +321 -321
- package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +372 -372
- package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +453 -453
- package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +460 -460
- package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +182 -182
- package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +266 -266
- package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +308 -308
- package/lib/assets/docs/article/getting-start-tdd/php/index.md +84 -84
- package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +201 -201
- package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +247 -247
- package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +199 -199
- package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +87 -87
- package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +274 -274
- package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +190 -190
- package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +208 -208
- package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +172 -172
- package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +130 -130
- package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +122 -122
- package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +116 -116
- package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +126 -126
- package/lib/assets/docs/article/getting-start-tdd/python/index.md +55 -55
- package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +231 -231
- package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +238 -238
- package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +228 -228
- package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +112 -112
- package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +287 -287
- package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +248 -248
- package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +279 -279
- package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +329 -329
- package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +196 -196
- package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +175 -175
- package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +237 -237
- package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +398 -398
- package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +83 -83
- package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +211 -211
- package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +264 -264
- package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +233 -233
- package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +92 -92
- package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +212 -212
- package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +164 -164
- package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +142 -142
- package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +145 -145
- package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +110 -110
- package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +94 -94
- package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +105 -105
- package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +112 -112
- package/lib/assets/docs/article/getting-start-tdd/rust/index.md +83 -83
- package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +111 -111
- package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +107 -107
- package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +99 -99
- package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +123 -123
- package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +196 -196
- package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +186 -186
- package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +139 -139
- package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +106 -106
- package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +75 -75
- package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +104 -104
- package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +94 -94
- package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +92 -92
- package/lib/assets/docs/article/getting-start-tdd/scala/index.md +65 -65
- package/lib/assets/docs/article/grokking-concurrency/all/index.md +404 -404
- package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +554 -554
- package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +469 -469
- package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +520 -520
- package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +420 -420
- package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +510 -510
- package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +435 -435
- package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +465 -465
- package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +377 -377
- package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +116 -116
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +108 -108
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +122 -122
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +123 -123
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +118 -118
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +89 -89
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +100 -100
- package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +120 -120
- package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +97 -97
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +123 -123
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +112 -112
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +99 -99
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +61 -61
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +84 -84
- package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +92 -92
- package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +65 -65
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +80 -80
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +103 -103
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +94 -94
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +110 -110
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +104 -104
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +93 -93
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +121 -121
- package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +107 -107
- package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +248 -248
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +96 -96
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +96 -96
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +91 -91
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +106 -106
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +99 -99
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +95 -95
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +111 -111
- package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +118 -118
- package/lib/assets/docs/article/grokking-concurrency/index.md +66 -66
- package/lib/assets/docs/article/grokking-concurrency/java/index.md +102 -102
- package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +308 -308
- package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +334 -334
- package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +221 -221
- package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +213 -213
- package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +112 -112
- package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +69 -69
- package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +101 -101
- package/lib/assets/docs/article/grokking-concurrency/python/index.md +313 -313
- package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +239 -239
- package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +418 -418
- package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +227 -227
- package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +299 -299
- package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +315 -315
- package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +297 -297
- package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +314 -314
- package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +360 -360
- package/lib/assets/docs/article/grokking-concurrency/rust/index.md +270 -270
- package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +108 -108
- package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +120 -120
- package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +126 -126
- package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +175 -175
- package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +158 -158
- package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +94 -94
- package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +133 -133
- package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +155 -155
- package/lib/assets/docs/article/grokking-concurrency/scala/index.md +69 -69
- package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +78 -78
- package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +112 -112
- package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +93 -93
- package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +110 -110
- package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +119 -119
- package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +83 -83
- package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +131 -131
- package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +129 -129
- package/lib/assets/docs/article/grokkingfp/all/index.md +368 -368
- package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +530 -530
- package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +923 -923
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +1128 -1128
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +1104 -1104
- package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +1026 -1026
- package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +785 -785
- package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +871 -871
- package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +972 -972
- package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +926 -926
- package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +870 -870
- package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +715 -715
- package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +626 -626
- package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +712 -712
- package/lib/assets/docs/article/grokkingfp/clojure/index.md +276 -276
- package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +667 -667
- package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +643 -643
- package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +620 -620
- package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +697 -697
- package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +751 -751
- package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +721 -721
- package/lib/assets/docs/article/grokkingfp/csharp/index.md +246 -246
- package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +811 -811
- package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +971 -971
- package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +981 -981
- package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +949 -949
- package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +947 -947
- package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +739 -739
- package/lib/assets/docs/article/grokkingfp/elixir/index.md +203 -203
- package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +712 -712
- package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +838 -838
- package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +985 -985
- package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +974 -974
- package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +1286 -1286
- package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +1049 -1049
- package/lib/assets/docs/article/grokkingfp/fsharp/index.md +210 -210
- package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +714 -714
- package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +961 -961
- package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +972 -972
- package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +832 -832
- package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +911 -911
- package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +922 -922
- package/lib/assets/docs/article/grokkingfp/haskell/index.md +234 -234
- package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +591 -591
- package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +866 -866
- package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +915 -915
- package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +878 -878
- package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +845 -845
- package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +844 -844
- package/lib/assets/docs/article/grokkingfp/index.md +143 -143
- package/lib/assets/docs/article/grokkingfp/java/index.md +211 -211
- package/lib/assets/docs/article/grokkingfp/java/part-1.md +648 -648
- package/lib/assets/docs/article/grokkingfp/java/part-2.md +675 -675
- package/lib/assets/docs/article/grokkingfp/java/part-3.md +672 -672
- package/lib/assets/docs/article/grokkingfp/java/part-4.md +771 -771
- package/lib/assets/docs/article/grokkingfp/java/part-5.md +959 -959
- package/lib/assets/docs/article/grokkingfp/java/part-6.md +1328 -1328
- package/lib/assets/docs/article/grokkingfp/python/index.md +258 -258
- package/lib/assets/docs/article/grokkingfp/python/part-1.md +443 -443
- package/lib/assets/docs/article/grokkingfp/python/part-2.md +958 -958
- package/lib/assets/docs/article/grokkingfp/python/part-3.md +1004 -1004
- package/lib/assets/docs/article/grokkingfp/python/part-4.md +765 -765
- package/lib/assets/docs/article/grokkingfp/python/part-5.md +747 -747
- package/lib/assets/docs/article/grokkingfp/python/part-6.md +861 -861
- package/lib/assets/docs/article/grokkingfp/ruby/index.md +330 -330
- package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +755 -755
- package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +938 -938
- package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +946 -946
- package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +921 -921
- package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +908 -908
- package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +1412 -1412
- package/lib/assets/docs/article/grokkingfp/rust/index.md +242 -242
- package/lib/assets/docs/article/grokkingfp/rust/part-1.md +634 -634
- package/lib/assets/docs/article/grokkingfp/rust/part-2.md +1060 -1060
- package/lib/assets/docs/article/grokkingfp/rust/part-3.md +994 -994
- package/lib/assets/docs/article/grokkingfp/rust/part-4.md +573 -573
- package/lib/assets/docs/article/grokkingfp/rust/part-5.md +705 -705
- package/lib/assets/docs/article/grokkingfp/rust/part-6.md +508 -508
- package/lib/assets/docs/article/grokkingfp/scala/index.md +171 -171
- package/lib/assets/docs/article/grokkingfp/scala/part-1.md +543 -543
- package/lib/assets/docs/article/grokkingfp/scala/part-2.md +946 -946
- package/lib/assets/docs/article/grokkingfp/scala/part-3.md +919 -919
- package/lib/assets/docs/article/grokkingfp/scala/part-4.md +742 -742
- package/lib/assets/docs/article/grokkingfp/scala/part-5.md +722 -722
- package/lib/assets/docs/article/grokkingfp/scala/part-6.md +867 -867
- package/lib/assets/docs/article/grokkingfp/typescript/index.md +273 -273
- package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +561 -561
- package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +1129 -1129
- package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +842 -842
- package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +1087 -1087
- package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +717 -717
- package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +982 -982
- package/lib/assets/docs/article/practical-database-design/index.md +121 -121
- package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +288 -288
- package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +518 -518
- package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +557 -557
- package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +924 -924
- package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +1627 -1627
- package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +2716 -2716
- package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +2082 -2082
- package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +2105 -2105
- package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +2031 -2031
- package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +1387 -1387
- package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +1677 -1677
- package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +1417 -1417
- package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +1434 -1434
- package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +667 -667
- package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +1625 -1625
- package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +1915 -1915
- package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +1708 -1708
- package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +2095 -2095
- package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +1123 -1123
- package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +1031 -1031
- package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +1382 -1382
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +991 -991
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +1300 -1300
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +1166 -1166
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +1584 -1584
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +1183 -1183
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +1016 -1016
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +1753 -1753
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +1447 -1447
- package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +1878 -1878
- package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +965 -965
- package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +2069 -2069
- package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +2439 -2439
- package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +3661 -3661
- package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +2916 -2916
- package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +3105 -3105
- package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +2697 -2697
- package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +2544 -2544
- package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +2180 -2180
- package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +1192 -1192
- package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +2101 -2101
- package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +1032 -1032
- package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +1609 -1609
- package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +1453 -1453
- package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +1292 -1292
- package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +1470 -1470
- package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +1698 -1698
- package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +2334 -2334
- package/lib/assets/docs/article/practical-database-design/study/study2-1.md +1693 -1693
- package/lib/assets/docs/article/practical-database-design/study/study2-2.md +1347 -1347
- package/lib/assets/docs/article/practical-database-design/study/study2-3.md +2044 -2044
- package/lib/assets/docs/article/practical-database-design/study/study2-4.md +2229 -2229
- package/lib/assets/docs/article/practical-database-design/study/study2-5.md +2418 -2418
- package/lib/assets/docs/article/practical-database-design/study/study3-1.md +2205 -2205
- package/lib/assets/docs/article/practical-database-design/study/study3-2.md +2221 -2221
- package/lib/assets/docs/article/practical-database-design/study/study3-3.md +2253 -2253
- package/lib/assets/docs/article/practical-database-design/study/study3-4.md +2106 -2106
- package/lib/assets/docs/article/practical-database-design/study/study3-5.md +2507 -2507
- package/lib/assets/docs/article/practical-database-design/study/study4-1.md +2587 -2587
- package/lib/assets/docs/article/practical-database-design/study/study4-2.md +2075 -2075
- package/lib/assets/docs/article/practical-database-design/study/study4-3.md +1805 -1805
- package/lib/assets/docs/article/practical-database-design/study/study4-4.md +1895 -1895
- package/lib/assets/docs/article/practical-database-design/study/study4-5.md +2878 -2878
- package/lib/assets/docs/assets/css/extra.css +29 -29
- package/lib/assets/docs/assets/js/extra.js +44 -44
- package/lib/assets/docs/development/index.md +39 -39
- package/lib/assets/docs/operation/index.md +11 -11
- package/lib/assets/docs/reference/CodexCLIMCP/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/351/226/213/347/231/272/343/203/225/343/203/255/343/203/274.md +532 -532
- package/lib/assets/docs/reference/CodexCLIMCP/343/202/265/343/203/274/343/203/220/343/203/274/350/250/255/345/256/232/346/211/213/351/240/206.md +341 -341
- package/lib/assets/docs/reference/Java/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/346/247/213/347/257/211/343/202/254/343/202/244/343/203/211.md +581 -580
- package/lib/assets/docs/reference/SonarQube/343/203/255/343/203/274/343/202/253/343/203/253/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +642 -642
- package/lib/assets/docs/reference/TypeScript/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/346/247/213/347/257/211/343/202/254/343/202/244/343/203/211.md +465 -465
- package/lib/assets/docs/reference/UI/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +450 -450
- package/lib/assets/docs/reference/images/Ansoff.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BrandBasicStrategy.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BrandCategorization.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BrandRecurutementStrategy.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BrandValue.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/BusinessActivitiy.svg +3 -3
- package/lib/assets/docs/reference/images/HRM.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/MarketingStructure.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/OrganizationElemnts.svg +3 -3
- package/lib/assets/docs/reference/images/PPM.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/PositioningMap.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/ProductLayer.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/ProductMix.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/SWOT.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/TargetMarket.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/ThreeGenericStrategies.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/VRIO.drawio.svg +3 -3
- package/lib/assets/docs/reference/images/ValueChain.drawio.svg +3 -3
- package/lib/assets/docs/reference/index.md +52 -52
- package/lib/assets/docs/reference//343/202/210/343/201/204/343/202/275/343/203/225/343/203/210/343/202/246/343/202/247/343/202/242/343/201/250/343/201/257.md +250 -242
- package/lib/assets/docs/reference//343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +2216 -2216
- package/lib/assets/docs/reference//343/202/244/343/203/263/343/203/225/343/203/251/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +1878 -1878
- package/lib/assets/docs/reference//343/202/250/343/202/257/343/202/271/343/203/210/343/203/252/343/203/274/343/203/240/343/203/227/343/203/255/343/202/260/343/203/251/343/203/237/343/203/263/343/202/260.md +550 -544
- package/lib/assets/docs/reference//343/202/263/343/203/274/343/203/207/343/202/243/343/203/263/343/202/260/343/201/250/343/203/206/343/202/271/343/203/210/343/202/254/343/202/244/343/203/211.md +705 -705
- package/lib/assets/docs/reference//343/203/206/343/202/271/343/203/210/346/210/246/347/225/245/343/202/254/343/202/244/343/203/211.md +1313 -1313
- package/lib/assets/docs/reference//343/203/207/343/203/274/343/202/277/343/203/242/343/203/207/343/203/253/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +311 -311
- package/lib/assets/docs/reference//343/203/211/343/203/241/343/202/244/343/203/263/343/203/242/343/203/207/343/203/253/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +599 -599
- package/lib/assets/docs/reference//343/203/223/343/202/270/343/203/215/343/202/271/343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243/345/210/206/346/236/220/343/202/254/343/202/244/343/203/211.md +528 -528
- package/lib/assets/docs/reference//343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/344/275/234/346/210/220/343/202/254/343/202/244/343/203/211.md +689 -682
- package/lib/assets/docs/reference//343/203/252/343/203/252/343/203/274/343/202/271/343/202/254/343/202/244/343/203/211.md +461 -461
- package/lib/assets/docs/reference//343/203/252/343/203/252/343/203/274/343/202/271/343/203/273/343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/350/250/210/347/224/273/343/202/254/343/202/244/343/203/211.md +580 -560
- package/lib/assets/docs/reference//343/203/255/343/202/270/343/202/253/343/203/253/343/202/267/343/203/263/343/202/255/343/203/263/343/202/260.md +1367 -1367
- package/lib/assets/docs/reference//344/274/201/346/245/255/347/265/214/345/226/266/350/253/226.md +2637 -2636
- package/lib/assets/docs/reference//347/222/260/345/242/203/345/244/211/346/225/260/347/256/241/347/220/206/343/202/254/343/202/244/343/203/211.md +665 -663
- package/lib/assets/docs/reference//350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +1248 -1248
- package/lib/assets/docs/reference//350/250/200/350/252/236/345/210/245/351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +28 -0
- package/lib/assets/docs/reference//351/201/213/345/226/266/347/256/241/347/220/206.md +1482 -1482
- package/lib/assets/docs/reference//351/201/213/347/224/250/343/202/271/343/202/257/343/203/252/343/203/227/343/203/210/344/275/234/346/210/220/343/202/254/343/202/244/343/203/211.md +421 -421
- package/lib/assets/docs/reference//351/201/213/347/224/250/350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +392 -392
- package/lib/assets/docs/reference//351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +299 -299
- package/lib/assets/docs/reference//351/235/236/346/251/237/350/203/275/350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +1236 -1236
- package/lib/assets/docs/review/index.md +5 -5
- package/lib/assets/docs/strategy/index.md +1 -1
- package/lib/assets/docs/template/ADR.md +30 -30
- package/lib/assets/docs/template/AWS/343/202/271/343/203/206/343/203/274/343/202/270/343/203/263/343/202/260/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +1366 -1366
- package/lib/assets/docs/template/AWS/343/203/227/343/203/255/343/203/200/343/202/257/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +634 -634
- package/lib/assets/docs/template/README.md +50 -50
- package/lib/assets/docs/template/index.md +23 -23
- package/lib/assets/docs/template//343/201/276/343/201/232/343/201/223/343/202/214/343/202/222/350/252/255/343/202/202/343/201/206/343/203/252/343/202/271/343/203/210.md +12 -12
- package/lib/assets/docs/template//343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/351/226/213/347/231/272/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +547 -547
- package/lib/assets/docs/template//343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/345/256/214/344/272/206/345/240/261/345/221/212/346/233/270.md +58 -58
- package/lib/assets/docs/template//343/202/244/343/203/263/343/202/273/343/203/227/343/202/267/343/203/247/343/203/263/343/203/207/343/203/203/343/202/255.md +13 -13
- package/lib/assets/docs/template//343/203/223/343/202/270/343/203/215/343/202/271/343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243.md +379 -379
- package/lib/assets/docs/template//344/274/201/346/245/255/345/210/206/346/236/220.md +573 -573
- package/lib/assets/docs/template//345/256/214/345/205/250/345/275/242/345/274/217/343/201/256/343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271.md +69 -68
- package/lib/assets/docs/template//350/246/201/344/273/266/345/256/232/347/276/251.md +669 -669
- package/lib/assets/docs/template//350/250/255/350/250/210.md +173 -173
- package/lib/assets/docs/template//351/226/213/347/231/272/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +688 -688
- package/lib/assets/gulpfile.js +25 -25
- package/lib/assets/mkdocs.yml +136 -135
- package/lib/assets/ops/docker/mkdoc/Dockerfile +19 -19
- package/lib/assets/ops/scripts/journal.js +180 -180
- package/lib/assets/ops/scripts/mkdocs.js +82 -82
- package/lib/assets/ops/scripts/release.js +431 -431
- package/lib/assets/ops/scripts/sonar_local.js +726 -726
- package/lib/assets/ops/scripts/ssh.js +190 -190
- package/lib/assets/ops/scripts/vault.js +299 -299
- package/lib/assets/package-lock.json +1653 -1653
- package/lib/assets/package.json +40 -40
- package/lib/gulpfile.js +37 -37
- package/package.json +41 -41
- package/lib/assets/.claude/agent-memory/xp-programmer/MEMORY.md +0 -6
- package/lib/assets/.claude/agent-memory/xp-programmer/project_cargo_tracker.md +0 -11
- package/lib/assets/.claude/agent-memory/xp-programmer/project_ddd_patterns.md +0 -27
- package/lib/assets/.claude/agent-memory/xp-programmer/project_us07_route_assignment.md +0 -19
|
@@ -1,596 +1,596 @@
|
|
|
1
|
-
# 第14章: Abstract Server パターン
|
|
2
|
-
|
|
3
|
-
## はじめに
|
|
4
|
-
|
|
5
|
-
Abstract Server パターンは、依存関係逆転の原則(DIP)を実現するパターンです。高レベルモジュールが低レベルモジュールの詳細に依存するのではなく、両者が抽象に依存することで疎結合を実現します。
|
|
6
|
-
|
|
7
|
-
本章では、スイッチとデバイス、リポジトリとサービスの例を通じて、インターフェースによる Abstract Server パターンの実装を学びます。
|
|
8
|
-
|
|
9
|
-
## 1. パターンの構造
|
|
10
|
-
|
|
11
|
-
Abstract Server パターンは以下の要素で構成されます:
|
|
12
|
-
|
|
13
|
-
- **Client**: サービスを利用するモジュール
|
|
14
|
-
- **Abstract Server**: サービスの抽象インターフェース
|
|
15
|
-
- **Concrete Server**: 具体的なサービスの実装
|
|
16
|
-
|
|
17
|
-
```plantuml
|
|
18
|
-
@startuml
|
|
19
|
-
skinparam classAttributeIconSize 0
|
|
20
|
-
|
|
21
|
-
class "Client\n(Switch)" as client {
|
|
22
|
-
+engage(device)
|
|
23
|
-
+disengage(device)
|
|
24
|
-
+toggle(device)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface "Abstract Server\n(ISwitchable)" as abstract {
|
|
28
|
-
+TurnOn()
|
|
29
|
-
+TurnOff()
|
|
30
|
-
+IsOn
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
class "Concrete Server\n(Light)" as light {
|
|
34
|
-
+State
|
|
35
|
-
+TurnOn()
|
|
36
|
-
+TurnOff()
|
|
37
|
-
+IsOn
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
class "Concrete Server\n(Fan)" as fan {
|
|
41
|
-
+State
|
|
42
|
-
+Speed
|
|
43
|
-
+TurnOn()
|
|
44
|
-
+TurnOff()
|
|
45
|
-
+IsOn
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
class "Concrete Server\n(Motor)" as motor {
|
|
49
|
-
+State
|
|
50
|
-
+Direction
|
|
51
|
-
+TurnOn()
|
|
52
|
-
+TurnOff()
|
|
53
|
-
+IsOn
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
client --> abstract : depends on
|
|
57
|
-
light ..|> abstract
|
|
58
|
-
fan ..|> abstract
|
|
59
|
-
motor ..|> abstract
|
|
60
|
-
|
|
61
|
-
note right of client
|
|
62
|
-
Clientは抽象に依存します。
|
|
63
|
-
具体的な実装を知りません。
|
|
64
|
-
end note
|
|
65
|
-
|
|
66
|
-
note right of abstract
|
|
67
|
-
Abstract Serverは
|
|
68
|
-
インターフェースを定義します。
|
|
69
|
-
F#ではinterfaceを使用します。
|
|
70
|
-
end note
|
|
71
|
-
@enduml
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## 2. ISwitchable インターフェース
|
|
75
|
-
|
|
76
|
-
### Abstract Server の定義
|
|
77
|
-
|
|
78
|
-
```fsharp
|
|
79
|
-
/// スイッチ可能なデバイスのインターフェース
|
|
80
|
-
type ISwitchable =
|
|
81
|
-
abstract member TurnOn: unit -> ISwitchable
|
|
82
|
-
abstract member TurnOff: unit -> ISwitchable
|
|
83
|
-
abstract member IsOn: bool
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
F# のインターフェースは、メソッドを定義する abstract member として宣言します。イミュータブルな実装のため、`TurnOn` と `TurnOff` は新しい `ISwitchable` を返します。
|
|
87
|
-
|
|
88
|
-
## 3. Concrete Server: Light
|
|
89
|
-
|
|
90
|
-
### 実装
|
|
91
|
-
|
|
92
|
-
```fsharp
|
|
93
|
-
type Light =
|
|
94
|
-
{ State: bool }
|
|
95
|
-
interface ISwitchable with
|
|
96
|
-
member this.TurnOn() = { State = true } :> ISwitchable
|
|
97
|
-
member this.TurnOff() = { State = false } :> ISwitchable
|
|
98
|
-
member this.IsOn = this.State
|
|
99
|
-
|
|
100
|
-
module Light =
|
|
101
|
-
let create () = { State = false }
|
|
102
|
-
let createOn () = { State = true }
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Light はレコード型として定義し、`ISwitchable` インターフェースを実装します。`:>` 演算子で基底型へのアップキャストを行います。
|
|
106
|
-
|
|
107
|
-
## 4. Concrete Server: Fan
|
|
108
|
-
|
|
109
|
-
### 実装
|
|
110
|
-
|
|
111
|
-
```fsharp
|
|
112
|
-
[<RequireQualifiedAccess>]
|
|
113
|
-
type FanSpeed = | Low | Medium | High
|
|
114
|
-
|
|
115
|
-
type Fan =
|
|
116
|
-
{ State: bool
|
|
117
|
-
Speed: FanSpeed option }
|
|
118
|
-
interface ISwitchable with
|
|
119
|
-
member this.TurnOn() = { State = true; Speed = Some FanSpeed.Low } :> ISwitchable
|
|
120
|
-
member this.TurnOff() = { State = false; Speed = None } :> ISwitchable
|
|
121
|
-
member this.IsOn = this.State
|
|
122
|
-
|
|
123
|
-
module Fan =
|
|
124
|
-
let create () = { State = false; Speed = None }
|
|
125
|
-
let setSpeed (speed: FanSpeed) (fan: Fan) =
|
|
126
|
-
if fan.State then { fan with Speed = Some speed }
|
|
127
|
-
else fan
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Fan はスピード設定を持つデバイスです。`[<RequireQualifiedAccess>]` 属性により、`FanSpeed.Low` のように修飾名でアクセスします。
|
|
131
|
-
|
|
132
|
-
## 5. Concrete Server: Motor
|
|
133
|
-
|
|
134
|
-
### 実装
|
|
135
|
-
|
|
136
|
-
```fsharp
|
|
137
|
-
[<RequireQualifiedAccess>]
|
|
138
|
-
type MotorDirection = | Forward | Reverse
|
|
139
|
-
|
|
140
|
-
type Motor =
|
|
141
|
-
{ State: bool
|
|
142
|
-
Direction: MotorDirection option }
|
|
143
|
-
interface ISwitchable with
|
|
144
|
-
member this.TurnOn() = { State = true; Direction = Some MotorDirection.Forward } :> ISwitchable
|
|
145
|
-
member this.TurnOff() = { State = false; Direction = None } :> ISwitchable
|
|
146
|
-
member this.IsOn = this.State
|
|
147
|
-
|
|
148
|
-
module Motor =
|
|
149
|
-
let create () = { State = false; Direction = None }
|
|
150
|
-
let reverse (motor: Motor) =
|
|
151
|
-
if motor.State then
|
|
152
|
-
let newDir =
|
|
153
|
-
match motor.Direction with
|
|
154
|
-
| Some MotorDirection.Forward -> Some MotorDirection.Reverse
|
|
155
|
-
| Some MotorDirection.Reverse -> Some MotorDirection.Forward
|
|
156
|
-
| None -> Some MotorDirection.Forward
|
|
157
|
-
{ motor with Direction = newDir }
|
|
158
|
-
else motor
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Motor は方向を持つデバイスで、`reverse` 関数で方向を反転できます。
|
|
162
|
-
|
|
163
|
-
## 6. Client: Switch
|
|
164
|
-
|
|
165
|
-
### 実装
|
|
166
|
-
|
|
167
|
-
```fsharp
|
|
168
|
-
module Switch =
|
|
169
|
-
/// スイッチを入れる
|
|
170
|
-
let engage (device: ISwitchable) : ISwitchable =
|
|
171
|
-
device.TurnOn()
|
|
172
|
-
|
|
173
|
-
/// スイッチを切る
|
|
174
|
-
let disengage (device: ISwitchable) : ISwitchable =
|
|
175
|
-
device.TurnOff()
|
|
176
|
-
|
|
177
|
-
/// スイッチを切り替える
|
|
178
|
-
let toggle (device: ISwitchable) : ISwitchable =
|
|
179
|
-
if device.IsOn then device.TurnOff()
|
|
180
|
-
else device.TurnOn()
|
|
181
|
-
|
|
182
|
-
/// デバイスの状態を取得
|
|
183
|
-
let status (device: ISwitchable) : string =
|
|
184
|
-
if device.IsOn then "ON" else "OFF"
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### 使用例
|
|
188
|
-
|
|
189
|
-
```fsharp
|
|
190
|
-
// 同じSwitchコードで異なるデバイスを操作
|
|
191
|
-
let light = Light.create ()
|
|
192
|
-
let lightOn = Switch.engage (light :> ISwitchable)
|
|
193
|
-
printfn "%s" (Switch.status lightOn) // "ON"
|
|
194
|
-
|
|
195
|
-
let fan = Fan.create ()
|
|
196
|
-
let fanOn = Switch.engage (fan :> ISwitchable)
|
|
197
|
-
printfn "%s" (Switch.status fanOn) // "ON"
|
|
198
|
-
|
|
199
|
-
let motor = Motor.create ()
|
|
200
|
-
let motorOn = Switch.engage (motor :> ISwitchable)
|
|
201
|
-
printfn "%s" (Switch.status motorOn) // "ON"
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
## 7. シーケンス図
|
|
205
|
-
|
|
206
|
-
```plantuml
|
|
207
|
-
@startuml
|
|
208
|
-
actor Client
|
|
209
|
-
participant "Switch" as switch
|
|
210
|
-
participant "ISwitchable\n(Interface)" as interface
|
|
211
|
-
participant "Light" as light
|
|
212
|
-
participant "Fan" as fan
|
|
213
|
-
|
|
214
|
-
== Light の操作 ==
|
|
215
|
-
Client -> switch : engage(light)
|
|
216
|
-
activate switch
|
|
217
|
-
switch -> interface : TurnOn(light)
|
|
218
|
-
activate interface
|
|
219
|
-
interface -> light : TurnOn()
|
|
220
|
-
activate light
|
|
221
|
-
light --> interface : updated-light
|
|
222
|
-
deactivate light
|
|
223
|
-
interface --> switch : updated-light
|
|
224
|
-
deactivate interface
|
|
225
|
-
switch --> Client : light-on
|
|
226
|
-
deactivate switch
|
|
227
|
-
|
|
228
|
-
== Fan の操作 ==
|
|
229
|
-
Client -> switch : engage(fan)
|
|
230
|
-
activate switch
|
|
231
|
-
switch -> interface : TurnOn(fan)
|
|
232
|
-
activate interface
|
|
233
|
-
interface -> fan : TurnOn()
|
|
234
|
-
activate fan
|
|
235
|
-
fan --> interface : updated-fan
|
|
236
|
-
deactivate fan
|
|
237
|
-
interface --> switch : updated-fan
|
|
238
|
-
deactivate interface
|
|
239
|
-
switch --> Client : fan-on
|
|
240
|
-
deactivate switch
|
|
241
|
-
|
|
242
|
-
note right
|
|
243
|
-
Switchは具体的なデバイスを
|
|
244
|
-
知らずに操作できます。
|
|
245
|
-
ISwitchableインターフェースを通じて
|
|
246
|
-
多態的に動作します。
|
|
247
|
-
end note
|
|
248
|
-
@enduml
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## 8. Repository の例
|
|
252
|
-
|
|
253
|
-
### Abstract Server: IRepository インターフェース
|
|
254
|
-
|
|
255
|
-
```fsharp
|
|
256
|
-
/// リポジトリインターフェース
|
|
257
|
-
type IRepository<'TEntity, 'TId> =
|
|
258
|
-
abstract member FindById: 'TId -> 'TEntity option
|
|
259
|
-
abstract member FindAll: unit -> 'TEntity list
|
|
260
|
-
abstract member Save: 'TEntity -> 'TEntity
|
|
261
|
-
abstract member Delete: 'TId -> bool
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
ジェネリック型パラメータを使用して、任意のエンティティと ID 型に対応します。
|
|
265
|
-
|
|
266
|
-
### Concrete Server: MemoryUserRepository
|
|
267
|
-
|
|
268
|
-
```fsharp
|
|
269
|
-
type User =
|
|
270
|
-
{ Id: string
|
|
271
|
-
Name: string
|
|
272
|
-
Email: string
|
|
273
|
-
CreatedAt: System.DateTime }
|
|
274
|
-
|
|
275
|
-
type MemoryUserRepository(initialData: Map<string, User>) =
|
|
276
|
-
let mutable data = initialData
|
|
277
|
-
|
|
278
|
-
interface IRepository<User, string> with
|
|
279
|
-
member _.FindById(id) = Map.tryFind id data
|
|
280
|
-
member _.FindAll() = data |> Map.toList |> List.map snd
|
|
281
|
-
member _.Save(user) =
|
|
282
|
-
let userId = if user.Id = "" then System.Guid.NewGuid().ToString() else user.Id
|
|
283
|
-
let userWithId = { user with Id = userId }
|
|
284
|
-
data <- Map.add userId userWithId data
|
|
285
|
-
userWithId
|
|
286
|
-
member _.Delete(id) =
|
|
287
|
-
if Map.containsKey id data then
|
|
288
|
-
data <- Map.remove id data
|
|
289
|
-
true
|
|
290
|
-
else false
|
|
291
|
-
|
|
292
|
-
module MemoryUserRepository =
|
|
293
|
-
let create () = MemoryUserRepository(Map.empty)
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### Client: UserService
|
|
297
|
-
|
|
298
|
-
```fsharp
|
|
299
|
-
module UserService =
|
|
300
|
-
/// ユーザーを作成
|
|
301
|
-
let createUser (repo: IRepository<User, string>) (name: string) (email: string) : User =
|
|
302
|
-
let user =
|
|
303
|
-
{ Id = ""
|
|
304
|
-
Name = name
|
|
305
|
-
Email = email
|
|
306
|
-
CreatedAt = System.DateTime.UtcNow }
|
|
307
|
-
repo.Save(user)
|
|
308
|
-
|
|
309
|
-
/// ユーザーを取得
|
|
310
|
-
let getUser (repo: IRepository<User, string>) (id: string) : User option =
|
|
311
|
-
repo.FindById(id)
|
|
312
|
-
|
|
313
|
-
/// 全ユーザーを取得
|
|
314
|
-
let getAllUsers (repo: IRepository<User, string>) : User list =
|
|
315
|
-
repo.FindAll()
|
|
316
|
-
|
|
317
|
-
/// ユーザーを削除
|
|
318
|
-
let deleteUser (repo: IRepository<User, string>) (id: string) : bool =
|
|
319
|
-
repo.Delete(id)
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
## 9. 依存関係の図
|
|
323
|
-
|
|
324
|
-
```plantuml
|
|
325
|
-
@startuml
|
|
326
|
-
skinparam classAttributeIconSize 0
|
|
327
|
-
|
|
328
|
-
package "Application Layer" {
|
|
329
|
-
class "UserService" as service {
|
|
330
|
-
+createUser(repo, name, email)
|
|
331
|
-
+getUser(repo, id)
|
|
332
|
-
+getAllUsers(repo)
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
package "Domain Layer" {
|
|
337
|
-
interface "IRepository" as repo {
|
|
338
|
-
+FindById(id)
|
|
339
|
-
+FindAll()
|
|
340
|
-
+Save(entity)
|
|
341
|
-
+Delete(id)
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
package "Infrastructure Layer" {
|
|
346
|
-
class "MemoryUserRepository" as memRepo {
|
|
347
|
-
+data: Map
|
|
348
|
-
+FindById(id)
|
|
349
|
-
+FindAll()
|
|
350
|
-
+Save(entity)
|
|
351
|
-
+Delete(id)
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
class "DatabaseRepository" as dbRepo {
|
|
355
|
-
+connection
|
|
356
|
-
+FindById(id)
|
|
357
|
-
+FindAll()
|
|
358
|
-
+Save(entity)
|
|
359
|
-
+Delete(id)
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
service --> repo : depends on
|
|
364
|
-
memRepo ..|> repo
|
|
365
|
-
dbRepo ..|> repo
|
|
366
|
-
|
|
367
|
-
note right of service
|
|
368
|
-
UserServiceはIRepositoryインターフェースに
|
|
369
|
-
依存します。具体的な実装は
|
|
370
|
-
実行時に注入されます。
|
|
371
|
-
end note
|
|
372
|
-
|
|
373
|
-
note bottom of memRepo
|
|
374
|
-
テスト時はMemoryUserRepository、
|
|
375
|
-
本番時はDatabaseRepositoryを
|
|
376
|
-
使用できます。
|
|
377
|
-
end note
|
|
378
|
-
@enduml
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
## 10. 関数型アプローチ:レコード+関数
|
|
382
|
-
|
|
383
|
-
F# では、インターフェースの代わりにレコード型で関数を束ねる方法もあります:
|
|
384
|
-
|
|
385
|
-
```fsharp
|
|
386
|
-
/// 関数型リポジトリ
|
|
387
|
-
type FunctionalRepository<'TEntity, 'TId> =
|
|
388
|
-
{ FindById: 'TId -> 'TEntity option
|
|
389
|
-
FindAll: unit -> 'TEntity list
|
|
390
|
-
Save: 'TEntity -> 'TEntity
|
|
391
|
-
Delete: 'TId -> bool }
|
|
392
|
-
|
|
393
|
-
module FunctionalRepository =
|
|
394
|
-
/// インメモリリポジトリを作成
|
|
395
|
-
let createInMemory<'TId, 'TEntity when 'TId: comparison>
|
|
396
|
-
(getId: 'TEntity -> 'TId)
|
|
397
|
-
(setId: 'TId -> 'TEntity -> 'TEntity)
|
|
398
|
-
(generateId: unit -> 'TId)
|
|
399
|
-
: FunctionalRepository<'TEntity, 'TId> =
|
|
400
|
-
let mutable data: Map<'TId, 'TEntity> = Map.empty
|
|
401
|
-
{ FindById = fun id -> Map.tryFind id data
|
|
402
|
-
FindAll = fun () -> data |> Map.toList |> List.map snd
|
|
403
|
-
Save = fun entity ->
|
|
404
|
-
let entityId = if getId entity = Unchecked.defaultof<'TId> then generateId() else getId entity
|
|
405
|
-
let entityWithId = setId entityId entity
|
|
406
|
-
data <- Map.add entityId entityWithId data
|
|
407
|
-
entityWithId
|
|
408
|
-
Delete = fun id ->
|
|
409
|
-
if Map.containsKey id data then
|
|
410
|
-
data <- Map.remove id data
|
|
411
|
-
true
|
|
412
|
-
else false }
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
使用例:
|
|
416
|
-
|
|
417
|
-
```fsharp
|
|
418
|
-
type SimpleUser = { Id: int; Name: string }
|
|
419
|
-
|
|
420
|
-
let mutable nextId = 1
|
|
421
|
-
let repo = FunctionalRepository.createInMemory<int, SimpleUser>
|
|
422
|
-
(fun u -> u.Id)
|
|
423
|
-
(fun id u -> { u with Id = id })
|
|
424
|
-
(fun () ->
|
|
425
|
-
let id = nextId
|
|
426
|
-
nextId <- nextId + 1
|
|
427
|
-
id)
|
|
428
|
-
|
|
429
|
-
let user = repo.Save { Id = 0; Name = "Alice" }
|
|
430
|
-
let found = repo.FindById user.Id
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
## 11. Logger と Cache の例
|
|
434
|
-
|
|
435
|
-
### ILogger インターフェース
|
|
436
|
-
|
|
437
|
-
```fsharp
|
|
438
|
-
[<RequireQualifiedAccess>]
|
|
439
|
-
type LogLevel = | Debug | Info | Warning | Error
|
|
440
|
-
|
|
441
|
-
type ILogger =
|
|
442
|
-
abstract member Log: LogLevel -> string -> unit
|
|
443
|
-
abstract member Debug: string -> unit
|
|
444
|
-
abstract member Info: string -> unit
|
|
445
|
-
abstract member Warning: string -> unit
|
|
446
|
-
abstract member Error: string -> unit
|
|
447
|
-
|
|
448
|
-
type BufferedLogger() =
|
|
449
|
-
let mutable logs: (LogLevel * string * System.DateTime) list = []
|
|
450
|
-
|
|
451
|
-
interface ILogger with
|
|
452
|
-
member _.Log level message =
|
|
453
|
-
logs <- (level, message, System.DateTime.UtcNow) :: logs
|
|
454
|
-
member this.Debug message = (this :> ILogger).Log LogLevel.Debug message
|
|
455
|
-
member this.Info message = (this :> ILogger).Log LogLevel.Info message
|
|
456
|
-
member this.Warning message = (this :> ILogger).Log LogLevel.Warning message
|
|
457
|
-
member this.Error message = (this :> ILogger).Log LogLevel.Error message
|
|
458
|
-
|
|
459
|
-
member _.GetLogs() = List.rev logs
|
|
460
|
-
member _.Clear() = logs <- []
|
|
461
|
-
|
|
462
|
-
type NullLogger() =
|
|
463
|
-
interface ILogger with
|
|
464
|
-
member _.Log _ _ = ()
|
|
465
|
-
member _.Debug _ = ()
|
|
466
|
-
member _.Info _ = ()
|
|
467
|
-
member _.Warning _ = ()
|
|
468
|
-
member _.Error _ = ()
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
### ICache インターフェース
|
|
472
|
-
|
|
473
|
-
```fsharp
|
|
474
|
-
type ICache<'TKey, 'TValue> =
|
|
475
|
-
abstract member Get: 'TKey -> 'TValue option
|
|
476
|
-
abstract member Set: 'TKey -> 'TValue -> unit
|
|
477
|
-
abstract member Remove: 'TKey -> bool
|
|
478
|
-
abstract member Clear: unit -> unit
|
|
479
|
-
|
|
480
|
-
type MemoryCache<'TKey, 'TValue when 'TKey: comparison>() =
|
|
481
|
-
let mutable data: Map<'TKey, 'TValue> = Map.empty
|
|
482
|
-
|
|
483
|
-
interface ICache<'TKey, 'TValue> with
|
|
484
|
-
member _.Get key = Map.tryFind key data
|
|
485
|
-
member _.Set key value = data <- Map.add key value data
|
|
486
|
-
member _.Remove key =
|
|
487
|
-
if Map.containsKey key data then
|
|
488
|
-
data <- Map.remove key data
|
|
489
|
-
true
|
|
490
|
-
else false
|
|
491
|
-
member _.Clear() = data <- Map.empty
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
## 12. 依存性注入コンテナ
|
|
495
|
-
|
|
496
|
-
シンプルな DI コンテナの実装例:
|
|
497
|
-
|
|
498
|
-
```fsharp
|
|
499
|
-
type ServiceContainer() =
|
|
500
|
-
let mutable services: Map<string, obj> = Map.empty
|
|
501
|
-
|
|
502
|
-
member _.Register<'T>(key: string) (service: 'T) =
|
|
503
|
-
services <- Map.add key (box service) services
|
|
504
|
-
|
|
505
|
-
member _.Resolve<'T>(key: string) : 'T option =
|
|
506
|
-
Map.tryFind key services |> Option.map (fun s -> s :?> 'T)
|
|
507
|
-
|
|
508
|
-
member _.RegisterSingleton<'T>(service: 'T) =
|
|
509
|
-
let key = typeof<'T>.FullName
|
|
510
|
-
services <- Map.add key (box service) services
|
|
511
|
-
|
|
512
|
-
member _.ResolveSingleton<'T>() : 'T option =
|
|
513
|
-
let key = typeof<'T>.FullName
|
|
514
|
-
Map.tryFind key services |> Option.map (fun s -> s :?> 'T)
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
## 13. パターンの利点
|
|
518
|
-
|
|
519
|
-
1. **疎結合**: クライアントは具体的な実装を知らない
|
|
520
|
-
2. **テスト容易性**: モック/スタブを簡単に注入可能
|
|
521
|
-
3. **柔軟性**: 実装の交換が容易
|
|
522
|
-
4. **依存関係逆転**: 高レベルモジュールが低レベルモジュールに依存しない
|
|
523
|
-
|
|
524
|
-
## 14. F# での特徴
|
|
525
|
-
|
|
526
|
-
F# での Abstract Server パターンの実装には以下の特徴があります:
|
|
527
|
-
|
|
528
|
-
1. **インターフェース**: 抽象サーバーを定義
|
|
529
|
-
2. **レコード型 + インターフェース実装**: 具体的なサーバーを実装
|
|
530
|
-
3. **イミュータブル**: 状態変更は新しいレコードを返す
|
|
531
|
-
4. **依存性注入**: 関数の引数としてインターフェースを渡す
|
|
532
|
-
|
|
533
|
-
```plantuml
|
|
534
|
-
@startuml
|
|
535
|
-
title F# での Abstract Server
|
|
536
|
-
|
|
537
|
-
rectangle "インターフェース (interface)" {
|
|
538
|
-
card "ISwitchable" as switchable
|
|
539
|
-
card "IRepository" as repo
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
rectangle "レコード + インターフェース実装" {
|
|
543
|
-
card "Light" as light
|
|
544
|
-
card "Fan" as fan
|
|
545
|
-
card "MemoryUserRepository" as memRepo
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
rectangle "クライアントモジュール" {
|
|
549
|
-
card "Switch.engage" as engage
|
|
550
|
-
card "UserService.createUser" as create
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
engage --> switchable : 依存
|
|
554
|
-
create --> repo : 依存
|
|
555
|
-
light ..|> switchable : 実装
|
|
556
|
-
fan ..|> switchable : 実装
|
|
557
|
-
memRepo ..|> repo : 実装
|
|
558
|
-
|
|
559
|
-
note bottom
|
|
560
|
-
インターフェースを使って抽象化し、
|
|
561
|
-
レコードやクラスで具体的な実装を提供します。
|
|
562
|
-
クライアントはインターフェースにのみ依存します。
|
|
563
|
-
end note
|
|
564
|
-
@enduml
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
## まとめ
|
|
568
|
-
|
|
569
|
-
本章では、Abstract Server パターンについて学びました:
|
|
570
|
-
|
|
571
|
-
1. **インターフェースによる抽象化**: ISwitchable、IRepository、ILogger、ICache
|
|
572
|
-
2. **レコード/クラスによる実装**: Light、Fan、Motor、MemoryUserRepository
|
|
573
|
-
3. **クライアントの独立性**: Switch、UserService
|
|
574
|
-
4. **依存関係逆転**: 高レベルモジュールが抽象に依存
|
|
575
|
-
5. **関数型アプローチ**: レコード型で関数を束ねる方法
|
|
576
|
-
|
|
577
|
-
Abstract Server パターンは、モジュール間の疎結合を実現し、テスト容易性と柔軟性を向上させます。
|
|
578
|
-
|
|
579
|
-
## 参考コード
|
|
580
|
-
|
|
581
|
-
本章のコード例は以下のファイルで確認できます:
|
|
582
|
-
|
|
583
|
-
- ソースコード: `apps/fsharp/part4/src/Library.fs`
|
|
584
|
-
- テストコード: `apps/fsharp/part4/tests/Tests.fs`
|
|
585
|
-
|
|
586
|
-
## 第4部のまとめ
|
|
587
|
-
|
|
588
|
-
第4部では、デザインパターンについて学びました:
|
|
589
|
-
|
|
590
|
-
- **Strategy パターン**: アルゴリズムをカプセル化して交換可能にする
|
|
591
|
-
- **Command パターン**: 操作をオブジェクトとしてカプセル化
|
|
592
|
-
- **Visitor パターン**: データ構造と処理を分離
|
|
593
|
-
- **Abstract Factory パターン**: 関連するオブジェクトのファミリーを一貫して生成
|
|
594
|
-
- **Abstract Server パターン**: 依存関係逆転による疎結合の実現
|
|
595
|
-
|
|
596
|
-
これらのパターンは、モジュールの独立性を高め、テスト容易性と保守性を向上させます。
|
|
1
|
+
# 第14章: Abstract Server パターン
|
|
2
|
+
|
|
3
|
+
## はじめに
|
|
4
|
+
|
|
5
|
+
Abstract Server パターンは、依存関係逆転の原則(DIP)を実現するパターンです。高レベルモジュールが低レベルモジュールの詳細に依存するのではなく、両者が抽象に依存することで疎結合を実現します。
|
|
6
|
+
|
|
7
|
+
本章では、スイッチとデバイス、リポジトリとサービスの例を通じて、インターフェースによる Abstract Server パターンの実装を学びます。
|
|
8
|
+
|
|
9
|
+
## 1. パターンの構造
|
|
10
|
+
|
|
11
|
+
Abstract Server パターンは以下の要素で構成されます:
|
|
12
|
+
|
|
13
|
+
- **Client**: サービスを利用するモジュール
|
|
14
|
+
- **Abstract Server**: サービスの抽象インターフェース
|
|
15
|
+
- **Concrete Server**: 具体的なサービスの実装
|
|
16
|
+
|
|
17
|
+
```plantuml
|
|
18
|
+
@startuml
|
|
19
|
+
skinparam classAttributeIconSize 0
|
|
20
|
+
|
|
21
|
+
class "Client\n(Switch)" as client {
|
|
22
|
+
+engage(device)
|
|
23
|
+
+disengage(device)
|
|
24
|
+
+toggle(device)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface "Abstract Server\n(ISwitchable)" as abstract {
|
|
28
|
+
+TurnOn()
|
|
29
|
+
+TurnOff()
|
|
30
|
+
+IsOn
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class "Concrete Server\n(Light)" as light {
|
|
34
|
+
+State
|
|
35
|
+
+TurnOn()
|
|
36
|
+
+TurnOff()
|
|
37
|
+
+IsOn
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class "Concrete Server\n(Fan)" as fan {
|
|
41
|
+
+State
|
|
42
|
+
+Speed
|
|
43
|
+
+TurnOn()
|
|
44
|
+
+TurnOff()
|
|
45
|
+
+IsOn
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
class "Concrete Server\n(Motor)" as motor {
|
|
49
|
+
+State
|
|
50
|
+
+Direction
|
|
51
|
+
+TurnOn()
|
|
52
|
+
+TurnOff()
|
|
53
|
+
+IsOn
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
client --> abstract : depends on
|
|
57
|
+
light ..|> abstract
|
|
58
|
+
fan ..|> abstract
|
|
59
|
+
motor ..|> abstract
|
|
60
|
+
|
|
61
|
+
note right of client
|
|
62
|
+
Clientは抽象に依存します。
|
|
63
|
+
具体的な実装を知りません。
|
|
64
|
+
end note
|
|
65
|
+
|
|
66
|
+
note right of abstract
|
|
67
|
+
Abstract Serverは
|
|
68
|
+
インターフェースを定義します。
|
|
69
|
+
F#ではinterfaceを使用します。
|
|
70
|
+
end note
|
|
71
|
+
@enduml
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 2. ISwitchable インターフェース
|
|
75
|
+
|
|
76
|
+
### Abstract Server の定義
|
|
77
|
+
|
|
78
|
+
```fsharp
|
|
79
|
+
/// スイッチ可能なデバイスのインターフェース
|
|
80
|
+
type ISwitchable =
|
|
81
|
+
abstract member TurnOn: unit -> ISwitchable
|
|
82
|
+
abstract member TurnOff: unit -> ISwitchable
|
|
83
|
+
abstract member IsOn: bool
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
F# のインターフェースは、メソッドを定義する abstract member として宣言します。イミュータブルな実装のため、`TurnOn` と `TurnOff` は新しい `ISwitchable` を返します。
|
|
87
|
+
|
|
88
|
+
## 3. Concrete Server: Light
|
|
89
|
+
|
|
90
|
+
### 実装
|
|
91
|
+
|
|
92
|
+
```fsharp
|
|
93
|
+
type Light =
|
|
94
|
+
{ State: bool }
|
|
95
|
+
interface ISwitchable with
|
|
96
|
+
member this.TurnOn() = { State = true } :> ISwitchable
|
|
97
|
+
member this.TurnOff() = { State = false } :> ISwitchable
|
|
98
|
+
member this.IsOn = this.State
|
|
99
|
+
|
|
100
|
+
module Light =
|
|
101
|
+
let create () = { State = false }
|
|
102
|
+
let createOn () = { State = true }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Light はレコード型として定義し、`ISwitchable` インターフェースを実装します。`:>` 演算子で基底型へのアップキャストを行います。
|
|
106
|
+
|
|
107
|
+
## 4. Concrete Server: Fan
|
|
108
|
+
|
|
109
|
+
### 実装
|
|
110
|
+
|
|
111
|
+
```fsharp
|
|
112
|
+
[<RequireQualifiedAccess>]
|
|
113
|
+
type FanSpeed = | Low | Medium | High
|
|
114
|
+
|
|
115
|
+
type Fan =
|
|
116
|
+
{ State: bool
|
|
117
|
+
Speed: FanSpeed option }
|
|
118
|
+
interface ISwitchable with
|
|
119
|
+
member this.TurnOn() = { State = true; Speed = Some FanSpeed.Low } :> ISwitchable
|
|
120
|
+
member this.TurnOff() = { State = false; Speed = None } :> ISwitchable
|
|
121
|
+
member this.IsOn = this.State
|
|
122
|
+
|
|
123
|
+
module Fan =
|
|
124
|
+
let create () = { State = false; Speed = None }
|
|
125
|
+
let setSpeed (speed: FanSpeed) (fan: Fan) =
|
|
126
|
+
if fan.State then { fan with Speed = Some speed }
|
|
127
|
+
else fan
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Fan はスピード設定を持つデバイスです。`[<RequireQualifiedAccess>]` 属性により、`FanSpeed.Low` のように修飾名でアクセスします。
|
|
131
|
+
|
|
132
|
+
## 5. Concrete Server: Motor
|
|
133
|
+
|
|
134
|
+
### 実装
|
|
135
|
+
|
|
136
|
+
```fsharp
|
|
137
|
+
[<RequireQualifiedAccess>]
|
|
138
|
+
type MotorDirection = | Forward | Reverse
|
|
139
|
+
|
|
140
|
+
type Motor =
|
|
141
|
+
{ State: bool
|
|
142
|
+
Direction: MotorDirection option }
|
|
143
|
+
interface ISwitchable with
|
|
144
|
+
member this.TurnOn() = { State = true; Direction = Some MotorDirection.Forward } :> ISwitchable
|
|
145
|
+
member this.TurnOff() = { State = false; Direction = None } :> ISwitchable
|
|
146
|
+
member this.IsOn = this.State
|
|
147
|
+
|
|
148
|
+
module Motor =
|
|
149
|
+
let create () = { State = false; Direction = None }
|
|
150
|
+
let reverse (motor: Motor) =
|
|
151
|
+
if motor.State then
|
|
152
|
+
let newDir =
|
|
153
|
+
match motor.Direction with
|
|
154
|
+
| Some MotorDirection.Forward -> Some MotorDirection.Reverse
|
|
155
|
+
| Some MotorDirection.Reverse -> Some MotorDirection.Forward
|
|
156
|
+
| None -> Some MotorDirection.Forward
|
|
157
|
+
{ motor with Direction = newDir }
|
|
158
|
+
else motor
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Motor は方向を持つデバイスで、`reverse` 関数で方向を反転できます。
|
|
162
|
+
|
|
163
|
+
## 6. Client: Switch
|
|
164
|
+
|
|
165
|
+
### 実装
|
|
166
|
+
|
|
167
|
+
```fsharp
|
|
168
|
+
module Switch =
|
|
169
|
+
/// スイッチを入れる
|
|
170
|
+
let engage (device: ISwitchable) : ISwitchable =
|
|
171
|
+
device.TurnOn()
|
|
172
|
+
|
|
173
|
+
/// スイッチを切る
|
|
174
|
+
let disengage (device: ISwitchable) : ISwitchable =
|
|
175
|
+
device.TurnOff()
|
|
176
|
+
|
|
177
|
+
/// スイッチを切り替える
|
|
178
|
+
let toggle (device: ISwitchable) : ISwitchable =
|
|
179
|
+
if device.IsOn then device.TurnOff()
|
|
180
|
+
else device.TurnOn()
|
|
181
|
+
|
|
182
|
+
/// デバイスの状態を取得
|
|
183
|
+
let status (device: ISwitchable) : string =
|
|
184
|
+
if device.IsOn then "ON" else "OFF"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 使用例
|
|
188
|
+
|
|
189
|
+
```fsharp
|
|
190
|
+
// 同じSwitchコードで異なるデバイスを操作
|
|
191
|
+
let light = Light.create ()
|
|
192
|
+
let lightOn = Switch.engage (light :> ISwitchable)
|
|
193
|
+
printfn "%s" (Switch.status lightOn) // "ON"
|
|
194
|
+
|
|
195
|
+
let fan = Fan.create ()
|
|
196
|
+
let fanOn = Switch.engage (fan :> ISwitchable)
|
|
197
|
+
printfn "%s" (Switch.status fanOn) // "ON"
|
|
198
|
+
|
|
199
|
+
let motor = Motor.create ()
|
|
200
|
+
let motorOn = Switch.engage (motor :> ISwitchable)
|
|
201
|
+
printfn "%s" (Switch.status motorOn) // "ON"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## 7. シーケンス図
|
|
205
|
+
|
|
206
|
+
```plantuml
|
|
207
|
+
@startuml
|
|
208
|
+
actor Client
|
|
209
|
+
participant "Switch" as switch
|
|
210
|
+
participant "ISwitchable\n(Interface)" as interface
|
|
211
|
+
participant "Light" as light
|
|
212
|
+
participant "Fan" as fan
|
|
213
|
+
|
|
214
|
+
== Light の操作 ==
|
|
215
|
+
Client -> switch : engage(light)
|
|
216
|
+
activate switch
|
|
217
|
+
switch -> interface : TurnOn(light)
|
|
218
|
+
activate interface
|
|
219
|
+
interface -> light : TurnOn()
|
|
220
|
+
activate light
|
|
221
|
+
light --> interface : updated-light
|
|
222
|
+
deactivate light
|
|
223
|
+
interface --> switch : updated-light
|
|
224
|
+
deactivate interface
|
|
225
|
+
switch --> Client : light-on
|
|
226
|
+
deactivate switch
|
|
227
|
+
|
|
228
|
+
== Fan の操作 ==
|
|
229
|
+
Client -> switch : engage(fan)
|
|
230
|
+
activate switch
|
|
231
|
+
switch -> interface : TurnOn(fan)
|
|
232
|
+
activate interface
|
|
233
|
+
interface -> fan : TurnOn()
|
|
234
|
+
activate fan
|
|
235
|
+
fan --> interface : updated-fan
|
|
236
|
+
deactivate fan
|
|
237
|
+
interface --> switch : updated-fan
|
|
238
|
+
deactivate interface
|
|
239
|
+
switch --> Client : fan-on
|
|
240
|
+
deactivate switch
|
|
241
|
+
|
|
242
|
+
note right
|
|
243
|
+
Switchは具体的なデバイスを
|
|
244
|
+
知らずに操作できます。
|
|
245
|
+
ISwitchableインターフェースを通じて
|
|
246
|
+
多態的に動作します。
|
|
247
|
+
end note
|
|
248
|
+
@enduml
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## 8. Repository の例
|
|
252
|
+
|
|
253
|
+
### Abstract Server: IRepository インターフェース
|
|
254
|
+
|
|
255
|
+
```fsharp
|
|
256
|
+
/// リポジトリインターフェース
|
|
257
|
+
type IRepository<'TEntity, 'TId> =
|
|
258
|
+
abstract member FindById: 'TId -> 'TEntity option
|
|
259
|
+
abstract member FindAll: unit -> 'TEntity list
|
|
260
|
+
abstract member Save: 'TEntity -> 'TEntity
|
|
261
|
+
abstract member Delete: 'TId -> bool
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
ジェネリック型パラメータを使用して、任意のエンティティと ID 型に対応します。
|
|
265
|
+
|
|
266
|
+
### Concrete Server: MemoryUserRepository
|
|
267
|
+
|
|
268
|
+
```fsharp
|
|
269
|
+
type User =
|
|
270
|
+
{ Id: string
|
|
271
|
+
Name: string
|
|
272
|
+
Email: string
|
|
273
|
+
CreatedAt: System.DateTime }
|
|
274
|
+
|
|
275
|
+
type MemoryUserRepository(initialData: Map<string, User>) =
|
|
276
|
+
let mutable data = initialData
|
|
277
|
+
|
|
278
|
+
interface IRepository<User, string> with
|
|
279
|
+
member _.FindById(id) = Map.tryFind id data
|
|
280
|
+
member _.FindAll() = data |> Map.toList |> List.map snd
|
|
281
|
+
member _.Save(user) =
|
|
282
|
+
let userId = if user.Id = "" then System.Guid.NewGuid().ToString() else user.Id
|
|
283
|
+
let userWithId = { user with Id = userId }
|
|
284
|
+
data <- Map.add userId userWithId data
|
|
285
|
+
userWithId
|
|
286
|
+
member _.Delete(id) =
|
|
287
|
+
if Map.containsKey id data then
|
|
288
|
+
data <- Map.remove id data
|
|
289
|
+
true
|
|
290
|
+
else false
|
|
291
|
+
|
|
292
|
+
module MemoryUserRepository =
|
|
293
|
+
let create () = MemoryUserRepository(Map.empty)
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Client: UserService
|
|
297
|
+
|
|
298
|
+
```fsharp
|
|
299
|
+
module UserService =
|
|
300
|
+
/// ユーザーを作成
|
|
301
|
+
let createUser (repo: IRepository<User, string>) (name: string) (email: string) : User =
|
|
302
|
+
let user =
|
|
303
|
+
{ Id = ""
|
|
304
|
+
Name = name
|
|
305
|
+
Email = email
|
|
306
|
+
CreatedAt = System.DateTime.UtcNow }
|
|
307
|
+
repo.Save(user)
|
|
308
|
+
|
|
309
|
+
/// ユーザーを取得
|
|
310
|
+
let getUser (repo: IRepository<User, string>) (id: string) : User option =
|
|
311
|
+
repo.FindById(id)
|
|
312
|
+
|
|
313
|
+
/// 全ユーザーを取得
|
|
314
|
+
let getAllUsers (repo: IRepository<User, string>) : User list =
|
|
315
|
+
repo.FindAll()
|
|
316
|
+
|
|
317
|
+
/// ユーザーを削除
|
|
318
|
+
let deleteUser (repo: IRepository<User, string>) (id: string) : bool =
|
|
319
|
+
repo.Delete(id)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## 9. 依存関係の図
|
|
323
|
+
|
|
324
|
+
```plantuml
|
|
325
|
+
@startuml
|
|
326
|
+
skinparam classAttributeIconSize 0
|
|
327
|
+
|
|
328
|
+
package "Application Layer" {
|
|
329
|
+
class "UserService" as service {
|
|
330
|
+
+createUser(repo, name, email)
|
|
331
|
+
+getUser(repo, id)
|
|
332
|
+
+getAllUsers(repo)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
package "Domain Layer" {
|
|
337
|
+
interface "IRepository" as repo {
|
|
338
|
+
+FindById(id)
|
|
339
|
+
+FindAll()
|
|
340
|
+
+Save(entity)
|
|
341
|
+
+Delete(id)
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
package "Infrastructure Layer" {
|
|
346
|
+
class "MemoryUserRepository" as memRepo {
|
|
347
|
+
+data: Map
|
|
348
|
+
+FindById(id)
|
|
349
|
+
+FindAll()
|
|
350
|
+
+Save(entity)
|
|
351
|
+
+Delete(id)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
class "DatabaseRepository" as dbRepo {
|
|
355
|
+
+connection
|
|
356
|
+
+FindById(id)
|
|
357
|
+
+FindAll()
|
|
358
|
+
+Save(entity)
|
|
359
|
+
+Delete(id)
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
service --> repo : depends on
|
|
364
|
+
memRepo ..|> repo
|
|
365
|
+
dbRepo ..|> repo
|
|
366
|
+
|
|
367
|
+
note right of service
|
|
368
|
+
UserServiceはIRepositoryインターフェースに
|
|
369
|
+
依存します。具体的な実装は
|
|
370
|
+
実行時に注入されます。
|
|
371
|
+
end note
|
|
372
|
+
|
|
373
|
+
note bottom of memRepo
|
|
374
|
+
テスト時はMemoryUserRepository、
|
|
375
|
+
本番時はDatabaseRepositoryを
|
|
376
|
+
使用できます。
|
|
377
|
+
end note
|
|
378
|
+
@enduml
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## 10. 関数型アプローチ:レコード+関数
|
|
382
|
+
|
|
383
|
+
F# では、インターフェースの代わりにレコード型で関数を束ねる方法もあります:
|
|
384
|
+
|
|
385
|
+
```fsharp
|
|
386
|
+
/// 関数型リポジトリ
|
|
387
|
+
type FunctionalRepository<'TEntity, 'TId> =
|
|
388
|
+
{ FindById: 'TId -> 'TEntity option
|
|
389
|
+
FindAll: unit -> 'TEntity list
|
|
390
|
+
Save: 'TEntity -> 'TEntity
|
|
391
|
+
Delete: 'TId -> bool }
|
|
392
|
+
|
|
393
|
+
module FunctionalRepository =
|
|
394
|
+
/// インメモリリポジトリを作成
|
|
395
|
+
let createInMemory<'TId, 'TEntity when 'TId: comparison>
|
|
396
|
+
(getId: 'TEntity -> 'TId)
|
|
397
|
+
(setId: 'TId -> 'TEntity -> 'TEntity)
|
|
398
|
+
(generateId: unit -> 'TId)
|
|
399
|
+
: FunctionalRepository<'TEntity, 'TId> =
|
|
400
|
+
let mutable data: Map<'TId, 'TEntity> = Map.empty
|
|
401
|
+
{ FindById = fun id -> Map.tryFind id data
|
|
402
|
+
FindAll = fun () -> data |> Map.toList |> List.map snd
|
|
403
|
+
Save = fun entity ->
|
|
404
|
+
let entityId = if getId entity = Unchecked.defaultof<'TId> then generateId() else getId entity
|
|
405
|
+
let entityWithId = setId entityId entity
|
|
406
|
+
data <- Map.add entityId entityWithId data
|
|
407
|
+
entityWithId
|
|
408
|
+
Delete = fun id ->
|
|
409
|
+
if Map.containsKey id data then
|
|
410
|
+
data <- Map.remove id data
|
|
411
|
+
true
|
|
412
|
+
else false }
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
使用例:
|
|
416
|
+
|
|
417
|
+
```fsharp
|
|
418
|
+
type SimpleUser = { Id: int; Name: string }
|
|
419
|
+
|
|
420
|
+
let mutable nextId = 1
|
|
421
|
+
let repo = FunctionalRepository.createInMemory<int, SimpleUser>
|
|
422
|
+
(fun u -> u.Id)
|
|
423
|
+
(fun id u -> { u with Id = id })
|
|
424
|
+
(fun () ->
|
|
425
|
+
let id = nextId
|
|
426
|
+
nextId <- nextId + 1
|
|
427
|
+
id)
|
|
428
|
+
|
|
429
|
+
let user = repo.Save { Id = 0; Name = "Alice" }
|
|
430
|
+
let found = repo.FindById user.Id
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## 11. Logger と Cache の例
|
|
434
|
+
|
|
435
|
+
### ILogger インターフェース
|
|
436
|
+
|
|
437
|
+
```fsharp
|
|
438
|
+
[<RequireQualifiedAccess>]
|
|
439
|
+
type LogLevel = | Debug | Info | Warning | Error
|
|
440
|
+
|
|
441
|
+
type ILogger =
|
|
442
|
+
abstract member Log: LogLevel -> string -> unit
|
|
443
|
+
abstract member Debug: string -> unit
|
|
444
|
+
abstract member Info: string -> unit
|
|
445
|
+
abstract member Warning: string -> unit
|
|
446
|
+
abstract member Error: string -> unit
|
|
447
|
+
|
|
448
|
+
type BufferedLogger() =
|
|
449
|
+
let mutable logs: (LogLevel * string * System.DateTime) list = []
|
|
450
|
+
|
|
451
|
+
interface ILogger with
|
|
452
|
+
member _.Log level message =
|
|
453
|
+
logs <- (level, message, System.DateTime.UtcNow) :: logs
|
|
454
|
+
member this.Debug message = (this :> ILogger).Log LogLevel.Debug message
|
|
455
|
+
member this.Info message = (this :> ILogger).Log LogLevel.Info message
|
|
456
|
+
member this.Warning message = (this :> ILogger).Log LogLevel.Warning message
|
|
457
|
+
member this.Error message = (this :> ILogger).Log LogLevel.Error message
|
|
458
|
+
|
|
459
|
+
member _.GetLogs() = List.rev logs
|
|
460
|
+
member _.Clear() = logs <- []
|
|
461
|
+
|
|
462
|
+
type NullLogger() =
|
|
463
|
+
interface ILogger with
|
|
464
|
+
member _.Log _ _ = ()
|
|
465
|
+
member _.Debug _ = ()
|
|
466
|
+
member _.Info _ = ()
|
|
467
|
+
member _.Warning _ = ()
|
|
468
|
+
member _.Error _ = ()
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### ICache インターフェース
|
|
472
|
+
|
|
473
|
+
```fsharp
|
|
474
|
+
type ICache<'TKey, 'TValue> =
|
|
475
|
+
abstract member Get: 'TKey -> 'TValue option
|
|
476
|
+
abstract member Set: 'TKey -> 'TValue -> unit
|
|
477
|
+
abstract member Remove: 'TKey -> bool
|
|
478
|
+
abstract member Clear: unit -> unit
|
|
479
|
+
|
|
480
|
+
type MemoryCache<'TKey, 'TValue when 'TKey: comparison>() =
|
|
481
|
+
let mutable data: Map<'TKey, 'TValue> = Map.empty
|
|
482
|
+
|
|
483
|
+
interface ICache<'TKey, 'TValue> with
|
|
484
|
+
member _.Get key = Map.tryFind key data
|
|
485
|
+
member _.Set key value = data <- Map.add key value data
|
|
486
|
+
member _.Remove key =
|
|
487
|
+
if Map.containsKey key data then
|
|
488
|
+
data <- Map.remove key data
|
|
489
|
+
true
|
|
490
|
+
else false
|
|
491
|
+
member _.Clear() = data <- Map.empty
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
## 12. 依存性注入コンテナ
|
|
495
|
+
|
|
496
|
+
シンプルな DI コンテナの実装例:
|
|
497
|
+
|
|
498
|
+
```fsharp
|
|
499
|
+
type ServiceContainer() =
|
|
500
|
+
let mutable services: Map<string, obj> = Map.empty
|
|
501
|
+
|
|
502
|
+
member _.Register<'T>(key: string) (service: 'T) =
|
|
503
|
+
services <- Map.add key (box service) services
|
|
504
|
+
|
|
505
|
+
member _.Resolve<'T>(key: string) : 'T option =
|
|
506
|
+
Map.tryFind key services |> Option.map (fun s -> s :?> 'T)
|
|
507
|
+
|
|
508
|
+
member _.RegisterSingleton<'T>(service: 'T) =
|
|
509
|
+
let key = typeof<'T>.FullName
|
|
510
|
+
services <- Map.add key (box service) services
|
|
511
|
+
|
|
512
|
+
member _.ResolveSingleton<'T>() : 'T option =
|
|
513
|
+
let key = typeof<'T>.FullName
|
|
514
|
+
Map.tryFind key services |> Option.map (fun s -> s :?> 'T)
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
## 13. パターンの利点
|
|
518
|
+
|
|
519
|
+
1. **疎結合**: クライアントは具体的な実装を知らない
|
|
520
|
+
2. **テスト容易性**: モック/スタブを簡単に注入可能
|
|
521
|
+
3. **柔軟性**: 実装の交換が容易
|
|
522
|
+
4. **依存関係逆転**: 高レベルモジュールが低レベルモジュールに依存しない
|
|
523
|
+
|
|
524
|
+
## 14. F# での特徴
|
|
525
|
+
|
|
526
|
+
F# での Abstract Server パターンの実装には以下の特徴があります:
|
|
527
|
+
|
|
528
|
+
1. **インターフェース**: 抽象サーバーを定義
|
|
529
|
+
2. **レコード型 + インターフェース実装**: 具体的なサーバーを実装
|
|
530
|
+
3. **イミュータブル**: 状態変更は新しいレコードを返す
|
|
531
|
+
4. **依存性注入**: 関数の引数としてインターフェースを渡す
|
|
532
|
+
|
|
533
|
+
```plantuml
|
|
534
|
+
@startuml
|
|
535
|
+
title F# での Abstract Server
|
|
536
|
+
|
|
537
|
+
rectangle "インターフェース (interface)" {
|
|
538
|
+
card "ISwitchable" as switchable
|
|
539
|
+
card "IRepository" as repo
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
rectangle "レコード + インターフェース実装" {
|
|
543
|
+
card "Light" as light
|
|
544
|
+
card "Fan" as fan
|
|
545
|
+
card "MemoryUserRepository" as memRepo
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
rectangle "クライアントモジュール" {
|
|
549
|
+
card "Switch.engage" as engage
|
|
550
|
+
card "UserService.createUser" as create
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
engage --> switchable : 依存
|
|
554
|
+
create --> repo : 依存
|
|
555
|
+
light ..|> switchable : 実装
|
|
556
|
+
fan ..|> switchable : 実装
|
|
557
|
+
memRepo ..|> repo : 実装
|
|
558
|
+
|
|
559
|
+
note bottom
|
|
560
|
+
インターフェースを使って抽象化し、
|
|
561
|
+
レコードやクラスで具体的な実装を提供します。
|
|
562
|
+
クライアントはインターフェースにのみ依存します。
|
|
563
|
+
end note
|
|
564
|
+
@enduml
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
## まとめ
|
|
568
|
+
|
|
569
|
+
本章では、Abstract Server パターンについて学びました:
|
|
570
|
+
|
|
571
|
+
1. **インターフェースによる抽象化**: ISwitchable、IRepository、ILogger、ICache
|
|
572
|
+
2. **レコード/クラスによる実装**: Light、Fan、Motor、MemoryUserRepository
|
|
573
|
+
3. **クライアントの独立性**: Switch、UserService
|
|
574
|
+
4. **依存関係逆転**: 高レベルモジュールが抽象に依存
|
|
575
|
+
5. **関数型アプローチ**: レコード型で関数を束ねる方法
|
|
576
|
+
|
|
577
|
+
Abstract Server パターンは、モジュール間の疎結合を実現し、テスト容易性と柔軟性を向上させます。
|
|
578
|
+
|
|
579
|
+
## 参考コード
|
|
580
|
+
|
|
581
|
+
本章のコード例は以下のファイルで確認できます:
|
|
582
|
+
|
|
583
|
+
- ソースコード: `apps/fsharp/part4/src/Library.fs`
|
|
584
|
+
- テストコード: `apps/fsharp/part4/tests/Tests.fs`
|
|
585
|
+
|
|
586
|
+
## 第4部のまとめ
|
|
587
|
+
|
|
588
|
+
第4部では、デザインパターンについて学びました:
|
|
589
|
+
|
|
590
|
+
- **Strategy パターン**: アルゴリズムをカプセル化して交換可能にする
|
|
591
|
+
- **Command パターン**: 操作をオブジェクトとしてカプセル化
|
|
592
|
+
- **Visitor パターン**: データ構造と処理を分離
|
|
593
|
+
- **Abstract Factory パターン**: 関連するオブジェクトのファミリーを一貫して生成
|
|
594
|
+
- **Abstract Server パターン**: 依存関係逆転による疎結合の実現
|
|
595
|
+
|
|
596
|
+
これらのパターンは、モジュールの独立性を高め、テスト容易性と保守性を向上させます。
|