@k2works/claude-code-booster 4.13.0 → 4.15.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 (752) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +42 -42
  3. package/bin/claude-code-booster +113 -90
  4. package/lib/assets/.claude/README.md +287 -283
  5. package/lib/assets/.claude/agents/xp-architect.md +250 -250
  6. package/lib/assets/.claude/agents/xp-executive.md +207 -207
  7. package/lib/assets/.claude/agents/xp-interaction-designer.md +239 -239
  8. package/lib/assets/.claude/agents/xp-product-manager.md +245 -245
  9. package/lib/assets/.claude/agents/xp-programmer.md +268 -268
  10. package/lib/assets/.claude/agents/xp-project-manager.md +229 -229
  11. package/lib/assets/.claude/agents/xp-technical-writer.md +224 -224
  12. package/lib/assets/.claude/agents/xp-tester.md +265 -265
  13. package/lib/assets/.claude/agents/xp-user-representative.md +204 -204
  14. package/lib/assets/.claude/scripts/generate-inception-deck.mjs +911 -911
  15. package/lib/assets/.claude/settings.json +11 -11
  16. package/lib/assets/.claude/skills/ai-agent-guidelines/SKILL.md +111 -111
  17. package/lib/assets/.claude/skills/analyzing-architecture/SKILL.md +83 -83
  18. package/lib/assets/.claude/skills/analyzing-business-architecture/SKILL.md +122 -122
  19. package/lib/assets/.claude/skills/analyzing-business-case/SKILL.md +148 -148
  20. package/lib/assets/.claude/skills/analyzing-business-strategy/SKILL.md +277 -277
  21. package/lib/assets/.claude/skills/analyzing-data-model/SKILL.md +77 -77
  22. package/lib/assets/.claude/skills/analyzing-domain-model/SKILL.md +117 -117
  23. package/lib/assets/.claude/skills/analyzing-inception-deck/SKILL.md +84 -84
  24. package/lib/assets/.claude/skills/analyzing-non-functional/SKILL.md +95 -95
  25. package/lib/assets/.claude/skills/analyzing-operation/SKILL.md +95 -95
  26. package/lib/assets/.claude/skills/analyzing-requirements/SKILL.md +91 -91
  27. package/lib/assets/.claude/skills/analyzing-review/SKILL.md +174 -174
  28. package/lib/assets/.claude/skills/analyzing-tech-stack/SKILL.md +101 -101
  29. package/lib/assets/.claude/skills/analyzing-test-strategy/SKILL.md +89 -89
  30. package/lib/assets/.claude/skills/analyzing-ui-design/SKILL.md +80 -80
  31. package/lib/assets/.claude/skills/analyzing-usecases/SKILL.md +72 -72
  32. package/lib/assets/.claude/skills/closing-iteration/SKILL.md +160 -146
  33. package/lib/assets/.claude/skills/creating-adr/SKILL.md +113 -113
  34. package/lib/assets/.claude/skills/creating-article/SKILL.md +156 -0
  35. package/lib/assets/.claude/skills/creating-development-strategy/SKILL.md +127 -127
  36. package/lib/assets/.claude/skills/creating-iteration-report/SKILL.md +210 -210
  37. package/lib/assets/.claude/skills/creating-journal/SKILL.md +129 -129
  38. package/lib/assets/.claude/skills/creating-manual/SKILL.md +199 -0
  39. package/lib/assets/.claude/skills/creating-release-report/SKILL.md +161 -161
  40. package/lib/assets/.claude/skills/creating-slides/SKILL.md +86 -86
  41. package/lib/assets/.claude/skills/creating-slides/agents/openai.yaml +4 -4
  42. package/lib/assets/.claude/skills/creating-slides/references/manga-css.md +45 -45
  43. package/lib/assets/.claude/skills/creating-slides/scripts/slide_tools.py +239 -239
  44. package/lib/assets/.claude/skills/developing-backend/SKILL.md +100 -100
  45. package/lib/assets/.claude/skills/developing-frontend/SKILL.md +93 -93
  46. package/lib/assets/.claude/skills/developing-release/SKILL.md +120 -120
  47. package/lib/assets/.claude/skills/developing-review/SKILL.md +175 -175
  48. package/lib/assets/.claude/skills/developing-uiux-review/SKILL.md +207 -207
  49. package/lib/assets/.claude/skills/generating-bmc/SKILL.md +123 -123
  50. package/lib/assets/.claude/skills/generating-slides/SKILL.md +94 -94
  51. package/lib/assets/.claude/skills/git-commit/SKILL.md +81 -81
  52. package/lib/assets/.claude/skills/killing-processes/SKILL.md +44 -44
  53. package/lib/assets/.claude/skills/opening-iteration/SKILL.md +109 -105
  54. package/lib/assets/.claude/skills/operating-backup/SKILL.md +59 -59
  55. package/lib/assets/.claude/skills/operating-cicd/SKILL.md +54 -54
  56. package/lib/assets/.claude/skills/operating-deploy/SKILL.md +67 -67
  57. package/lib/assets/.claude/skills/operating-docs/SKILL.md +219 -219
  58. package/lib/assets/.claude/skills/operating-provision/SKILL.md +77 -77
  59. package/lib/assets/.claude/skills/operating-qt/SKILL.md +147 -147
  60. package/lib/assets/.claude/skills/operating-review/SKILL.md +171 -171
  61. package/lib/assets/.claude/skills/operating-script/SKILL.md +145 -145
  62. package/lib/assets/.claude/skills/operating-setup/SKILL.md +63 -63
  63. package/lib/assets/.claude/skills/orchestrating-analysis/SKILL.md +104 -104
  64. package/lib/assets/.claude/skills/orchestrating-development/SKILL.md +168 -168
  65. package/lib/assets/.claude/skills/orchestrating-operation/SKILL.md +158 -158
  66. package/lib/assets/.claude/skills/orchestrating-project/SKILL.md +144 -144
  67. package/lib/assets/.claude/skills/planning-releases/SKILL.md +119 -119
  68. package/lib/assets/.claude/skills/practicing-getting-start-tdd/SKILL.md +266 -266
  69. package/lib/assets/.claude/skills/syncing-github-project/SKILL.md +151 -151
  70. package/lib/assets/.claude/skills/tracking-progress/SKILL.md +91 -91
  71. package/lib/assets/.claude/skills/validating-design/SKILL.md +130 -130
  72. package/lib/assets/.claude/skills/validating-iteration-plan/SKILL.md +238 -238
  73. package/lib/assets/.claude/skills/validating-operating-setup/SKILL.md +118 -118
  74. package/lib/assets/.devcontainer/devcontainer.json +37 -37
  75. package/lib/assets/.env.example +23 -17
  76. package/lib/assets/.gitattributes +4 -4
  77. package/lib/assets/.github/workflows/docker-publish.yml +77 -77
  78. package/lib/assets/.github/workflows/mkdocs.yml +39 -39
  79. package/lib/assets/AGENTS.md +94 -94
  80. package/lib/assets/CLAUDE.md +201 -197
  81. package/lib/assets/README.md +304 -291
  82. package/lib/assets/docker-compose.yml +33 -33
  83. package/lib/assets/docs/adr/index.md +10 -10
  84. package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +475 -475
  85. package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +519 -519
  86. package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +537 -537
  87. package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +300 -300
  88. package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +320 -320
  89. package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +498 -498
  90. package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +298 -298
  91. package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +291 -291
  92. package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +336 -336
  93. package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +303 -303
  94. package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +286 -286
  95. package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +322 -322
  96. package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +319 -319
  97. package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +365 -365
  98. package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +156 -156
  99. package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +178 -178
  100. package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +312 -312
  101. package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +287 -287
  102. package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +286 -286
  103. package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +274 -274
  104. package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +294 -294
  105. package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +337 -337
  106. package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +388 -388
  107. package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +273 -273
  108. package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +380 -380
  109. package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +384 -384
  110. package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +350 -350
  111. package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +352 -352
  112. package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +383 -383
  113. package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +529 -529
  114. package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +395 -395
  115. package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +399 -399
  116. package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +485 -485
  117. package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +566 -566
  118. package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +567 -567
  119. package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +475 -475
  120. package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +462 -462
  121. package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +325 -325
  122. package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +401 -401
  123. package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +450 -450
  124. package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +475 -475
  125. package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +739 -739
  126. package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +567 -567
  127. package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +518 -518
  128. package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +532 -532
  129. package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +241 -241
  130. package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +383 -383
  131. package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +374 -374
  132. package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +375 -375
  133. package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +195 -195
  134. package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +268 -268
  135. package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +294 -294
  136. package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +164 -164
  137. package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +168 -168
  138. package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +254 -254
  139. package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +269 -269
  140. package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +148 -148
  141. package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +176 -176
  142. package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +604 -604
  143. package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +729 -729
  144. package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +291 -291
  145. package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +420 -420
  146. package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +319 -319
  147. package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +466 -466
  148. package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +523 -523
  149. package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +287 -287
  150. package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +340 -340
  151. package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +395 -395
  152. package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +248 -248
  153. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +384 -384
  154. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +452 -452
  155. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +495 -495
  156. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +416 -416
  157. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +382 -382
  158. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +687 -687
  159. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +442 -442
  160. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +479 -479
  161. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +479 -479
  162. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +427 -427
  163. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +428 -428
  164. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +339 -339
  165. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +309 -309
  166. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +596 -596
  167. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +355 -355
  168. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +350 -350
  169. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +414 -414
  170. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +367 -367
  171. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +403 -403
  172. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +291 -291
  173. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +324 -324
  174. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +332 -332
  175. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +274 -274
  176. package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +298 -298
  177. package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +304 -304
  178. package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +362 -362
  179. package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +257 -257
  180. package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +254 -254
  181. package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +283 -283
  182. package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +395 -395
  183. package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +319 -319
  184. package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +382 -382
  185. package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +287 -287
  186. package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +303 -303
  187. package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +326 -326
  188. package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +332 -332
  189. package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +379 -379
  190. package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +177 -177
  191. package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +219 -219
  192. package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +244 -244
  193. package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +363 -363
  194. package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +438 -438
  195. package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +325 -325
  196. package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +403 -403
  197. package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +469 -469
  198. package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +174 -174
  199. package/lib/assets/docs/article/functional-desgin-ppp/index.md +90 -90
  200. package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +450 -450
  201. package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +463 -463
  202. package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +425 -425
  203. package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +273 -273
  204. package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +247 -247
  205. package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +841 -841
  206. package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +384 -384
  207. package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +383 -383
  208. package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +339 -339
  209. package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +331 -331
  210. package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +356 -356
  211. package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +379 -379
  212. package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +361 -361
  213. package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +392 -392
  214. package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +300 -300
  215. package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +297 -297
  216. package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +304 -304
  217. package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +315 -315
  218. package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +311 -311
  219. package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +304 -304
  220. package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +336 -336
  221. package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +349 -349
  222. package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +243 -243
  223. package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +328 -328
  224. package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +348 -348
  225. package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +357 -357
  226. package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +364 -364
  227. package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +515 -515
  228. package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +557 -557
  229. package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +363 -363
  230. package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +327 -327
  231. package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +517 -517
  232. package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +441 -441
  233. package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +407 -407
  234. package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +379 -379
  235. package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +398 -398
  236. package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +476 -476
  237. package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +391 -391
  238. package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +342 -342
  239. package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +324 -324
  240. package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +730 -730
  241. package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +624 -624
  242. package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +512 -512
  243. package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +433 -433
  244. package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +688 -688
  245. package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +243 -243
  246. package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +166 -166
  247. package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +162 -162
  248. package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +135 -135
  249. package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +88 -88
  250. package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +299 -299
  251. package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +241 -241
  252. package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +131 -131
  253. package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +130 -130
  254. package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +127 -127
  255. package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +114 -114
  256. package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +138 -138
  257. package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +161 -161
  258. package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +65 -65
  259. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +232 -232
  260. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +244 -244
  261. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +202 -202
  262. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +92 -92
  263. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +256 -256
  264. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +195 -195
  265. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +214 -214
  266. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +249 -249
  267. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +174 -174
  268. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +166 -166
  269. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +192 -192
  270. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +211 -211
  271. package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +83 -83
  272. package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +87 -87
  273. package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +95 -95
  274. package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +109 -109
  275. package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +96 -96
  276. package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +88 -88
  277. package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +71 -71
  278. package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +110 -110
  279. package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +108 -108
  280. package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +104 -104
  281. package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +178 -178
  282. package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +142 -142
  283. package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +145 -145
  284. package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +35 -35
  285. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +202 -202
  286. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +246 -246
  287. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +218 -218
  288. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +179 -179
  289. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +267 -267
  290. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +190 -190
  291. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +161 -161
  292. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +175 -175
  293. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +222 -222
  294. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +189 -189
  295. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +212 -212
  296. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +215 -215
  297. package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +71 -71
  298. package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +213 -213
  299. package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +302 -302
  300. package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +339 -339
  301. package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +112 -112
  302. package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +272 -272
  303. package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +233 -233
  304. package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +394 -394
  305. package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +422 -422
  306. package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +400 -400
  307. package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +226 -226
  308. package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +296 -296
  309. package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +411 -411
  310. package/lib/assets/docs/article/getting-start-tdd/go/index.md +83 -83
  311. package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +279 -279
  312. package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +337 -337
  313. package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +257 -257
  314. package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +182 -182
  315. package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +313 -313
  316. package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +309 -309
  317. package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +412 -412
  318. package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +390 -390
  319. package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +461 -461
  320. package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +434 -434
  321. package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +392 -392
  322. package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +631 -631
  323. package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +49 -49
  324. package/lib/assets/docs/article/getting-start-tdd/index.md +93 -93
  325. package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +375 -375
  326. package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +349 -349
  327. package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +445 -445
  328. package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +409 -409
  329. package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +330 -330
  330. package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +290 -290
  331. package/lib/assets/docs/article/getting-start-tdd/integration/index.md +69 -69
  332. package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +234 -234
  333. package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +261 -261
  334. package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +185 -185
  335. package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +115 -115
  336. package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +382 -382
  337. package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +272 -272
  338. package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +626 -626
  339. package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +393 -393
  340. package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +310 -310
  341. package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +188 -188
  342. package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +167 -167
  343. package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +205 -205
  344. package/lib/assets/docs/article/getting-start-tdd/java/index.md +61 -61
  345. package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +244 -244
  346. package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +262 -262
  347. package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +169 -169
  348. package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +112 -112
  349. package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +314 -314
  350. package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +235 -235
  351. package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +327 -327
  352. package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +322 -322
  353. package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +285 -285
  354. package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +199 -199
  355. package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +207 -207
  356. package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +295 -295
  357. package/lib/assets/docs/article/getting-start-tdd/node/index.md +56 -56
  358. package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +259 -259
  359. package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +200 -200
  360. package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +248 -248
  361. package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +141 -141
  362. package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +410 -410
  363. package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +321 -321
  364. package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +372 -372
  365. package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +453 -453
  366. package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +460 -460
  367. package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +182 -182
  368. package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +266 -266
  369. package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +308 -308
  370. package/lib/assets/docs/article/getting-start-tdd/php/index.md +84 -84
  371. package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +201 -201
  372. package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +247 -247
  373. package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +199 -199
  374. package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +87 -87
  375. package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +274 -274
  376. package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +190 -190
  377. package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +208 -208
  378. package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +172 -172
  379. package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +130 -130
  380. package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +122 -122
  381. package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +116 -116
  382. package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +126 -126
  383. package/lib/assets/docs/article/getting-start-tdd/python/index.md +55 -55
  384. package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +231 -231
  385. package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +238 -238
  386. package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +228 -228
  387. package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +112 -112
  388. package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +287 -287
  389. package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +248 -248
  390. package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +279 -279
  391. package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +329 -329
  392. package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +196 -196
  393. package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +175 -175
  394. package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +237 -237
  395. package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +398 -398
  396. package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +83 -83
  397. package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +211 -211
  398. package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +264 -264
  399. package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +233 -233
  400. package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +92 -92
  401. package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +212 -212
  402. package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +164 -164
  403. package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +142 -142
  404. package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +145 -145
  405. package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +110 -110
  406. package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +94 -94
  407. package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +105 -105
  408. package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +112 -112
  409. package/lib/assets/docs/article/getting-start-tdd/rust/index.md +83 -83
  410. package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +111 -111
  411. package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +107 -107
  412. package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +99 -99
  413. package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +123 -123
  414. package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +196 -196
  415. package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +186 -186
  416. package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +139 -139
  417. package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +106 -106
  418. package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +75 -75
  419. package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +104 -104
  420. package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +94 -94
  421. package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +92 -92
  422. package/lib/assets/docs/article/getting-start-tdd/scala/index.md +65 -65
  423. package/lib/assets/docs/article/grokking-concurrency/all/index.md +404 -404
  424. package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +554 -554
  425. package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +469 -469
  426. package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +520 -520
  427. package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +420 -420
  428. package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +510 -510
  429. package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +435 -435
  430. package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +465 -465
  431. package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +377 -377
  432. package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +116 -116
  433. package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +108 -108
  434. package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +101 -101
  435. package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +122 -122
  436. package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +123 -123
  437. package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +118 -118
  438. package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +89 -89
  439. package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +100 -100
  440. package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +120 -120
  441. package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +101 -101
  442. package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +97 -97
  443. package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +123 -123
  444. package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +101 -101
  445. package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +112 -112
  446. package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +99 -99
  447. package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +61 -61
  448. package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +84 -84
  449. package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +92 -92
  450. package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +65 -65
  451. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +80 -80
  452. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +103 -103
  453. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +94 -94
  454. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +110 -110
  455. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +104 -104
  456. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +93 -93
  457. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +121 -121
  458. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +107 -107
  459. package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +248 -248
  460. package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +96 -96
  461. package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +96 -96
  462. package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +91 -91
  463. package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +106 -106
  464. package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +99 -99
  465. package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +95 -95
  466. package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +111 -111
  467. package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +118 -118
  468. package/lib/assets/docs/article/grokking-concurrency/index.md +66 -66
  469. package/lib/assets/docs/article/grokking-concurrency/java/index.md +102 -102
  470. package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +308 -308
  471. package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +334 -334
  472. package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +221 -221
  473. package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +213 -213
  474. package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +112 -112
  475. package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +69 -69
  476. package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +101 -101
  477. package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +101 -101
  478. package/lib/assets/docs/article/grokking-concurrency/python/index.md +313 -313
  479. package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +239 -239
  480. package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +418 -418
  481. package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +227 -227
  482. package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +299 -299
  483. package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +315 -315
  484. package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +297 -297
  485. package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +314 -314
  486. package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +360 -360
  487. package/lib/assets/docs/article/grokking-concurrency/rust/index.md +270 -270
  488. package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +108 -108
  489. package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +120 -120
  490. package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +126 -126
  491. package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +175 -175
  492. package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +158 -158
  493. package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +94 -94
  494. package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +133 -133
  495. package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +155 -155
  496. package/lib/assets/docs/article/grokking-concurrency/scala/index.md +69 -69
  497. package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +78 -78
  498. package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +112 -112
  499. package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +93 -93
  500. package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +110 -110
  501. package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +119 -119
  502. package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +83 -83
  503. package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +131 -131
  504. package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +129 -129
  505. package/lib/assets/docs/article/grokkingfp/all/index.md +368 -368
  506. package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +530 -530
  507. package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +923 -923
  508. package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +1128 -1128
  509. package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +1104 -1104
  510. package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +1026 -1026
  511. package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +785 -785
  512. package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +871 -871
  513. package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +972 -972
  514. package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +926 -926
  515. package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +870 -870
  516. package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +715 -715
  517. package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +626 -626
  518. package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +712 -712
  519. package/lib/assets/docs/article/grokkingfp/clojure/index.md +276 -276
  520. package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +667 -667
  521. package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +643 -643
  522. package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +620 -620
  523. package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +697 -697
  524. package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +751 -751
  525. package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +721 -721
  526. package/lib/assets/docs/article/grokkingfp/csharp/index.md +246 -246
  527. package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +811 -811
  528. package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +971 -971
  529. package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +981 -981
  530. package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +949 -949
  531. package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +947 -947
  532. package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +739 -739
  533. package/lib/assets/docs/article/grokkingfp/elixir/index.md +203 -203
  534. package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +712 -712
  535. package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +838 -838
  536. package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +985 -985
  537. package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +974 -974
  538. package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +1286 -1286
  539. package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +1049 -1049
  540. package/lib/assets/docs/article/grokkingfp/fsharp/index.md +210 -210
  541. package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +714 -714
  542. package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +961 -961
  543. package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +972 -972
  544. package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +832 -832
  545. package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +911 -911
  546. package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +922 -922
  547. package/lib/assets/docs/article/grokkingfp/haskell/index.md +234 -234
  548. package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +591 -591
  549. package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +866 -866
  550. package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +915 -915
  551. package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +878 -878
  552. package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +845 -845
  553. package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +844 -844
  554. package/lib/assets/docs/article/grokkingfp/index.md +143 -143
  555. package/lib/assets/docs/article/grokkingfp/java/index.md +211 -211
  556. package/lib/assets/docs/article/grokkingfp/java/part-1.md +648 -648
  557. package/lib/assets/docs/article/grokkingfp/java/part-2.md +675 -675
  558. package/lib/assets/docs/article/grokkingfp/java/part-3.md +672 -672
  559. package/lib/assets/docs/article/grokkingfp/java/part-4.md +771 -771
  560. package/lib/assets/docs/article/grokkingfp/java/part-5.md +959 -959
  561. package/lib/assets/docs/article/grokkingfp/java/part-6.md +1328 -1328
  562. package/lib/assets/docs/article/grokkingfp/python/index.md +258 -258
  563. package/lib/assets/docs/article/grokkingfp/python/part-1.md +443 -443
  564. package/lib/assets/docs/article/grokkingfp/python/part-2.md +958 -958
  565. package/lib/assets/docs/article/grokkingfp/python/part-3.md +1004 -1004
  566. package/lib/assets/docs/article/grokkingfp/python/part-4.md +765 -765
  567. package/lib/assets/docs/article/grokkingfp/python/part-5.md +747 -747
  568. package/lib/assets/docs/article/grokkingfp/python/part-6.md +861 -861
  569. package/lib/assets/docs/article/grokkingfp/ruby/index.md +330 -330
  570. package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +755 -755
  571. package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +938 -938
  572. package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +946 -946
  573. package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +921 -921
  574. package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +908 -908
  575. package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +1412 -1412
  576. package/lib/assets/docs/article/grokkingfp/rust/index.md +242 -242
  577. package/lib/assets/docs/article/grokkingfp/rust/part-1.md +634 -634
  578. package/lib/assets/docs/article/grokkingfp/rust/part-2.md +1060 -1060
  579. package/lib/assets/docs/article/grokkingfp/rust/part-3.md +994 -994
  580. package/lib/assets/docs/article/grokkingfp/rust/part-4.md +573 -573
  581. package/lib/assets/docs/article/grokkingfp/rust/part-5.md +705 -705
  582. package/lib/assets/docs/article/grokkingfp/rust/part-6.md +508 -508
  583. package/lib/assets/docs/article/grokkingfp/scala/index.md +171 -171
  584. package/lib/assets/docs/article/grokkingfp/scala/part-1.md +543 -543
  585. package/lib/assets/docs/article/grokkingfp/scala/part-2.md +946 -946
  586. package/lib/assets/docs/article/grokkingfp/scala/part-3.md +919 -919
  587. package/lib/assets/docs/article/grokkingfp/scala/part-4.md +742 -742
  588. package/lib/assets/docs/article/grokkingfp/scala/part-5.md +722 -722
  589. package/lib/assets/docs/article/grokkingfp/scala/part-6.md +867 -867
  590. package/lib/assets/docs/article/grokkingfp/typescript/index.md +273 -273
  591. package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +561 -561
  592. package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +1129 -1129
  593. package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +842 -842
  594. package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +1087 -1087
  595. package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +717 -717
  596. package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +982 -982
  597. package/lib/assets/docs/article/index.md +41 -41
  598. package/lib/assets/docs/article/practical-database-design/index.md +121 -121
  599. package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +288 -288
  600. package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +518 -518
  601. package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +557 -557
  602. package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +924 -924
  603. package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +1627 -1627
  604. package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +2716 -2716
  605. package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +2082 -2082
  606. package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +2105 -2105
  607. package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +2031 -2031
  608. package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +1387 -1387
  609. package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +1677 -1677
  610. package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +1417 -1417
  611. package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +1434 -1434
  612. package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +667 -667
  613. package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +1625 -1625
  614. package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +1915 -1915
  615. package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +1708 -1708
  616. package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +2095 -2095
  617. package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +1123 -1123
  618. package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +1031 -1031
  619. package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +1382 -1382
  620. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +991 -991
  621. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +1300 -1300
  622. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +1166 -1166
  623. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +1584 -1584
  624. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +1183 -1183
  625. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +1016 -1016
  626. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +1753 -1753
  627. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +1447 -1447
  628. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +1878 -1878
  629. package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +965 -965
  630. package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +2069 -2069
  631. package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +2439 -2439
  632. package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +3661 -3661
  633. package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +2916 -2916
  634. package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +3105 -3105
  635. package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +2697 -2697
  636. package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +2544 -2544
  637. package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +2180 -2180
  638. package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +1192 -1192
  639. package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +2101 -2101
  640. package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +1032 -1032
  641. package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +1609 -1609
  642. package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +1453 -1453
  643. package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +1292 -1292
  644. package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +1470 -1470
  645. package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +1698 -1698
  646. package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +2334 -2334
  647. package/lib/assets/docs/article/practical-database-design/study/study2-1.md +1693 -1693
  648. package/lib/assets/docs/article/practical-database-design/study/study2-2.md +1347 -1347
  649. package/lib/assets/docs/article/practical-database-design/study/study2-3.md +2044 -2044
  650. package/lib/assets/docs/article/practical-database-design/study/study2-4.md +2229 -2229
  651. package/lib/assets/docs/article/practical-database-design/study/study2-5.md +2418 -2418
  652. package/lib/assets/docs/article/practical-database-design/study/study3-1.md +2205 -2205
  653. package/lib/assets/docs/article/practical-database-design/study/study3-2.md +2221 -2221
  654. package/lib/assets/docs/article/practical-database-design/study/study3-3.md +2253 -2253
  655. package/lib/assets/docs/article/practical-database-design/study/study3-4.md +2106 -2106
  656. package/lib/assets/docs/article/practical-database-design/study/study3-5.md +2507 -2507
  657. package/lib/assets/docs/article/practical-database-design/study/study4-1.md +2587 -2587
  658. package/lib/assets/docs/article/practical-database-design/study/study4-2.md +2075 -2075
  659. package/lib/assets/docs/article/practical-database-design/study/study4-3.md +1805 -1805
  660. package/lib/assets/docs/article/practical-database-design/study/study4-4.md +1895 -1895
  661. package/lib/assets/docs/article/practical-database-design/study/study4-5.md +2878 -2878
  662. package/lib/assets/docs/assets/css/extra.css +29 -29
  663. package/lib/assets/docs/assets/js/extra.js +44 -44
  664. package/lib/assets/docs/design/index.md +44 -44
  665. package/lib/assets/docs/development/index.md +39 -39
  666. package/lib/assets/docs/index.md +33 -33
  667. package/lib/assets/docs/operation/index.md +27 -27
  668. 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 +546 -546
  669. 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
  670. 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 -581
  671. 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
  672. 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
  673. package/lib/assets/docs/reference/UI/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +450 -450
  674. package/lib/assets/docs/reference/images/Ansoff.drawio.svg +3 -3
  675. package/lib/assets/docs/reference/images/BMC.drawio.svg +3 -3
  676. package/lib/assets/docs/reference/images/BrandBasicStrategy.drawio.svg +3 -3
  677. package/lib/assets/docs/reference/images/BrandCategorization.drawio.svg +3 -3
  678. package/lib/assets/docs/reference/images/BrandRecurutementStrategy.drawio.svg +3 -3
  679. package/lib/assets/docs/reference/images/BrandValue.drawio.svg +3 -3
  680. package/lib/assets/docs/reference/images/BusinessActivitiy.svg +3 -3
  681. package/lib/assets/docs/reference/images/HRM.drawio.svg +3 -3
  682. package/lib/assets/docs/reference/images/MarketingStructure.drawio.svg +3 -3
  683. package/lib/assets/docs/reference/images/OrganizationElemnts.svg +3 -3
  684. package/lib/assets/docs/reference/images/PPM.drawio.svg +3 -3
  685. package/lib/assets/docs/reference/images/PositioningMap.drawio.svg +3 -3
  686. package/lib/assets/docs/reference/images/ProductLayer.drawio.svg +3 -3
  687. package/lib/assets/docs/reference/images/ProductMix.drawio.svg +3 -3
  688. package/lib/assets/docs/reference/images/SWOT.drawio.svg +3 -3
  689. package/lib/assets/docs/reference/images/TargetMarket.drawio.svg +3 -3
  690. package/lib/assets/docs/reference/images/ThreeGenericStrategies.drawio.svg +3 -3
  691. package/lib/assets/docs/reference/images/VRIO.drawio.svg +3 -3
  692. package/lib/assets/docs/reference/images/ValueChain.drawio.svg +3 -3
  693. package/lib/assets/docs/reference/index.md +53 -53
  694. 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 -250
  695. 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
  696. 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
  697. 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 -550
  698. 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
  699. 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
  700. 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
  701. 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
  702. 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
  703. 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 -689
  704. 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
  705. 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 -580
  706. 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
  707. package/lib/assets/docs/reference//344/274/201/346/245/255/347/265/214/345/226/266/350/253/226.md +2637 -2637
  708. 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 -665
  709. package/lib/assets/docs/reference//347/265/214/345/226/266/346/210/246/347/225/245/345/210/206/346/236/220/343/202/254/343/202/244/343/203/211.md +566 -566
  710. 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
  711. 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 +518 -518
  712. package/lib/assets/docs/reference//351/201/213/345/226/266/347/256/241/347/220/206.md +1482 -1482
  713. 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
  714. 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
  715. package/lib/assets/docs/reference//351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +305 -305
  716. 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
  717. package/lib/assets/docs/requirements/index.md +17 -17
  718. package/lib/assets/docs/review/index.md +5 -5
  719. package/lib/assets/docs/strategy/index.md +17 -17
  720. package/lib/assets/docs/template/ADR.md +30 -30
  721. 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
  722. 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
  723. package/lib/assets/docs/template/README.md +50 -50
  724. package/lib/assets/docs/template/index.md +24 -24
  725. 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
  726. 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
  727. 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
  728. 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/350/250/210/347/224/273.md +327 -327
  729. 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
  730. 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
  731. package/lib/assets/docs/template//343/203/252/343/203/252/343/203/274/343/202/271/345/256/214/344/272/206/345/240/261/345/221/212/346/233/270.md +275 -275
  732. package/lib/assets/docs/template//344/272/213/344/276/213/345/210/206/346/236/220.md +513 -513
  733. package/lib/assets/docs/template//344/274/201/346/245/255/345/210/206/346/236/220.md +573 -573
  734. 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 -69
  735. package/lib/assets/docs/template//350/246/201/344/273/266/345/256/232/347/276/251.md +669 -669
  736. package/lib/assets/docs/template//350/250/255/350/250/210.md +173 -173
  737. 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
  738. package/lib/assets/gulpfile.js +27 -25
  739. package/lib/assets/mkdocs.yml +139 -139
  740. package/lib/assets/ops/docker/mkdoc/Dockerfile +19 -19
  741. package/lib/assets/ops/docker/sonarqube-local/docker-compose.yml +57 -57
  742. package/lib/assets/ops/scripts/journal.js +180 -180
  743. package/lib/assets/ops/scripts/manual.js +198 -0
  744. package/lib/assets/ops/scripts/mkdocs.js +82 -82
  745. package/lib/assets/ops/scripts/release.js +431 -431
  746. package/lib/assets/ops/scripts/sonar_local.js +726 -726
  747. package/lib/assets/ops/scripts/ssh.js +190 -190
  748. package/lib/assets/ops/scripts/vault.js +299 -299
  749. package/lib/assets/package-lock.json +1673 -1653
  750. package/lib/assets/package.json +43 -40
  751. package/lib/gulpfile.js +37 -37
  752. package/package.json +41 -41
@@ -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>