@k2works/claude-code-booster 3.4.1 → 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.
Files changed (712) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +42 -42
  3. package/bin/claude-code-booster +90 -90
  4. package/lib/assets/.claude/README.md +239 -239
  5. package/lib/assets/.claude/scripts/generate-inception-deck.mjs +911 -911
  6. package/lib/assets/.claude/settings.json +11 -11
  7. package/lib/assets/.claude/skills/ai-agent-guidelines/SKILL.md +111 -111
  8. package/lib/assets/.claude/skills/analyzing-architecture/SKILL.md +83 -83
  9. package/lib/assets/.claude/skills/analyzing-business/SKILL.md +95 -95
  10. package/lib/assets/.claude/skills/analyzing-data-model/SKILL.md +77 -77
  11. package/lib/assets/.claude/skills/analyzing-domain-model/SKILL.md +117 -88
  12. package/lib/assets/.claude/skills/analyzing-inception-deck/SKILL.md +84 -84
  13. package/lib/assets/.claude/skills/analyzing-non-functional/SKILL.md +95 -95
  14. package/lib/assets/.claude/skills/analyzing-operation/SKILL.md +95 -95
  15. package/lib/assets/.claude/skills/analyzing-requirements/SKILL.md +91 -91
  16. package/lib/assets/.claude/skills/analyzing-tech-stack/SKILL.md +101 -101
  17. package/lib/assets/.claude/skills/analyzing-test-strategy/SKILL.md +89 -89
  18. package/lib/assets/.claude/skills/analyzing-ui-design/SKILL.md +80 -80
  19. package/lib/assets/.claude/skills/analyzing-usecases/SKILL.md +72 -72
  20. package/lib/assets/.claude/skills/creating-adr/SKILL.md +113 -113
  21. package/lib/assets/.claude/skills/developing-backend/SKILL.md +100 -100
  22. package/lib/assets/.claude/skills/developing-frontend/SKILL.md +93 -93
  23. package/lib/assets/.claude/skills/developing-release/SKILL.md +120 -120
  24. package/lib/assets/.claude/skills/generating-slides/SKILL.md +94 -94
  25. package/lib/assets/.claude/skills/git-commit/SKILL.md +81 -81
  26. package/lib/assets/.claude/skills/killing-processes/SKILL.md +44 -44
  27. package/lib/assets/.claude/skills/operating-backup/SKILL.md +59 -59
  28. package/lib/assets/.claude/skills/operating-cicd/SKILL.md +54 -54
  29. package/lib/assets/.claude/skills/operating-deploy/SKILL.md +67 -67
  30. package/lib/assets/.claude/skills/operating-docs/SKILL.md +219 -219
  31. package/lib/assets/.claude/skills/operating-provision/SKILL.md +77 -77
  32. package/lib/assets/.claude/skills/operating-setup/SKILL.md +63 -63
  33. package/lib/assets/.claude/skills/orchestrating-analysis/SKILL.md +104 -104
  34. package/lib/assets/.claude/skills/orchestrating-development/SKILL.md +162 -161
  35. package/lib/assets/.claude/skills/orchestrating-operation/SKILL.md +158 -158
  36. package/lib/assets/.claude/skills/orchestrating-project/SKILL.md +144 -144
  37. package/lib/assets/.claude/skills/planning-releases/SKILL.md +119 -119
  38. package/lib/assets/.claude/skills/syncing-github-project/SKILL.md +151 -151
  39. package/lib/assets/.claude/skills/tracking-progress/SKILL.md +91 -91
  40. package/lib/assets/.claude/skills/validating-iteration-plan/SKILL.md +29 -1
  41. package/lib/assets/.devcontainer/devcontainer.json +34 -34
  42. package/lib/assets/.env.example +17 -17
  43. package/lib/assets/.gitattributes +4 -4
  44. package/lib/assets/.github/workflows/docker-publish.yml +77 -77
  45. package/lib/assets/.github/workflows/mkdocs.yml +39 -39
  46. package/lib/assets/AGENTS.md +94 -94
  47. package/lib/assets/CLAUDE.md +183 -183
  48. package/lib/assets/README.md +254 -254
  49. package/lib/assets/docker-compose.yml +33 -33
  50. package/lib/assets/docs/adr/index.md +10 -10
  51. package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +475 -475
  52. package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +519 -519
  53. package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +537 -537
  54. package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +300 -300
  55. package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +320 -320
  56. package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +498 -498
  57. package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +298 -298
  58. package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +291 -291
  59. package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +336 -336
  60. package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +303 -303
  61. package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +286 -286
  62. package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +322 -322
  63. package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +319 -319
  64. package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +365 -365
  65. package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +156 -156
  66. package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +178 -178
  67. package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +312 -312
  68. package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +287 -287
  69. package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +286 -286
  70. package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +274 -274
  71. package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +294 -294
  72. package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +337 -337
  73. package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +388 -388
  74. package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +273 -273
  75. package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +380 -380
  76. package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +384 -384
  77. package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +350 -350
  78. package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +352 -352
  79. package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +383 -383
  80. package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +529 -529
  81. package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +395 -395
  82. package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +399 -399
  83. package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +485 -485
  84. package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +566 -566
  85. package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +567 -567
  86. package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +475 -475
  87. package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +462 -462
  88. package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +325 -325
  89. package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +401 -401
  90. package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +450 -450
  91. package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +475 -475
  92. package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +739 -739
  93. package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +567 -567
  94. package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +518 -518
  95. package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +532 -532
  96. package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +241 -241
  97. package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +383 -383
  98. package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +374 -374
  99. package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +375 -375
  100. package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +195 -195
  101. package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +268 -268
  102. package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +294 -294
  103. package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +164 -164
  104. package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +168 -168
  105. package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +254 -254
  106. package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +269 -269
  107. package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +148 -148
  108. package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +176 -176
  109. package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +604 -604
  110. package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +729 -729
  111. package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +291 -291
  112. package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +420 -420
  113. package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +319 -319
  114. package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +466 -466
  115. package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +523 -523
  116. package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +287 -287
  117. package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +340 -340
  118. package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +395 -395
  119. package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +248 -248
  120. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +384 -384
  121. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +452 -452
  122. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +495 -495
  123. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +416 -416
  124. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +382 -382
  125. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +687 -687
  126. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +442 -442
  127. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +479 -479
  128. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +479 -479
  129. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +427 -427
  130. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +428 -428
  131. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +339 -339
  132. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +309 -309
  133. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +596 -596
  134. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +355 -355
  135. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +350 -350
  136. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +414 -414
  137. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +367 -367
  138. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +403 -403
  139. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +291 -291
  140. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +324 -324
  141. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +332 -332
  142. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +274 -274
  143. package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +298 -298
  144. package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +304 -304
  145. package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +362 -362
  146. package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +257 -257
  147. package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +254 -254
  148. package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +283 -283
  149. package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +395 -395
  150. package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +319 -319
  151. package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +382 -382
  152. package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +287 -287
  153. package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +303 -303
  154. package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +326 -326
  155. package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +332 -332
  156. package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +379 -379
  157. package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +177 -177
  158. package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +219 -219
  159. package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +244 -244
  160. package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +363 -363
  161. package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +438 -438
  162. package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +325 -325
  163. package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +403 -403
  164. package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +469 -469
  165. package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +174 -174
  166. package/lib/assets/docs/article/functional-desgin-ppp/index.md +90 -90
  167. package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +450 -450
  168. package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +463 -463
  169. package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +425 -425
  170. package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +273 -273
  171. package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +247 -247
  172. package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +841 -841
  173. package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +384 -384
  174. package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +383 -383
  175. package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +339 -339
  176. package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +331 -331
  177. package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +356 -356
  178. package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +379 -379
  179. package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +361 -361
  180. package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +392 -392
  181. package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +300 -300
  182. package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +297 -297
  183. package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +304 -304
  184. package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +315 -315
  185. package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +311 -311
  186. package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +304 -304
  187. package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +336 -336
  188. package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +349 -349
  189. package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +243 -243
  190. package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +328 -328
  191. package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +348 -348
  192. package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +357 -357
  193. package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +364 -364
  194. package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +515 -515
  195. package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +557 -557
  196. package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +363 -363
  197. package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +327 -327
  198. package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +517 -517
  199. package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +441 -441
  200. package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +407 -407
  201. package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +379 -379
  202. package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +398 -398
  203. package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +476 -476
  204. package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +391 -391
  205. package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +342 -342
  206. package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +324 -324
  207. package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +730 -730
  208. package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +624 -624
  209. package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +512 -512
  210. package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +433 -433
  211. package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +688 -688
  212. package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +243 -243
  213. package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +166 -166
  214. package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +162 -162
  215. package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +135 -135
  216. package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +88 -88
  217. package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +299 -299
  218. package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +241 -241
  219. package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +131 -131
  220. package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +130 -130
  221. package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +127 -127
  222. package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +114 -114
  223. package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +138 -138
  224. package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +161 -161
  225. package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +65 -65
  226. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +232 -232
  227. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +244 -244
  228. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +202 -202
  229. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +92 -92
  230. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +256 -256
  231. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +195 -195
  232. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +214 -214
  233. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +249 -249
  234. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +174 -174
  235. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +166 -166
  236. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +192 -192
  237. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +211 -211
  238. package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +83 -83
  239. package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +87 -87
  240. package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +95 -95
  241. package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +109 -109
  242. package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +96 -96
  243. package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +88 -88
  244. package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +71 -71
  245. package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +110 -110
  246. package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +108 -108
  247. package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +104 -104
  248. package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +178 -178
  249. package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +142 -142
  250. package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +145 -145
  251. package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +35 -35
  252. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +202 -202
  253. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +246 -246
  254. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +218 -218
  255. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +179 -179
  256. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +267 -267
  257. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +190 -190
  258. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +161 -161
  259. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +175 -175
  260. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +222 -222
  261. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +189 -189
  262. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +212 -212
  263. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +215 -215
  264. package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +71 -71
  265. package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +213 -213
  266. package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +302 -302
  267. package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +339 -339
  268. package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +112 -112
  269. package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +272 -272
  270. package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +233 -233
  271. package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +394 -394
  272. package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +422 -422
  273. package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +400 -400
  274. package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +226 -226
  275. package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +296 -296
  276. package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +411 -411
  277. package/lib/assets/docs/article/getting-start-tdd/go/index.md +83 -83
  278. package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +279 -279
  279. package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +337 -337
  280. package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +257 -257
  281. package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +182 -182
  282. package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +313 -313
  283. package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +309 -309
  284. package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +412 -412
  285. package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +390 -390
  286. package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +461 -461
  287. package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +434 -434
  288. package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +392 -392
  289. package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +631 -631
  290. package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +49 -49
  291. package/lib/assets/docs/article/getting-start-tdd/index.md +93 -93
  292. package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +375 -375
  293. package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +349 -349
  294. package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +445 -445
  295. package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +409 -409
  296. package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +330 -330
  297. package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +290 -290
  298. package/lib/assets/docs/article/getting-start-tdd/integration/index.md +69 -69
  299. package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +234 -234
  300. package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +261 -261
  301. package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +185 -185
  302. package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +115 -115
  303. package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +382 -382
  304. package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +272 -272
  305. package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +626 -626
  306. package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +393 -393
  307. package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +310 -310
  308. package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +188 -188
  309. package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +167 -167
  310. package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +205 -205
  311. package/lib/assets/docs/article/getting-start-tdd/java/index.md +61 -61
  312. package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +244 -244
  313. package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +262 -262
  314. package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +169 -169
  315. package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +112 -112
  316. package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +314 -314
  317. package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +235 -235
  318. package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +327 -327
  319. package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +322 -322
  320. package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +285 -285
  321. package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +199 -199
  322. package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +207 -207
  323. package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +295 -295
  324. package/lib/assets/docs/article/getting-start-tdd/node/index.md +56 -56
  325. package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +259 -259
  326. package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +200 -200
  327. package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +248 -248
  328. package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +141 -141
  329. package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +410 -410
  330. package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +321 -321
  331. package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +372 -372
  332. package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +453 -453
  333. package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +460 -460
  334. package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +182 -182
  335. package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +266 -266
  336. package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +308 -308
  337. package/lib/assets/docs/article/getting-start-tdd/php/index.md +84 -84
  338. package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +201 -201
  339. package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +247 -247
  340. package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +199 -199
  341. package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +87 -87
  342. package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +274 -274
  343. package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +190 -190
  344. package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +208 -208
  345. package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +172 -172
  346. package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +130 -130
  347. package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +122 -122
  348. package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +116 -116
  349. package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +126 -126
  350. package/lib/assets/docs/article/getting-start-tdd/python/index.md +55 -55
  351. package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +231 -231
  352. package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +238 -238
  353. package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +228 -228
  354. package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +112 -112
  355. package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +287 -287
  356. package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +248 -248
  357. package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +279 -279
  358. package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +329 -329
  359. package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +196 -196
  360. package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +175 -175
  361. package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +237 -237
  362. package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +398 -398
  363. package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +83 -83
  364. package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +211 -211
  365. package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +264 -264
  366. package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +233 -233
  367. package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +92 -92
  368. package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +212 -212
  369. package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +164 -164
  370. package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +142 -142
  371. package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +145 -145
  372. package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +110 -110
  373. package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +94 -94
  374. package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +105 -105
  375. package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +112 -112
  376. package/lib/assets/docs/article/getting-start-tdd/rust/index.md +83 -83
  377. package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +111 -111
  378. package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +107 -107
  379. package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +99 -99
  380. package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +123 -123
  381. package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +196 -196
  382. package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +186 -186
  383. package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +139 -139
  384. package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +106 -106
  385. package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +75 -75
  386. package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +104 -104
  387. package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +94 -94
  388. package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +92 -92
  389. package/lib/assets/docs/article/getting-start-tdd/scala/index.md +65 -65
  390. package/lib/assets/docs/article/grokking-concurrency/all/index.md +404 -404
  391. package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +554 -554
  392. package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +469 -469
  393. package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +520 -520
  394. package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +420 -420
  395. package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +510 -510
  396. package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +435 -435
  397. package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +465 -465
  398. package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +377 -377
  399. package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +116 -116
  400. package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +108 -108
  401. package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +101 -101
  402. package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +122 -122
  403. package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +123 -123
  404. package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +118 -118
  405. package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +89 -89
  406. package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +100 -100
  407. package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +120 -120
  408. package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +101 -101
  409. package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +97 -97
  410. package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +123 -123
  411. package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +101 -101
  412. package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +112 -112
  413. package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +99 -99
  414. package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +61 -61
  415. package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +84 -84
  416. package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +92 -92
  417. package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +65 -65
  418. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +80 -80
  419. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +103 -103
  420. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +94 -94
  421. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +110 -110
  422. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +104 -104
  423. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +93 -93
  424. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +121 -121
  425. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +107 -107
  426. package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +248 -248
  427. package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +96 -96
  428. package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +96 -96
  429. package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +91 -91
  430. package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +106 -106
  431. package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +99 -99
  432. package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +95 -95
  433. package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +111 -111
  434. package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +118 -118
  435. package/lib/assets/docs/article/grokking-concurrency/index.md +66 -66
  436. package/lib/assets/docs/article/grokking-concurrency/java/index.md +102 -102
  437. package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +308 -308
  438. package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +334 -334
  439. package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +221 -221
  440. package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +213 -213
  441. package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +112 -112
  442. package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +69 -69
  443. package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +101 -101
  444. package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +101 -101
  445. package/lib/assets/docs/article/grokking-concurrency/python/index.md +313 -313
  446. package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +239 -239
  447. package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +418 -418
  448. package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +227 -227
  449. package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +299 -299
  450. package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +315 -315
  451. package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +297 -297
  452. package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +314 -314
  453. package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +360 -360
  454. package/lib/assets/docs/article/grokking-concurrency/rust/index.md +270 -270
  455. package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +108 -108
  456. package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +120 -120
  457. package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +126 -126
  458. package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +175 -175
  459. package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +158 -158
  460. package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +94 -94
  461. package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +133 -133
  462. package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +155 -155
  463. package/lib/assets/docs/article/grokking-concurrency/scala/index.md +69 -69
  464. package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +78 -78
  465. package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +112 -112
  466. package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +93 -93
  467. package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +110 -110
  468. package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +119 -119
  469. package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +83 -83
  470. package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +131 -131
  471. package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +129 -129
  472. package/lib/assets/docs/article/grokkingfp/all/index.md +368 -368
  473. package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +530 -530
  474. package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +923 -923
  475. package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +1128 -1128
  476. package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +1104 -1104
  477. package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +1026 -1026
  478. package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +785 -785
  479. package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +871 -871
  480. package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +972 -972
  481. package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +926 -926
  482. package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +870 -870
  483. package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +715 -715
  484. package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +626 -626
  485. package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +712 -712
  486. package/lib/assets/docs/article/grokkingfp/clojure/index.md +276 -276
  487. package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +667 -667
  488. package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +643 -643
  489. package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +620 -620
  490. package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +697 -697
  491. package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +751 -751
  492. package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +721 -721
  493. package/lib/assets/docs/article/grokkingfp/csharp/index.md +246 -246
  494. package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +811 -811
  495. package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +971 -971
  496. package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +981 -981
  497. package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +949 -949
  498. package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +947 -947
  499. package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +739 -739
  500. package/lib/assets/docs/article/grokkingfp/elixir/index.md +203 -203
  501. package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +712 -712
  502. package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +838 -838
  503. package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +985 -985
  504. package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +974 -974
  505. package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +1286 -1286
  506. package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +1049 -1049
  507. package/lib/assets/docs/article/grokkingfp/fsharp/index.md +210 -210
  508. package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +714 -714
  509. package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +961 -961
  510. package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +972 -972
  511. package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +832 -832
  512. package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +911 -911
  513. package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +922 -922
  514. package/lib/assets/docs/article/grokkingfp/haskell/index.md +234 -234
  515. package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +591 -591
  516. package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +866 -866
  517. package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +915 -915
  518. package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +878 -878
  519. package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +845 -845
  520. package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +844 -844
  521. package/lib/assets/docs/article/grokkingfp/index.md +143 -143
  522. package/lib/assets/docs/article/grokkingfp/java/index.md +211 -211
  523. package/lib/assets/docs/article/grokkingfp/java/part-1.md +648 -648
  524. package/lib/assets/docs/article/grokkingfp/java/part-2.md +675 -675
  525. package/lib/assets/docs/article/grokkingfp/java/part-3.md +672 -672
  526. package/lib/assets/docs/article/grokkingfp/java/part-4.md +771 -771
  527. package/lib/assets/docs/article/grokkingfp/java/part-5.md +959 -959
  528. package/lib/assets/docs/article/grokkingfp/java/part-6.md +1328 -1328
  529. package/lib/assets/docs/article/grokkingfp/python/index.md +258 -258
  530. package/lib/assets/docs/article/grokkingfp/python/part-1.md +443 -443
  531. package/lib/assets/docs/article/grokkingfp/python/part-2.md +958 -958
  532. package/lib/assets/docs/article/grokkingfp/python/part-3.md +1004 -1004
  533. package/lib/assets/docs/article/grokkingfp/python/part-4.md +765 -765
  534. package/lib/assets/docs/article/grokkingfp/python/part-5.md +747 -747
  535. package/lib/assets/docs/article/grokkingfp/python/part-6.md +861 -861
  536. package/lib/assets/docs/article/grokkingfp/ruby/index.md +330 -330
  537. package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +755 -755
  538. package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +938 -938
  539. package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +946 -946
  540. package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +921 -921
  541. package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +908 -908
  542. package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +1412 -1412
  543. package/lib/assets/docs/article/grokkingfp/rust/index.md +242 -242
  544. package/lib/assets/docs/article/grokkingfp/rust/part-1.md +634 -634
  545. package/lib/assets/docs/article/grokkingfp/rust/part-2.md +1060 -1060
  546. package/lib/assets/docs/article/grokkingfp/rust/part-3.md +994 -994
  547. package/lib/assets/docs/article/grokkingfp/rust/part-4.md +573 -573
  548. package/lib/assets/docs/article/grokkingfp/rust/part-5.md +705 -705
  549. package/lib/assets/docs/article/grokkingfp/rust/part-6.md +508 -508
  550. package/lib/assets/docs/article/grokkingfp/scala/index.md +171 -171
  551. package/lib/assets/docs/article/grokkingfp/scala/part-1.md +543 -543
  552. package/lib/assets/docs/article/grokkingfp/scala/part-2.md +946 -946
  553. package/lib/assets/docs/article/grokkingfp/scala/part-3.md +919 -919
  554. package/lib/assets/docs/article/grokkingfp/scala/part-4.md +742 -742
  555. package/lib/assets/docs/article/grokkingfp/scala/part-5.md +722 -722
  556. package/lib/assets/docs/article/grokkingfp/scala/part-6.md +867 -867
  557. package/lib/assets/docs/article/grokkingfp/typescript/index.md +273 -273
  558. package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +561 -561
  559. package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +1129 -1129
  560. package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +842 -842
  561. package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +1087 -1087
  562. package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +717 -717
  563. package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +982 -982
  564. package/lib/assets/docs/article/practical-database-design/index.md +121 -121
  565. package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +288 -288
  566. package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +518 -518
  567. package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +557 -557
  568. package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +924 -924
  569. package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +1627 -1627
  570. package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +2716 -2716
  571. package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +2082 -2082
  572. package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +2105 -2105
  573. package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +2031 -2031
  574. package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +1387 -1387
  575. package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +1677 -1677
  576. package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +1417 -1417
  577. package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +1434 -1434
  578. package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +667 -667
  579. package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +1625 -1625
  580. package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +1915 -1915
  581. package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +1708 -1708
  582. package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +2095 -2095
  583. package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +1123 -1123
  584. package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +1031 -1031
  585. package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +1382 -1382
  586. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +991 -991
  587. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +1300 -1300
  588. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +1166 -1166
  589. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +1584 -1584
  590. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +1183 -1183
  591. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +1016 -1016
  592. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +1753 -1753
  593. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +1447 -1447
  594. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +1878 -1878
  595. package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +965 -965
  596. package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +2069 -2069
  597. package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +2439 -2439
  598. package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +3661 -3661
  599. package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +2916 -2916
  600. package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +3105 -3105
  601. package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +2697 -2697
  602. package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +2544 -2544
  603. package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +2180 -2180
  604. package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +1192 -1192
  605. package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +2101 -2101
  606. package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +1032 -1032
  607. package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +1609 -1609
  608. package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +1453 -1453
  609. package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +1292 -1292
  610. package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +1470 -1470
  611. package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +1698 -1698
  612. package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +2334 -2334
  613. package/lib/assets/docs/article/practical-database-design/study/study2-1.md +1693 -1693
  614. package/lib/assets/docs/article/practical-database-design/study/study2-2.md +1347 -1347
  615. package/lib/assets/docs/article/practical-database-design/study/study2-3.md +2044 -2044
  616. package/lib/assets/docs/article/practical-database-design/study/study2-4.md +2229 -2229
  617. package/lib/assets/docs/article/practical-database-design/study/study2-5.md +2418 -2418
  618. package/lib/assets/docs/article/practical-database-design/study/study3-1.md +2205 -2205
  619. package/lib/assets/docs/article/practical-database-design/study/study3-2.md +2221 -2221
  620. package/lib/assets/docs/article/practical-database-design/study/study3-3.md +2253 -2253
  621. package/lib/assets/docs/article/practical-database-design/study/study3-4.md +2106 -2106
  622. package/lib/assets/docs/article/practical-database-design/study/study3-5.md +2507 -2507
  623. package/lib/assets/docs/article/practical-database-design/study/study4-1.md +2587 -2587
  624. package/lib/assets/docs/article/practical-database-design/study/study4-2.md +2075 -2075
  625. package/lib/assets/docs/article/practical-database-design/study/study4-3.md +1805 -1805
  626. package/lib/assets/docs/article/practical-database-design/study/study4-4.md +1895 -1895
  627. package/lib/assets/docs/article/practical-database-design/study/study4-5.md +2878 -2878
  628. package/lib/assets/docs/assets/css/extra.css +29 -29
  629. package/lib/assets/docs/assets/js/extra.js +44 -44
  630. package/lib/assets/docs/development/index.md +39 -39
  631. package/lib/assets/docs/operation/index.md +11 -11
  632. 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
  633. 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
  634. 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
  635. 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
  636. 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
  637. package/lib/assets/docs/reference/UI/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +450 -450
  638. package/lib/assets/docs/reference/images/Ansoff.drawio.svg +3 -3
  639. package/lib/assets/docs/reference/images/BrandBasicStrategy.drawio.svg +3 -3
  640. package/lib/assets/docs/reference/images/BrandCategorization.drawio.svg +3 -3
  641. package/lib/assets/docs/reference/images/BrandRecurutementStrategy.drawio.svg +3 -3
  642. package/lib/assets/docs/reference/images/BrandValue.drawio.svg +3 -3
  643. package/lib/assets/docs/reference/images/BusinessActivitiy.svg +3 -3
  644. package/lib/assets/docs/reference/images/HRM.drawio.svg +3 -3
  645. package/lib/assets/docs/reference/images/MarketingStructure.drawio.svg +3 -3
  646. package/lib/assets/docs/reference/images/OrganizationElemnts.svg +3 -3
  647. package/lib/assets/docs/reference/images/PPM.drawio.svg +3 -3
  648. package/lib/assets/docs/reference/images/PositioningMap.drawio.svg +3 -3
  649. package/lib/assets/docs/reference/images/ProductLayer.drawio.svg +3 -3
  650. package/lib/assets/docs/reference/images/ProductMix.drawio.svg +3 -3
  651. package/lib/assets/docs/reference/images/SWOT.drawio.svg +3 -3
  652. package/lib/assets/docs/reference/images/TargetMarket.drawio.svg +3 -3
  653. package/lib/assets/docs/reference/images/ThreeGenericStrategies.drawio.svg +3 -3
  654. package/lib/assets/docs/reference/images/VRIO.drawio.svg +3 -3
  655. package/lib/assets/docs/reference/images/ValueChain.drawio.svg +3 -3
  656. package/lib/assets/docs/reference/index.md +52 -52
  657. 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
  658. 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
  659. 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
  660. 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
  661. 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
  662. 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
  663. 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
  664. 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
  665. 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
  666. 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
  667. 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
  668. 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
  669. 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
  670. package/lib/assets/docs/reference//344/274/201/346/245/255/347/265/214/345/226/266/350/253/226.md +2637 -2636
  671. 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
  672. 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
  673. 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
  674. package/lib/assets/docs/reference//351/201/213/345/226/266/347/256/241/347/220/206.md +1482 -1482
  675. 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
  676. 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
  677. package/lib/assets/docs/reference//351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +299 -299
  678. 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
  679. package/lib/assets/docs/review/index.md +5 -5
  680. package/lib/assets/docs/strategy/index.md +1 -1
  681. package/lib/assets/docs/template/ADR.md +30 -30
  682. 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
  683. 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
  684. package/lib/assets/docs/template/README.md +50 -50
  685. package/lib/assets/docs/template/index.md +23 -23
  686. 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
  687. 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
  688. 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
  689. 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
  690. 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
  691. package/lib/assets/docs/template//344/274/201/346/245/255/345/210/206/346/236/220.md +573 -573
  692. 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
  693. package/lib/assets/docs/template//350/246/201/344/273/266/345/256/232/347/276/251.md +669 -669
  694. package/lib/assets/docs/template//350/250/255/350/250/210.md +173 -173
  695. 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
  696. package/lib/assets/gulpfile.js +25 -25
  697. package/lib/assets/mkdocs.yml +136 -135
  698. package/lib/assets/ops/docker/mkdoc/Dockerfile +19 -19
  699. package/lib/assets/ops/scripts/journal.js +180 -180
  700. package/lib/assets/ops/scripts/mkdocs.js +82 -82
  701. package/lib/assets/ops/scripts/release.js +431 -431
  702. package/lib/assets/ops/scripts/sonar_local.js +726 -726
  703. package/lib/assets/ops/scripts/ssh.js +190 -190
  704. package/lib/assets/ops/scripts/vault.js +299 -299
  705. package/lib/assets/package-lock.json +1653 -1653
  706. package/lib/assets/package.json +40 -40
  707. package/lib/gulpfile.js +37 -37
  708. package/package.json +41 -41
  709. package/lib/assets/.claude/agent-memory/xp-programmer/MEMORY.md +0 -6
  710. package/lib/assets/.claude/agent-memory/xp-programmer/project_cargo_tracker.md +0 -11
  711. package/lib/assets/.claude/agent-memory/xp-programmer/project_ddd_patterns.md +0 -27
  712. package/lib/assets/.claude/agent-memory/xp-programmer/project_us07_route_assignment.md +0 -19
