oh-my-oop 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MCP_STRUCTURE.md +301 -0
- package/README.md +167 -0
- package/SCOPE.md +27 -0
- package/dist/application/discovery.d.ts +133 -0
- package/dist/application/discovery.js +62 -0
- package/dist/application/discovery.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +80 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/domain/collaborators.d.ts +2 -0
- package/dist/domain/collaborators.js +26 -0
- package/dist/domain/collaborators.js.map +1 -0
- package/dist/domain/ids.d.ts +4 -0
- package/dist/domain/ids.js +23 -0
- package/dist/domain/ids.js.map +1 -0
- package/dist/domain/model.d.ts +71 -0
- package/dist/domain/model.js +2 -0
- package/dist/domain/model.js.map +1 -0
- package/dist/domain/schemas.d.ts +213 -0
- package/dist/domain/schemas.js +79 -0
- package/dist/domain/schemas.js.map +1 -0
- package/dist/domain/stereotypes.d.ts +7 -0
- package/dist/domain/stereotypes.js +65 -0
- package/dist/domain/stereotypes.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/io/classStore.d.ts +9 -0
- package/dist/io/classStore.js +39 -0
- package/dist/io/classStore.js.map +1 -0
- package/dist/io/collaborationStore.d.ts +7 -0
- package/dist/io/collaborationStore.js +32 -0
- package/dist/io/collaborationStore.js.map +1 -0
- package/dist/io/design.d.ts +3 -0
- package/dist/io/design.js +22 -0
- package/dist/io/design.js.map +1 -0
- package/dist/io/designIndex.d.ts +6 -0
- package/dist/io/designIndex.js +49 -0
- package/dist/io/designIndex.js.map +1 -0
- package/dist/io/frontmatter.d.ts +8 -0
- package/dist/io/frontmatter.js +31 -0
- package/dist/io/frontmatter.js.map +1 -0
- package/dist/io/history.d.ts +10 -0
- package/dist/io/history.js +38 -0
- package/dist/io/history.js.map +1 -0
- package/dist/io/useCaseStore.d.ts +8 -0
- package/dist/io/useCaseStore.js +36 -0
- package/dist/io/useCaseStore.js.map +1 -0
- package/dist/io/workspace.d.ts +14 -0
- package/dist/io/workspace.js +82 -0
- package/dist/io/workspace.js.map +1 -0
- package/dist/oop/commands.d.ts +446 -0
- package/dist/oop/commands.js +319 -0
- package/dist/oop/commands.js.map +1 -0
- package/dist/oop/conformance.d.ts +16 -0
- package/dist/oop/conformance.js +30 -0
- package/dist/oop/conformance.js.map +1 -0
- package/dist/prompts/discovery.d.ts +2 -0
- package/dist/prompts/discovery.js +41 -0
- package/dist/prompts/discovery.js.map +1 -0
- package/dist/prompts/imagineWithoutController.d.ts +2 -0
- package/dist/prompts/imagineWithoutController.js +75 -0
- package/dist/prompts/imagineWithoutController.js.map +1 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.js +17 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/phasePressureTest.d.ts +2 -0
- package/dist/prompts/phasePressureTest.js +69 -0
- package/dist/prompts/phasePressureTest.js.map +1 -0
- package/dist/prompts/rddIntro.d.ts +2 -0
- package/dist/prompts/rddIntro.js +53 -0
- package/dist/prompts/rddIntro.js.map +1 -0
- package/dist/prompts/review.d.ts +2 -0
- package/dist/prompts/review.js +45 -0
- package/dist/prompts/review.js.map +1 -0
- package/dist/prompts/stateMachineIntrospect.d.ts +2 -0
- package/dist/prompts/stateMachineIntrospect.js +80 -0
- package/dist/prompts/stateMachineIntrospect.js.map +1 -0
- package/dist/prompts/tellDontAskRephrase.d.ts +2 -0
- package/dist/prompts/tellDontAskRephrase.js +66 -0
- package/dist/prompts/tellDontAskRephrase.js.map +1 -0
- package/dist/render/diff.d.ts +21 -0
- package/dist/render/diff.js +84 -0
- package/dist/render/diff.js.map +1 -0
- package/dist/render/mermaid.d.ts +24 -0
- package/dist/render/mermaid.js +53 -0
- package/dist/render/mermaid.js.map +1 -0
- package/dist/render/sideBySide.d.ts +14 -0
- package/dist/render/sideBySide.js +91 -0
- package/dist/render/sideBySide.js.map +1 -0
- package/dist/resources/index.d.ts +2 -0
- package/dist/resources/index.js +349 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +22 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/alternatives.d.ts +2 -0
- package/dist/tools/alternatives.js +9 -0
- package/dist/tools/alternatives.js.map +1 -0
- package/dist/tools/classes.d.ts +2 -0
- package/dist/tools/classes.js +13 -0
- package/dist/tools/classes.js.map +1 -0
- package/dist/tools/collaborations.d.ts +2 -0
- package/dist/tools/collaborations.js +8 -0
- package/dist/tools/collaborations.js.map +1 -0
- package/dist/tools/compare.d.ts +2 -0
- package/dist/tools/compare.js +9 -0
- package/dist/tools/compare.js.map +1 -0
- package/dist/tools/conformance.d.ts +3 -0
- package/dist/tools/conformance.js +11 -0
- package/dist/tools/conformance.js.map +1 -0
- package/dist/tools/diagram.d.ts +2 -0
- package/dist/tools/diagram.js +9 -0
- package/dist/tools/diagram.js.map +1 -0
- package/dist/tools/discovery.d.ts +2 -0
- package/dist/tools/discovery.js +23 -0
- package/dist/tools/discovery.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +27 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/init.d.ts +2 -0
- package/dist/tools/init.js +9 -0
- package/dist/tools/init.js.map +1 -0
- package/dist/tools/oop.d.ts +9 -0
- package/dist/tools/oop.js +26 -0
- package/dist/tools/oop.js.map +1 -0
- package/dist/tools/responsibilities.d.ts +2 -0
- package/dist/tools/responsibilities.js +13 -0
- package/dist/tools/responsibilities.js.map +1 -0
- package/dist/tools/state.d.ts +2 -0
- package/dist/tools/state.js +8 -0
- package/dist/tools/state.js.map +1 -0
- package/dist/tools/useCases.d.ts +2 -0
- package/dist/tools/useCases.js +18 -0
- package/dist/tools/useCases.js.map +1 -0
- package/dist/tools/validate.d.ts +2 -0
- package/dist/tools/validate.js +9 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/tradeoff/engine.d.ts +61 -0
- package/dist/tradeoff/engine.js +171 -0
- package/dist/tradeoff/engine.js.map +1 -0
- package/dist/tradeoff/heuristics/classSplit.d.ts +3 -0
- package/dist/tradeoff/heuristics/classSplit.js +94 -0
- package/dist/tradeoff/heuristics/classSplit.js.map +1 -0
- package/dist/tradeoff/heuristics/collaborationShape.d.ts +2 -0
- package/dist/tradeoff/heuristics/collaborationShape.js +82 -0
- package/dist/tradeoff/heuristics/collaborationShape.js.map +1 -0
- package/dist/tradeoff/heuristics/collectionShape.d.ts +2 -0
- package/dist/tradeoff/heuristics/collectionShape.js +113 -0
- package/dist/tradeoff/heuristics/collectionShape.js.map +1 -0
- package/dist/tradeoff/heuristics/dualSubjectComparison.d.ts +2 -0
- package/dist/tradeoff/heuristics/dualSubjectComparison.js +114 -0
- package/dist/tradeoff/heuristics/dualSubjectComparison.js.map +1 -0
- package/dist/tradeoff/heuristics/errorHandling.d.ts +2 -0
- package/dist/tradeoff/heuristics/errorHandling.js +110 -0
- package/dist/tradeoff/heuristics/errorHandling.js.map +1 -0
- package/dist/tradeoff/heuristics/responsibilitySplit.d.ts +23 -0
- package/dist/tradeoff/heuristics/responsibilitySplit.js +183 -0
- package/dist/tradeoff/heuristics/responsibilitySplit.js.map +1 -0
- package/dist/tradeoff/heuristics/stereotypeChoice.d.ts +2 -0
- package/dist/tradeoff/heuristics/stereotypeChoice.js +23 -0
- package/dist/tradeoff/heuristics/stereotypeChoice.js.map +1 -0
- package/dist/tradeoff/heuristics/strategyOrPolicy.d.ts +2 -0
- package/dist/tradeoff/heuristics/strategyOrPolicy.js +110 -0
- package/dist/tradeoff/heuristics/strategyOrPolicy.js.map +1 -0
- package/dist/tradeoff/heuristics/valueObjectShape.d.ts +2 -0
- package/dist/tradeoff/heuristics/valueObjectShape.js +111 -0
- package/dist/tradeoff/heuristics/valueObjectShape.js.map +1 -0
- package/dist/tradeoff/templates.d.ts +2 -0
- package/dist/tradeoff/templates.js +33 -0
- package/dist/tradeoff/templates.js.map +1 -0
- package/dist/util/log.d.ts +1 -0
- package/dist/util/log.js +7 -0
- package/dist/util/log.js.map +1 -0
- package/dist/util/mcp.d.ts +4 -0
- package/dist/util/mcp.js +18 -0
- package/dist/util/mcp.js.map +1 -0
- package/dist/validate/cohesion.d.ts +3 -0
- package/dist/validate/cohesion.js +88 -0
- package/dist/validate/cohesion.js.map +1 -0
- package/dist/validate/collectionWrapper.d.ts +3 -0
- package/dist/validate/collectionWrapper.js +131 -0
- package/dist/validate/collectionWrapper.js.map +1 -0
- package/dist/validate/coupling.d.ts +3 -0
- package/dist/validate/coupling.js +47 -0
- package/dist/validate/coupling.js.map +1 -0
- package/dist/validate/cycle.d.ts +3 -0
- package/dist/validate/cycle.js +101 -0
- package/dist/validate/cycle.js.map +1 -0
- package/dist/validate/dataDuplication.d.ts +3 -0
- package/dist/validate/dataDuplication.js +150 -0
- package/dist/validate/dataDuplication.js.map +1 -0
- package/dist/validate/dependencyDirection.d.ts +3 -0
- package/dist/validate/dependencyDirection.js +106 -0
- package/dist/validate/dependencyDirection.js.map +1 -0
- package/dist/validate/dualUseKnowing.d.ts +3 -0
- package/dist/validate/dualUseKnowing.js +137 -0
- package/dist/validate/dualUseKnowing.js.map +1 -0
- package/dist/validate/emptyObjectFill.d.ts +3 -0
- package/dist/validate/emptyObjectFill.js +119 -0
- package/dist/validate/emptyObjectFill.js.map +1 -0
- package/dist/validate/findings.d.ts +22 -0
- package/dist/validate/findings.js +12 -0
- package/dist/validate/findings.js.map +1 -0
- package/dist/validate/functionDecompositionExcess.d.ts +3 -0
- package/dist/validate/functionDecompositionExcess.js +120 -0
- package/dist/validate/functionDecompositionExcess.js.map +1 -0
- package/dist/validate/functionNotObject.d.ts +3 -0
- package/dist/validate/functionNotObject.js +80 -0
- package/dist/validate/functionNotObject.js.map +1 -0
- package/dist/validate/godObject.d.ts +6 -0
- package/dist/validate/godObject.js +76 -0
- package/dist/validate/godObject.js.map +1 -0
- package/dist/validate/presentationInDomain.d.ts +3 -0
- package/dist/validate/presentationInDomain.js +57 -0
- package/dist/validate/presentationInDomain.js.map +1 -0
- package/dist/validate/primitiveWrapper.d.ts +3 -0
- package/dist/validate/primitiveWrapper.js +106 -0
- package/dist/validate/primitiveWrapper.js.map +1 -0
- package/dist/validate/rules.d.ts +24 -0
- package/dist/validate/rules.js +269 -0
- package/dist/validate/rules.js.map +1 -0
- package/dist/validate/singletonStatefulHolder.d.ts +3 -0
- package/dist/validate/singletonStatefulHolder.js +128 -0
- package/dist/validate/singletonStatefulHolder.js.map +1 -0
- package/dist/validate/strategyAsymmetry.d.ts +3 -0
- package/dist/validate/strategyAsymmetry.js +131 -0
- package/dist/validate/strategyAsymmetry.js.map +1 -0
- package/dist/validate/testability.d.ts +5 -0
- package/dist/validate/testability.js +157 -0
- package/dist/validate/testability.js.map +1 -0
- package/dist/validate/vagueName.d.ts +3 -0
- package/dist/validate/vagueName.js +136 -0
- package/dist/validate/vagueName.js.map +1 -0
- package/dist/validate/validationLocation.d.ts +3 -0
- package/dist/validate/validationLocation.js +120 -0
- package/dist/validate/validationLocation.js.map +1 -0
- package/lessons/STYLE_GUIDE.md +304 -0
- package/lessons/woowacourse-kotlin-blackjack/2chang5/33-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +293 -0
- package/lessons/woowacourse-kotlin-blackjack/Choisehyeon/52-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +106 -0
- package/lessons/woowacourse-kotlin-blackjack/Choisehyeon/9-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +282 -0
- package/lessons/woowacourse-kotlin-blackjack/DYGames/14-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +182 -0
- package/lessons/woowacourse-kotlin-blackjack/DYGames/37-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +122 -0
- package/lessons/woowacourse-kotlin-blackjack/EmilyCh0/12-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +117 -0
- package/lessons/woowacourse-kotlin-blackjack/EmilyCh0/38-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +291 -0
- package/lessons/woowacourse-kotlin-blackjack/HANDOVER.md +1475 -0
- package/lessons/woowacourse-kotlin-blackjack/HamBeomJoon/119-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +251 -0
- package/lessons/woowacourse-kotlin-blackjack/HamBeomJoon/137-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +459 -0
- package/lessons/woowacourse-kotlin-blackjack/Hevton/100-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +282 -0
- package/lessons/woowacourse-kotlin-blackjack/Hevton/82-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +303 -0
- package/lessons/woowacourse-kotlin-blackjack/Hogu59/71-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +134 -0
- package/lessons/woowacourse-kotlin-blackjack/Hogu59/96-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +323 -0
- package/lessons/woowacourse-kotlin-blackjack/JoYehyun99/66-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +210 -0
- package/lessons/woowacourse-kotlin-blackjack/Junyoung-WON/101-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +191 -0
- package/lessons/woowacourse-kotlin-blackjack/Junyoung-WON/80-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +253 -0
- package/lessons/woowacourse-kotlin-blackjack/Leeyerin0210/108-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +516 -0
- package/lessons/woowacourse-kotlin-blackjack/Leeyerin0210/133-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +541 -0
- package/lessons/woowacourse-kotlin-blackjack/RightHennessy/22-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +278 -0
- package/lessons/woowacourse-kotlin-blackjack/RightHennessy/48-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +188 -0
- package/lessons/woowacourse-kotlin-blackjack/SeongHoonC/16-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +228 -0
- package/lessons/woowacourse-kotlin-blackjack/SeongHoonC/54-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +227 -0
- package/lessons/woowacourse-kotlin-blackjack/Yunseok-Nam/76-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +279 -0
- package/lessons/woowacourse-kotlin-blackjack/Yunseok-Nam/86-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +203 -0
- package/lessons/woowacourse-kotlin-blackjack/aprilgom/105-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +162 -0
- package/lessons/woowacourse-kotlin-blackjack/aprilgom/64-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +279 -0
- package/lessons/woowacourse-kotlin-blackjack/boogi-woogi/18-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +188 -0
- package/lessons/woowacourse-kotlin-blackjack/boogi-woogi/36-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +769 -0
- package/lessons/woowacourse-kotlin-blackjack/briandr97/19-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +226 -0
- package/lessons/woowacourse-kotlin-blackjack/briandr97/59-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +193 -0
- package/lessons/woowacourse-kotlin-blackjack/chaehyuns/70-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +175 -0
- package/lessons/woowacourse-kotlin-blackjack/chaehyuns/98-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +206 -0
- package/lessons/woowacourse-kotlin-blackjack/chanho0908/123-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +277 -0
- package/lessons/woowacourse-kotlin-blackjack/chanho0908/150-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +219 -0
- package/lessons/woowacourse-kotlin-blackjack/chws0508/26-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +259 -0
- package/lessons/woowacourse-kotlin-blackjack/chws0508/43-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +189 -0
- package/lessons/woowacourse-kotlin-blackjack/cucumber99/109-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +351 -0
- package/lessons/woowacourse-kotlin-blackjack/cucumber99/149-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +147 -0
- package/lessons/woowacourse-kotlin-blackjack/devfeijoa/121-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +168 -0
- package/lessons/woowacourse-kotlin-blackjack/devfeijoa/153-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +116 -0
- package/lessons/woowacourse-kotlin-blackjack/doabletuple/126-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +680 -0
- package/lessons/woowacourse-kotlin-blackjack/doabletuple/142-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +739 -0
- package/lessons/woowacourse-kotlin-blackjack/donghyun81/116-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +297 -0
- package/lessons/woowacourse-kotlin-blackjack/donghyun81/147-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +244 -0
- package/lessons/woowacourse-kotlin-blackjack/dpcks0509/78-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +232 -0
- package/lessons/woowacourse-kotlin-blackjack/dpcks0509/88-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +137 -0
- package/lessons/woowacourse-kotlin-blackjack/etama123/112-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +269 -0
- package/lessons/woowacourse-kotlin-blackjack/etama123/148-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +240 -0
- package/lessons/woowacourse-kotlin-blackjack/gaeun5744/102-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +146 -0
- package/lessons/woowacourse-kotlin-blackjack/gaeun5744/69-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +224 -0
- package/lessons/woowacourse-kotlin-blackjack/gahyunkim/118-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +397 -0
- package/lessons/woowacourse-kotlin-blackjack/gahyunkim/141-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +215 -0
- package/lessons/woowacourse-kotlin-blackjack/giovannijunseokim/106-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +395 -0
- package/lessons/woowacourse-kotlin-blackjack/giovannijunseokim/134-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +219 -0
- package/lessons/woowacourse-kotlin-blackjack/haeum808/62-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +230 -0
- package/lessons/woowacourse-kotlin-blackjack/haeum808/89-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +169 -0
- package/lessons/woowacourse-kotlin-blackjack/hwannow/110-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +221 -0
- package/lessons/woowacourse-kotlin-blackjack/hwannow/132-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +573 -0
- package/lessons/woowacourse-kotlin-blackjack/hxeyexn/103-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +188 -0
- package/lessons/woowacourse-kotlin-blackjack/hxeyexn/81-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +301 -0
- package/lessons/woowacourse-kotlin-blackjack/hyemdooly/21-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +613 -0
- package/lessons/woowacourse-kotlin-blackjack/hyemdooly/35-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +691 -0
- package/lessons/woowacourse-kotlin-blackjack/hyunji1203/13-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +206 -0
- package/lessons/woowacourse-kotlin-blackjack/ii2001/79-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +153 -0
- package/lessons/woowacourse-kotlin-blackjack/ii2001/85-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +318 -0
- package/lessons/woowacourse-kotlin-blackjack/ijh1298/128-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +250 -0
- package/lessons/woowacourse-kotlin-blackjack/ijh1298/135-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +269 -0
- package/lessons/woowacourse-kotlin-blackjack/inseonyun/28-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +346 -0
- package/lessons/woowacourse-kotlin-blackjack/inseonyun/49-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +360 -0
- package/lessons/woowacourse-kotlin-blackjack/ippnsj/30-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +152 -0
- package/lessons/woowacourse-kotlin-blackjack/ippnsj/42-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +213 -0
- package/lessons/woowacourse-kotlin-blackjack/jaeyeongjo/73-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +247 -0
- package/lessons/woowacourse-kotlin-blackjack/jaeyeongjo/87-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +900 -0
- package/lessons/woowacourse-kotlin-blackjack/jerry8282/125-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +248 -0
- package/lessons/woowacourse-kotlin-blackjack/jerry8282/151-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +243 -0
- package/lessons/woowacourse-kotlin-blackjack/jinuemong/63-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +281 -0
- package/lessons/woowacourse-kotlin-blackjack/jinuemong/92-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +283 -0
- package/lessons/woowacourse-kotlin-blackjack/jiyuneel/113-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +348 -0
- package/lessons/woowacourse-kotlin-blackjack/jiyuneel/140-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +265 -0
- package/lessons/woowacourse-kotlin-blackjack/junjange/61-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +270 -0
- package/lessons/woowacourse-kotlin-blackjack/junjange/93-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +465 -0
- package/lessons/woowacourse-kotlin-blackjack/junseo511/107-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +296 -0
- package/lessons/woowacourse-kotlin-blackjack/junseo511/145-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +316 -0
- package/lessons/woowacourse-kotlin-blackjack/ki960213/11-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +175 -0
- package/lessons/woowacourse-kotlin-blackjack/kimhm0728/72-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +458 -0
- package/lessons/woowacourse-kotlin-blackjack/kimhm0728/97-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +225 -0
- package/lessons/woowacourse-kotlin-blackjack/kkosang/68-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +221 -0
- package/lessons/woowacourse-kotlin-blackjack/kkosang/94-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +158 -0
- package/lessons/woowacourse-kotlin-blackjack/kmkim2689/65-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +252 -0
- package/lessons/woowacourse-kotlin-blackjack/kmkim2689/90-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +460 -0
- package/lessons/woowacourse-kotlin-blackjack/krrong/32-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +216 -0
- package/lessons/woowacourse-kotlin-blackjack/krrong/46-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +285 -0
- package/lessons/woowacourse-kotlin-blackjack/m6z1/122-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +177 -0
- package/lessons/woowacourse-kotlin-blackjack/m6z1/144-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +155 -0
- package/lessons/woowacourse-kotlin-blackjack/medAndro/130-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +683 -0
- package/lessons/woowacourse-kotlin-blackjack/medAndro/143-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +678 -0
- package/lessons/woowacourse-kotlin-blackjack/moondev03/114-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +262 -0
- package/lessons/woowacourse-kotlin-blackjack/moondev03/131-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +498 -0
- package/lessons/woowacourse-kotlin-blackjack/murjune/77-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +287 -0
- package/lessons/woowacourse-kotlin-blackjack/murjune/91-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +280 -0
- package/lessons/woowacourse-kotlin-blackjack/no1msh/31-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +250 -0
- package/lessons/woowacourse-kotlin-blackjack/otter66/24-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +302 -0
- package/lessons/woowacourse-kotlin-blackjack/otter66/58-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +391 -0
- package/lessons/woowacourse-kotlin-blackjack/oungsi2000/111-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +253 -0
- package/lessons/woowacourse-kotlin-blackjack/oungsi2000/136-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +540 -0
- package/lessons/woowacourse-kotlin-blackjack/parkjiminnnn/117-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +819 -0
- package/lessons/woowacourse-kotlin-blackjack/parkjiminnnn/139-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +683 -0
- package/lessons/woowacourse-kotlin-blackjack/pingu244/20-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +258 -0
- package/lessons/woowacourse-kotlin-blackjack/pingu244/41-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +171 -0
- package/lessons/woowacourse-kotlin-blackjack/re4rk/34-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +289 -0
- package/lessons/woowacourse-kotlin-blackjack/re4rk/8-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +297 -0
- package/lessons/woowacourse-kotlin-blackjack/rhkrwngud445/17-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +279 -0
- package/lessons/woowacourse-kotlin-blackjack/rhkrwngud445/50-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +145 -0
- package/lessons/woowacourse-kotlin-blackjack/rhthrhrl0/23-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +253 -0
- package/lessons/woowacourse-kotlin-blackjack/rhthrhrl0/39-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +238 -0
- package/lessons/woowacourse-kotlin-blackjack/rosemin928/129-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +726 -0
- package/lessons/woowacourse-kotlin-blackjack/rosemin928/138-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +845 -0
- package/lessons/woowacourse-kotlin-blackjack/s6m1n/67-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +220 -0
- package/lessons/woowacourse-kotlin-blackjack/s6m1n/99-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +229 -0
- package/lessons/woowacourse-kotlin-blackjack/s9hn/10-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +284 -0
- package/lessons/woowacourse-kotlin-blackjack/sh1mj1/75-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +224 -0
- package/lessons/woowacourse-kotlin-blackjack/songpink/74-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +238 -0
- package/lessons/woowacourse-kotlin-blackjack/songpink/95-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +216 -0
- package/lessons/woowacourse-kotlin-blackjack/sujin9/15-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +132 -0
- package/lessons/woowacourse-kotlin-blackjack/sujin9/47-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +265 -0
- package/lessons/woowacourse-kotlin-blackjack/tmdgh1592/29-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +305 -0
- package/lessons/woowacourse-kotlin-blackjack/tmdgh1592/51-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +278 -0
- package/lessons/woowacourse-kotlin-blackjack/tobae-time/115-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +305 -0
- package/lessons/woowacourse-kotlin-blackjack/tobae-time/154-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +298 -0
- package/lessons/woowacourse-kotlin-blackjack/whk06061/25-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +235 -0
- package/lessons/woowacourse-kotlin-blackjack/whk06061/53-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +130 -0
- package/lessons/woowacourse-kotlin-blackjack/wondroid-world/124-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +486 -0
- package/lessons/woowacourse-kotlin-blackjack/wondroid-world/152-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +482 -0
- package/lessons/woowacourse-kotlin-blackjack/yrsel/120-1/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +194 -0
- package/lessons/woowacourse-kotlin-blackjack/yrsel/146-2/353/213/250/352/263/204-/353/270/224/353/236/231/354/236/255.md +444 -0
- package/lessons/woowacourse-kotlin-lotto/2chang5/27-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +155 -0
- package/lessons/woowacourse-kotlin-lotto/2chang5/52-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +187 -0
- package/lessons/woowacourse-kotlin-lotto/Choisehyeon/14-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +206 -0
- package/lessons/woowacourse-kotlin-lotto/Choisehyeon/47-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +119 -0
- package/lessons/woowacourse-kotlin-lotto/DYGames/2-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +83 -0
- package/lessons/woowacourse-kotlin-lotto/DYGames/34-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +88 -0
- package/lessons/woowacourse-kotlin-lotto/EmilyCh0/12-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +107 -0
- package/lessons/woowacourse-kotlin-lotto/EmilyCh0/40-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +135 -0
- package/lessons/woowacourse-kotlin-lotto/HANDOVER.md +217 -0
- package/lessons/woowacourse-kotlin-lotto/HamBeomJoon/121-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +66 -0
- package/lessons/woowacourse-kotlin-lotto/HamBeomJoon/139-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +75 -0
- package/lessons/woowacourse-kotlin-lotto/Hevton/76-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +21 -0
- package/lessons/woowacourse-kotlin-lotto/Hevton/92-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +122 -0
- package/lessons/woowacourse-kotlin-lotto/Hogu59/100-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +110 -0
- package/lessons/woowacourse-kotlin-lotto/Hogu59/68-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +84 -0
- package/lessons/woowacourse-kotlin-lotto/JoYehyun99/60-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +176 -0
- package/lessons/woowacourse-kotlin-lotto/JoYehyun99/96-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +71 -0
- package/lessons/woowacourse-kotlin-lotto/Junyoung-WON/61-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +143 -0
- package/lessons/woowacourse-kotlin-lotto/Junyoung-WON/93-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +16 -0
- package/lessons/woowacourse-kotlin-lotto/Leeyerin0210/109-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +57 -0
- package/lessons/woowacourse-kotlin-lotto/Leeyerin0210/135-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +115 -0
- package/lessons/woowacourse-kotlin-lotto/PROGRESS.md +160 -0
- package/lessons/woowacourse-kotlin-lotto/README.md +77 -0
- package/lessons/woowacourse-kotlin-lotto/RightHennessy/32-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +178 -0
- package/lessons/woowacourse-kotlin-lotto/RightHennessy/5-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +149 -0
- package/lessons/woowacourse-kotlin-lotto/SUMMARY.md +369 -0
- package/lessons/woowacourse-kotlin-lotto/SeongHoonC/25-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +129 -0
- package/lessons/woowacourse-kotlin-lotto/SeongHoonC/37-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +27 -0
- package/lessons/woowacourse-kotlin-lotto/Yunseok-Nam/72-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +137 -0
- package/lessons/woowacourse-kotlin-lotto/Yunseok-Nam/86-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +17 -0
- package/lessons/woowacourse-kotlin-lotto/aprilgom/102-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +62 -0
- package/lessons/woowacourse-kotlin-lotto/aprilgom/64-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +146 -0
- package/lessons/woowacourse-kotlin-lotto/boogi-woogi/11-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +26 -0
- package/lessons/woowacourse-kotlin-lotto/boogi-woogi/29-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +26 -0
- package/lessons/woowacourse-kotlin-lotto/briandr97/26-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +52 -0
- package/lessons/woowacourse-kotlin-lotto/briandr97/51-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +123 -0
- package/lessons/woowacourse-kotlin-lotto/chaehyuns/71-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +115 -0
- package/lessons/woowacourse-kotlin-lotto/chaehyuns/97-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +107 -0
- package/lessons/woowacourse-kotlin-lotto/chanho0908/124-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +51 -0
- package/lessons/woowacourse-kotlin-lotto/chanho0908/129-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +149 -0
- package/lessons/woowacourse-kotlin-lotto/chws0508/24-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +117 -0
- package/lessons/woowacourse-kotlin-lotto/chws0508/50-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +167 -0
- package/lessons/woowacourse-kotlin-lotto/cucumber99/116-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +155 -0
- package/lessons/woowacourse-kotlin-lotto/cucumber99/147-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +223 -0
- package/lessons/woowacourse-kotlin-lotto/devfeijoa/125-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +68 -0
- package/lessons/woowacourse-kotlin-lotto/devfeijoa/153-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +107 -0
- package/lessons/woowacourse-kotlin-lotto/doabletuple/119-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +157 -0
- package/lessons/woowacourse-kotlin-lotto/doabletuple/138-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +77 -0
- package/lessons/woowacourse-kotlin-lotto/donghyun81/111-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +67 -0
- package/lessons/woowacourse-kotlin-lotto/donghyun81/152-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +124 -0
- package/lessons/woowacourse-kotlin-lotto/dpcks0509/80-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +141 -0
- package/lessons/woowacourse-kotlin-lotto/dpcks0509/87-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +134 -0
- package/lessons/woowacourse-kotlin-lotto/etama123/112-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +170 -0
- package/lessons/woowacourse-kotlin-lotto/etama123/148-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +183 -0
- package/lessons/woowacourse-kotlin-lotto/gaeun5744/101-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +21 -0
- package/lessons/woowacourse-kotlin-lotto/gaeun5744/78-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +158 -0
- package/lessons/woowacourse-kotlin-lotto/gahyunkim/107-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +83 -0
- package/lessons/woowacourse-kotlin-lotto/gahyunkim/136-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +51 -0
- package/lessons/woowacourse-kotlin-lotto/giovannijunseokim/106-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +171 -0
- package/lessons/woowacourse-kotlin-lotto/giovannijunseokim/137-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +111 -0
- package/lessons/woowacourse-kotlin-lotto/haeum808/67-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +52 -0
- package/lessons/woowacourse-kotlin-lotto/haeum808/95-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +97 -0
- package/lessons/woowacourse-kotlin-lotto/hwannow/113-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +235 -0
- package/lessons/woowacourse-kotlin-lotto/hwannow/132-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +149 -0
- package/lessons/woowacourse-kotlin-lotto/hxeyexn/77-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +141 -0
- package/lessons/woowacourse-kotlin-lotto/hxeyexn/98-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +162 -0
- package/lessons/woowacourse-kotlin-lotto/hyemdooly/17-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +19 -0
- package/lessons/woowacourse-kotlin-lotto/hyemdooly/28-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +23 -0
- package/lessons/woowacourse-kotlin-lotto/hyunji1203/15-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +171 -0
- package/lessons/woowacourse-kotlin-lotto/hyunji1203/48-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +150 -0
- package/lessons/woowacourse-kotlin-lotto/ii2001/62-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +104 -0
- package/lessons/woowacourse-kotlin-lotto/ii2001/88-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +20 -0
- package/lessons/woowacourse-kotlin-lotto/ijh1298/122-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +179 -0
- package/lessons/woowacourse-kotlin-lotto/ijh1298/133-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +153 -0
- package/lessons/woowacourse-kotlin-lotto/inseonyun/3-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +222 -0
- package/lessons/woowacourse-kotlin-lotto/inseonyun/49-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +166 -0
- package/lessons/woowacourse-kotlin-lotto/ippnsj/16-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +154 -0
- package/lessons/woowacourse-kotlin-lotto/ippnsj/55-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +145 -0
- package/lessons/woowacourse-kotlin-lotto/jaeyeongjo/59-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +68 -0
- package/lessons/woowacourse-kotlin-lotto/jaeyeongjo/83-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +53 -0
- package/lessons/woowacourse-kotlin-lotto/jerry8282/115-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +97 -0
- package/lessons/woowacourse-kotlin-lotto/jerry8282/134-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +145 -0
- package/lessons/woowacourse-kotlin-lotto/jinuemong/63-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +144 -0
- package/lessons/woowacourse-kotlin-lotto/jinuemong/89-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +148 -0
- package/lessons/woowacourse-kotlin-lotto/jiyuneel/128-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +52 -0
- package/lessons/woowacourse-kotlin-lotto/jiyuneel/144-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +149 -0
- package/lessons/woowacourse-kotlin-lotto/junjange/58-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +148 -0
- package/lessons/woowacourse-kotlin-lotto/junjange/81-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +178 -0
- package/lessons/woowacourse-kotlin-lotto/junseo511/120-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +153 -0
- package/lessons/woowacourse-kotlin-lotto/junseo511/131-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +188 -0
- package/lessons/woowacourse-kotlin-lotto/ki960213/43-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +24 -0
- package/lessons/woowacourse-kotlin-lotto/ki960213/8-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +159 -0
- package/lessons/woowacourse-kotlin-lotto/kimhm0728/74-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +50 -0
- package/lessons/woowacourse-kotlin-lotto/kimhm0728/94-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +176 -0
- package/lessons/woowacourse-kotlin-lotto/kkosang/85-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +145 -0
- package/lessons/woowacourse-kotlin-lotto/kmkim2689/70-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +97 -0
- package/lessons/woowacourse-kotlin-lotto/kmkim2689/82-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +157 -0
- package/lessons/woowacourse-kotlin-lotto/krrong/19-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +161 -0
- package/lessons/woowacourse-kotlin-lotto/krrong/41-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +73 -0
- package/lessons/woowacourse-kotlin-lotto/m6z1/105-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +67 -0
- package/lessons/woowacourse-kotlin-lotto/m6z1/151-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +104 -0
- package/lessons/woowacourse-kotlin-lotto/medAndro/127-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +186 -0
- package/lessons/woowacourse-kotlin-lotto/medAndro/130-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +132 -0
- package/lessons/woowacourse-kotlin-lotto/moondev03/110-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +66 -0
- package/lessons/woowacourse-kotlin-lotto/moondev03/141-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +155 -0
- package/lessons/woowacourse-kotlin-lotto/murjune/69-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +143 -0
- package/lessons/woowacourse-kotlin-lotto/murjune/90-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +177 -0
- package/lessons/woowacourse-kotlin-lotto/no1msh/20-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +69 -0
- package/lessons/woowacourse-kotlin-lotto/no1msh/46-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +143 -0
- package/lessons/woowacourse-kotlin-lotto/otter66/13-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +178 -0
- package/lessons/woowacourse-kotlin-lotto/otter66/53-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +160 -0
- package/lessons/woowacourse-kotlin-lotto/oungsi2000/126-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +71 -0
- package/lessons/woowacourse-kotlin-lotto/oungsi2000/149-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +56 -0
- package/lessons/woowacourse-kotlin-lotto/parkjiminnnn/117-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +129 -0
- package/lessons/woowacourse-kotlin-lotto/parkjiminnnn/146-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +173 -0
- package/lessons/woowacourse-kotlin-lotto/pingu244/33-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +21 -0
- package/lessons/woowacourse-kotlin-lotto/pingu244/54-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +30 -0
- package/lessons/woowacourse-kotlin-lotto/pingu244/7-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +19 -0
- package/lessons/woowacourse-kotlin-lotto/re4rk/31-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +143 -0
- package/lessons/woowacourse-kotlin-lotto/re4rk/4-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +66 -0
- package/lessons/woowacourse-kotlin-lotto/rhkrwngud445/23-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +26 -0
- package/lessons/woowacourse-kotlin-lotto/rhkrwngud445/38-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +129 -0
- package/lessons/woowacourse-kotlin-lotto/rhthrhrl0/21-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +146 -0
- package/lessons/woowacourse-kotlin-lotto/rhthrhrl0/36-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +150 -0
- package/lessons/woowacourse-kotlin-lotto/rosemin928/123-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +179 -0
- package/lessons/woowacourse-kotlin-lotto/rosemin928/140-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +126 -0
- package/lessons/woowacourse-kotlin-lotto/s6m1n/103-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +119 -0
- package/lessons/woowacourse-kotlin-lotto/s6m1n/66-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +118 -0
- package/lessons/woowacourse-kotlin-lotto/s9hn/18-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +112 -0
- package/lessons/woowacourse-kotlin-lotto/sh1mj1/75-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +104 -0
- package/lessons/woowacourse-kotlin-lotto/sh1mj1/91-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +140 -0
- package/lessons/woowacourse-kotlin-lotto/songpink/65-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +96 -0
- package/lessons/woowacourse-kotlin-lotto/songpink/99-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +64 -0
- package/lessons/woowacourse-kotlin-lotto/sujin9/10-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +20 -0
- package/lessons/woowacourse-kotlin-lotto/sujin9/35-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +124 -0
- package/lessons/woowacourse-kotlin-lotto/tmdgh1592/22-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +30 -0
- package/lessons/woowacourse-kotlin-lotto/tmdgh1592/30-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +20 -0
- package/lessons/woowacourse-kotlin-lotto/tobae-time/114-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +158 -0
- package/lessons/woowacourse-kotlin-lotto/tobae-time/145-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +120 -0
- package/lessons/woowacourse-kotlin-lotto/whk06061/42-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +21 -0
- package/lessons/woowacourse-kotlin-lotto/whk06061/9-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +89 -0
- package/lessons/woowacourse-kotlin-lotto/wondroid-world/118-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +100 -0
- package/lessons/woowacourse-kotlin-lotto/wondroid-world/150-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +142 -0
- package/lessons/woowacourse-kotlin-lotto/yrsel/108-1/353/213/250/352/263/204-/353/241/234/353/230/220.md +124 -0
- package/lessons/woowacourse-kotlin-lotto/yrsel/143-2/353/213/250/352/263/204-/353/241/234/353/230/220.md +108 -0
- package/lessons/woowacourse-racingcar/2chang5/33-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/2chang5/75-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/CFalws/85-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/Choisehyeon/46-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +61 -0
- package/lessons/woowacourse-racingcar/DYGames/49-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +62 -0
- package/lessons/woowacourse-racingcar/EmilyCh0/40-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +64 -0
- package/lessons/woowacourse-racingcar/EmilyCh0/57-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/HamBeomJoon/137-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/HamBeomJoon/170-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/Hevton/106-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/Hevton/118-/353/246/254/355/214/251/355/204/260/353/247/201.md +51 -0
- package/lessons/woowacourse-racingcar/Hogu59/108-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/Hogu59/125-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/JoYehyun99/111-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/JoYehyun99/88-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +45 -0
- package/lessons/woowacourse-racingcar/Junyoung-WON/127-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/Junyoung-WON/90-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/Leeyerin0210/133-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/Leeyerin0210/159-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/PROGRESS.md +94 -0
- package/lessons/woowacourse-racingcar/README.md +69 -0
- package/lessons/woowacourse-racingcar/RightHennessy/51-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/RightHennessy/58-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/RunaNam/81-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +44 -0
- package/lessons/woowacourse-racingcar/SUMMARY.md +339 -0
- package/lessons/woowacourse-racingcar/SeongHoonC/37-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/SeongHoonC/66-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/Songusika/84-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/Yunseok-Nam/114-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +43 -0
- package/lessons/woowacourse-racingcar/Yunseok-Nam/96-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/aprilgom/130-/353/246/254/355/214/251/355/204/260/353/247/201.md +52 -0
- package/lessons/woowacourse-racingcar/aprilgom/97-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/awesomeo184/23-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/boogi-woogi/35-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +62 -0
- package/lessons/woowacourse-racingcar/boogi-woogi/59-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/briandr97/54-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/chaehyuns/131-/353/246/254/355/214/251/355/204/260/353/247/201.md +49 -0
- package/lessons/woowacourse-racingcar/chaehyuns/99-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/chanho0908/147-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/chanho0908/160-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/chws0508/45-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +61 -0
- package/lessons/woowacourse-racingcar/chws0508/73-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +46 -0
- package/lessons/woowacourse-racingcar/cucumber99/132-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/cucumber99/177-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/devfeijoa/146-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/doabletuple/149-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/doabletuple/175-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/donghyun81/154-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/dpcks0509/103-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/dpcks0509/112-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/drunkenhw/82-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/etama123/145-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/gaeun5744/124-/353/246/254/355/214/251/355/204/260/353/247/201.md +53 -0
- package/lessons/woowacourse-racingcar/gaeun5744/93-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/gahyunkim/134-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/gahyunkim/164-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/giovannijunseokim/140-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/haeum808/101-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/haeum808/129-/353/246/254/355/214/251/355/204/260/353/247/201.md +46 -0
- package/lessons/woowacourse-racingcar/hwannow/141-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/hwannow/157-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +45 -0
- package/lessons/woowacourse-racingcar/hxeyexn/109-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +61 -0
- package/lessons/woowacourse-racingcar/hxeyexn/128-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/hyemdooly/50-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/hyemdooly/68-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/hyunji1203/29-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/hyunji1203/60-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/ii2001/102-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +42 -0
- package/lessons/woowacourse-racingcar/ii2001/122-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/ijh1298/144-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/injoon2019/24-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/inseonyun/44-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/inseonyun/76-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/ippnsj/36-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/ippnsj/67-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/jaeyeongjo/110-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +39 -0
- package/lessons/woowacourse-racingcar/jaeyeongjo/89-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +46 -0
- package/lessons/woowacourse-racingcar/jinuemong/104-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/jinuemong/117-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +42 -0
- package/lessons/woowacourse-racingcar/jiyuneel/142-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/junjange/113-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +41 -0
- package/lessons/woowacourse-racingcar/junjange/87-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +39 -0
- package/lessons/woowacourse-racingcar/junseo511/148-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/junseo511/165-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +51 -0
- package/lessons/woowacourse-racingcar/ki960213/32-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/ki960213/63-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +51 -0
- package/lessons/woowacourse-racingcar/kimhm0728/100-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/kimhm0728/116-/353/246/254/355/214/251/355/204/260/353/247/201.md +54 -0
- package/lessons/woowacourse-racingcar/kkosang/105-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/kkosang/126-/353/246/254/355/214/251/355/204/260/353/247/201.md +53 -0
- package/lessons/woowacourse-racingcar/kmkim2689/123-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/kmkim2689/92-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/krrong/34-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +63 -0
- package/lessons/woowacourse-racingcar/m6z1/150-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/m6z1/156-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +40 -0
- package/lessons/woowacourse-racingcar/medAndro/153-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/moondev03/135-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +57 -0
- package/lessons/woowacourse-racingcar/moondev03/161-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/murjune/121-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/murjune/95-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/no1msh/43-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/no1msh/69-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/otter66/48-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/otter66/77-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +52 -0
- package/lessons/woowacourse-racingcar/oungsi2000/152-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +56 -0
- package/lessons/woowacourse-racingcar/oungsi2000/187-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/parkjiminnnn/143-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/parkjiminnnn/158-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/pingu244/38-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/pingu244/62-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/lessons/woowacourse-racingcar/re4rk/28-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +60 -0
- package/lessons/woowacourse-racingcar/re4rk/55-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/rhkrwngud445/42-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/rhkrwngud445/74-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +47 -0
- package/lessons/woowacourse-racingcar/rhthrhrl0/31-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +43 -0
- package/lessons/woowacourse-racingcar/rosemin928/138-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/rosemin928/171-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +38 -0
- package/lessons/woowacourse-racingcar/s6m1n/120-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +54 -0
- package/lessons/woowacourse-racingcar/s6m1n/91-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +62 -0
- package/lessons/woowacourse-racingcar/s9hn/53-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +44 -0
- package/lessons/woowacourse-racingcar/s9hn/78-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +43 -0
- package/lessons/woowacourse-racingcar/sh1mj1/107-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/sh1mj1/115-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +61 -0
- package/lessons/woowacourse-racingcar/songpink/119-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +51 -0
- package/lessons/woowacourse-racingcar/songpink/98-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +55 -0
- package/lessons/woowacourse-racingcar/sujin9/52-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +48 -0
- package/lessons/woowacourse-racingcar/sujin9/61-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +47 -0
- package/lessons/woowacourse-racingcar/tmdgh1592/47-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/tmdgh1592/64-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/tobae-time/151-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +51 -0
- package/lessons/woowacourse-racingcar/tobae-time/167-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +43 -0
- package/lessons/woowacourse-racingcar/whk06061/41-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +58 -0
- package/lessons/woowacourse-racingcar/wondroid-world/136-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +49 -0
- package/lessons/woowacourse-racingcar/wondroid-world/166-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +50 -0
- package/lessons/woowacourse-racingcar/yrsel/139-1/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +53 -0
- package/lessons/woowacourse-racingcar/yujamint/83-2/353/213/250/352/263/204-/354/236/220/353/217/231/354/260/250-/352/262/275/354/243/274.md +59 -0
- package/package.json +46 -0
- package/skills/oh-my-oop/SKILL.md +39 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# PR #53 — [블랙잭 2단계] 베리 미션
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@whk06061](https://github.com/whk06061)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-blackjack/pull/53
|
|
5
|
+
- **단계:** 2단계 (베팅 / 수익률 / 블랙잭 1.5배)
|
|
6
|
+
- **리뷰어:** @namjackson (잭슨)
|
|
7
|
+
- **라인 코멘트:** 12 스레드 / 20 코멘트 — *공통 코드 다른 PR* 패턴 (#41 핑구와 같은 reviewer + 같은 결의 진단)
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **`blackjackManager.playGame()` 단일 진입점 자가 반영** — 잭슨 진단 *"playParticipantsTurns 이후, playDealerTurn이 순차적으로 실행되는 부분은 blackjackManager에서 관리되어야하는 관심사가 아닐까요? Controller에서는 '블랙잭의 게임을 플레이'의 관심사만 있고, 어떻게 진행이 되는지는 blackjackManager에서 관리해보면 어떨까요?"* 후속 반영. PR #41 (핑구) 와 같은 결.
|
|
12
|
+
- **`GameResult` 가 *참여자 수익 + 딜러 수익 응집***
|
|
13
|
+
잭슨 진단 *"이름이 같은 플레이어가 있다면 버그가 있을거 같아요, calculateParticipantsEarningRate 와 calculateParticipantsProfit를 나눠서 관리될 필요가 있을까요? 게임 결과에는 승/패와 수익까지 모두 포함될거같아요!"* 후속 반영: *"GameResult 클래스가 참여자들의 수익과 딜러의 수익을 관리하도록 수정했습니다!"*. PR #132·#41 와 같은 결의 *결과 객체 응집*.
|
|
14
|
+
- **매직넘버 상수화 자가 반영** — 잭슨 진단 *"10라는 매직넘버는 무엇을 의미할까요? 가독성이 관리 측면에서, 상수로 관리해보면 어떨까요?"* + 학생: *"매직넘버를 상수화했습니다!"*.
|
|
15
|
+
- **`OutputView` 계산 로직 제거 자가 반영** — 잭슨 진단 *"계산 로직은 View에서 제거해주세요! gameResult를 통해, participantsProfit, dealerProfit을 관리해주면 어떨까요?"* 후속 반영. PR #41·#90·#88·#132 와 같은 결.
|
|
16
|
+
- **`blackjackManager.playGame()` 결과 반환 = 람다 → 반환 메시지 자가 학습** — 잭슨 진단 *"람다를 통해 결과를 표시하는 것과 결과를 리턴받아서 사용하는것과 어떤부분이 다를까요? `val result = blackjackManager.~~`. 결과를 리턴받아 뷰에게 전달해보아요!"* + 학생 자가 답변: *"결과를 리턴받아서 컨트롤러에서 처리를 해주는 것이 더 직관적인 것 같습니다..!"*. PR #41·#136 와 같은 결.
|
|
17
|
+
- **`SoftAssertion (assertAll)` 자가 학습** — 잭슨 진단 *"Soft Assertion, Hard Assertion 의 차이를 학습해보셔도 좋을거같아요! assertAll을 사용해보셔도 좋을거같아요!"* + 학생: *"하나의 테스트 함수에 여러 assertThat 구문이 있는 경우 SoftAssertion의 assertAll을 사용하도록 수정했습니다!"*. AssertJ 어휘 학습.
|
|
18
|
+
- **카드 부족 예외 자가 반영** — 잭슨 진단 *"View의 로직이 침투해있네요! deck의 카드가 없다면, 게임 진행이 되지않으니, 게임이 종료되어야하지 않을까요?"* 학생: *"발급할 카드가 없는 경우 예외를 던지도록 수정했습니다!"*. PR #108·#133·#136 (시아) 의 *카지노 무한 게임 메타포* 와 *반대 트레이드오프* — *베리는 예외 처리 선호*.
|
|
19
|
+
|
|
20
|
+
## 못한 점 (설계 관점)
|
|
21
|
+
|
|
22
|
+
### 1. `BlackjackManager.calculateParticipantsEarningRate + calculateParticipantsProfit` 두 단계 호출 → *GameResult 응집 자가 반영*
|
|
23
|
+
|
|
24
|
+
```kotlin
|
|
25
|
+
// 학생 초기 (추정)
|
|
26
|
+
val earningRate = blackjackManager.calculateParticipantsEarningRate(...)
|
|
27
|
+
val profit = blackjackManager.calculateParticipantsProfit(earningRate, ...)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
잭슨 진단: *"blackjackManager의 함수의 결과를 다시 blackjackManager의 함수로 호출하고 있어요! 객체에게 메시지만 전달하여, 해당 동작이 되도록 수정해보면 어떨까요?"*
|
|
31
|
+
|
|
32
|
+
학생 자가 반영: *"blackjackManager가 해당 로직을 담당하도록 수정했습니다!"*
|
|
33
|
+
|
|
34
|
+
→ **객체에게 메시지만 전달 = Tell-Don't-Ask 응집**. *호출자가 결과 빼서 다시 호출 = Ask 패턴*. *blackjackManager 단일 메시지*로 *내부 흐름 응집*. PR #41 와 같은 결.
|
|
35
|
+
|
|
36
|
+
### 2. `이름 중복 플레이어 = Map<String, *>` 버그 가능성
|
|
37
|
+
|
|
38
|
+
잭슨 진단: *"이름이 같은 플레이어가 있다면 버그가 있을거 같아요"*
|
|
39
|
+
|
|
40
|
+
→ **`Map<Player.name, ...>` 사용 시 같은 이름 = key 충돌**. *PR #88·#132·#133 와 같은 결의 *Player 중복 검증** (Players init require). *현재 코드는 Map key 사용 의심* — *Player 객체 자체를 key* 또는 *id 별도* 가 *안전*.
|
|
41
|
+
|
|
42
|
+
### 3. `EarningRate.BLACKJACK_WIN` vs `WIN` 중복 — PR #41 와 같은 결
|
|
43
|
+
|
|
44
|
+
잭슨 진단 (EarningRate.kt — 미해결): *"BLACKJACK_WIN과 WIN 모두 승리라는 결과 아닐까요? BLACKJACK으로 승리하는 로직을 처리하는 다른 방법은 없을까요? (고민만 해주셔도 좋아요!)"*
|
|
45
|
+
|
|
46
|
+
→ **`BLACKJACK_WIN` enum 멤버 별도 + WIN 중복 의미**. PR #41 와 같은 결. *enum 멤버 응집 vs 분리* 트레이드오프. *PR #132·#108·#136 의 별도 멤버 (BlackjackWin)* 와 *반대 트레이드오프* — 잭슨은 *결과는 WIN 하나 + 블랙잭 별도 체크*가 *명시* 봄.
|
|
47
|
+
|
|
48
|
+
### 4. `CardDeck` 테스트 외 미사용 + 테스트를 위한 코드 지양
|
|
49
|
+
|
|
50
|
+
잭슨 진단 (CardDeck.kt — 미해결): *"테스트 외에선 사용되지 않고 있어요, 테스트를 위한 코드는 지양하는것이 좋아요! 필요하다면, 다른 테스트 방법을 찾아보아요"*
|
|
51
|
+
|
|
52
|
+
→ **테스트 전용 코드 지양**. *생산 코드에 테스트만을 위한 메서드*는 *외부 인터페이스 노출 = 의도치 않은 사용 가능성*. *internal Kotlin 키워드* 또는 *전략 패턴* 활용. PR #41 (핑구) 의 *private fun 테스트 = 클래스 분리 신호* 와 같은 결.
|
|
53
|
+
|
|
54
|
+
### 5. `GameResult` 의 *Backing Properties 권고*
|
|
55
|
+
|
|
56
|
+
잭슨 진단 (GameResult.kt — 미해결): *"Backing Properties를 활용해보면 어떨까요? 프로퍼티 공식문서를 가볍게 읽어보셔도 좋을거같아요! https://kotlinlang.org/docs/properties.html#backing-properties"*
|
|
57
|
+
|
|
58
|
+
→ **Kotlin backing properties = `private val _x` + `val x: get() = _x.toList()` 패턴**. *외부 read-only + 내부 mutable*. PR #133·#132·#108·#85 와 같은 결. *Kotlin 어휘 학습 권고*.
|
|
59
|
+
|
|
60
|
+
### 6. `TestCardsGenerator2` 각 케이스마다 Generator — *재활용 부재*
|
|
61
|
+
|
|
62
|
+
잭슨 진단 (TestCardsGenerator2.kt — 미해결): *"각각의 케이스마다 Generator를 만들기보다, 생성자로 generate된 Cards를 입력받는 구조로 만들어보면 어떨까요? 재활용이 가능하고 관리가 좋을거 같아요! `class FakeCardsGenerator(val cards: Cards): CardsGenerator { override fun generate(): Cards = cards }`"*
|
|
63
|
+
|
|
64
|
+
→ **테스트 전략 = `Fake(data)` 주입 패턴**. *각 케이스마다 Generator 클래스 X*. *한 Fake 클래스 + 다른 데이터 인자*. PR #108·#133·#136 의 *ShuffleStrategy / EventListener* 와 같은 결의 *interface + 다양한 구현* 패턴.
|
|
65
|
+
|
|
66
|
+
## 리뷰어 의견 요지
|
|
67
|
+
|
|
68
|
+
- **객체에게 메시지만 전달 (Tell-Don't-Ask)** — *결과 빼서 다시 호출 X*.
|
|
69
|
+
- **게임 흐름 = Game 객체 응집** — *Controller = 게임을 플레이 의도*.
|
|
70
|
+
- **이름 중복 시 Map key 충돌 가능성** — *Player 객체 자체 key 또는 id*.
|
|
71
|
+
- **결과 객체에 승/패 + 수익 응집** — *별도 함수 분리 X*.
|
|
72
|
+
- **View 계산 로직 제거** — *전달 데이터만 그림*.
|
|
73
|
+
- **테스트를 위한 코드 지양 — 클래스 분리 신호** — *Internal vs Public*.
|
|
74
|
+
- **Backing Properties 학습 권고** — *Kotlin 어휘*.
|
|
75
|
+
- **테스트 전략 = Fake(data) 주입 + interface** — *재활용 + 다양한 구현*.
|
|
76
|
+
- **카드 부족 = 예외 vs 무한 게임 트레이드오프** — *베리는 예외 선호*.
|
|
77
|
+
- **람다 vs 반환 메시지 — 반환 메시지 선호**.
|
|
78
|
+
|
|
79
|
+
## 대표 인용
|
|
80
|
+
|
|
81
|
+
**잭슨 (메시지 응집, BlackjackController.kt):**
|
|
82
|
+
> blackjackManager의 함수의 결과를 다시 blackjackManager의 함수로 호출하고 있어요!
|
|
83
|
+
> 객체에게 메시지만 전달하여, 해당 동작이 되도록 수정해보면 어떨까요?
|
|
84
|
+
|
|
85
|
+
**잭슨 (Game 응집, BlackjackController.kt):**
|
|
86
|
+
> playParticipantsTurns 이후, playDealerTurn이 순차적으로 실행되는 부분은
|
|
87
|
+
> blackjackManager에서 관리되어야하는 관심사가 아닐까요?
|
|
88
|
+
> Controller에서는 "블랙잭의 게임을 플레이"의 관심사만 있고, 어떻게 진행이 되는지는 blackjackManager에서 관리해보면 어떨까요?
|
|
89
|
+
> `blackjackManager.playGame( ... )`
|
|
90
|
+
|
|
91
|
+
**잭슨 (이름 중복 + 결과 응집, BlackjackManager.kt):**
|
|
92
|
+
> 이름이 같은 플레이어가 있다면 버그가 있을거 같아요,
|
|
93
|
+
> calculateParticipantsEarningRate 와 calculateParticipantsProfit를 나눠서 관리될 필요가 있을까요?
|
|
94
|
+
> 게임 결과에는 승/패와 수익까지 모두 포함될거같아요!
|
|
95
|
+
|
|
96
|
+
**잭슨 (테스트 Fake 주입, TestCardsGenerator2.kt):**
|
|
97
|
+
> 각각의 케이스마다 Generator를 만들기보다,
|
|
98
|
+
> 생성자로 generate된 Cards를 입력받는 구조로 만들어보면 어떨까요?
|
|
99
|
+
> 재활용이 가능하고 관리가 좋을거 같아요!
|
|
100
|
+
> ```kotlin
|
|
101
|
+
> class FakeCardsGenerator(val cards: Cards): CardsGenerator {
|
|
102
|
+
> override fun generate(): Cards = cards
|
|
103
|
+
> }
|
|
104
|
+
> ```
|
|
105
|
+
|
|
106
|
+
## 얻은 교훈
|
|
107
|
+
|
|
108
|
+
1. ***메시지 응집 = 결과 빼서 다시 호출 X***. *blackjackManager.f() → result → blackjackManager.g(result)* 흐름은 *Ask*. *blackjackManager.combined() 단일 메시지*가 *Tell-Don't-Ask*. PR #41·#136·#152 와 같은 결.
|
|
109
|
+
|
|
110
|
+
2. ***Game 흐름 = Game 객체 책임, Controller = 게임 플레이 의도***. *Controller 가 게임 진행 순서 결정 = Game 룰 누수*. PR #41·#131·#132·#136·#152 와 같은 결.
|
|
111
|
+
|
|
112
|
+
3. ***Map<name, *>` 이름 중복 = key 충돌 버그***. *Player 객체 자체 key 또는 id 분리*. PR #88·#132·#133 와 같은 결의 *Players 중복 검증*.
|
|
113
|
+
|
|
114
|
+
4. ***결과 객체에 승/패 + 수익 응집 = 별도 함수 분리 X***. *GameResult 가 둘 다 보유* 가 *책임 응집*. PR #132·#41·#90 와 같은 결.
|
|
115
|
+
|
|
116
|
+
5. ***테스트를 위한 코드 지양 — 클래스 분리 신호***. *생산 코드에 테스트 메서드 = 외부 인터페이스 노출*. *Kotlin internal* 또는 *전략 패턴*. PR #41 (핑구) 의 *private fun 테스트 = 클래스 분리 신호* 와 같은 결.
|
|
117
|
+
|
|
118
|
+
6. ***Backing Properties = Kotlin 어휘 (`private val _x + val x: get() = _x.toList()`)*** — *외부 read-only + 내부 mutable 캡슐화*. PR #133·#132·#108·#85 와 같은 결.
|
|
119
|
+
|
|
120
|
+
7. ***테스트 전략 = Fake(data) 주입 + interface***. *각 케이스마다 Generator X*. *한 Fake 클래스 + 다른 데이터 인자*. PR #108·#133·#136 의 *ShuffleStrategy / EventListener* 와 같은 결.
|
|
121
|
+
|
|
122
|
+
8. ***카드 부족 = 예외 vs 무한 게임 트레이드오프***. *베리 = 예외 선호 (도메인 invariant 강제)*. *시아 PR #108·#133·#136 = 카지노 무한 게임 메타포 (자동 새 덱)*. *둘 다 합리* — *도메인 메타포 선택 의존*.
|
|
123
|
+
|
|
124
|
+
9. ***`SoftAssertion (assertAll) = AssertJ 어휘***. *Hard Assertion 첫 실패 → 멈춤* vs *Soft = 모든 어설션 실행 + 결과 보고*. *디버깅 친화*. PR #90·#133·#136 와 같은 결.
|
|
125
|
+
|
|
126
|
+
10. ***View 계산 로직 = View 책임 누수***. *View = 전달 데이터만 그림*. PR #132·#90·#88·#41 와 같은 결.
|
|
127
|
+
|
|
128
|
+
11. ***`EarningRate.BLACKJACK_WIN` 별도 멤버 vs `WIN + 블랙잭 분기`*** — PR #41 와 같은 결. *enum 멤버 응집 vs 분리* 트레이드오프. *잭슨 = 결과 WIN 하나 + 블랙잭 별도 체크 선호*. PR #132·#108·#136 의 *별도 멤버* 와 *반대*.
|
|
129
|
+
|
|
130
|
+
12. ***학생 100% 후속 반영 + 모든 진단 즉시 반영 = 학습 가시화***. *베리의 모든 코멘트 후속 반영* (PR #88 (채드) 와 같은 결). *짧은 PR + 완전 반영* 모범.
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
# PR #124 — [블랙잭 1단계] 모찌 미션
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@wondroid-world](https://github.com/wondroid-world)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-blackjack/pull/124
|
|
5
|
+
- **단계:** 1단계
|
|
6
|
+
- **리뷰어:** @laco-dev (페로로)
|
|
7
|
+
- **라인 코멘트:** 30 스레드 / 45 코멘트 (리뷰어 다수 / 리뷰이 자가 답변·커밋 해시 다수)
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **PR 본문 자가 토론 — 메시징 vs 화면 포맷 / 확장성 범위** — 학생이 *"객체는 메시징을 던진다"*를 두고 처음에는 *"상대가 원하는 String 포맷으로 주는 것"*이라 생각했다가 *"객체는 자율적으로 행동한다 → 상태 메시징"*으로 자가 수정. 페로로 의문 → 자가 토론 → 자가 결론 → 자가 답변에 *커밋 해시 첨부* 패턴이 PR 전체에 일관됨.
|
|
12
|
+
- **`Card.isAce()` 자기 정보 노출 메시지로 줄임** — `isDenominationAce(card: Card)` (자기 자신을 파라미터로 받는 모순) → 후속 반영 `isAce()` 으로 변경. *Tell-Don't-Ask*의 가장 단순한 형태 학습.
|
|
13
|
+
- **`Cards`/`CardsStatus` 책임 이전 후속 반영** — 처음에는 *`Cards`의 상태를 외부 함수가 결정* → 후속에서 *"카드의 상태는 카드 스스로가 판단한다"* 로 자가 깨달음. `Cards.getStatus(): CardsStatus`로 메시지 패턴 통일. 학생 자가 인용: *"카드의 상태는 카드가 가지는 속성 중 일부라고 판단을 하였습니다."*
|
|
14
|
+
- **블랙잭 룰 정확성 자가 학습 — *"카드가 2장일 때 합계가 21점"*** — 학생이 처음에는 *"첫번째 턴"*으로 접근. 페로로 교정 후 *"페로로처럼 생각하면, 더 객체 지향적인 코드가 되겠어요...(감동받았습니다)"* 학습 가시화. 후속 반영 커밋 `eff2d3e`.
|
|
15
|
+
- **Ace 보너스 점수 단일 +10 정착** — `Cards.calculateScore`에 *"카드뭉치에 에이스가 있고 +10 해도 ≤21이면 +10"* 단일 규칙. PR #128·#135·#114 와 같은 *Ace 1 기본 + 단일 +10* 베스트 결.
|
|
16
|
+
- **`Participant` 추상 클래스 추출 — open class 안티패턴 회피** — 페로로의 *"#1 Participant ⨽Player ⨽Dealer / #2 Player ⨽Dealer 중 어떤 관계?"* 힌트에 대해 학생이 *open/abstract/interface 차이*를 정리한 후 *Participant 추상화*를 선택. `lateinit var result: GameResult` 자체는 살아있으나 구조 결정의 *근거가 명시*됨.
|
|
17
|
+
- **PlayerBehavior enum 의 UI 의존(`Y`/`N`) 제거 후속 반영** — 페로로가 *"화면이 바뀌면 Y/N 타이핑이 아니라 버튼 클릭이 된다"* 지적. 학생이 `answer` 필드 삭제 + Y/N 매핑을 `InputView`로 이전. 후속 반영 커밋 `a67c225`.
|
|
18
|
+
- **`enum.koreanName`·`Denomination.title` 삭제 후속 반영** — 8개 PR 연속(#28·#78·#112·#125·#128·#135·#116·#124) 등장하는 *enum의 UI value 안티패턴*을 *PR 내 후속 커밋*으로 해소한 사례. 학생 자가 인용: *"이 블랙잭 게임에서 중요한 게 카드 모양이 뭐가 있는 지만 중요하지, 굳이 koreanName이라는 view에서 쓰는 내용을 정의하지 않아야겠다."*
|
|
19
|
+
|
|
20
|
+
## 못한 점 (설계 관점)
|
|
21
|
+
|
|
22
|
+
### 1. `CardShape.koreanName` / `Denomination.title` / `PlayerBehavior.answer("Y"/"N")` — **enum의 UI value 9연속**
|
|
23
|
+
|
|
24
|
+
초기 코드:
|
|
25
|
+
|
|
26
|
+
```kotlin
|
|
27
|
+
enum class CardShape(val koreanName: String) {
|
|
28
|
+
DIAMOND("다이아몬드"), SPADE("스페이드"), HEART("하트"), CLOVER("클로버"),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
enum class Denomination(val title: String, val number: Int) {
|
|
32
|
+
ACE("A", 0), TWO("2", 2), ...
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// PlayerBehavior (초기)
|
|
36
|
+
enum class PlayerBehavior(val answer: String) {
|
|
37
|
+
HIT("Y"), STAY("N"),
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
페로로(CardShape): *"마찬가지로 카드 모형이 위와 같이 출력될 것이라는 것을 결정하는 것은 도메인이 아닌 UI 의 관심사입니다. 😓"*
|
|
42
|
+
|
|
43
|
+
페로로(Denomination/Card.combine — `getCardsInfomation()` 으로 String 반환): *"어떻게 출력할 지 결정하는 것은 Card로부터 필요한 기능이 아니기 때문인데요. 가령 `2하트` 라고 출력하는 것을 화면에 따라 `❤️2` 이렇게 출력할지도 모릅니다. 혹은 그림으로 출력할수도 있죠."*
|
|
44
|
+
|
|
45
|
+
페로로(PlayerBehavior.answer): *"플레이어가 어떻게 행동할지 또한, `Y` `N`으로 결정되는 것이 아닌 Hit Stay로 결정되어야 합니다. 만약 화면에서 진행하는 게임이었다면 유저는 `Y`라고 타이핑 하지 않고 버튼을 클릭합니다. **도메인 모델이 UI 패키지에 의존만 하지 않으면 괜찮다는 뜻이 아니에요. UI와 관심사를 나누는게 근본적인 목적입니다.**"*
|
|
46
|
+
|
|
47
|
+
학생 자가 답변(`koreanName` 삭제 커밋 `71ed45f`): *"아! 그럼 페로로의 의미는 카드의 정보만 주면 되고 그것을 어떻게 사용할지는 view의 관심사라고 말하는 걸까요? ... 이 블랙잭 게임에서 중요한 게 카드 모양이 뭐가 있는 지만 중요하지, 굳이 koreanName이라는 view에서 쓰는 내용을 정의하지 않아야겠다는 생각이 듭니다. ... 재사용성을 위해서는 관심사 분리가 정말 중요한 부분이네요!"*
|
|
48
|
+
|
|
49
|
+
→ **PR #28·#78·#112·#125·#128·#135·#116·#24 와 같은 결**. *UI 의존성을 "import 의존"으로 좁게 해석*하는 안티패턴. 페로로의 *"의존만 하지 않으면 괜찮다는 뜻이 아니에요"* 는 이 안티패턴의 핵심 진단. 후속 반영(`koreanName` 삭제 / `title` 삭제 / `answer` 삭제) 모두 PR 내에서 일어남. **MCP 룰 후보 최강 — `enum-with-ui-value`**.
|
|
50
|
+
|
|
51
|
+
### 2. `Card.copy()` 딥카피 강박 — 불변 객체에 대한 무용 방어
|
|
52
|
+
|
|
53
|
+
```kotlin
|
|
54
|
+
class Cards(value: List<Card>) {
|
|
55
|
+
private val _value: MutableList<Card> = value.toMutableList()
|
|
56
|
+
val value: List<Card> get() = _value.map { card -> card.copy() } // ⚠ 매 호출 deep copy
|
|
57
|
+
...
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
페로로 (Cards 의 첫 의문): *"`card.copy()` 라는 코드는 왜 필요한가요?"*
|
|
62
|
+
|
|
63
|
+
학생: *"일차적으로 mutable 주소값을 노출하지 않기위해서, 딥카피를 해서, 값을 전달하고 싶었습니다!"*
|
|
64
|
+
|
|
65
|
+
페로로 후속(이번 PR 미해결): *"Card가 이미 불변 객체인데 노출이 되어서 문제가 될 점이 있을까요?"*
|
|
66
|
+
|
|
67
|
+
→ **불변 객체의 참조 노출은 안전하다는 사실의 미인지**. *공유 가변 상태를 막는 것*과 *불변 객체의 참조 누수*는 다른 문제. 페로로의 두 단계 의문 (왜 필요? → 불변인데 왜 보호?)이 학생의 *방어 본능 vs 실제 필요* 를 가르는 좋은 교육 순서.
|
|
68
|
+
|
|
69
|
+
또한 `value` 게터가 *매 호출 N장 카드 모두 새 객체*를 만드는 비용도 따라온다. *원본 List 참조를 `toList()` 로 immutable view 변환* 정도가 자연. *`val value: List<Card> get() = _value.toList()`* 면 충분.
|
|
70
|
+
|
|
71
|
+
### 3. `Cards.getStatus(): CardsStatus` — *상태 enum vs 자기 상태 메시지* 의 중간 단계
|
|
72
|
+
|
|
73
|
+
```kotlin
|
|
74
|
+
enum class CardsStatus { BLACKJACK, BUST, NONE }
|
|
75
|
+
|
|
76
|
+
class Cards(...) {
|
|
77
|
+
fun getStatus(): CardsStatus {
|
|
78
|
+
val cardsScore = calculateScore()
|
|
79
|
+
if (_value.size == 2 && cardsScore == 21) return CardsStatus.BLACKJACK
|
|
80
|
+
if (cardsScore > 21) return CardsStatus.BUST
|
|
81
|
+
return CardsStatus.NONE
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
페로로 (초기 `CardsStatus.of(cards: Cards)` 같은 외부 함수에 대한 의문): *"카드의 상태를 결정하는 것은 카드가 스스로 해야 하지 않을까요? 만약 카드 상태를 결정하는데 필요한게 늘어날수록 이 함수도 비대해지게 됩니다. 아래 시그니처와 비교하면 어떤가요? `class Cards { fun getStatus(): CardsStatus { ... } }`"*
|
|
87
|
+
|
|
88
|
+
→ **첫 책임 이전은 성공 — 카드가 자기 상태 판단**. 다만 *상태 enum 반환*은 여전히 *호출자에게 분기를 떠넘기는 신호*. 사용처 (`Controller.executePlayerGameLogic`) 를 보면:
|
|
89
|
+
|
|
90
|
+
```kotlin
|
|
91
|
+
while (player.cards.getStatus() != CardsStatus.BUST) { ... }
|
|
92
|
+
if (player.cards.getStatus() == CardsStatus.BLACKJACK) { ... }
|
|
93
|
+
if (dealer.cards.getStatus() == CardsStatus.BUST) { ... }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`isBust()` / `isBlackjack()` / `canDraw()` 같은 *부울 메시지*면 호출자가 *enum 매칭*을 안 해도 됨. *enum 반환 자체*가 안티패턴은 아니지만, *모든 사용처가 단일 상태 비교*만 한다면 *부울 메시지*가 더 자연 (페로로 후속 `canDraw()` 코멘트와 정합).
|
|
97
|
+
|
|
98
|
+
페로로 (1단계 미해결 코멘트): *"사실 Hit는 상태라기 보다는 더 뽑겠다고 행동한 액션에 가까워요. 그런 의미에서 본다면 딜러가 카드를 더 뽑을 수 있는지 여부를 뜻하는 `isHit()` 대신 `canDraw()`와 같이 접근하면 플레이어도 동일한 역할을 부여할 수 있습니다."*
|
|
99
|
+
|
|
100
|
+
→ ***Hit는 상태가 아니라 액션*** 진단. PR #112·#33·#119 와 같은 결 (`canHit()`/`canDraw()` vs `isHit()`).
|
|
101
|
+
|
|
102
|
+
### 4. `GameResult.of(standardScore, comparedScore)` — *점수 비교만으로* 승부 결정 + Bust/블랙잭 룰 무시
|
|
103
|
+
|
|
104
|
+
```kotlin
|
|
105
|
+
enum class GameResult {
|
|
106
|
+
PUSH, WIN, LOSE;
|
|
107
|
+
companion object {
|
|
108
|
+
fun of(standardScore: Int, comparedScore: Int): GameResult {
|
|
109
|
+
when {
|
|
110
|
+
standardScore == comparedScore -> return PUSH
|
|
111
|
+
standardScore > comparedScore -> return WIN
|
|
112
|
+
}
|
|
113
|
+
return LOSE
|
|
114
|
+
}
|
|
115
|
+
fun reversed(result: GameResult): GameResult = when (result) {
|
|
116
|
+
PUSH -> PUSH; WIN -> LOSE; LOSE -> WIN
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
페로로: *"블랙잭 규칙으로 보면, 21점이 넘는다거나 하면 무조건 패배가 됩니다. 참가자 입장에서 승부가 벌어지고 있는데 단순히 점수만으로 추가로 결정하기에는 로직이 분산되어 있는 느낌이 들기도 합니다. 가령 점수가 높더라도 질 수도 있으니까요."*
|
|
123
|
+
|
|
124
|
+
→ **블랙잭 룰 정확성 + 책임 분산 동시 진단**. *점수 비교 = 자체 도메인 메시지*가 아니라 *외부 enum의 `of(score, score)` 정적 호출*. PR #112·#114·#79·#125 와 같은 결 (*승부 = 참가자 메시지로 일반화*).
|
|
125
|
+
|
|
126
|
+
페로로(추가): *"플레이어가 딜러 결과를 통해 내 결과를 업데이트 한다는 점이 꽤나 어색하게 느껴지고, 재사용이 어렵습니다. 승부를 벌이는 것은 참가자와 참가자간의 승부로 일반화를 할 수 있으려나요? 1. 딜러 vs 플레이어 / 2. 플레이어 vs 플레이어 / 3. 참가자 vs 참가자"*
|
|
127
|
+
|
|
128
|
+
→ **승부 일반화 = `Participant.compete(other: Participant): GameResult`**. *딜러 vs 플레이어*만 다루는 1단계의 한계가 *Dealer 의존*을 만든다. *Participant끼리의 승부 메시지*면 *플레이어 vs 플레이어*도 자연.
|
|
129
|
+
|
|
130
|
+
또한 `Bust 양측 처리`가 빠짐 — 학생이 미해결 그룹에서 *"블랙잭 구조를 아예 손을 보고 있어요"* 라고 다음 PR로 미룸. 1단계 종료 시점에서는 *21 초과 → 무조건 패배*가 점수 비교에 묻혀 있음.
|
|
131
|
+
|
|
132
|
+
### 5. `Player.lateinit var result: GameResult` + `updateResult(dealerGameResult)` — 호출 순서 invariant
|
|
133
|
+
|
|
134
|
+
```kotlin
|
|
135
|
+
class Player(name: String, cards: Cards = Cards(emptyList())) : Participant(name, cards) {
|
|
136
|
+
lateinit var result: GameResult
|
|
137
|
+
|
|
138
|
+
fun updateResult(dealerGameResult: GameResult) {
|
|
139
|
+
result = GameResult.reversed(dealerGameResult)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
페로로 (Dealer.kt 23 — 미해결): *"아까 적었던 의견인데 결국 승부를 한다는 행위가 게임 결과를 반환하기만 하면 되는데 굳이 상태까지 업데이트 하고 있을 이유가 있나? 싶네요."*
|
|
145
|
+
|
|
146
|
+
→ **`lateinit var` 안티패턴**. PR #28·#92·#65·#10 (`lateinit var callback`) 와 같은 결. *호출 전에 `result` 접근하면 `UninitializedPropertyAccessException`*. *결과를 반환 메시지로 받으면* `lateinit var`을 들이지 않아도 됨.
|
|
147
|
+
|
|
148
|
+
또한 `updateResult(dealerGameResult)` 는 *딜러의 결과로 자기 결과를 도출*. `GameResult.reversed`라는 *역변환 함수*가 *플레이어가 딜러에 종속*되었다는 신호. *참가자 vs 참가자 메시지*면 *각자 자기 결과를 직접 받음*.
|
|
149
|
+
|
|
150
|
+
### 6. `Dealer._results: MutableMap<GameResult, Int>` — *집계가 Dealer 책임?*
|
|
151
|
+
|
|
152
|
+
```kotlin
|
|
153
|
+
class Dealer(...) : Participant(...) {
|
|
154
|
+
private var _results: MutableMap<GameResult, Int> = mutableMapOf()
|
|
155
|
+
val results: Map<GameResult, Int> get() = _results.toMap()
|
|
156
|
+
|
|
157
|
+
fun updateResult(playerScore: Int): GameResult {
|
|
158
|
+
val dealerScore: Int = cards.calculateScore()
|
|
159
|
+
val result: GameResult = GameResult.of(dealerScore, playerScore)
|
|
160
|
+
_results[result] = _results.getOrDefault(result, 0) + 1
|
|
161
|
+
return result
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
→ **Dealer가 *집계 카운터*를 보유**. *딜러의 책임*인가, *게임 결과 집계자*인가? 게임 결과 집계는 *Game/Match 같은 진행 객체*나 *Results 일급 컬렉션*이 자연. *Dealer의 isHit/카드 관리 책임* 과 *결과 집계 책임* 이 한 클래스에 응집되어 있음 (god-object 변형).
|
|
167
|
+
|
|
168
|
+
또한 `updateResult(playerScore: Int)` 가 *`Int` 점수*를 받음 — *플레이어를 받으면 일반화*가 자연. *`updateResult(player: Player)` → 내부에서 `player.cards.calculateScore()`* 가 메시지에 더 가까움.
|
|
169
|
+
|
|
170
|
+
### 7. `BlackjackController` — *게임 비즈니스 로직 처리 = god-object*
|
|
171
|
+
|
|
172
|
+
```kotlin
|
|
173
|
+
class BlackjackController(...) {
|
|
174
|
+
private val cardDeck = CardDeck(CardsMaker.CARDS)
|
|
175
|
+
|
|
176
|
+
fun run() {
|
|
177
|
+
outputView.printStartMessage()
|
|
178
|
+
val players: Players = inputView.readPlayers()
|
|
179
|
+
val dealer = Dealer()
|
|
180
|
+
getCards(players, dealer)
|
|
181
|
+
playGames(players, dealer)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private fun getCards(players: Players, dealer: Dealer) { ... }
|
|
185
|
+
private fun playGames(players: Players, dealer: Dealer) {
|
|
186
|
+
if (dealer.cards.getStatus() == CardsStatus.BLACKJACK) { ... }
|
|
187
|
+
players.value.forEach { player -> playGame(player, dealer) }
|
|
188
|
+
displayResult(players, dealer)
|
|
189
|
+
}
|
|
190
|
+
private fun executePlayerGameLogic(player: Player) {
|
|
191
|
+
while (player.cards.getStatus() != CardsStatus.BUST) {
|
|
192
|
+
outputView.printPlayerBehaviorGuide(player)
|
|
193
|
+
val playerBehavior: PlayerBehavior = inputView.readPlayerBehavior()
|
|
194
|
+
if (executePlayerBehavior(playerBehavior, player)) break
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
private fun executeDealerGameLogic(dealer: Dealer) {
|
|
198
|
+
while (dealer.isHit()) {
|
|
199
|
+
dealer.addCard(cardDeck.pickCard())
|
|
200
|
+
outputView.printDealerGettingCard()
|
|
201
|
+
if (isDealerBust(dealer)) break
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ... isPlayerBust, isAllPlayerBlackjack, updateGameResult ...
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
페로로(BlackjackController.kt 27 — 미해결): *"전반적으로 컨트롤러에서 게임에 대한 비즈니스로직을 처리하고 있어요. 만약 지금 구조에서는 컨트롤러 없이 게임을 진행할 수 있을까요? 꽤나 어려울 수 있는 주제이지만 게임을 진행하기 위한 도메인 모델을 고려해볼 수 있겠습니다."*
|
|
209
|
+
|
|
210
|
+
→ **god-object Controller**. PR #28·#78·#79·#125·#114·#92·#10·#33 등 *Controller 절차적 명령 + 게임 비즈니스 처리*의 거대 클래스. 페로로의 *"컨트롤러 없이 게임을 진행할 수 있을까요?"* 는 *게임 진행 = 도메인 책임*이라는 디자인 시각.
|
|
211
|
+
|
|
212
|
+
PR #108 (시아) 에서 같은 진단에 학생이 `BlackjackEngine` 객체를 도입한 사례 비교 가능. **`controller-as-game-logic` MCP 룰 후보 강화**.
|
|
213
|
+
|
|
214
|
+
### 8. `getCards` / `getCardsToPlayer` / `getCardsToDealer` — *getXXX 가 상태 변경*
|
|
215
|
+
|
|
216
|
+
```kotlin
|
|
217
|
+
private fun getCards(players: Players, dealer: Dealer) {
|
|
218
|
+
repeat(2) {
|
|
219
|
+
getCardsToPlayer(players.value)
|
|
220
|
+
getCardsToDealer(dealer)
|
|
221
|
+
}
|
|
222
|
+
outputView.printPlayersCards(dealer, players.value)
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
페로로: *"생성자로 준비한 Cards를 테스트에서만 쓰이다보니, 처음 플레이어와 딜러를 준비 할 때 2장의 카드를 같이 만들어서 활용할 수 있지 않을까요? 또한 이 함수이름이 getXXX 형태인데 반해 반환도 하지 않고 상태를 바꾸기 때문에 함수 이름이 적절하지 않습니다."*
|
|
227
|
+
|
|
228
|
+
→ **getXXX naming 안티패턴**. `getCards` 는 *카드를 받아오는* 메시지 이름. *Unit 반환 + 상태 변경*은 `dealCards`/`drawInitialCards` 같은 동사가 자연. PR #112·#10·#119 와 같은 결 (`takeCard`/`runPhase` 등 *상태 변경 + 명사형 이름*).
|
|
229
|
+
|
|
230
|
+
또한 *Player/Dealer 생성 시점에 2장을 동시에 받지 않고* 빈 `Cards(emptyList())`로 시작 → `getCardsToPlayer` 반복 → `addCard` 누적. *lotto `empty-object-external-fill`* 안티패턴의 변형 (참가자가 빈 손으로 만들어지고 외부가 채움).
|
|
231
|
+
|
|
232
|
+
### 9. `executePlayerBehavior(...): Boolean` — *Boolean 반환의 의미 모호*
|
|
233
|
+
|
|
234
|
+
```kotlin
|
|
235
|
+
private fun executePlayerBehavior(playerBehavior: PlayerBehavior, player: Player): Boolean {
|
|
236
|
+
when (playerBehavior) {
|
|
237
|
+
PlayerBehavior.HIT -> {
|
|
238
|
+
player.addCard(cardDeck.pickCard())
|
|
239
|
+
outputView.printPlayerCard(player)
|
|
240
|
+
if (isPlayerBust(player)) return true
|
|
241
|
+
}
|
|
242
|
+
PlayerBehavior.STAY -> return true
|
|
243
|
+
}
|
|
244
|
+
return false
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
페로로: *"execute가 Boolean을 반환하면 어떤 값인지 사용하는 입장에서 예측이 될까요?"*
|
|
249
|
+
|
|
250
|
+
학생 자가 답변: *"맞아요 페로로 이부분은 함수명에서도 유츄가 안되어서 판단하기 힘들거 같아요!"*
|
|
251
|
+
|
|
252
|
+
→ **`Boolean` 반환의 의미 부재**. *`true` = 루프 종료* 인지 *`true` = 성공* 인지 호출자가 모름. *enum 반환*이나 *`isFinished` / `shouldStop` 같은 명시적 부울 이름*이 자연. PR #20·#65 와 같은 결 (*반환 부울의 의미 모호*).
|
|
253
|
+
|
|
254
|
+
### 10. `isPlayerBust` — *Bust 판정 + 출력* 2 가지 일
|
|
255
|
+
|
|
256
|
+
```kotlin
|
|
257
|
+
private fun isPlayerBust(player: Player): Boolean {
|
|
258
|
+
if (player.cards.getStatus() == CardsStatus.BUST) {
|
|
259
|
+
outputView.printBust(player) // ⚠ 판정 함수가 출력
|
|
260
|
+
return true
|
|
261
|
+
}
|
|
262
|
+
return false
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
페로로: *"플레이어가 버스트인지 확인하는데 출력까지 2가지 일을 하고 있지 않을까요?"*
|
|
267
|
+
|
|
268
|
+
→ **`is*()` 가 부수효과를 가짐**. PR #92·#125·#33 (`isACE`/`isBust`가 출력 함수 호출) 와 같은 결. *부울 메시지는 부수효과를 가지지 않아야* 호출자가 *분기 안에서 안심하고 다른 메시지*를 보낼 수 있음.
|
|
269
|
+
|
|
270
|
+
### 11. `Dealer.isHit()` — *딜러 hit 판단을 Dealer가 자기 정보로* (좋은 방향이지만 일관성 신호 누락)
|
|
271
|
+
|
|
272
|
+
```kotlin
|
|
273
|
+
fun isHit(): Boolean {
|
|
274
|
+
val dealerScore = cards.calculateScore()
|
|
275
|
+
return dealerScore <= 16
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
페로로 (PlayerBehavior 미해결 코멘트): *"한편으로는 딜러 점수가 16점보다 낮으면 HIT라는 결과는 플레이어 행동이 결정할 책임일까요? 아니면 딜러가 스스로 판단할 책임일까요?"*
|
|
280
|
+
|
|
281
|
+
학생 자가 답변 (커밋 `dbb7ad8`): *"페로로, 저는 enum class를 사용하는 이유가 값을 나열하기 위해서 사용한다고 생각해요. 여기서는 블랙잭의 규칙을 나열하기 위해서, enum class를 사용했어요. 그래서, 경기 규칙이 딜러의 상태를 변화시켜야 한다고 생각했습니다. 그런데, 저의 현재 domain들을 생각해봤을 때, 딜러는 player를 상속받고 있습니다. 그 말은 딜러도 player처럼 hit or stay를 할것인지 자유롭게 판단하는 객체라는 사실입니다. 이 구조를 바탕으로 생각 했을 때, 딜러가 hit or stay를 하는 것은 딜러의 자율성(책임)에 맡겨야한다고 생각합니다."*
|
|
282
|
+
|
|
283
|
+
→ **딜러 자율성 = 딜러가 hit 판단**. *Player.isHit* 도 *플레이어가 hit 판단* 인데 *결정 트리거는 외부 입력*이라는 차이가 사라짐. 페로로의 `canDraw()` 후속 코멘트는 이 *Player/Dealer 일관 메시지*를 위한 이름 통일 제안.
|
|
284
|
+
|
|
285
|
+
또한 *16 매직 넘버*가 `isHit` 안에 내장. *상수화 + "딜러는 16 이하면 hit" 룰 명시*가 자연. PR #128·#135·#92·#114 와 같은 결.
|
|
286
|
+
|
|
287
|
+
### 12. `Player.init { require(name != "딜러") }` — *Dealer 이름 모순*의 우회
|
|
288
|
+
|
|
289
|
+
```kotlin
|
|
290
|
+
class Player(name: String, cards: Cards = Cards(emptyList())) : Participant(name, cards) {
|
|
291
|
+
init {
|
|
292
|
+
require(name != "딜러") { "플레이어는 딜러라는 이름을 가질 수 없습니다." }
|
|
293
|
+
require(name.length in 1..5) { "플레이어는 1에서 5사이 길이의 이름만 가질 수 있습니다." }
|
|
294
|
+
}
|
|
295
|
+
...
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
페로로 (미해결): *"한편 지금 상속 구조라면 딜러 == 플레이어인데 플레이어가 딜러 이름을 가질 수 없다는 점이 매우 모순적으로 느껴지기는 합니다..."*
|
|
300
|
+
|
|
301
|
+
→ **`abstract Participant` 구조 자체는 적절**. 다만 *Player에서 `"딜러"` 이름 require*는 *Participant 차원에서 처리하지 못한 신호*. *Dealer 이름이 상수 `"딜러"`로 고정*되었다면, *Player 검증을 Dealer.name 참조*가 아닌 *Dealer 이름 상수*와 비교가 자연. 더 근본적으로는 *Dealer는 이름 외부 입력을 받지 않는다*는 사실에서 *Player.require("딜러")* 자체가 *외부 String 우회 방어*일 수 있음.
|
|
302
|
+
|
|
303
|
+
### 13. `Players.findBlackjackPlayer()` — *컬렉션의 상태 필터 = 호출자에 분기 떠넘기기*
|
|
304
|
+
|
|
305
|
+
```kotlin
|
|
306
|
+
class Players(val value: List<Player>) {
|
|
307
|
+
fun findBlackjackPlayer(): List<Player> = value.filter { player ->
|
|
308
|
+
player.cards.getStatus() == CardsStatus.BLACKJACK
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
페로로 (미해결): *"결과를 출력하는 과정에서. 플레이어의 상태가 블랙잭인지를 판단하도록 할 수 있지 않나요? 블랙잭 플레이어들을 찾는 과정이 필요할지 궁금해서요. 이 또한 플레이어에게 메시지를 전달하도록 만들어도 되겠구요"*
|
|
314
|
+
|
|
315
|
+
→ **외부 필터 vs 자기 상태 메시지**. *블랙잭 플레이어 *목록* 자체가 필요한 시점*은 *딜러 블랙잭 + 동시 비교* 정도. *각 플레이어가 자기 결과를 알려주는 흐름*이면 *별도 필터*가 불필요. 컬렉션 일급화는 좋지만 *상태 필터링 책임*이 일급 컬렉션에 모이면 *각 Player의 자율성*을 우회.
|
|
316
|
+
|
|
317
|
+
### 14. `OutputView` — *최초 카드 공개 규칙 (딜러 1장 / 플레이어 2장)* 도메인 미반영
|
|
318
|
+
|
|
319
|
+
```kotlin
|
|
320
|
+
// OutputView 의 출력 코드 (Controller 가 호출)
|
|
321
|
+
// 딜러 1장 / 플레이어 2장 공개 규칙이 OutputView 내부 분기로만 표현됨
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
페로로 (OutputView.kt 30 — 미해결): *"최초에 딜러는 1장의 카드를, 플레이어는 2장의 카드를 공개한다 라는 규칙이 있을거에요. 이 규칙은 명확한 비즈니스 로직인데 어떻게 구현할지 추상화 관점에서 접근해보면 도움이 될거에요"*
|
|
325
|
+
|
|
326
|
+
→ **OutputView 가 *공개 규칙*을 분기로 표현 = 도메인 규칙 누수**. *Participant.openCards(): Cards* 같은 *공개 카드 메시지*를 *Player/Dealer가 각각 구현*하면 *OutputView는 받은 카드를 그대로 출력*. 도메인 규칙(*딜러 1장, 플레이어 2장*)이 *코드 분기*가 아닌 *객체 메시지*로 표현됨.
|
|
327
|
+
|
|
328
|
+
### 15. `BlackjackController.executePlayerGameLogic` — *Bust 무한 루프 가능성 신호*
|
|
329
|
+
|
|
330
|
+
```kotlin
|
|
331
|
+
private fun executePlayerGameLogic(player: Player) {
|
|
332
|
+
while (player.cards.getStatus() != CardsStatus.BUST) {
|
|
333
|
+
outputView.printPlayerBehaviorGuide(player)
|
|
334
|
+
val playerBehavior: PlayerBehavior = inputView.readPlayerBehavior()
|
|
335
|
+
if (executePlayerBehavior(playerBehavior, player)) break
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
→ **Player가 *블랙잭(21)*이거나 *21 미만 STAY*가 아니면 무한 루프 가능성**. 정상 흐름에서는 STAY 입력으로 `executePlayerBehavior` 가 `true` 반환 → break. 다만 *블랙잭 상태(2장 21)* 라도 *Bust가 아니므로* 루프에 들어옴. `executePlayerGameLogic` 진입 전에 `isPlayerBlackjack` 분기로 *블랙잭은 별도 처리* 한 결과 *블랙잭 플레이어는 진입 자체 안 함*. 흐름 분기가 *복수 레이어로 흩어져* 한눈에 안 보임.
|
|
341
|
+
|
|
342
|
+
페로로의 *"게임을 진행하기 위한 도메인 모델"* 코멘트와 정합 — *Player.canDraw() / Player.takeAction(action)* 메시지로 한 군데 응집되면 *블랙잭/Bust/STAY 분기*가 *Player 내부*에서 결정.
|
|
343
|
+
|
|
344
|
+
### 16. `Cards.calculateScore` — `21` 매직 넘버
|
|
345
|
+
|
|
346
|
+
```kotlin
|
|
347
|
+
fun calculateScore(): Int {
|
|
348
|
+
var score: Int = value.sumOf { card -> card.denomination.number }
|
|
349
|
+
if (value.any { card -> card.isAce() } && score + 10 <= 21) { // ⚠ 21 매직 넘버
|
|
350
|
+
score += 10
|
|
351
|
+
}
|
|
352
|
+
return score
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
페로로(미해결): *"좋습니다 :) 반복되는 21점에 대한 값만 상수화 해주면 좋겠어요"*
|
|
357
|
+
|
|
358
|
+
→ **상수화 미반영**. `BLACKJACK_SCORE = 21` / `BUST_THRESHOLD = 22` 같은 상수가 *Cards companion*에 자연. PR #128·#125·#114 의 *상수 분리* 결과와 같은 결.
|
|
359
|
+
|
|
360
|
+
### 17. DSL Builder — *필수 속성 강제 부재*
|
|
361
|
+
|
|
362
|
+
```kotlin
|
|
363
|
+
// src/test/kotlin/dsl/PersonBuilder.kt — 추정 구조
|
|
364
|
+
class PersonBuilder {
|
|
365
|
+
var name: String = ""
|
|
366
|
+
var age: Int = 0
|
|
367
|
+
fun build() = Person(name, age)
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
페로로(PersonBuilder.kt:16 — 미해결): *"Builder의 특징은 선택적으로 속성을 부여하는 것 일텐데, name을 호출하지 않고 build() 하면 어떤 문제가 생기나요? 어떻게 해결해야 할까요? `호출하지 않으면 이름은 빈값이다` 라는 답변은 아니길 바랍니다.. 힌트는 이름은 필수라는 점입니다."*
|
|
372
|
+
|
|
373
|
+
페로로(CatBuilder.kt:17 — 미해결): *"요기는 대응을 해둔 것 같은데... build 함수에 파라미터로 넘기는게 맞나요? 아니면 또 다른 방법이 있나요?"*
|
|
374
|
+
|
|
375
|
+
→ **Builder 의 *필수/선택* 구분 부재**. *DSL Builder의 본질*은 *선택적 속성을 가독성 있게 부여*. *필수 속성*은 *생성자/팩토리 함수의 첫 파라미터*나 *진입 함수 (`person("이름") { age = ... }`)* 패턴으로 강제. 학생이 *"호출하지 않으면 빈값"* 회피하려고 했지만 *`build()` 시점 검증*은 *컴파일 타임 보호*가 안 됨.
|
|
376
|
+
|
|
377
|
+
PR #128·#135 의 DSL Builder 토론과 같은 결.
|
|
378
|
+
|
|
379
|
+
### 18. `ParameterizedTest` 이름 활용 — 학습 권고
|
|
380
|
+
|
|
381
|
+
```kotlin
|
|
382
|
+
// DenominationTest.kt:15 — 추정
|
|
383
|
+
@ParameterizedTest
|
|
384
|
+
fun "끗수 점수 확인"(...) { ... }
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
페로로(미해결): *"ParameterizedTest를 활용한다면 테스트 이름을 이렇게도 작성해 볼 수 있을거에요 > `끗수가 {0}일 경우 숫자가 10이다.`"*
|
|
388
|
+
|
|
389
|
+
→ **테스트 이름 = 의도 명세**. JUnit `@ParameterizedTest` 의 `{0}` placeholder 활용. 코드 안티패턴은 아니지만 *테스트 문화 권고*.
|
|
390
|
+
|
|
391
|
+
### 19. 첫턴 관심사 제거 후 테스트 케이스 동기화 누락
|
|
392
|
+
|
|
393
|
+
페로로(CardsTest.kt:146 — 미해결): *"첫 턴이라는 관심사가 없어졌기 때문에 테스트 케이스도 맞춰서 수정되어야 할 것 같네요"*
|
|
394
|
+
|
|
395
|
+
→ **도메인 변경에 테스트 동기화 누락**. `첫 턴 → 카드 2장`으로 룰을 바꿨으면 *기존 "첫 턴 21 = 블랙잭" 테스트*도 *"카드 2장 21 = 블랙잭"*으로 갱신 필요. 학생이 *다음 PR에서 반영 예정*으로 미룸.
|
|
396
|
+
|
|
397
|
+
## 리뷰어 의견 요지
|
|
398
|
+
|
|
399
|
+
- **UI 의존 = "import 안 함"이 아니라 "관심사 분리"** — `koreanName`/`title`/`Y`/`N` 모두 *도메인이 UI 패키지를 import 안 한다*는 단순 기준으로 통과한 코드. 페로로의 *"UI와 관심사를 나누는게 근본적인 목적"* 진단으로 *enum 멤버 = 도메인 값만*으로 정착.
|
|
400
|
+
- **확장성 ≠ 무한 일반화** — 학생이 PR 본문에서 *"모든 카지노에서 쓸 수 있도록"* 13장 카드 일반화 → 블랙잭 점수 분기 폭증으로 *블랙잭 핏한 카드*로 후퇴. 페로로: *"점수가 동적으로 결정될 것을 고민하는 확장성이라면 애초에 enum에 포함되는 것 자체가 모순이겠죠? 다만 지금 블랙잭 규칙에서는 그러한 요구사항이 없기 때문에 enum에 포함되어도 괜찮다고 봅니다. 확장성을 고려하는 것은 중요하지만 과한 확장성은 객체의 복잡도를 크게 높이거나 오버 엔지니어링이 될 위험이 있습니다."* — **오버 엔지니어링 경계**.
|
|
401
|
+
- **Hit는 상태가 아니라 액션 → `canDraw()`로 통일** — `isHit()` / `PlayerBehavior` enum / `StateXX` 같은 *상태 이름*이 *액션 의미*를 표현하면 *Player와 Dealer의 동일 메시지*를 못 만든다. *`canDraw()` 메시지*가 *Player/Dealer 둘 다 같은 메시지*로 통일.
|
|
402
|
+
- **승부는 참가자 vs 참가자 메시지** — `GameResult.of(score, score)` 정적 호출 → *`Participant.compete(other: Participant): GameResult`* 일반화. *플레이어 vs 플레이어*도 자연스럽게 표현.
|
|
403
|
+
- **Controller 없이 게임을 진행할 수 있는가?** — 모든 `executeXXX`/`playGame`/`getCards`가 컨트롤러에 있는 구조를 *게임 도메인 모델*로 끌어올리라는 의문. *"꽤나 어려울 수 있는 주제"*라고 명시.
|
|
404
|
+
- **불변 객체는 노출되어도 안전** — `card.copy()` 딥카피 강박이 *불변/가변 구분 미숙*에서 옴. *불변 객체의 참조 누수는 문제 아님*.
|
|
405
|
+
- **메시징은 "원하는 포맷" 전달이 아님** — 학생이 PR 본문에서 자가 학습한 핵심. *상태 메시지*는 *상대가 원하는 포맷*이 아니라 *자기 상태*를 그대로 알려주는 것.
|
|
406
|
+
- **블랙잭 룰 정확성** — *"카드가 2장일 때 합계가 21"* 만 진짜 블랙잭. *Bust는 양측 무조건 패배*. *21 이하 점수 비교*는 *블랙잭/Bust 분기 이후*.
|
|
407
|
+
|
|
408
|
+
## 대표 인용
|
|
409
|
+
|
|
410
|
+
**페로로 (UI 의존 = 관심사 분리, PlayerBehavior.kt):**
|
|
411
|
+
> 도메인 모델이 UI 패키지에 의존만 하지 않으면 괜찮다는 뜻이 아니에요.
|
|
412
|
+
> UI와 관심사를 나누는게 근본적인 목적입니다.
|
|
413
|
+
|
|
414
|
+
**페로로 (확장성 경계, Denomination.kt):**
|
|
415
|
+
> 점수가 동적으로 결정될 것을 고민하는 확장성이라면 애초에 enum에 포함되는 것 자체가 모순이겠죠?
|
|
416
|
+
> 다만 지금 블랙잭 규칙에서는 그러한 요구사항이 없기 때문에 enum에 포함되어도 괜찮다고 봅니다.
|
|
417
|
+
> 확장성을 고려하는 것은 중요하지만 과한 확장성은 객체의 복잡도를 크게 높이거나 오버 엔지니어링이 될 위험이 있습니다.
|
|
418
|
+
|
|
419
|
+
**페로로 (Hit는 상태가 아니라 액션, BlackjackController.kt:121):**
|
|
420
|
+
> 사실 Hit는 상태라기 보다는 더 뽑겠다고 행동한 액션에 가까워요.
|
|
421
|
+
> 그런 의미에서 본다면 딜러가 카드를 더 뽑을 수 있는지 여부를 뜻하는 isHit() 대신 canDraw()와 같이 접근하면 플레이어도 동일한 역할을 부여할 수 있습니다.
|
|
422
|
+
|
|
423
|
+
**페로로 (Controller 없이 게임을 진행할 수 있는가, BlackjackController.kt:27):**
|
|
424
|
+
> 전반적으로 컨트롤러에서 게임에 대한 비즈니스로직을 처리하고 있어요.
|
|
425
|
+
> 만약 지금 구조에서는 컨트롤러 없이 게임을 진행할 수 있을까요?
|
|
426
|
+
> 꽤나 어려울 수 있는 주제이지만 게임을 진행하기 위한 도메인 모델을 고려해볼 수 있겠습니다.
|
|
427
|
+
|
|
428
|
+
**페로로 (승부 일반화, Player.kt:19):**
|
|
429
|
+
> 플레이어가 딜러 결과를 통해 내 결과를 업데이트 한다는 점이 꽤나 어색하게 느껴지고, 재사용이 어렵습니다.
|
|
430
|
+
> 승부를 벌이는 것은 참가자와 참가자간의 승부로 일반화를 할 수 있으려나요?
|
|
431
|
+
> 1. 딜러 vs 플레이어 / 2. 플레이어 vs 플레이어 / 3. 참가자 vs 참가자
|
|
432
|
+
|
|
433
|
+
**페로로 (블랙잭 룰 정확성, Cards.kt):**
|
|
434
|
+
> 블랙잭 상태는, 첫번째 턴이라기 보다는 "카드가 2장일 때 합계가 21점이면" 으로 접근을 하시는 방향이 좋을거에요!
|
|
435
|
+
|
|
436
|
+
**학생 자가 답변 (메시징 학습, PR 본문 + Card.kt):**
|
|
437
|
+
> 처음에는 객체는 메시징을 던진다라는 말을 들었을 때, 다른 객체에서 완전히 원하는 포맷의 주어야한다고 생각을 했습니다.
|
|
438
|
+
> ...
|
|
439
|
+
> 객사오를 읽으면서 객체는 자율적으로 행동한다라는 문장을 읽으면서 완전히 상대방이 원하는 값을 주는 것이 아니라, 상태에 대한 메시징을 던지는 것이 중요하다고 생각했습니다.
|
|
440
|
+
|
|
441
|
+
**학생 자가 답변 (Cards가 자기 상태 판단, Cards.kt):**
|
|
442
|
+
> 처음 코드는 카드 상태가 자신의 상태가 무엇인지 판단을 하도록 코드를 작성했습니다.
|
|
443
|
+
> 지금 생각해보면, 카드의 상태는 카드가 가지는 속성 중 일부라고 판단을 하였습니다. 카드 스스로가 자신의 상태를 판별할 수 있는 로직을 구현했습니다. 이러니, player에서 중복적으로 가진 isBalckjack, isBust 코드도 삭제하여, 다 카드 내에서 판단할 수 있도록 했습니다.
|
|
444
|
+
> "객체 스스로 자율적으로 일을 한다." 라는 관점에서 player들이 카드가 isblackjack인지 isBust인지 판단하는 것이 아니라, 카드가 자신 스스로 판단할 수 있도록 로직을 수정했습니다.
|
|
445
|
+
|
|
446
|
+
**학생 자가 답변 (딜러 자율성, PlayerBehavior.kt):**
|
|
447
|
+
> 딜러는 player를 상속받고 있습니다. 그 말은 딜러도 player처럼 hit or stay를 할것인지 자유롭게 판단하는 객체라는 사실입니다.
|
|
448
|
+
> 이 구조를 바탕으로 생각 했을 때, 딜러가 hit or stay를 하는 것은 딜러의 자율성(책임)에 맡겨야한다고 생각합니다.
|
|
449
|
+
> 이렇게 도메인 구조에 따라, hit or stay하는 책임이 누군지 달라진다고 생각합니다.
|
|
450
|
+
|
|
451
|
+
**학생 감동 표현 (Cards.kt — "첫 턴" → "카드 2장"):**
|
|
452
|
+
> 페로로..... 페로로처럼 생각하면, 더 객체 지향적인 코드가 되겠어요......(조금 많이 감동받았습니다....*)
|
|
453
|
+
|
|
454
|
+
## 얻은 교훈
|
|
455
|
+
|
|
456
|
+
1. **UI 의존성 판정 기준 = "import 안 함"이 아니라 *관심사 분리***. enum 멤버 `koreanText`/`title`/`Y/N` 값은 *도메인이 UI를 import 안 해도* 화면 형식이 도메인에 새어들어온 상태. 페로로의 *"UI와 관심사를 나누는게 근본적인 목적"* 진단이 이 안티패턴의 핵심. *enum 멤버 = 식별자만*이 정착 기준 — `enum class CardShape { DIAMOND, SPADE, HEART, CLOVER }`로 충분. *한글/이모지/약어*는 *OutputView 매핑 테이블*이 자연.
|
|
457
|
+
|
|
458
|
+
2. ***메시징은 "원하는 포맷 전달"이 아니라 "자기 상태 통보"***. 학생이 PR 본문에서 *"객체에서 완전히 원하는 포맷을 주어야 한다고 생각했다"* 라고 자가 회고 → *"객체는 자율적으로 행동한다 → 상태 메시징"* 으로 수정. *`Card.combine(): String`* 같은 *호출자 친화 포맷*은 *호출자에게 종속*. *`Card.shape`/`Card.denomination`* 그대로 노출 + *OutputView가 포맷팅* 이 자율성 보존.
|
|
459
|
+
|
|
460
|
+
3. ***Hit는 상태가 아니라 액션 → 메시지 이름은 액션의 *가능성*을 묻는 형태***. `isHit()` (현재 상태?) vs `canDraw()` (행위 가능성?). *Player.canDraw() / Dealer.canDraw()* 가 *둘 다 같은 메시지*로 통일되어 *Participant 인터페이스 통일*까지 끌어올 수 있음. PR #112·#33·#119 의 동일 결.
|
|
461
|
+
|
|
462
|
+
4. ***확장성은 도메인 요구사항이 부를 때 도입***. 학생이 PR 본문에서 *"모든 카지노에서 쓸 수 있도록"* 13장 카드를 일반화했다가 *블랙잭 점수 분기 폭증* 으로 후퇴. 페로로의 *"점수가 동적으로 결정될 것을 고민하는 확장성이라면 애초에 enum에 포함되는 것 자체가 모순"* 진단이 *추상화의 적정 시점*을 가르는 룰. **"확장성을 위한 확장성"은 복잡도만 늘리고 유연성은 안 준다.** *YAGNI*의 OOP 변형.
|
|
463
|
+
|
|
464
|
+
5. ***Cards가 자기 상태를 판단 → "카드 상태 = 카드가 가지는 속성"***. 학생 자가 답변의 *"카드의 상태는 카드가 가지는 속성 중 일부"* 가 *상태 = 외부 함수 결정*이라는 절차적 사고에서 *상태 = 객체 자기 정보*라는 OOP 사고로의 전환. PR #28·#125·#65·#10 와 같은 결.
|
|
465
|
+
|
|
466
|
+
6. ***블랙잭 룰 정확성 = "카드 2장 + 21 = 블랙잭"***. 학생이 *"첫번째 턴"* 으로 접근했다가 *카드 수 + 점수*로 교정. *21 == 블랙잭*이 아님 (3장 21은 그냥 21점). *Ace+10 두 장만 블랙잭*. PR #128·#135·#114·#125 와 같은 결.
|
|
467
|
+
|
|
468
|
+
7. ***Controller가 게임 진행 = 도메인 모델 부재***. 페로로의 *"컨트롤러 없이 게임을 진행할 수 있을까요?"* 가 *Controller god-object 진단*의 핵심 질문. *getCards/playGames/executePlayerGameLogic* 같은 *진행 로직*이 *Game/Match 도메인 객체*로 옮겨가야 *Controller = I/O 어댑터*만 됨. PR #28·#78·#79·#125·#10·#33 와 같은 결.
|
|
469
|
+
|
|
470
|
+
8. ***`lateinit var` 은 호출 순서 invariant 미선언 신호***. `Player.lateinit var result` 가 *외부가 `updateResult` 부르기 전에 `result` 접근하면 예외*. *반환 메시지로 받는 흐름*이면 `lateinit`이 필요 없음. PR #28·#92·#65·#10 와 같은 결.
|
|
471
|
+
|
|
472
|
+
9. ***불변 객체의 참조 노출은 안전***. `card.copy()` 딥카피 강박은 *공유 가변 상태*와 *불변 참조 누수*를 혼동한 결과. 페로로의 *"Card가 이미 불변 객체인데 노출이 되어서 문제가 될 점이 있을까요?"* 가 *방어 본능 vs 실제 필요* 의 경계 질문.
|
|
473
|
+
|
|
474
|
+
10. ***승부는 참가자 vs 참가자 메시지로 일반화***. `GameResult.of(score, score)` 정적 호출은 *플레이어가 딜러 결과의 reverse 로 자기 결과를 받음* 이라는 *비대칭 의존* 을 만든다. *Participant.compete(other) → GameResult* 면 *플레이어 vs 플레이어*도 자연. PR #112·#114·#79·#125 와 같은 결.
|
|
475
|
+
|
|
476
|
+
11. ***getXXX 가 상태 변경하면 명사형 → 동사로***. `getCards` (Unit 반환 + Cards 누적) 는 *받아오는 메시지*가 아니라 *분배하는 액션*. `dealCards`/`drawInitialCards` 가 자연. PR #112·#10·#119 와 같은 결 (`takeCard`/`runPhase`).
|
|
477
|
+
|
|
478
|
+
12. ***`is*()` 부울 메시지는 부수효과 X***. `isPlayerBust` 가 *Bust면 OutputView.printBust 호출* → *호출자가 분기 안에서 다시 출력*하려 하면 *중복 출력*. *판정과 출력 분리* 가 *호출자 안전성* 의 기본. PR #92·#125·#33 와 같은 결.
|
|
479
|
+
|
|
480
|
+
13. ***`Boolean` 반환의 의미가 호출자에 안 보이면 enum / 명시적 이름으로 교정***. `executePlayerBehavior(...): Boolean` 의 `true` = 루프 종료인지 성공인지 모호. *enum (`LoopControl.CONTINUE/BREAK`)* 이나 *`hasFinished` / `shouldBreak`* 같은 이름이 의미 노출. PR #20·#65 와 같은 결.
|
|
481
|
+
|
|
482
|
+
14. ***DSL Builder 의 필수 속성은 컴파일 타임 보호 = 진입 함수 파라미터 또는 팩토리***. `PersonBuilder { age = 30 }.build()` 에서 *name 미설정*이 *런타임 `IllegalStateException`* 으로만 잡히면 *Builder 의 본질 (선택적 속성 가독성)* 과 충돌. *`person("이름") { age = 30 }`* 같은 *진입 함수가 필수 속성을 받는 패턴* 이 자연.
|
|
483
|
+
|
|
484
|
+
15. ***도메인 규칙 변경 시 테스트 동기화*** — *"첫 턴 21 = 블랙잭"* 룰을 *"2장 21 = 블랙잭"* 으로 바꿨으면 *기존 테스트 케이스 이름·시나리오*도 새 도메인 어휘로 갱신. 코드만 바꾸고 테스트 이름이 옛 어휘면 *문서로서의 테스트* 가치 손상.
|
|
485
|
+
|
|
486
|
+
16. ***학생 자가 답변에 커밋 해시 첨부 = 학습 가시화 모범***. wondroid-world 가 *모든 자가 답변에 후속 커밋 SHA*를 명시 (`71ed45f`, `99e5057`, `a67c225`, `dbb7ad8`, `a7eb267`, `eff2d3e`, `525b463` 등) → *리뷰어가 "어디서 반영됐는지"* 즉시 확인 가능. PR 본문의 *학생 자가 질문 → 페로로 답변 → 학생 자가 결론 → 커밋 해시* 4 단 흐름이 *학습 패턴 모범*. PR #128·#135·#111·#120 와 같은 결.
|