@@ -1,1286 +1,1286 @@
1
- # Part V: 並行処理と OTP
2
-
3
- 本章では、Elixir における並行処理を学びます。軽量プロセスによる並行実行、Agent/Task による安全な状態管理と非同期処理、そして OTP パターン(GenServer、Supervisor)による堅牢な並行システムの構築方法を習得します。
4
-
5
- ---
6
-
7
- ## 第10章: 並行処理
8
-
9
- ### 10.1 並行処理の課題
10
-
11
- 従来の並行処理には多くの課題があります:
12
-
13
- - デッドロック
14
- - 競合状態(Race Condition)
15
- - 共有状態の管理の複雑さ
16
- - スレッドのオーバーヘッド
17
-
18
- ```plantuml
19
- @startuml
20
- !theme plain
21
-
22
- rectangle "従来の並行処理の問題" {
23
- rectangle "問題" as problems {
24
- card "デッドロック"
25
- card "競合状態"
26
- card "可変状態の共有"
27
- card "スレッド管理"
28
- }
29
-
30
- rectangle "Elixir の解決策" as solutions {
31
- card "イミュータブルデータ"
32
- card "Agent(共有状態)"
33
- card "軽量プロセス"
34
- card "メッセージパッシング"
35
- }
36
- }
37
-
38
- problems --> solutions : Elixir/OTP アプローチ
39
-
40
- @enduml
41
- ```
42
-
43
- ### 10.2 Elixir の並行モデル
44
-
45
- Elixir は **アクターモデル** に基づいた並行処理を提供します:
46
-
47
- - 各プロセスは独立した状態を持つ
48
- - プロセス間はメッセージで通信
49
- - プロセスは非常に軽量(数 KB)
50
- - 数百万のプロセスを同時に実行可能
51
-
52
- ```plantuml
53
- @startuml
54
- !theme plain
55
-
56
- rectangle "Elixir のプロセスモデル" {
57
- rectangle "プロセス 1" as p1 {
58
- card "状態"
59
- card "メールボックス"
60
- }
61
-
62
- rectangle "プロセス 2" as p2 {
63
- card "状態"
64
- card "メールボックス"
65
- }
66
-
67
- rectangle "プロセス 3" as p3 {
68
- card "状態"
69
- card "メールボックス"
70
- }
71
-
72
- p1 --> p2 : メッセージ
73
- p2 --> p3 : メッセージ
74
- p3 --> p1 : メッセージ
75
- }
76
-
77
- note bottom
78
- 各プロセスは独立
79
- 共有状態なし
80
- end note
81
-
82
- @enduml
83
- ```
84
-
85
- ### 10.3 チェックインのリアルタイム集計
86
-
87
- **ソースファイル**: `app/elixir/lib/ch10/concurrency.ex`
88
-
89
- 都市へのチェックインをリアルタイムで集計し、ランキングを更新する例を見ていきます。
90
-
91
- ```elixir
92
- defmodule City do
93
- defstruct [:name]
94
- end
95
-
96
- defmodule CityStats do
97
- defstruct [:city, :check_ins]
98
- end
99
- ```
100
-
101
- #### トップ N 都市の計算(純粋関数)
102
-
103
- ```elixir
104
- def top_cities(city_check_ins, n \\ 3) do
105
- city_check_ins
106
- |> Enum.map(fn {city, check_ins} ->
107
- %CityStats{city: city, check_ins: check_ins}
108
- end)
109
- |> Enum.sort_by(& &1.check_ins, :desc)
110
- |> Enum.take(n)
111
- end
112
- ```
113
-
114
- ### 10.4 Agent - 共有状態の管理
115
-
116
- **Agent** は、プロセスベースの状態管理を提供します。Scala の `Ref` に相当します。
117
-
118
- ```elixir
119
- # Agent の作成
120
- {:ok, counter} = Agent.start_link(fn -> 0 end)
121
-
122
- # 値の取得
123
- Agent.get(counter, & &1) # 0
124
-
125
- # アトミックな更新
126
- Agent.update(counter, &(&1 + 1))
127
- Agent.get(counter, & &1) # 1
128
-
129
- # 停止
130
- Agent.stop(counter)
131
- ```
132
-
133
- ```plantuml
134
- @startuml
135
- !theme plain
136
-
137
- rectangle "Agent の操作" {
138
- card "Agent.start_link(fn -> 0 end)" as create
139
- card "Agent.update(counter, &(&1 + 3))" as update
140
- card "Agent.get(counter, & &1)" as get
141
-
142
- create --> update : 作成
143
- update --> get : 更新
144
- }
145
-
146
- note bottom of update
147
- update はアトミック
148
- 他の処理と競合しない
149
- end note
150
-
151
- @enduml
152
- ```
153
-
154
- #### Agent の主要関数
155
-
156
- | 関数 | 説明 | 例 |
157
- |------|------|-----|
158
- | `Agent.start_link(fun)` | 初期値で Agent を作成 | `Agent.start_link(fn -> 0 end)` |
159
- | `Agent.get(agent, fun)` | 現在の値を取得 | `Agent.get(counter, & &1)` |
160
- | `Agent.update(agent, fun)` | アトミックに更新 | `Agent.update(counter, &(&1 + 1))` |
161
- | `Agent.get_and_update(agent, fun)` | 取得と更新を同時に | `Agent.get_and_update(counter, &{&1, &1 + 1})` |
162
-
163
- #### チェックインストアの実装
164
-
165
- ```elixir
166
- def create_check_in_store do
167
- Agent.start_link(fn -> %{} end)
168
- end
169
-
170
- def store_check_in(agent, city) do
171
- Agent.update(agent, fn state ->
172
- Map.update(state, city, 1, &(&1 + 1))
173
- end)
174
- end
175
-
176
- def get_check_ins(agent) do
177
- Agent.get(agent, & &1)
178
- end
179
- ```
180
-
181
- ### 10.5 Task - 並列実行
182
-
183
- `Task` を使って処理を並列に実行できます。Scala の `parSequence` に相当します。
184
-
185
- ```elixir
186
- # 複数のタスクを並列実行
187
- tasks = [fn -> 1 end, fn -> 2 end, fn -> 3 end]
188
-
189
- results =
190
- tasks
191
- |> Enum.map(&Task.async/1)
192
- |> Task.await_many()
193
-
194
- # [1, 2, 3]
195
- ```
196
-
197
- ```plantuml
198
- @startuml
199
- !theme plain
200
-
201
- rectangle "Task による並列実行" {
202
- rectangle "順次実行" as seq {
203
- card "Task 1" as s1
204
- card "Task 2" as s2
205
- card "Task 3" as s3
206
- s1 --> s2
207
- s2 --> s3
208
- }
209
-
210
- rectangle "並列実行" as par {
211
- card "Task 1" as p1
212
- card "Task 2" as p2
213
- card "Task 3" as p3
214
- }
215
- }
216
-
217
- note bottom of seq
218
- 合計時間 = T1 + T2 + T3
219
- end note
220
-
221
- note bottom of par
222
- 合計時間 ≈ max(T1, T2, T3)
223
- end note
224
-
225
- @enduml
226
- ```
227
-
228
- #### 並列マッピング
229
-
230
- ```elixir
231
- def parallel_map(items, f) do
232
- items
233
- |> Enum.map(fn item -> Task.async(fn -> f.(item) end) end)
234
- |> Task.await_many()
235
- end
236
-
237
- # 使用例
238
- parallel_map([1, 2, 3], &(&1 * 2)) # [2, 4, 6]
239
- ```
240
-
241
- ### 10.6 サイコロを並行して振る
242
-
243
- ```elixir
244
- def cast_the_die do
245
- :rand.uniform(6)
246
- end
247
-
248
- def cast_dice_parallel(n) do
249
- 1..n
250
- |> Enum.map(fn _ -> Task.async(&cast_the_die/0) end)
251
- |> Task.await_many()
252
- |> Enum.sum()
253
- end
254
-
255
- # 3つのサイコロを並行して振って合計
256
- cast_dice_parallel(3) # 3〜18 の値
257
- ```
258
-
259
- #### Agent と Task の組み合わせ
260
-
261
- ```elixir
262
- def cast_dice_and_store(n, agent) do
263
- tasks =
264
- 1..n
265
- |> Enum.map(fn _ ->
266
- Task.async(fn ->
267
- result = cast_the_die()
268
- Agent.update(agent, &[result | &1])
269
- result
270
- end)
271
- end)
272
-
273
- Task.await_many(tasks)
274
- :ok
275
- end
276
-
277
- # 使用例
278
- {:ok, agent} = Agent.start_link(fn -> [] end)
279
- cast_dice_and_store(5, agent)
280
- results = Agent.get(agent, & &1) # 5つのサイコロの結果
281
- ```
282
-
283
- ### 10.7 プロセスによる軽量スレッド
284
-
285
- Elixir のプロセスは、Scala の `Fiber` に相当する軽量な実行単位です。
286
-
287
- ```plantuml
288
- @startuml
289
- !theme plain
290
-
291
- rectangle "Thread vs Process" {
292
- rectangle "OS Thread" as thread {
293
- card "重い(MB単位のメモリ)"
294
- card "OS が管理"
295
- card "数千程度が限界"
296
- }
297
-
298
- rectangle "Elixir Process" as process {
299
- card "軽い(KB単位のメモリ)"
300
- card "BEAM VM が管理"
301
- card "数百万も可能"
302
- }
303
- }
304
-
305
- @enduml
306
- ```
307
-
308
- #### プロセスの起動とキャンセル
309
-
310
- ```elixir
311
- def start_background(f) do
312
- pid = spawn(f)
313
- {:ok, pid}
314
- end
315
-
316
- def cancel(pid) do
317
- Process.exit(pid, :kill)
318
- :ok
319
- end
320
-
321
- # 使用例
322
- {:ok, pid} = start_background(fn ->
323
- Process.sleep(1000)
324
- IO.puts("done")
325
- end)
326
-
327
- # 途中でキャンセル
328
- cancel(pid)
329
- ```
330
-
331
- #### 繰り返し実行するプロセス
332
-
333
- ```elixir
334
- def start_repeating(f, interval_ms) do
335
- pid =
336
- spawn(fn ->
337
- repeat_forever(f, interval_ms)
338
- end)
339
-
340
- {:ok, pid}
341
- end
342
-
343
- defp repeat_forever(f, interval_ms) do
344
- f.()
345
- Process.sleep(interval_ms)
346
- repeat_forever(f, interval_ms)
347
- end
348
-
349
- # 100ms ごとにカウントアップ
350
- {:ok, agent} = Agent.start_link(fn -> 0 end)
351
- {:ok, pid} = start_repeating(fn -> Agent.update(agent, &(&1 + 1)) end, 100)
352
- ```
353
-
354
- ### 10.8 チェックイン処理の並行版
355
-
356
- ```elixir
357
- defmodule ProcessingCheckIns do
358
- defstruct [:check_in_store, :ranking_store, :ranking_updater_pid, :check_in_processor_pid]
359
- end
360
-
361
- def start_processing(cities) do
362
- {:ok, check_in_store} = create_check_in_store()
363
- {:ok, ranking_store} = create_ranking_store()
364
-
365
- # ランキング更新プロセスを起動
366
- {:ok, ranking_updater_pid} =
367
- start_repeating(
368
- fn ->
369
- check_ins = get_check_ins(check_in_store)
370
- ranking = top_cities(check_ins)
371
- update_ranking(ranking_store, ranking)
372
- end,
373
- 10
374
- )
375
-
376
- # チェックイン処理プロセスを起動
377
- check_in_processor_pid =
378
- spawn(fn ->
379
- Enum.each(cities, fn city ->
380
- store_check_in(check_in_store, city)
381
- end)
382
- end)
383
-
384
- {:ok, %ProcessingCheckIns{...}}
385
- end
386
-
387
- def current_ranking(processing) do
388
- get_ranking(processing.ranking_store)
389
- end
390
-
391
- def stop_processing(processing) do
392
- cancel(processing.ranking_updater_pid)
393
- cancel(processing.check_in_processor_pid)
394
- Agent.stop(processing.check_in_store)
395
- Agent.stop(processing.ranking_store)
396
- :ok
397
- end
398
- ```
399
-
400
- ```plantuml
401
- @startuml
402
- !theme plain
403
-
404
- rectangle "並行処理の構造" {
405
- rectangle "チェックイン処理" as checkin {
406
- card "Stream からチェックインを受信"
407
- card "Agent に保存"
408
- }
409
-
410
- rectangle "ランキング更新" as ranking {
411
- card "Agent からデータを読み取り"
412
- card "ランキングを計算"
413
- card "結果を Agent に保存"
414
- }
415
- }
416
-
417
- note bottom
418
- 2つの処理が並行して実行される
419
- end note
420
-
421
- @enduml
422
- ```
423
-
424
- ### 10.9 並行カウント
425
-
426
- ```elixir
427
- def count_evens(ios) do
428
- {:ok, counter} = Agent.start_link(fn -> 0 end)
429
-
430
- ios
431
- |> Enum.map(fn io ->
432
- Task.async(fn ->
433
- n = io.()
434
-
435
- if rem(n, 2) == 0 do
436
- Agent.update(counter, &(&1 + 1))
437
- end
438
- end)
439
- end)
440
- |> Task.await_many()
441
-
442
- result = Agent.get(counter, & &1)
443
- Agent.stop(counter)
444
- result
445
- end
446
-
447
- # 使用例
448
- ios = Enum.map(1..100, fn n -> fn -> n end end)
449
- count_evens(ios) # 50
450
- ```
451
-
452
- ### 10.10 Process.sleep の特性
453
-
454
- Elixir の `Process.sleep` は他のプロセスをブロックしません。
455
-
456
- | 特性 | Process.sleep | Thread.sleep (Java) |
457
- |------|---------------|---------------------|
458
- | ブロック対象 | 現在のプロセスのみ | OS スレッド |
459
- | リソース | 軽量 | 重い |
460
- | 並行性 | 他のプロセスは実行可能 | スレッドがブロック |
461
-
462
- ```elixir
463
- # 3つのプロセスで並列スリープ → 約100msで完了
464
- {time, _} = :timer.tc(fn ->
465
- 1..3
466
- |> Enum.map(fn _ -> Task.async(fn -> Process.sleep(100) end) end)
467
- |> Task.await_many()
468
- end)
469
-
470
- time < 200_000 # true(200ms未満)
471
- ```
472
-
473
- ---
474
-
475
- ## 第11章: OTP パターン
476
-
477
- ### 11.1 OTP とは
478
-
479
- **OTP (Open Telecom Platform)** は、Erlang/Elixir で堅牢な並行システムを構築するためのフレームワークです。
480
-
481
- 主なコンポーネント:
482
-
483
-
484
- - **GenServer**: 汎用サーバープロセス
485
- - **Supervisor**: プロセスの監視と再起動
486
- - **Application**: アプリケーションの管理
487
-
488
- ```plantuml
489
- @startuml
490
- !theme plain
491
-
492
- rectangle "OTP の構成" {
493
- rectangle "Application" as app {
494
- rectangle "Supervisor" as sup {
495
- card "GenServer 1" as gs1
496
- card "GenServer 2" as gs2
497
- card "GenServer 3" as gs3
498
- }
499
- }
500
- }
501
-
502
- sup --> gs1 : 監視
503
- sup --> gs2 : 監視
504
- sup --> gs3 : 監視
505
-
506
- note bottom
507
- Supervisor がプロセスを監視
508
- クラッシュ時は自動再起動
509
- end note
510
-
511
- @enduml
512
- ```
513
-
514
- ### 11.2 GenServer によるカウンター
515
-
516
- **ソースファイル**: `app/elixir/lib/ch11/otp_patterns.ex`
517
-
518
- GenServer は、状態を持つサーバープロセスを簡単に実装できます。
519
-
520
- ```elixir
521
- defmodule Counter do
522
- use GenServer
523
-
524
- # クライアント API
525
-
526
- def start_link(initial_value \\ 0) do
527
- GenServer.start_link(__MODULE__, initial_value)
528
- end
529
-
530
- def get(counter) do
531
- GenServer.call(counter, :get)
532
- end
533
-
534
- def increment(counter) do
535
- GenServer.cast(counter, :increment)
536
- end
537
-
538
- def add(counter, value) do
539
- GenServer.cast(counter, {:add, value})
540
- end
541
-
542
- # サーバーコールバック
543
-
544
- @impl true
545
- def init(initial_value) do
546
- {:ok, initial_value}
547
- end
548
-
549
- @impl true
550
- def handle_call(:get, _from, state) do
551
- {:reply, state, state}
552
- end
553
-
554
- @impl true
555
- def handle_cast(:increment, state) do
556
- {:noreply, state + 1}
557
- end
558
-
559
- @impl true
560
- def handle_cast({:add, value}, state) do
561
- {:noreply, state + value}
562
- end
563
- end
564
- ```
565
-
566
- ```elixir
567
- # 使用例
568
- {:ok, counter} = Counter.start_link(0)
569
- Counter.get(counter) # 0
570
- Counter.increment(counter)
571
- Counter.get(counter) # 1
572
- Counter.add(counter, 10)
573
- Counter.get(counter) # 11
574
- GenServer.stop(counter)
575
- ```
576
-
577
- ```plantuml
578
- @startuml
579
- !theme plain
580
-
581
- rectangle "GenServer の通信パターン" {
582
- card "クライアント" as client
583
-
584
- rectangle "GenServer" as server {
585
- card "状態"
586
- card "メールボックス"
587
- }
588
-
589
- client --> server : call (同期)
590
- client --> server : cast (非同期)
591
- server --> client : reply
592
- }
593
-
594
- note bottom
595
- call: 応答を待つ
596
- cast: 応答を待たない
597
- end note
598
-
599
- @enduml
600
- ```
601
-
602
- ### 11.3 GenServer によるチェックインストア
603
-
604
- ```elixir
605
- defmodule CheckInStore do
606
- use GenServer
607
-
608
- # クライアント API
609
-
610
- def start_link(opts \\ []) do
611
- GenServer.start_link(__MODULE__, %{}, opts)
612
- end
613
-
614
- def check_in(store, city) do
615
- GenServer.cast(store, {:check_in, city})
616
- end
617
-
618
- def get_count(store, city) do
619
- GenServer.call(store, {:get_count, city})
620
- end
621
-
622
- def get_all(store) do
623
- GenServer.call(store, :get_all)
624
- end
625
-
626
- def top_cities(store, n \\ 3) do
627
- GenServer.call(store, {:top_cities, n})
628
- end
629
-
630
- # サーバーコールバック
631
-
632
- @impl true
633
- def init(state) do
634
- {:ok, state}
635
- end
636
-
637
- @impl true
638
- def handle_cast({:check_in, city}, state) do
639
- new_state = Map.update(state, city, 1, &(&1 + 1))
640
- {:noreply, new_state}
641
- end
642
-
643
- @impl true
644
- def handle_call({:get_count, city}, _from, state) do
645
- {:reply, Map.get(state, city, 0), state}
646
- end
647
-
648
- @impl true
649
- def handle_call(:get_all, _from, state) do
650
- {:reply, state, state}
651
- end
652
-
653
- @impl true
654
- def handle_call({:top_cities, n}, _from, state) do
655
- top =
656
- state
657
- |> Enum.sort_by(fn {_city, count} -> count end, :desc)
658
- |> Enum.take(n)
659
-
660
- {:reply, top, state}
661
- end
662
- end
663
- ```
664
-
665
- ### 11.4 定期実行タスク
666
-
667
- ```elixir
668
- defmodule PeriodicTask do
669
- use GenServer
670
-
671
- def start_link(task_fn, interval_ms) do
672
- GenServer.start_link(__MODULE__, {task_fn, interval_ms})
673
- end
674
-
675
- @impl true
676
- def init({task_fn, interval_ms}) do
677
- schedule_work(interval_ms)
678
- {:ok, %{task_fn: task_fn, interval_ms: interval_ms}}
679
- end
680
-
681
- @impl true
682
- def handle_info(:work, %{task_fn: task_fn, interval_ms: interval_ms} = state) do
683
- task_fn.()
684
- schedule_work(interval_ms)
685
- {:noreply, state}
686
- end
687
-
688
- defp schedule_work(interval_ms) do
689
- Process.send_after(self(), :work, interval_ms)
690
- end
691
- end
692
-
693
- # 使用例:100ms ごとにタスクを実行
694
- {:ok, agent} = Agent.start_link(fn -> 0 end)
695
- {:ok, task} = PeriodicTask.start_link(
696
- fn -> Agent.update(agent, &(&1 + 1)) end,
697
- 100
698
- )
699
- ```
700
-
701
- ### 11.5 状態マシン
702
-
703
- GenServer で状態マシンを実装できます。
704
-
705
- ```elixir
706
- defmodule TrafficLight do
707
- use GenServer
708
-
709
- def start_link do
710
- GenServer.start_link(__MODULE__, :red)
711
- end
712
-
713
- def current(light) do
714
- GenServer.call(light, :current)
715
- end
716
-
717
- def next(light) do
718
- GenServer.cast(light, :next)
719
- end
720
-
721
- @impl true
722
- def init(initial_state) do
723
- {:ok, initial_state}
724
- end
725
-
726
- @impl true
727
- def handle_call(:current, _from, state) do
728
- {:reply, state, state}
729
- end
730
-
731
- @impl true
732
- def handle_cast(:next, state) do
733
- next_state =
734
- case state do
735
- :red -> :green
736
- :green -> :yellow
737
- :yellow -> :red
738
- end
739
-
740
- {:noreply, next_state}
741
- end
742
- end
743
- ```
744
-
745
- ```plantuml
746
- @startuml
747
- !theme plain
748
-
749
- state "Red" as red
750
- state "Green" as green
751
- state "Yellow" as yellow
752
-
753
- [*] --> red
754
- red --> green : next
755
- green --> yellow : next
756
- yellow --> red : next
757
-
758
- @enduml
759
- ```
760
-
761
- ### 11.6 ジョブキュー
762
-
763
- ```elixir
764
- defmodule JobQueue do
765
- use GenServer
766
-
767
- def start_link do
768
- GenServer.start_link(__MODULE__, :queue.new())
769
- end
770
-
771
- def enqueue(queue, job) do
772
- GenServer.cast(queue, {:enqueue, job})
773
- end
774
-
775
- def dequeue(queue) do
776
- GenServer.call(queue, :dequeue)
777
- end
778
-
779
- def size(queue) do
780
- GenServer.call(queue, :size)
781
- end
782
-
783
- @impl true
784
- def init(queue), do: {:ok, queue}
785
-
786
- @impl true
787
- def handle_cast({:enqueue, job}, queue) do
788
- {:noreply, :queue.in(job, queue)}
789
- end
790
-
791
- @impl true
792
- def handle_call(:dequeue, _from, queue) do
793
- case :queue.out(queue) do
794
- {{:value, job}, new_queue} -> {:reply, {:ok, job}, new_queue}
795
- {:empty, queue} -> {:reply, :empty, queue}
796
- end
797
- end
798
-
799
- @impl true
800
- def handle_call(:size, _from, queue) do
801
- {:reply, :queue.len(queue), queue}
802
- end
803
- end
804
- ```
805
-
806
- ### 11.7 Supervisor による耐障害性
807
-
808
- Supervisor は子プロセスを監視し、クラッシュ時に自動再起動します。
809
-
810
- ```elixir
811
- defmodule CounterSupervisor do
812
- use Supervisor
813
-
814
- def start_link do
815
- Supervisor.start_link(__MODULE__, :ok)
816
- end
817
-
818
- def get_counter(supervisor) do
819
- [{_, counter, _, _}] = Supervisor.which_children(supervisor)
820
- counter
821
- end
822
-
823
- @impl true
824
- def init(:ok) do
825
- children = [
826
- {Counter, 0}
827
- ]
828
-
829
- Supervisor.init(children, strategy: :one_for_one)
830
- end
831
- end
832
- ```
833
-
834
- ```plantuml
835
- @startuml
836
- !theme plain
837
-
838
- rectangle "Supervisor 戦略" {
839
- rectangle ":one_for_one" as o4o {
840
- card "クラッシュしたプロセスのみ再起動"
841
- }
842
-
843
- rectangle ":one_for_all" as o4a {
844
- card "1つがクラッシュしたら全て再起動"
845
- }
846
-
847
- rectangle ":rest_for_one" as r4o {
848
- card "クラッシュしたプロセスと後続を再起動"
849
- }
850
- }
851
-
852
- @enduml
853
- ```
854
-
855
- ### 11.8 DynamicSupervisor
856
-
857
- 動的にプロセスを追加・削除できる Supervisor です。
858
-
859
- ```elixir
860
- defmodule WorkerSupervisor do
861
- use DynamicSupervisor
862
-
863
- def start_link do
864
- DynamicSupervisor.start_link(__MODULE__, :ok)
865
- end
866
-
867
- def start_worker(supervisor, initial_value) do
868
- spec = {Counter, initial_value}
869
- DynamicSupervisor.start_child(supervisor, spec)
870
- end
871
-
872
- def stop_worker(supervisor, worker) do
873
- DynamicSupervisor.terminate_child(supervisor, worker)
874
- end
875
-
876
- def count_workers(supervisor) do
877
- DynamicSupervisor.count_children(supervisor).active
878
- end
879
-
880
- @impl true
881
- def init(:ok) do
882
- DynamicSupervisor.init(strategy: :one_for_one)
883
- end
884
- end
885
-
886
- # 使用例
887
- {:ok, sup} = WorkerSupervisor.start_link()
888
- {:ok, worker1} = WorkerSupervisor.start_worker(sup, 0)
889
- {:ok, worker2} = WorkerSupervisor.start_worker(sup, 100)
890
-
891
- Counter.increment(worker1)
892
- Counter.get(worker1) # 1
893
- Counter.get(worker2) # 100
894
-
895
- WorkerSupervisor.count_workers(sup) # 2
896
- ```
897
-
898
- ### 11.9 Task.Supervisor
899
-
900
- Task を監視付きで実行できます。
901
-
902
- ```elixir
903
- defmodule TaskRunner do
904
- def start_link do
905
- Task.Supervisor.start_link()
906
- end
907
-
908
- def run_async(supervisor, task_fn) do
909
- Task.Supervisor.async(supervisor, task_fn)
910
- end
911
-
912
- def run_all(supervisor, task_fns) do
913
- task_fns
914
- |> Enum.map(&Task.Supervisor.async(supervisor, &1))
915
- |> Task.await_many()
916
- end
917
-
918
- def run_with_timeout(supervisor, task_fn, timeout_ms) do
919
- task = Task.Supervisor.async_nolink(supervisor, task_fn)
920
-
921
- case Task.yield(task, timeout_ms) do
922
- {:ok, result} -> {:ok, result}
923
- nil ->
924
- Task.shutdown(task, :brutal_kill)
925
- {:error, :timeout}
926
- end
927
- end
928
- end
929
-
930
- # 使用例
931
- {:ok, runner} = TaskRunner.start_link()
932
- results = TaskRunner.run_all(runner, [fn -> 1 end, fn -> 2 end, fn -> 3 end])
933
- # [1, 2, 3]
934
- ```
935
-
936
- ### 11.10 PubSub パターン
937
-
938
- Publish/Subscribe パターンの実装です。
939
-
940
- ```elixir
941
- defmodule PubSub do
942
- use GenServer
943
-
944
- def start_link do
945
- GenServer.start_link(__MODULE__, %{})
946
- end
947
-
948
- def subscribe(server, topic) do
949
- GenServer.call(server, {:subscribe, topic, self()})
950
- end
951
-
952
- def unsubscribe(server, topic) do
953
- GenServer.call(server, {:unsubscribe, topic, self()})
954
- end
955
-
956
- def publish(server, topic, message) do
957
- GenServer.cast(server, {:publish, topic, message})
958
- end
959
-
960
- @impl true
961
- def init(state), do: {:ok, state}
962
-
963
- @impl true
964
- def handle_call({:subscribe, topic, pid}, _from, state) do
965
- subscribers = Map.get(state, topic, MapSet.new())
966
- new_subscribers = MapSet.put(subscribers, pid)
967
- {:reply, :ok, Map.put(state, topic, new_subscribers)}
968
- end
969
-
970
- @impl true
971
- def handle_cast({:publish, topic, message}, state) do
972
- subscribers = Map.get(state, topic, MapSet.new())
973
-
974
- Enum.each(subscribers, fn pid ->
975
- send(pid, {:pubsub, topic, message})
976
- end)
977
-
978
- {:noreply, state}
979
- end
980
- end
981
-
982
- # 使用例
983
- {:ok, pubsub} = PubSub.start_link()
984
- PubSub.subscribe(pubsub, "events")
985
- PubSub.publish(pubsub, "events", :hello)
986
-
987
- receive do
988
- {:pubsub, "events", message} -> IO.inspect(message) # :hello
989
- end
990
- ```
991
-
992
- ---
993
-
994
- ## まとめ
995
-
996
- ### Part V で学んだこと
997
-
998
- ```plantuml
999
- @startuml
1000
- !theme plain
1001
-
1002
- rectangle "Part V: 並行処理と OTP" {
1003
- rectangle "第10章" as ch10 {
1004
- card "Agent(共有状態)"
1005
- card "Task(並列実行)"
1006
- card "軽量プロセス"
1007
- card "spawn / cancel"
1008
- }
1009
-
1010
- rectangle "第11章" as ch11 {
1011
- card "GenServer"
1012
- card "Supervisor"
1013
- card "DynamicSupervisor"
1014
- card "Task.Supervisor"
1015
- card "PubSub パターン"
1016
- }
1017
- }
1018
-
1019
- ch10 --> ch11
1020
-
1021
- @enduml
1022
- ```
1023
-
1024
- ### Scala との対応
1025
-
1026
- | Scala | Elixir |
1027
- |-------|--------|
1028
- | `Ref[IO, A]` | `Agent` |
1029
- | `parSequence` | `Task.await_many` |
1030
- | `Fiber` | プロセス(`spawn`) |
1031
- | `fiber.start` | `spawn` / `Task.async` |
1032
- | `fiber.cancel` | `Process.exit(pid, :kill)` |
1033
- | `foreverM` | 再帰的プロセス |
1034
- | - | `GenServer` |
1035
- | - | `Supervisor` |
1036
-
1037
- ### キーポイント
1038
-
1039
- 1. **Agent**: プロセスベースの状態管理(Ref 相当)
1040
- 2. **Task**: 非同期タスクの実行と結果の取得
1041
- 3. **プロセス**: 軽量な実行単位(数百万も可能)
1042
- 4. **GenServer**: 汎用的なサーバープロセス
1043
- 5. **Supervisor**: プロセスの監視と自動再起動
1044
- 6. **DynamicSupervisor**: 動的なプロセス管理
1045
-
1046
- ### 設計パターン
1047
-
1048
- ```plantuml
1049
- @startuml
1050
- !theme plain
1051
-
1052
- rectangle "並行処理の設計パターン" {
1053
- rectangle "パターン1: Agent + Task" as p1 {
1054
- card "Agent で状態を共有"
1055
- card "Task で並列処理"
1056
- }
1057
-
1058
- rectangle "パターン2: GenServer" as p2 {
1059
- card "状態とロジックをカプセル化"
1060
- card "同期/非同期 API を提供"
1061
- }
1062
-
1063
- rectangle "パターン3: Supervisor Tree" as p3 {
1064
- card "Supervisor で監視"
1065
- card "障害時は自動復旧"
1066
- }
1067
- }
1068
-
1069
- @enduml
1070
- ```
1071
-
1072
- ### 次のステップ
1073
-
1074
- Part VI では、以下のトピックを学びます:
1075
-
1076
- - 実践的なアプリケーション構築
1077
- - 外部 API との連携
1078
- - テスト戦略
1079
-
1080
- ---
1081
-
1082
- ## 演習問題
1083
-
1084
- ### 問題 1: Agent の基本
1085
-
1086
- 以下のプログラムを実装してください。カウンターを 0 から始めて、3回インクリメントした結果を返します。
1087
-
1088
- ```elixir
1089
- def increment_three_times do
1090
- ???
1091
- end
1092
-
1093
- # 期待される動作
1094
- increment_three_times() # 3
1095
- ```
1096
-
1097
- <details>
1098
- <summary>解答</summary>
1099
-
1100
- ```elixir
1101
- def increment_three_times do
1102
- {:ok, counter} = Agent.start_link(fn -> 0 end)
1103
- Agent.update(counter, &(&1 + 1))
1104
- Agent.update(counter, &(&1 + 1))
1105
- Agent.update(counter, &(&1 + 1))
1106
- result = Agent.get(counter, & &1)
1107
- Agent.stop(counter)
1108
- result
1109
- end
1110
- ```
1111
-
1112
- </details>
1113
-
1114
- ### 問題 2: 並列実行
1115
-
1116
- 以下のプログラムを実装してください。3つのタスクを並列実行し、結果の合計を返します。
1117
-
1118
- ```elixir
1119
- def sum_parallel(tasks) do
1120
- ???
1121
- end
1122
-
1123
- # 期待される動作
1124
- sum_parallel([fn -> 1 end, fn -> 2 end, fn -> 3 end]) # 6
1125
- ```
1126
-
1127
- <details>
1128
- <summary>解答</summary>
1129
-
1130
- ```elixir
1131
- def sum_parallel(tasks) do
1132
- tasks
1133
- |> Enum.map(&Task.async/1)
1134
- |> Task.await_many()
1135
- |> Enum.sum()
1136
- end
1137
- ```
1138
-
1139
- </details>
1140
-
1141
- ### 問題 3: GenServer
1142
-
1143
- 以下の GenServer を実装してください。リストを管理し、要素の追加と取得ができます。
1144
-
1145
- ```elixir
1146
- defmodule ListStore do
1147
- use GenServer
1148
-
1149
- # ???
1150
- end
1151
-
1152
- # 期待される動作
1153
- {:ok, store} = ListStore.start_link()
1154
- ListStore.add(store, 1)
1155
- ListStore.add(store, 2)
1156
- ListStore.add(store, 3)
1157
- ListStore.get_all(store) # [1, 2, 3]
1158
- ```
1159
-
1160
- <details>
1161
- <summary>解答</summary>
1162
-
1163
- ```elixir
1164
- defmodule ListStore do
1165
- use GenServer
1166
-
1167
- def start_link do
1168
- GenServer.start_link(__MODULE__, [])
1169
- end
1170
-
1171
- def add(store, item) do
1172
- GenServer.cast(store, {:add, item})
1173
- end
1174
-
1175
- def get_all(store) do
1176
- GenServer.call(store, :get_all)
1177
- end
1178
-
1179
- @impl true
1180
- def init(state), do: {:ok, state}
1181
-
1182
- @impl true
1183
- def handle_cast({:add, item}, state) do
1184
- {:noreply, state ++ [item]}
1185
- end
1186
-
1187
- @impl true
1188
- def handle_call(:get_all, _from, state) do
1189
- {:reply, state, state}
1190
- end
1191
- end
1192
- ```
1193
-
1194
- </details>
1195
-
1196
- ### 問題 4: タイムアウト付き収集
1197
-
1198
- 以下のプログラムを実装してください。指定時間後にプロセスを停止し、それまでに蓄積された結果を返します。
1199
-
1200
- ```elixir
1201
- def collect_for(duration_ms, interval_ms, generator) do
1202
- ???
1203
- end
1204
-
1205
- # 期待される動作
1206
- # 100ms 間、10ms ごとに乱数を生成
1207
- results = collect_for(100, 10, fn -> :rand.uniform(100) end)
1208
- # 約10個の要素が返される
1209
- ```
1210
-
1211
- <details>
1212
- <summary>解答</summary>
1213
-
1214
- ```elixir
1215
- def collect_for(duration_ms, interval_ms, generator) do
1216
- {:ok, collected} = Agent.start_link(fn -> [] end)
1217
-
1218
- {:ok, producer_pid} =
1219
- start_repeating(
1220
- fn ->
1221
- value = generator.()
1222
- Agent.update(collected, &[value | &1])
1223
- end,
1224
- interval_ms
1225
- )
1226
-
1227
- Process.sleep(duration_ms)
1228
- cancel(producer_pid)
1229
-
1230
- result = Agent.get(collected, &Enum.reverse/1)
1231
- Agent.stop(collected)
1232
- result
1233
- end
1234
- ```
1235
-
1236
- </details>
1237
-
1238
- ### 問題 5: Supervisor
1239
-
1240
- 以下の Supervisor を実装してください。2つのカウンターを監視します。
1241
-
1242
- ```elixir
1243
- defmodule DualCounterSupervisor do
1244
- use Supervisor
1245
-
1246
- # ???
1247
- end
1248
-
1249
- # 期待される動作
1250
- {:ok, sup} = DualCounterSupervisor.start_link()
1251
- {counter1, counter2} = DualCounterSupervisor.get_counters(sup)
1252
- Counter.increment(counter1)
1253
- Counter.get(counter1) # 1
1254
- Counter.get(counter2) # 0
1255
- ```
1256
-
1257
- <details>
1258
- <summary>解答</summary>
1259
-
1260
- ```elixir
1261
- defmodule DualCounterSupervisor do
1262
- use Supervisor
1263
-
1264
- def start_link do
1265
- Supervisor.start_link(__MODULE__, :ok)
1266
- end
1267
-
1268
- def get_counters(supervisor) do
1269
- children = Supervisor.which_children(supervisor)
1270
- [{:counter1, c1, _, _}, {:counter2, c2, _, _}] = children
1271
- {c1, c2}
1272
- end
1273
-
1274
- @impl true
1275
- def init(:ok) do
1276
- children = [
1277
- Supervisor.child_spec({Counter, 0}, id: :counter1),
1278
- Supervisor.child_spec({Counter, 0}, id: :counter2)
1279
- ]
1280
-
1281
- Supervisor.init(children, strategy: :one_for_one)
1282
- end
1283
- end
1284
- ```
1285
-
1286
- </details>
1
+ # Part V: 並行処理と OTP
2
+
3
+ 本章では、Elixir における並行処理を学びます。軽量プロセスによる並行実行、Agent/Task による安全な状態管理と非同期処理、そして OTP パターン(GenServer、Supervisor)による堅牢な並行システムの構築方法を習得します。
4
+
5
+ ---
6
+
7
+ ## 第10章: 並行処理
8
+
9
+ ### 10.1 並行処理の課題
10
+
11
+ 従来の並行処理には多くの課題があります:
12
+
13
+ - デッドロック
14
+ - 競合状態(Race Condition)
15
+ - 共有状態の管理の複雑さ
16
+ - スレッドのオーバーヘッド
17
+
18
+ ```plantuml
19
+ @startuml
20
+ !theme plain
21
+
22
+ rectangle "従来の並行処理の問題" {
23
+ rectangle "問題" as problems {
24
+ card "デッドロック"
25
+ card "競合状態"
26
+ card "可変状態の共有"
27
+ card "スレッド管理"
28
+ }
29
+
30
+ rectangle "Elixir の解決策" as solutions {
31
+ card "イミュータブルデータ"
32
+ card "Agent(共有状態)"
33
+ card "軽量プロセス"
34
+ card "メッセージパッシング"
35
+ }
36
+ }
37
+
38
+ problems --> solutions : Elixir/OTP アプローチ
39
+
40
+ @enduml
41
+ ```
42
+
43
+ ### 10.2 Elixir の並行モデル
44
+
45
+ Elixir は **アクターモデル** に基づいた並行処理を提供します:
46
+
47
+ - 各プロセスは独立した状態を持つ
48
+ - プロセス間はメッセージで通信
49
+ - プロセスは非常に軽量(数 KB)
50
+ - 数百万のプロセスを同時に実行可能
51
+
52
+ ```plantuml
53
+ @startuml
54
+ !theme plain
55
+
56
+ rectangle "Elixir のプロセスモデル" {
57
+ rectangle "プロセス 1" as p1 {
58
+ card "状態"
59
+ card "メールボックス"
60
+ }
61
+
62
+ rectangle "プロセス 2" as p2 {
63
+ card "状態"
64
+ card "メールボックス"
65
+ }
66
+
67
+ rectangle "プロセス 3" as p3 {
68
+ card "状態"
69
+ card "メールボックス"
70
+ }
71
+
72
+ p1 --> p2 : メッセージ
73
+ p2 --> p3 : メッセージ
74
+ p3 --> p1 : メッセージ
75
+ }
76
+
77
+ note bottom
78
+ 各プロセスは独立
79
+ 共有状態なし
80
+ end note
81
+
82
+ @enduml
83
+ ```
84
+
85
+ ### 10.3 チェックインのリアルタイム集計
86
+
87
+ **ソースファイル**: `app/elixir/lib/ch10/concurrency.ex`
88
+
89
+ 都市へのチェックインをリアルタイムで集計し、ランキングを更新する例を見ていきます。
90
+
91
+ ```elixir
92
+ defmodule City do
93
+ defstruct [:name]
94
+ end
95
+
96
+ defmodule CityStats do
97
+ defstruct [:city, :check_ins]
98
+ end
99
+ ```
100
+
101
+ #### トップ N 都市の計算(純粋関数)
102
+
103
+ ```elixir
104
+ def top_cities(city_check_ins, n \\ 3) do
105
+ city_check_ins
106
+ |> Enum.map(fn {city, check_ins} ->
107
+ %CityStats{city: city, check_ins: check_ins}
108
+ end)
109
+ |> Enum.sort_by(& &1.check_ins, :desc)
110
+ |> Enum.take(n)
111
+ end
112
+ ```
113
+
114
+ ### 10.4 Agent - 共有状態の管理
115
+
116
+ **Agent** は、プロセスベースの状態管理を提供します。Scala の `Ref` に相当します。
117
+
118
+ ```elixir
119
+ # Agent の作成
120
+ {:ok, counter} = Agent.start_link(fn -> 0 end)
121
+
122
+ # 値の取得
123
+ Agent.get(counter, & &1) # 0
124
+
125
+ # アトミックな更新
126
+ Agent.update(counter, &(&1 + 1))
127
+ Agent.get(counter, & &1) # 1
128
+
129
+ # 停止
130
+ Agent.stop(counter)
131
+ ```
132
+
133
+ ```plantuml
134
+ @startuml
135
+ !theme plain
136
+
137
+ rectangle "Agent の操作" {
138
+ card "Agent.start_link(fn -> 0 end)" as create
139
+ card "Agent.update(counter, &(&1 + 3))" as update
140
+ card "Agent.get(counter, & &1)" as get
141
+
142
+ create --> update : 作成
143
+ update --> get : 更新
144
+ }
145
+
146
+ note bottom of update
147
+ update はアトミック
148
+ 他の処理と競合しない
149
+ end note
150
+
151
+ @enduml
152
+ ```
153
+
154
+ #### Agent の主要関数
155
+
156
+ | 関数 | 説明 | 例 |
157
+ |------|------|-----|
158
+ | `Agent.start_link(fun)` | 初期値で Agent を作成 | `Agent.start_link(fn -> 0 end)` |
159
+ | `Agent.get(agent, fun)` | 現在の値を取得 | `Agent.get(counter, & &1)` |
160
+ | `Agent.update(agent, fun)` | アトミックに更新 | `Agent.update(counter, &(&1 + 1))` |
161
+ | `Agent.get_and_update(agent, fun)` | 取得と更新を同時に | `Agent.get_and_update(counter, &{&1, &1 + 1})` |
162
+
163
+ #### チェックインストアの実装
164
+
165
+ ```elixir
166
+ def create_check_in_store do
167
+ Agent.start_link(fn -> %{} end)
168
+ end
169
+
170
+ def store_check_in(agent, city) do
171
+ Agent.update(agent, fn state ->
172
+ Map.update(state, city, 1, &(&1 + 1))
173
+ end)
174
+ end
175
+
176
+ def get_check_ins(agent) do
177
+ Agent.get(agent, & &1)
178
+ end
179
+ ```
180
+
181
+ ### 10.5 Task - 並列実行
182
+
183
+ `Task` を使って処理を並列に実行できます。Scala の `parSequence` に相当します。
184
+
185
+ ```elixir
186
+ # 複数のタスクを並列実行
187
+ tasks = [fn -> 1 end, fn -> 2 end, fn -> 3 end]
188
+
189
+ results =
190
+ tasks
191
+ |> Enum.map(&Task.async/1)
192
+ |> Task.await_many()
193
+
194
+ # [1, 2, 3]
195
+ ```
196
+
197
+ ```plantuml
198
+ @startuml
199
+ !theme plain
200
+
201
+ rectangle "Task による並列実行" {
202
+ rectangle "順次実行" as seq {
203
+ card "Task 1" as s1
204
+ card "Task 2" as s2
205
+ card "Task 3" as s3
206
+ s1 --> s2
207
+ s2 --> s3
208
+ }
209
+
210
+ rectangle "並列実行" as par {
211
+ card "Task 1" as p1
212
+ card "Task 2" as p2
213
+ card "Task 3" as p3
214
+ }
215
+ }
216
+
217
+ note bottom of seq
218
+ 合計時間 = T1 + T2 + T3
219
+ end note
220
+
221
+ note bottom of par
222
+ 合計時間 ≈ max(T1, T2, T3)
223
+ end note
224
+
225
+ @enduml
226
+ ```
227
+
228
+ #### 並列マッピング
229
+
230
+ ```elixir
231
+ def parallel_map(items, f) do
232
+ items
233
+ |> Enum.map(fn item -> Task.async(fn -> f.(item) end) end)
234
+ |> Task.await_many()
235
+ end
236
+
237
+ # 使用例
238
+ parallel_map([1, 2, 3], &(&1 * 2)) # [2, 4, 6]
239
+ ```
240
+
241
+ ### 10.6 サイコロを並行して振る
242
+
243
+ ```elixir
244
+ def cast_the_die do
245
+ :rand.uniform(6)
246
+ end
247
+
248
+ def cast_dice_parallel(n) do
249
+ 1..n
250
+ |> Enum.map(fn _ -> Task.async(&cast_the_die/0) end)
251
+ |> Task.await_many()
252
+ |> Enum.sum()
253
+ end
254
+
255
+ # 3つのサイコロを並行して振って合計
256
+ cast_dice_parallel(3) # 3〜18 の値
257
+ ```
258
+
259
+ #### Agent と Task の組み合わせ
260
+
261
+ ```elixir
262
+ def cast_dice_and_store(n, agent) do
263
+ tasks =
264
+ 1..n
265
+ |> Enum.map(fn _ ->
266
+ Task.async(fn ->
267
+ result = cast_the_die()
268
+ Agent.update(agent, &[result | &1])
269
+ result
270
+ end)
271
+ end)
272
+
273
+ Task.await_many(tasks)
274
+ :ok
275
+ end
276
+
277
+ # 使用例
278
+ {:ok, agent} = Agent.start_link(fn -> [] end)
279
+ cast_dice_and_store(5, agent)
280
+ results = Agent.get(agent, & &1) # 5つのサイコロの結果
281
+ ```
282
+
283
+ ### 10.7 プロセスによる軽量スレッド
284
+
285
+ Elixir のプロセスは、Scala の `Fiber` に相当する軽量な実行単位です。
286
+
287
+ ```plantuml
288
+ @startuml
289
+ !theme plain
290
+
291
+ rectangle "Thread vs Process" {
292
+ rectangle "OS Thread" as thread {
293
+ card "重い(MB単位のメモリ)"
294
+ card "OS が管理"
295
+ card "数千程度が限界"
296
+ }
297
+
298
+ rectangle "Elixir Process" as process {
299
+ card "軽い(KB単位のメモリ)"
300
+ card "BEAM VM が管理"
301
+ card "数百万も可能"
302
+ }
303
+ }
304
+
305
+ @enduml
306
+ ```
307
+
308
+ #### プロセスの起動とキャンセル
309
+
310
+ ```elixir
311
+ def start_background(f) do
312
+ pid = spawn(f)
313
+ {:ok, pid}
314
+ end
315
+
316
+ def cancel(pid) do
317
+ Process.exit(pid, :kill)
318
+ :ok
319
+ end
320
+
321
+ # 使用例
322
+ {:ok, pid} = start_background(fn ->
323
+ Process.sleep(1000)
324
+ IO.puts("done")
325
+ end)
326
+
327
+ # 途中でキャンセル
328
+ cancel(pid)
329
+ ```
330
+
331
+ #### 繰り返し実行するプロセス
332
+
333
+ ```elixir
334
+ def start_repeating(f, interval_ms) do
335
+ pid =
336
+ spawn(fn ->
337
+ repeat_forever(f, interval_ms)
338
+ end)
339
+
340
+ {:ok, pid}
341
+ end
342
+
343
+ defp repeat_forever(f, interval_ms) do
344
+ f.()
345
+ Process.sleep(interval_ms)
346
+ repeat_forever(f, interval_ms)
347
+ end
348
+
349
+ # 100ms ごとにカウントアップ
350
+ {:ok, agent} = Agent.start_link(fn -> 0 end)
351
+ {:ok, pid} = start_repeating(fn -> Agent.update(agent, &(&1 + 1)) end, 100)
352
+ ```
353
+
354
+ ### 10.8 チェックイン処理の並行版
355
+
356
+ ```elixir
357
+ defmodule ProcessingCheckIns do
358
+ defstruct [:check_in_store, :ranking_store, :ranking_updater_pid, :check_in_processor_pid]
359
+ end
360
+
361
+ def start_processing(cities) do
362
+ {:ok, check_in_store} = create_check_in_store()
363
+ {:ok, ranking_store} = create_ranking_store()
364
+
365
+ # ランキング更新プロセスを起動
366
+ {:ok, ranking_updater_pid} =
367
+ start_repeating(
368
+ fn ->
369
+ check_ins = get_check_ins(check_in_store)
370
+ ranking = top_cities(check_ins)
371
+ update_ranking(ranking_store, ranking)
372
+ end,
373
+ 10
374
+ )
375
+
376
+ # チェックイン処理プロセスを起動
377
+ check_in_processor_pid =
378
+ spawn(fn ->
379
+ Enum.each(cities, fn city ->
380
+ store_check_in(check_in_store, city)
381
+ end)
382
+ end)
383
+
384
+ {:ok, %ProcessingCheckIns{...}}
385
+ end
386
+
387
+ def current_ranking(processing) do
388
+ get_ranking(processing.ranking_store)
389
+ end
390
+
391
+ def stop_processing(processing) do
392
+ cancel(processing.ranking_updater_pid)
393
+ cancel(processing.check_in_processor_pid)
394
+ Agent.stop(processing.check_in_store)
395
+ Agent.stop(processing.ranking_store)
396
+ :ok
397
+ end
398
+ ```
399
+
400
+ ```plantuml
401
+ @startuml
402
+ !theme plain
403
+
404
+ rectangle "並行処理の構造" {
405
+ rectangle "チェックイン処理" as checkin {
406
+ card "Stream からチェックインを受信"
407
+ card "Agent に保存"
408
+ }
409
+
410
+ rectangle "ランキング更新" as ranking {
411
+ card "Agent からデータを読み取り"
412
+ card "ランキングを計算"
413
+ card "結果を Agent に保存"
414
+ }
415
+ }
416
+
417
+ note bottom
418
+ 2つの処理が並行して実行される
419
+ end note
420
+
421
+ @enduml
422
+ ```
423
+
424
+ ### 10.9 並行カウント
425
+
426
+ ```elixir
427
+ def count_evens(ios) do
428
+ {:ok, counter} = Agent.start_link(fn -> 0 end)
429
+
430
+ ios
431
+ |> Enum.map(fn io ->
432
+ Task.async(fn ->
433
+ n = io.()
434
+
435
+ if rem(n, 2) == 0 do
436
+ Agent.update(counter, &(&1 + 1))
437
+ end
438
+ end)
439
+ end)
440
+ |> Task.await_many()
441
+
442
+ result = Agent.get(counter, & &1)
443
+ Agent.stop(counter)
444
+ result
445
+ end
446
+
447
+ # 使用例
448
+ ios = Enum.map(1..100, fn n -> fn -> n end end)
449
+ count_evens(ios) # 50
450
+ ```
451
+
452
+ ### 10.10 Process.sleep の特性
453
+
454
+ Elixir の `Process.sleep` は他のプロセスをブロックしません。
455
+
456
+ | 特性 | Process.sleep | Thread.sleep (Java) |
457
+ |------|---------------|---------------------|
458
+ | ブロック対象 | 現在のプロセスのみ | OS スレッド |
459
+ | リソース | 軽量 | 重い |
460
+ | 並行性 | 他のプロセスは実行可能 | スレッドがブロック |
461
+
462
+ ```elixir
463
+ # 3つのプロセスで並列スリープ → 約100msで完了
464
+ {time, _} = :timer.tc(fn ->
465
+ 1..3
466
+ |> Enum.map(fn _ -> Task.async(fn -> Process.sleep(100) end) end)
467
+ |> Task.await_many()
468
+ end)
469
+
470
+ time < 200_000 # true(200ms未満)
471
+ ```
472
+
473
+ ---
474
+
475
+ ## 第11章: OTP パターン
476
+
477
+ ### 11.1 OTP とは
478
+
479
+ **OTP (Open Telecom Platform)** は、Erlang/Elixir で堅牢な並行システムを構築するためのフレームワークです。
480
+
481
+ 主なコンポーネント:
482
+
483
+
484
+ - **GenServer**: 汎用サーバープロセス
485
+ - **Supervisor**: プロセスの監視と再起動
486
+ - **Application**: アプリケーションの管理
487
+
488
+ ```plantuml
489
+ @startuml
490
+ !theme plain
491
+
492
+ rectangle "OTP の構成" {
493
+ rectangle "Application" as app {
494
+ rectangle "Supervisor" as sup {
495
+ card "GenServer 1" as gs1
496
+ card "GenServer 2" as gs2
497
+ card "GenServer 3" as gs3
498
+ }
499
+ }
500
+ }
501
+
502
+ sup --> gs1 : 監視
503
+ sup --> gs2 : 監視
504
+ sup --> gs3 : 監視
505
+
506
+ note bottom
507
+ Supervisor がプロセスを監視
508
+ クラッシュ時は自動再起動
509
+ end note
510
+
511
+ @enduml
512
+ ```
513
+
514
+ ### 11.2 GenServer によるカウンター
515
+
516
+ **ソースファイル**: `app/elixir/lib/ch11/otp_patterns.ex`
517
+
518
+ GenServer は、状態を持つサーバープロセスを簡単に実装できます。
519
+
520
+ ```elixir
521
+ defmodule Counter do
522
+ use GenServer
523
+
524
+ # クライアント API
525
+
526
+ def start_link(initial_value \\ 0) do
527
+ GenServer.start_link(__MODULE__, initial_value)
528
+ end
529
+
530
+ def get(counter) do
531
+ GenServer.call(counter, :get)
532
+ end
533
+
534
+ def increment(counter) do
535
+ GenServer.cast(counter, :increment)
536
+ end
537
+
538
+ def add(counter, value) do
539
+ GenServer.cast(counter, {:add, value})
540
+ end
541
+
542
+ # サーバーコールバック
543
+
544
+ @impl true
545
+ def init(initial_value) do
546
+ {:ok, initial_value}
547
+ end
548
+
549
+ @impl true
550
+ def handle_call(:get, _from, state) do
551
+ {:reply, state, state}
552
+ end
553
+
554
+ @impl true
555
+ def handle_cast(:increment, state) do
556
+ {:noreply, state + 1}
557
+ end
558
+
559
+ @impl true
560
+ def handle_cast({:add, value}, state) do
561
+ {:noreply, state + value}
562
+ end
563
+ end
564
+ ```
565
+
566
+ ```elixir
567
+ # 使用例
568
+ {:ok, counter} = Counter.start_link(0)
569
+ Counter.get(counter) # 0
570
+ Counter.increment(counter)
571
+ Counter.get(counter) # 1
572
+ Counter.add(counter, 10)
573
+ Counter.get(counter) # 11
574
+ GenServer.stop(counter)
575
+ ```
576
+
577
+ ```plantuml
578
+ @startuml
579
+ !theme plain
580
+
581
+ rectangle "GenServer の通信パターン" {
582
+ card "クライアント" as client
583
+
584
+ rectangle "GenServer" as server {
585
+ card "状態"
586
+ card "メールボックス"
587
+ }
588
+
589
+ client --> server : call (同期)
590
+ client --> server : cast (非同期)
591
+ server --> client : reply
592
+ }
593
+
594
+ note bottom
595
+ call: 応答を待つ
596
+ cast: 応答を待たない
597
+ end note
598
+
599
+ @enduml
600
+ ```
601
+
602
+ ### 11.3 GenServer によるチェックインストア
603
+
604
+ ```elixir
605
+ defmodule CheckInStore do
606
+ use GenServer
607
+
608
+ # クライアント API
609
+
610
+ def start_link(opts \\ []) do
611
+ GenServer.start_link(__MODULE__, %{}, opts)
612
+ end
613
+
614
+ def check_in(store, city) do
615
+ GenServer.cast(store, {:check_in, city})
616
+ end
617
+
618
+ def get_count(store, city) do
619
+ GenServer.call(store, {:get_count, city})
620
+ end
621
+
622
+ def get_all(store) do
623
+ GenServer.call(store, :get_all)
624
+ end
625
+
626
+ def top_cities(store, n \\ 3) do
627
+ GenServer.call(store, {:top_cities, n})
628
+ end
629
+
630
+ # サーバーコールバック
631
+
632
+ @impl true
633
+ def init(state) do
634
+ {:ok, state}
635
+ end
636
+
637
+ @impl true
638
+ def handle_cast({:check_in, city}, state) do
639
+ new_state = Map.update(state, city, 1, &(&1 + 1))
640
+ {:noreply, new_state}
641
+ end
642
+
643
+ @impl true
644
+ def handle_call({:get_count, city}, _from, state) do
645
+ {:reply, Map.get(state, city, 0), state}
646
+ end
647
+
648
+ @impl true
649
+ def handle_call(:get_all, _from, state) do
650
+ {:reply, state, state}
651
+ end
652
+
653
+ @impl true
654
+ def handle_call({:top_cities, n}, _from, state) do
655
+ top =
656
+ state
657
+ |> Enum.sort_by(fn {_city, count} -> count end, :desc)
658
+ |> Enum.take(n)
659
+
660
+ {:reply, top, state}
661
+ end
662
+ end
663
+ ```
664
+
665
+ ### 11.4 定期実行タスク
666
+
667
+ ```elixir
668
+ defmodule PeriodicTask do
669
+ use GenServer
670
+
671
+ def start_link(task_fn, interval_ms) do
672
+ GenServer.start_link(__MODULE__, {task_fn, interval_ms})
673
+ end
674
+
675
+ @impl true
676
+ def init({task_fn, interval_ms}) do
677
+ schedule_work(interval_ms)
678
+ {:ok, %{task_fn: task_fn, interval_ms: interval_ms}}
679
+ end
680
+
681
+ @impl true
682
+ def handle_info(:work, %{task_fn: task_fn, interval_ms: interval_ms} = state) do
683
+ task_fn.()
684
+ schedule_work(interval_ms)
685
+ {:noreply, state}
686
+ end
687
+
688
+ defp schedule_work(interval_ms) do
689
+ Process.send_after(self(), :work, interval_ms)
690
+ end
691
+ end
692
+
693
+ # 使用例:100ms ごとにタスクを実行
694
+ {:ok, agent} = Agent.start_link(fn -> 0 end)
695
+ {:ok, task} = PeriodicTask.start_link(
696
+ fn -> Agent.update(agent, &(&1 + 1)) end,
697
+ 100
698
+ )
699
+ ```
700
+
701
+ ### 11.5 状態マシン
702
+
703
+ GenServer で状態マシンを実装できます。
704
+
705
+ ```elixir
706
+ defmodule TrafficLight do
707
+ use GenServer
708
+
709
+ def start_link do
710
+ GenServer.start_link(__MODULE__, :red)
711
+ end
712
+
713
+ def current(light) do
714
+ GenServer.call(light, :current)
715
+ end
716
+
717
+ def next(light) do
718
+ GenServer.cast(light, :next)
719
+ end
720
+
721
+ @impl true
722
+ def init(initial_state) do
723
+ {:ok, initial_state}
724
+ end
725
+
726
+ @impl true
727
+ def handle_call(:current, _from, state) do
728
+ {:reply, state, state}
729
+ end
730
+
731
+ @impl true
732
+ def handle_cast(:next, state) do
733
+ next_state =
734
+ case state do
735
+ :red -> :green
736
+ :green -> :yellow
737
+ :yellow -> :red
738
+ end
739
+
740
+ {:noreply, next_state}
741
+ end
742
+ end
743
+ ```
744
+
745
+ ```plantuml
746
+ @startuml
747
+ !theme plain
748
+
749
+ state "Red" as red
750
+ state "Green" as green
751
+ state "Yellow" as yellow
752
+
753
+ [*] --> red
754
+ red --> green : next
755
+ green --> yellow : next
756
+ yellow --> red : next
757
+
758
+ @enduml
759
+ ```
760
+
761
+ ### 11.6 ジョブキュー
762
+
763
+ ```elixir
764
+ defmodule JobQueue do
765
+ use GenServer
766
+
767
+ def start_link do
768
+ GenServer.start_link(__MODULE__, :queue.new())
769
+ end
770
+
771
+ def enqueue(queue, job) do
772
+ GenServer.cast(queue, {:enqueue, job})
773
+ end
774
+
775
+ def dequeue(queue) do
776
+ GenServer.call(queue, :dequeue)
777
+ end
778
+
779
+ def size(queue) do
780
+ GenServer.call(queue, :size)
781
+ end
782
+
783
+ @impl true
784
+ def init(queue), do: {:ok, queue}
785
+
786
+ @impl true
787
+ def handle_cast({:enqueue, job}, queue) do
788
+ {:noreply, :queue.in(job, queue)}
789
+ end
790
+
791
+ @impl true
792
+ def handle_call(:dequeue, _from, queue) do
793
+ case :queue.out(queue) do
794
+ {{:value, job}, new_queue} -> {:reply, {:ok, job}, new_queue}
795
+ {:empty, queue} -> {:reply, :empty, queue}
796
+ end
797
+ end
798
+
799
+ @impl true
800
+ def handle_call(:size, _from, queue) do
801
+ {:reply, :queue.len(queue), queue}
802
+ end
803
+ end
804
+ ```
805
+
806
+ ### 11.7 Supervisor による耐障害性
807
+
808
+ Supervisor は子プロセスを監視し、クラッシュ時に自動再起動します。
809
+
810
+ ```elixir
811
+ defmodule CounterSupervisor do
812
+ use Supervisor
813
+
814
+ def start_link do
815
+ Supervisor.start_link(__MODULE__, :ok)
816
+ end
817
+
818
+ def get_counter(supervisor) do
819
+ [{_, counter, _, _}] = Supervisor.which_children(supervisor)
820
+ counter
821
+ end
822
+
823
+ @impl true
824
+ def init(:ok) do
825
+ children = [
826
+ {Counter, 0}
827
+ ]
828
+
829
+ Supervisor.init(children, strategy: :one_for_one)
830
+ end
831
+ end
832
+ ```
833
+
834
+ ```plantuml
835
+ @startuml
836
+ !theme plain
837
+
838
+ rectangle "Supervisor 戦略" {
839
+ rectangle ":one_for_one" as o4o {
840
+ card "クラッシュしたプロセスのみ再起動"
841
+ }
842
+
843
+ rectangle ":one_for_all" as o4a {
844
+ card "1つがクラッシュしたら全て再起動"
845
+ }
846
+
847
+ rectangle ":rest_for_one" as r4o {
848
+ card "クラッシュしたプロセスと後続を再起動"
849
+ }
850
+ }
851
+
852
+ @enduml
853
+ ```
854
+
855
+ ### 11.8 DynamicSupervisor
856
+
857
+ 動的にプロセスを追加・削除できる Supervisor です。
858
+
859
+ ```elixir
860
+ defmodule WorkerSupervisor do
861
+ use DynamicSupervisor
862
+
863
+ def start_link do
864
+ DynamicSupervisor.start_link(__MODULE__, :ok)
865
+ end
866
+
867
+ def start_worker(supervisor, initial_value) do
868
+ spec = {Counter, initial_value}
869
+ DynamicSupervisor.start_child(supervisor, spec)
870
+ end
871
+
872
+ def stop_worker(supervisor, worker) do
873
+ DynamicSupervisor.terminate_child(supervisor, worker)
874
+ end
875
+
876
+ def count_workers(supervisor) do
877
+ DynamicSupervisor.count_children(supervisor).active
878
+ end
879
+
880
+ @impl true
881
+ def init(:ok) do
882
+ DynamicSupervisor.init(strategy: :one_for_one)
883
+ end
884
+ end
885
+
886
+ # 使用例
887
+ {:ok, sup} = WorkerSupervisor.start_link()
888
+ {:ok, worker1} = WorkerSupervisor.start_worker(sup, 0)
889
+ {:ok, worker2} = WorkerSupervisor.start_worker(sup, 100)
890
+
891
+ Counter.increment(worker1)
892
+ Counter.get(worker1) # 1
893
+ Counter.get(worker2) # 100
894
+
895
+ WorkerSupervisor.count_workers(sup) # 2
896
+ ```
897
+
898
+ ### 11.9 Task.Supervisor
899
+
900
+ Task を監視付きで実行できます。
901
+
902
+ ```elixir
903
+ defmodule TaskRunner do
904
+ def start_link do
905
+ Task.Supervisor.start_link()
906
+ end
907
+
908
+ def run_async(supervisor, task_fn) do
909
+ Task.Supervisor.async(supervisor, task_fn)
910
+ end
911
+
912
+ def run_all(supervisor, task_fns) do
913
+ task_fns
914
+ |> Enum.map(&Task.Supervisor.async(supervisor, &1))
915
+ |> Task.await_many()
916
+ end
917
+
918
+ def run_with_timeout(supervisor, task_fn, timeout_ms) do
919
+ task = Task.Supervisor.async_nolink(supervisor, task_fn)
920
+
921
+ case Task.yield(task, timeout_ms) do
922
+ {:ok, result} -> {:ok, result}
923
+ nil ->
924
+ Task.shutdown(task, :brutal_kill)
925
+ {:error, :timeout}
926
+ end
927
+ end
928
+ end
929
+
930
+ # 使用例
931
+ {:ok, runner} = TaskRunner.start_link()
932
+ results = TaskRunner.run_all(runner, [fn -> 1 end, fn -> 2 end, fn -> 3 end])
933
+ # [1, 2, 3]
934
+ ```
935
+
936
+ ### 11.10 PubSub パターン
937
+
938
+ Publish/Subscribe パターンの実装です。
939
+
940
+ ```elixir
941
+ defmodule PubSub do
942
+ use GenServer
943
+
944
+ def start_link do
945
+ GenServer.start_link(__MODULE__, %{})
946
+ end
947
+
948
+ def subscribe(server, topic) do
949
+ GenServer.call(server, {:subscribe, topic, self()})
950
+ end
951
+
952
+ def unsubscribe(server, topic) do
953
+ GenServer.call(server, {:unsubscribe, topic, self()})
954
+ end
955
+
956
+ def publish(server, topic, message) do
957
+ GenServer.cast(server, {:publish, topic, message})
958
+ end
959
+
960
+ @impl true
961
+ def init(state), do: {:ok, state}
962
+
963
+ @impl true
964
+ def handle_call({:subscribe, topic, pid}, _from, state) do
965
+ subscribers = Map.get(state, topic, MapSet.new())
966
+ new_subscribers = MapSet.put(subscribers, pid)
967
+ {:reply, :ok, Map.put(state, topic, new_subscribers)}
968
+ end
969
+
970
+ @impl true
971
+ def handle_cast({:publish, topic, message}, state) do
972
+ subscribers = Map.get(state, topic, MapSet.new())
973
+
974
+ Enum.each(subscribers, fn pid ->
975
+ send(pid, {:pubsub, topic, message})
976
+ end)
977
+
978
+ {:noreply, state}
979
+ end
980
+ end
981
+
982
+ # 使用例
983
+ {:ok, pubsub} = PubSub.start_link()
984
+ PubSub.subscribe(pubsub, "events")
985
+ PubSub.publish(pubsub, "events", :hello)
986
+
987
+ receive do
988
+ {:pubsub, "events", message} -> IO.inspect(message) # :hello
989
+ end
990
+ ```
991
+
992
+ ---
993
+
994
+ ## まとめ
995
+
996
+ ### Part V で学んだこと
997
+
998
+ ```plantuml
999
+ @startuml
1000
+ !theme plain
1001
+
1002
+ rectangle "Part V: 並行処理と OTP" {
1003
+ rectangle "第10章" as ch10 {
1004
+ card "Agent(共有状態)"
1005
+ card "Task(並列実行)"
1006
+ card "軽量プロセス"
1007
+ card "spawn / cancel"
1008
+ }
1009
+
1010
+ rectangle "第11章" as ch11 {
1011
+ card "GenServer"
1012
+ card "Supervisor"
1013
+ card "DynamicSupervisor"
1014
+ card "Task.Supervisor"
1015
+ card "PubSub パターン"
1016
+ }
1017
+ }
1018
+
1019
+ ch10 --> ch11
1020
+
1021
+ @enduml
1022
+ ```
1023
+
1024
+ ### Scala との対応
1025
+
1026
+ | Scala | Elixir |
1027
+ |-------|--------|
1028
+ | `Ref[IO, A]` | `Agent` |
1029
+ | `parSequence` | `Task.await_many` |
1030
+ | `Fiber` | プロセス(`spawn`) |
1031
+ | `fiber.start` | `spawn` / `Task.async` |
1032
+ | `fiber.cancel` | `Process.exit(pid, :kill)` |
1033
+ | `foreverM` | 再帰的プロセス |
1034
+ | - | `GenServer` |
1035
+ | - | `Supervisor` |
1036
+
1037
+ ### キーポイント
1038
+
1039
+ 1. **Agent**: プロセスベースの状態管理(Ref 相当)
1040
+ 2. **Task**: 非同期タスクの実行と結果の取得
1041
+ 3. **プロセス**: 軽量な実行単位(数百万も可能)
1042
+ 4. **GenServer**: 汎用的なサーバープロセス
1043
+ 5. **Supervisor**: プロセスの監視と自動再起動
1044
+ 6. **DynamicSupervisor**: 動的なプロセス管理
1045
+
1046
+ ### 設計パターン
1047
+
1048
+ ```plantuml
1049
+ @startuml
1050
+ !theme plain
1051
+
1052
+ rectangle "並行処理の設計パターン" {
1053
+ rectangle "パターン1: Agent + Task" as p1 {
1054
+ card "Agent で状態を共有"
1055
+ card "Task で並列処理"
1056
+ }
1057
+
1058
+ rectangle "パターン2: GenServer" as p2 {
1059
+ card "状態とロジックをカプセル化"
1060
+ card "同期/非同期 API を提供"
1061
+ }
1062
+
1063
+ rectangle "パターン3: Supervisor Tree" as p3 {
1064
+ card "Supervisor で監視"
1065
+ card "障害時は自動復旧"
1066
+ }
1067
+ }
1068
+
1069
+ @enduml
1070
+ ```
1071
+
1072
+ ### 次のステップ
1073
+
1074
+ Part VI では、以下のトピックを学びます:
1075
+
1076
+ - 実践的なアプリケーション構築
1077
+ - 外部 API との連携
1078
+ - テスト戦略
1079
+
1080
+ ---
1081
+
1082
+ ## 演習問題
1083
+
1084
+ ### 問題 1: Agent の基本
1085
+
1086
+ 以下のプログラムを実装してください。カウンターを 0 から始めて、3回インクリメントした結果を返します。
1087
+
1088
+ ```elixir
1089
+ def increment_three_times do
1090
+ ???
1091
+ end
1092
+
1093
+ # 期待される動作
1094
+ increment_three_times() # 3
1095
+ ```
1096
+
1097
+ <details>
1098
+ <summary>解答</summary>
1099
+
1100
+ ```elixir
1101
+ def increment_three_times do
1102
+ {:ok, counter} = Agent.start_link(fn -> 0 end)
1103
+ Agent.update(counter, &(&1 + 1))
1104
+ Agent.update(counter, &(&1 + 1))
1105
+ Agent.update(counter, &(&1 + 1))
1106
+ result = Agent.get(counter, & &1)
1107
+ Agent.stop(counter)
1108
+ result
1109
+ end
1110
+ ```
1111
+
1112
+ </details>
1113
+
1114
+ ### 問題 2: 並列実行
1115
+
1116
+ 以下のプログラムを実装してください。3つのタスクを並列実行し、結果の合計を返します。
1117
+
1118
+ ```elixir
1119
+ def sum_parallel(tasks) do
1120
+ ???
1121
+ end
1122
+
1123
+ # 期待される動作
1124
+ sum_parallel([fn -> 1 end, fn -> 2 end, fn -> 3 end]) # 6
1125
+ ```
1126
+
1127
+ <details>
1128
+ <summary>解答</summary>
1129
+
1130
+ ```elixir
1131
+ def sum_parallel(tasks) do
1132
+ tasks
1133
+ |> Enum.map(&Task.async/1)
1134
+ |> Task.await_many()
1135
+ |> Enum.sum()
1136
+ end
1137
+ ```
1138
+
1139
+ </details>
1140
+
1141
+ ### 問題 3: GenServer
1142
+
1143
+ 以下の GenServer を実装してください。リストを管理し、要素の追加と取得ができます。
1144
+
1145
+ ```elixir
1146
+ defmodule ListStore do
1147
+ use GenServer
1148
+
1149
+ # ???
1150
+ end
1151
+
1152
+ # 期待される動作
1153
+ {:ok, store} = ListStore.start_link()
1154
+ ListStore.add(store, 1)
1155
+ ListStore.add(store, 2)
1156
+ ListStore.add(store, 3)
1157
+ ListStore.get_all(store) # [1, 2, 3]
1158
+ ```
1159
+
1160
+ <details>
1161
+ <summary>解答</summary>
1162
+
1163
+ ```elixir
1164
+ defmodule ListStore do
1165
+ use GenServer
1166
+
1167
+ def start_link do
1168
+ GenServer.start_link(__MODULE__, [])
1169
+ end
1170
+
1171
+ def add(store, item) do
1172
+ GenServer.cast(store, {:add, item})
1173
+ end
1174
+
1175
+ def get_all(store) do
1176
+ GenServer.call(store, :get_all)
1177
+ end
1178
+
1179
+ @impl true
1180
+ def init(state), do: {:ok, state}
1181
+
1182
+ @impl true
1183
+ def handle_cast({:add, item}, state) do
1184
+ {:noreply, state ++ [item]}
1185
+ end
1186
+
1187
+ @impl true
1188
+ def handle_call(:get_all, _from, state) do
1189
+ {:reply, state, state}
1190
+ end
1191
+ end
1192
+ ```
1193
+
1194
+ </details>
1195
+
1196
+ ### 問題 4: タイムアウト付き収集
1197
+
1198
+ 以下のプログラムを実装してください。指定時間後にプロセスを停止し、それまでに蓄積された結果を返します。
1199
+
1200
+ ```elixir
1201
+ def collect_for(duration_ms, interval_ms, generator) do
1202
+ ???
1203
+ end
1204
+
1205
+ # 期待される動作
1206
+ # 100ms 間、10ms ごとに乱数を生成
1207
+ results = collect_for(100, 10, fn -> :rand.uniform(100) end)
1208
+ # 約10個の要素が返される
1209
+ ```
1210
+
1211
+ <details>
1212
+ <summary>解答</summary>
1213
+
1214
+ ```elixir
1215
+ def collect_for(duration_ms, interval_ms, generator) do
1216
+ {:ok, collected} = Agent.start_link(fn -> [] end)
1217
+
1218
+ {:ok, producer_pid} =
1219
+ start_repeating(
1220
+ fn ->
1221
+ value = generator.()
1222
+ Agent.update(collected, &[value | &1])
1223
+ end,
1224
+ interval_ms
1225
+ )
1226
+
1227
+ Process.sleep(duration_ms)
1228
+ cancel(producer_pid)
1229
+
1230
+ result = Agent.get(collected, &Enum.reverse/1)
1231
+ Agent.stop(collected)
1232
+ result
1233
+ end
1234
+ ```
1235
+
1236
+ </details>
1237
+
1238
+ ### 問題 5: Supervisor
1239
+
1240
+ 以下の Supervisor を実装してください。2つのカウンターを監視します。
1241
+
1242
+ ```elixir
1243
+ defmodule DualCounterSupervisor do
1244
+ use Supervisor
1245
+
1246
+ # ???
1247
+ end
1248
+
1249
+ # 期待される動作
1250
+ {:ok, sup} = DualCounterSupervisor.start_link()
1251
+ {counter1, counter2} = DualCounterSupervisor.get_counters(sup)
1252
+ Counter.increment(counter1)
1253
+ Counter.get(counter1) # 1
1254
+ Counter.get(counter2) # 0
1255
+ ```
1256
+
1257
+ <details>
1258
+ <summary>解答</summary>
1259
+
1260
+ ```elixir
1261
+ defmodule DualCounterSupervisor do
1262
+ use Supervisor
1263
+
1264
+ def start_link do
1265
+ Supervisor.start_link(__MODULE__, :ok)
1266
+ end
1267
+
1268
+ def get_counters(supervisor) do
1269
+ children = Supervisor.which_children(supervisor)
1270
+ [{:counter1, c1, _, _}, {:counter2, c2, _, _}] = children
1271
+ {c1, c2}
1272
+ end
1273
+
1274
+ @impl true
1275
+ def init(:ok) do
1276
+ children = [
1277
+ Supervisor.child_spec({Counter, 0}, id: :counter1),
1278
+ Supervisor.child_spec({Counter, 0}, id: :counter2)
1279
+ ]
1280
+
1281
+ Supervisor.init(children, strategy: :one_for_one)
1282
+ end
1283
+ end
1284
+ ```
1285
+
1286
+ </details>