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,179 @@
|
|
|
1
|
+
# PR #122 — [로또 1단계] 크림 미션
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@ijh1298](https://github.com/ijh1298)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-lotto/pull/122
|
|
5
|
+
- **단계:** 1단계
|
|
6
|
+
- **리뷰어:** @KwonDae (제이든)
|
|
7
|
+
- **라인 코멘트:** 34
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **`enum class Rank(countOfMatch, winningMoney, requiresBonusMatch)`** — 보너스 여부를 enum 필드로 흡수.
|
|
12
|
+
- **`PurchasePrice`/`BonusNumber` `value class`** — 원시값 포장.
|
|
13
|
+
- **`fun interface LottoNumbersGenerator`** 도입 (이후 라운드) — 함수형 인터페이스로 SAM 활용.
|
|
14
|
+
- **자가 의문 PR에 풍부히 명시** — *enum의 책임 범위*, *일급 컬렉션 과사용*, *NumericValidator의 위치* 등 학생이 먼저 논점화.
|
|
15
|
+
- **runCatching의 Result API 학습** — `getOrDefault`, `getOrNull`, `exceptionOrNull` 등 학습 흔적.
|
|
16
|
+
|
|
17
|
+
## 못한 점 (설계 관점)
|
|
18
|
+
|
|
19
|
+
### 1. `PurchaseLotto`(일급 컬렉션)이 `Lotto` 컬렉션 위에 또 일급 컬렉션
|
|
20
|
+
|
|
21
|
+
```kotlin
|
|
22
|
+
class PurchaseLotto(val values: List<Lotto>) {
|
|
23
|
+
override fun toString(): String =.
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
학생 자가 의문: "단지 toString을 오버라이드 하기 위한 일급 컬렉션 사용에 대해 어떻게 생각하시나요? 이미 일급 컬렉션인 Lotto를 담는 컬렉션을 또 클래스로 감싸고 있는데다 유효성 검증 로직이 없다 보니, 사용하면서 장점보다 단점이 더 많다고 느꼈습니다." 리뷰어: "현재 케이스에서는 이미 Int라는 원시값을 감싼 일급 컬렉션(Lotto)을 만들어 주셨기 때문에, toString을 override 하기 위해 일급 컬렉션으로 다시 감싸는 건 과하다고 생각합니다. 다만, `LottoTicket` 같은 객체로 생성한다면(생성된 로또들의 집합) 해당 객체가 가질 수 있는 역할이 어떤 게 있을까요?" — *역할이 있으면 객체, 없으면 컬렉션*.
|
|
28
|
+
|
|
29
|
+
### 2. `Lotto(numbers: List<Int>)` — `LottoNumber` 객체 부재 + 범위 검증 자체 수행
|
|
30
|
+
|
|
31
|
+
```kotlin
|
|
32
|
+
class Lotto(val numbers: List<Int>) {
|
|
33
|
+
init {
|
|
34
|
+
require(numbers.size == LOTTO_SIZE) { INVALID_LOTTO_SIZE }
|
|
35
|
+
require(numbers.all { it in (1..45) }) { INVALID_LOTTO_NUMBERS }
|
|
36
|
+
require(numbers.size == numbers.toSet().size) { DUPLICATED_LOTTO_NUMBERS }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
리뷰어: "현재 구조에서는 numbers의 각 원소들이 1~45 사이에 들어간다는 걸 확신할 수 있을까요? 아마 Lotto의 초기화 부분을 보지 않는다면 해당 원소가 1..45에 해당함을 쉽게 알지 못할 겁니다. *로또 번호*라는 객체로 분리하면서 해당 객체가 스스로 할 수 있는 역할에 대해 고민해 보시죠!" — `LottoNumber`를 빼면 *범위*가 타입 책임.
|
|
42
|
+
|
|
43
|
+
### 3. `NumericValidator` — Validator 클래스 분리
|
|
44
|
+
|
|
45
|
+
```kotlin
|
|
46
|
+
class NumericValidator(val value: String) {
|
|
47
|
+
init {
|
|
48
|
+
require(value.isNotBlank()) { EMPTY_INPUT_ERROR }
|
|
49
|
+
require(value.toIntOrNull() != null) { NOT_NUMERIC_ERROR }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
학생 답변: "단순 문자열 유효성 검사는 입력단에서 검증하는 게 좋다고 생각했고, 수의 범위나 비즈니스 로직과 관련된 유효성 검증은 모델 객체에서 진행하는 것이 적절하다 생각했습니다!" — 그러나 리뷰어는 추가: "LottoNumber에서 검증하는 건 어떻게 생각하시나요?" + 추가 의견 "지금 NumericValidator의 역할은 String에서 Int로 넘어가는 과정에 문제가 있는지에 대한 검증입니다. LottoNumber를 value class로 정의했기 때문에 Int형을 다루는 검증만 가능한 상태입니다." → 학생도 *value class*의 단일 인자 제약을 의식.
|
|
55
|
+
|
|
56
|
+
### 4. `Rank` enum의 *책임* — 학생 자가 의문
|
|
57
|
+
|
|
58
|
+
학생: "enum class는 이름에 맞게 열거만 하는 역할을 하는 것이 좋을까요? 프리코스에서 이 미션을 진행할 때는 Rank 클래스의 프로퍼티로 이 Rank에 해당하는 당첨 개수를 가지도록 두었습니다. 페어와 의견을 맞추면서 매번 enum class가 변경되는 것보다 Map 자료구조를 통해 다른 곳에서 저장하고 있는 게 좋을 것 같다고 생각했으나…" 리뷰어: "가장 중요한 건, **'당첨 개수'는 어느 객체의 역할에 해당하는가?** 입니다. 당첨 개수는 누구의 역할이고 어느 객체가 관심사가 가장 가까울까요?" — 결국 *Rank의 정체성*에 속하므로 enum 필드가 자연스러움.
|
|
59
|
+
|
|
60
|
+
### 5. `LottoResult`가 `MutableMap`을 *공개*
|
|
61
|
+
|
|
62
|
+
```kotlin
|
|
63
|
+
class LottoResult(
|
|
64
|
+
val result: MutableMap<Rank, Int> =
|
|
65
|
+
Rank.entries.reversed().associateWith { 0 }.toMutableMap(),
|
|
66
|
+
) {. }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
리뷰어: "result에 MutableMap 타입이 필요한가요? 외부에서 해당 프로퍼티에 접근하여 내부 값에 직접 접근이 가능한데, 어떤 문제가 발생할 수 있을까요?" 후속: "외부에서 result에 직접 접근해야 할 일이 어떤 게 있을까요? 외부에서 LottoResult 객체 스스로 판단하여 필요로 하는 result 결과값을 함수를 통해 반환해볼 수 있지 않을까요? `private val result: Map<Rank, Int>` 이렇게 되었을 때 외부에서 이루어지는 역할을 LottoResult가 비로소 스스로 일을 하고…"
|
|
70
|
+
|
|
71
|
+
### 6. `LottoMatchCalculator` — `WinningLotto`의 책임 흡수
|
|
72
|
+
|
|
73
|
+
```kotlin
|
|
74
|
+
class LottoMatchCalculator(
|
|
75
|
+
private val purchaseLotto: PurchaseLotto,
|
|
76
|
+
private val winningLotto: WinningLotto,
|
|
77
|
+
) {
|
|
78
|
+
fun calculate(): LottoResult {
|
|
79
|
+
val result = LottoResult()
|
|
80
|
+
purchaseLotto.values.forEach {
|
|
81
|
+
result.result[getRank(it)] = result.result.getOrDefault(getRank(it), 0) + 1
|
|
82
|
+
}
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
리뷰어: "당첨로또를 계산하는 건 WinningLotto에게 책임을 주어도 가능할 것 같아요. WinningLotto는 당첨번호를 알고 있고, 구매한 로또 정보만 받으면 계산할 수 있지 않을까요?" 학생 결론: "페어와 상의해 보며 '당첨 로또', '구매한 로또들' 이 두 모델 간 의존성을 줄이기 위해 다른 새로운 클래스가 둘을 불러 계산하고 통계를 반영하자고 결론 내렸습니다. 재고해 보니, WinningLotto 클래스가 유효성 검사 외에 큰 역할이 없다는 생각이 듭니다!"
|
|
89
|
+
|
|
90
|
+
### 7. `LottoGenerator`가 `shuffled()` 내장 — 테스트 불가
|
|
91
|
+
|
|
92
|
+
```kotlin
|
|
93
|
+
class LottoGenerator(private val money: PurchasePrice) {
|
|
94
|
+
private fun makeOneLotto(): Lotto {
|
|
95
|
+
val newLotto = (LOTTO_MIN..LOTTO_MAX).shuffled().take(6) // ⚠ 내장
|
|
96
|
+
return Lotto(newLotto)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
리뷰어: "랜덤으로 생성되는 로또는 어떻게 테스트할 수 있을까요? … 테스트가 어려운 코드의 의존관계를 객체 그래프 상위로 이동시키는 내용이 있습니다." 학생 답변: "[Functional interface] 번호를 생성하는 함수 인터페이스만 정의하고, 자동 로또 Generator에서는 이것을 랜덤으로 생성하도록 하고, 수동 로또 Generator에서는 직접 값을 주입할 수 있도록 리팩토링." → `fun interface LottoNumbersGenerator { fun makeLottoNumbers(): Set<LottoNumber> }`.
|
|
102
|
+
|
|
103
|
+
### 8. `PurchasePrice.STANDARD_AMOUNT_UNIT` 내부 상수
|
|
104
|
+
|
|
105
|
+
리뷰어: "시간에 따라 가격이 변하거나 가격이 인상되어 비즈니스 로직이 변경됨 위 상황이 발생한다면 상수값을 변경해줘야 할까요? 어떻게 유연하게 대응이 가능할까요?" 후속: "`STANDARD_AMOUNT_UNIT` 자체에 대해 내부 상수로 갖고 있는 것 / 외부에서 주입받는 것 이 두 가지에 대해 고민해 보셔도 좋습니다." 학생 답: `value class PurchasePrice(val value: Int, private val unit: Int = DEFAULT_AMOUNT_UNIT)` — *하지만 value class는 단일 인자*이므로 `value` 키워드 제거 필요.
|
|
106
|
+
|
|
107
|
+
### 9. `retryWhenException` — *다른 행동* 필요할 때 한계
|
|
108
|
+
|
|
109
|
+
```kotlin
|
|
110
|
+
fun <T> retryWhenException(action: () -> T, onError: (String?) -> Unit): T {
|
|
111
|
+
while (true) {
|
|
112
|
+
runCatching { return action() }.onFailure { onError(it.message) }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
리뷰어: "요구사항에 의해 에러가 발생했을 때 동일 로직이 아닌 다른 형태의 행동을 취해야 한다면 어떻게 될까요? 가령, `금액을 입력받고 올바르지 않은 값이라면 5000원을 기본 시작값으로 설정한다.` hint. runCatching의 반환형태를 살펴보기" — *재시도*만 가능한 함수는 *기본값 사용/조용한 무시* 같은 분기에 무력.
|
|
118
|
+
|
|
119
|
+
### 10. `Lotto(val numbers: List<LottoNumber>)` — 자료구조로 중복 표현
|
|
120
|
+
|
|
121
|
+
리뷰어: "Lotto는 하나의 게임(로또번호 6개 묶음)을 이야기하는 거겠죠? 그렇다면 하나의 Lotto 안에 중복되는 LottoNumber는 없다는 이야기가 됩니다. 이것을 자료구조를 사용하여 명확하게 표시하면서도, 로직으로도 중복을 허용하지 않도록 할 수 있을까요?" 학생: "Set 자료구조로 변경 가능할 것 같습니다."
|
|
122
|
+
|
|
123
|
+
### 11. `LottoMatchCalculator()`가 매번 새로 인스턴스
|
|
124
|
+
|
|
125
|
+
리뷰어: "LottoMatchCalculator는 매번 인스턴스가 새로 생성되어야 하는 걸까요?" — 상태 없는 협력자는 단일 인스턴스 or `object`.
|
|
126
|
+
|
|
127
|
+
### 12. `Controller`가 `amount` 직접 계산
|
|
128
|
+
|
|
129
|
+
```kotlin
|
|
130
|
+
val amount = money.value / PurchasePrice.STANDARD_AMOUNT_UNIT
|
|
131
|
+
return List(amount) { lottoGenerator.makeLotto() }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
리뷰어: "Controller가 직접 amount를 계산하는 거에 대해 어떻게 생각하시나요? `val ticket = lottoGenerator.makeLotto(amount, lottoUnit)`" — *나누기*는 도메인 로직(가능 수량 계산), Controller가 알 필요 없음.
|
|
135
|
+
|
|
136
|
+
### 13. `LottoNumber` Flyweight 부재 — 다음 미션 힌트
|
|
137
|
+
|
|
138
|
+
리뷰어: "2단계에서 생각해 볼만한 재밌는 요소가 하나 있어요. 로또 번호는 1~45로 정해져 있습니다. 만약 동일한 로또 번호가 다른 게임에도 여러 번 사용이 된다면 해당 로또번호는 다른 객체이어야만 할까요? 로또를 발행할 때마다 새로운 인스턴스가 생성이 된다면 리소스가 많이 들어갈 것 같아요." — 차기 미션 학습 시드.
|
|
139
|
+
|
|
140
|
+
## 리뷰어 의견 요지
|
|
141
|
+
|
|
142
|
+
1. **일급 컬렉션은 *역할이 있을 때*** — Lotto 위에 한 번 더 감싸는 것은 *역할이 늘면* OK, 없으면 toString만으로 정당화 X.
|
|
143
|
+
2. **`LottoNumber` 분리 = 범위가 타입 책임** — Lotto가 범위 검증을 하면 캡슐화 손실.
|
|
144
|
+
3. **`Validator` 분리 vs *객체의 자기 검증*** — Validator는 *상태 없는 행위*. 검증을 객체로 옮기면 위치-검증-사용 한 곳.
|
|
145
|
+
4. **Rank의 정체성에 속하는 정보 = enum 필드** — 매번 변경 우려는 *enum 변경에 익숙해지면* 해소.
|
|
146
|
+
5. **`Map`을 외부 노출하지 말 것** — *get* 메서드로 캡슐화.
|
|
147
|
+
6. **`WinningLotto`/`LottoMatchCalculator` 중 *책임의 자연스러운 자리*** — Calculator를 따로 두는 결정이 항상 옳지는 않음, 그러나 *공통 객체*를 만드는 것도 합리적 선택.
|
|
148
|
+
7. **랜덤 의존은 인터페이스로 상위 주입** — `fun interface`로 SAM 활용.
|
|
149
|
+
8. **`PurchasePrice` 상수 외부 주입** — 다중 가격 대응.
|
|
150
|
+
9. **`runCatching`은 *분기*가 가능한 도구** — 재시도만 추출하지 말고 *기본값/조용한 실패*도.
|
|
151
|
+
10. **상태 없는 협력자는 단일 인스턴스** — Calculator가 매번 새 인스턴스일 필요 없음.
|
|
152
|
+
11. **Controller = 조립**, *계산*은 도메인.
|
|
153
|
+
|
|
154
|
+
- **대표 인용:**
|
|
155
|
+
> 가장 중요한 건, "당첨 개수"는 어느 객체의 역할에 해당하는가? 입니다. 당첨 개수는 누구의 역할이고 어느 객체가 관심사가 가장 가까울까요?
|
|
156
|
+
> — @KwonDae on `src/main/kotlin/domain/model/Rank.kt`
|
|
157
|
+
|
|
158
|
+
> 다만, LottoTicket 같은 객체로 생성한다면(생성된 로또들의 집합) 해당 객체가 가질 수 있는 역할이 어떤 게 있을까요?
|
|
159
|
+
> — @KwonDae on `src/main/kotlin/domain/model/PurchaseLotto.kt`
|
|
160
|
+
|
|
161
|
+
> 외부에서 result에 직접 접근해야 할 일이 어떤 게 있을까요? 외부에서 LottoResult 객체 스스로 판단하여 필요로 하는 result 결과값을 함수를 통해 반환해 볼 수 있지 않을까요?
|
|
162
|
+
> — @KwonDae on `src/main/kotlin/domain/model/LottoResult.kt`
|
|
163
|
+
|
|
164
|
+
> 의존 관계란 무엇일까요? 현재 `makeLotto()` 함수는 shuffled() 함수에 의존적이어서, 우리는 결과를 예측할 수 없습니다.
|
|
165
|
+
> — @KwonDae on `src/main/kotlin/domain/service/LottoGenerator.kt`
|
|
166
|
+
|
|
167
|
+
## 얻은 교훈
|
|
168
|
+
|
|
169
|
+
- **일급 컬렉션은 *역할*이 있어야 정당화**. `toString`만 위해서면 *함수 확장*이나 `data class`로 충분. 역할이 생기면 그 때 일급 컬렉션으로 승격.
|
|
170
|
+
- **`LottoNumber` 분리 = 범위가 타입에 표현**. `List<LottoNumber>`면 Lotto는 *범위*를 더 이상 검증하지 않음 — 책임이 *수직 단계*로 분리됨.
|
|
171
|
+
- **Validator vs *객체의 자기 검증*** — Validator는 *행위만*. 객체가 검증을 직접 하면 *사용 시점에 보장*. value class의 *단일 인자* 제약이 분리를 강제하는 경우도 있음 — 그건 *제약*이지 *원칙*이 아님.
|
|
172
|
+
- **enum의 필드 = enum이 *반드시* 알아야 하는 정보**. *변경 빈도*에 대한 두려움보다 *책임의 자연성*이 우선.
|
|
173
|
+
- **`Map`/`MutableList`를 외부 노출하지 말 것** — *get*/*sumOf* 같은 함수로 캡슐화. 외부에서 *어떤 자료구조*인지 알 필요 없음.
|
|
174
|
+
- **`WinningLotto`가 행위가 부재하면 *유효성 검사 클래스*** — *Tell, Don't Ask*. 매칭/통계까지 들고 가면 객체가 살아남.
|
|
175
|
+
- **랜덤 의존은 *함수형 인터페이스*** — `fun interface LottoNumbersGenerator { fun makeLottoNumbers(): Set<LottoNumber> }` 한 줄.
|
|
176
|
+
- ***`runCatching`은 try-catch 대체가 아니라 *결과 타입*** — `getOrDefault`/`getOrNull`/`fold`로 분기 표현 가능. 단순 *재시도*만 사용하면 가치 절반.
|
|
177
|
+
- **상태 없는 협력자는 단일 인스턴스 or `object`** — Calculator/Mapper.
|
|
178
|
+
- **Controller = 조립, *계산은 도메인***. `money.value / STANDARD_UNIT`을 Controller가 하면 *나누기 의미*가 도메인 외부로 흐름.
|
|
179
|
+
- **차기 미션 학습 시드** — 1~45 캐싱(Flyweight)은 *원시 도메인이 유한할 때*의 표준 패턴.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# PR #133 — [로또 2단계] 크림 미션
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@ijh1298](https://github.com/ijh1298)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-lotto/pull/133
|
|
5
|
+
- **단계:** 2단계 (수동 로또 추가)
|
|
6
|
+
- **리뷰어:** @KwonDae (제이든)
|
|
7
|
+
- **라인 코멘트:** 32
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **`LottoNumber` Flyweight + `private constructor` + `LottoNumber.from(value)`** — 1단계 미션 힌트 반영.
|
|
12
|
+
- **`sealed class PurchasePriceResult` / `ManualLottoAmountResult`** — sealed로 *실패 케이스를 타입화*.
|
|
13
|
+
- **`fun interface LottoGenerator`** + `AutoLottoGenerator`/`ManualLottoGenerator` — Strategy.
|
|
14
|
+
- **runCatching + getOrElse 활용** — `try-catch` 대체.
|
|
15
|
+
- **자가 의문 PR에 풍부히 명시** — *value class vs class*, *생성자 vs 팩토리*, *Exception vs sealed* 등 학생이 먼저 논점화.
|
|
16
|
+
- **현실 비유로 설계 결정 정당화** — "로또 용지에 이상하게 작성해도 가게 주인에게 건네기 전까지는 오류를 인지하지 못한다" — *2번째 방법(일괄 검증)*의 도메인 정당성.
|
|
17
|
+
|
|
18
|
+
## 못한 점 (설계 관점)
|
|
19
|
+
|
|
20
|
+
### 1. `value class → class` 변경 — 이유 명시 부재
|
|
21
|
+
|
|
22
|
+
```kotlin
|
|
23
|
+
// 1단계
|
|
24
|
+
@JvmInline value class LottoNumber(val value: Int)
|
|
25
|
+
|
|
26
|
+
// 2단계
|
|
27
|
+
class LottoNumber private constructor(val value: Int)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
리뷰어: "기존의 value class에서 class로 변경이 되었네요? 어떤 배경이 있었을까요?" 학생 답: "미션 피드백에 주어진 코드를 참고하고 옮기다 보니 value 키워드를 실수로 제거하게 되었습니다. 다시 적용해 보겠습니다." — *실수성 변경*이지만 리뷰어는 *왜를 명시*하기를 기대.
|
|
31
|
+
|
|
32
|
+
### 2. `ManualLottoGenerator`에 `setManualLottoNumbers` setter
|
|
33
|
+
|
|
34
|
+
```kotlin
|
|
35
|
+
class ManualLottoGenerator : LottoNumbersGenerator {
|
|
36
|
+
private var manualLottoNumbers = setOf<Int>()
|
|
37
|
+
fun setManualLottoNumbers(inputLottoNumbers: Set<Int>) { // ⚠ setter 패턴
|
|
38
|
+
manualLottoNumbers = inputLottoNumbers
|
|
39
|
+
}
|
|
40
|
+
override fun makeLottoNumbers(): Set<LottoNumber> = manualLottoNumbers.map { LottoNumber.from(it) }.toSet()
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
학생 의도: "Generator를 한 줄 입력을 단위로 매번 생성해야 하는 불편함이 있었습니다. 따라서 Generator 내에 private 필드를 선언해서, 외부에서 한 줄의 로또 번호를 넣을 수 있게 setter를 구현했습니다." 리뷰어: "수동 로또를 세트로 생성하는 것 또한 수동로또 객체의 역할입니다! 필요한 만큼 로또를 생성해 주도록 하면 어떨까요? `fun makeManualLotto(input:.): List<Lotto>`."
|
|
45
|
+
|
|
46
|
+
### 3. `Controller`가 `NumericValidator` + `toInt()` 직접 호출
|
|
47
|
+
|
|
48
|
+
```kotlin
|
|
49
|
+
private fun getManualLottoAmount(purchasePrice: PurchasePrice): ManualLottoAmount =
|
|
50
|
+
retryWhenException(
|
|
51
|
+
action = {
|
|
52
|
+
val input = inputView.readManualLottoAmount()
|
|
53
|
+
NumericValidator(input)
|
|
54
|
+
ManualLottoAmount(input.toInt(), purchasePrice.toAmount())
|
|
55
|
+
},
|
|
56
|
+
onError = { outputView.printErrorMessage(it) },
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
리뷰어: "현재 Controller에서 변환을 직접 담당하고 있는데, `ManualLottoAmount` 객체 스스로가 input에 대해 검증하고, 논리적 오류가 존재하면 예외 처리, 논리 오류가 아니라면 예외 발생을 시키는 게 아닌 다양한 방법으로 대처가 가능할 것 같아요. `String.toInt()`와 `String.toIntOrNull()` 존재가 그 이유입니다." — 검증 + 변환은 *대상 객체의 자기 책임*으로.
|
|
61
|
+
|
|
62
|
+
### 4. `NumericValidator` — null 처리 vs 예외 발생 혼재
|
|
63
|
+
|
|
64
|
+
리뷰어: "`NumericValidator` 클래스 또한 논리 오류가 아닌 경우에 어떻게 처리하면 좋을지 고민해 보시죠! 현재는 null 처리와 예외 던지는 로직이 섞여 있네요!" — *비논리적 오류 = null + 재입력*, *논리적 오류 = 예외*. 한 객체 안에 두 흐름이 섞이면 호출자가 *무엇을 받는지* 불명확.
|
|
65
|
+
|
|
66
|
+
### 5. `AutoLottoGenerator`/`ManualLottoGenerator` — 추상화 깊이가 충분하지 않음
|
|
67
|
+
|
|
68
|
+
```kotlin
|
|
69
|
+
class AutoLottoGenerator : LottoGenerator {
|
|
70
|
+
private fun makeRandomNumbers(): Set<Int> = (LOTTO_MIN..LOTTO_MAX).shuffled().take(6).toSet()
|
|
71
|
+
override fun getLottoNumbers(lottoNumbers: Set<Int>): Set<LottoNumber> = lottoNumbers.map { LottoNumber.from(it) }.toSet()
|
|
72
|
+
override fun makeLotto(amount: Int): List<Lotto> = List(amount) { Lotto(getLottoNumbers(makeRandomNumbers())) }
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
리뷰어: "현재 LottoGenerator를 구현하는 AutoLottoGenerator, ManualLottoGenerator의 구현 부분이 정확히 같습니다. 본래의 LottoGenerator는 `로또 번호 생성`에 관심이 있었습니다. 그렇다면 예를 들어, LottoTicket이라는 객체가 존재하여 해당 객체가 Lotto를 관리할 수 있다면 어떨까요? 현실세계에서도 LottoTicket에 여러 개 Lotto가 존재하죠? (최대 5개)" — *Lotto 묶음*은 `LottoTicket`이라는 *자연어 객체*가 자연스럽다.
|
|
77
|
+
|
|
78
|
+
### 6. 테스트가 *예외 발생*을 검증
|
|
79
|
+
|
|
80
|
+
```kotlin
|
|
81
|
+
@Test
|
|
82
|
+
fun `구입 금액이 0 이하면 예외가 발생한다`() {
|
|
83
|
+
assertThrows<IllegalArgumentException> { PurchasePrice(0) }
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
리뷰어: "이제 논리 오류에 대해 다뤄봤으니, 테스트를 작성하는 관점에서도 살펴볼 만한데요. *도메인을 테스트할 때 예외 발생하는 것*이 중요할까요? 아니면 *구입 금액은 0원 이상*이 의도였을까요?" — 테스트명은 *비즈니스 의도*에 맞춰야.
|
|
88
|
+
|
|
89
|
+
### 7. `sealed class` 분기 시 모든 분기가 같은 동작
|
|
90
|
+
|
|
91
|
+
```kotlin
|
|
92
|
+
private fun getPurchasePrice(): PurchasePrice {
|
|
93
|
+
val input: Int = inputView.readPurchasePrice()
|
|
94
|
+
return when (val result = input.toPurchasePriceResult()) {
|
|
95
|
+
is PurchasePriceResult.Success -> result.purchasePrice
|
|
96
|
+
is PurchasePriceResult.InvalidMinimumPurchaseAmount -> {
|
|
97
|
+
outputView.printExceptionMessage(result.errorMsg)
|
|
98
|
+
getPurchasePrice()
|
|
99
|
+
}
|
|
100
|
+
is PurchasePriceResult.InvalidThousandWonUnit -> {
|
|
101
|
+
outputView.printExceptionMessage(result.errorMsg)
|
|
102
|
+
getPurchasePrice()
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
리뷰어: "현재로서는 요구사항에 `PurchasePriceResult.InvalidThousandWonUnit`일 때 다른 동작을 요구하고 있진 않기에 같은 로직이 수행되고 있네요! 하지만 방향은 정말 좋았어요. … 현재 단계에서는 활용해 주신 것처럼 `runCatching {. }.getOrElse { outputView.printException; getPurchasePrice() }` 정도로도 가능할 것 같아요." — sealed의 가치는 *분기별 다른 동작*이 있을 때 발현. 같은 동작이면 *예외 + 재시도*가 더 간결.
|
|
109
|
+
|
|
110
|
+
### 8. 학생 자가 의문 — Exception vs sealed
|
|
111
|
+
|
|
112
|
+
학생: "생성자를 막아버리고 to자료형 같은 함수로만 생성하도록 하는 게 좋은 걸까? 이때까지 프로그래밍하면서 매번 생성자를 사용해 왔는데. 논리적 오류를 방지하는 게 좋지만 Exception 발생은 최대한 피하는 게 좋다 하니, require을 없애고 모두 if 조건문을 통해 sealed class 반환하는 방식으로 바꾸는 게 좋을까?" 리뷰어 답: "Exception 발생은 최대한 피하는 것보다는 *논리 오류가 발생했을 때 예외를 발생시켜 사용자로 하여금 어떤 logical 오류를 범했는지 알려주고자* 하는 의도가 큽니다. 적절한 예외 발생은 필요합니다(ex. 카드 결제 시 잔액부족). API에서 발생할 수 있는 모든 케이스를 Sealed Class로 대응이 가능할까?"
|
|
113
|
+
|
|
114
|
+
### 9. 두 가지 *수동 로또 검증* 전략 — 학생의 도메인 비유
|
|
115
|
+
|
|
116
|
+
학생: "1) 한 줄 입력 시 바로 로또 객체 생성 → 즉시 오류 발견 vs 2) 모든 입력 받은 후 Generator가 한꺼번에 생성하며 오류 발견." → "현실 세계에 빗대어보면 *로또 용지에 이상하게 작성하고 있더라도 마지막에 로또 가게 주인에게 건네기 전까지는 오류를 인지하지 못한다*는 점에서 2번도 잘못된 건 아니지 않을까?" 리뷰어: "현실세계에 대입해 고민해 보는 것도 정말 좋았어요. 만약 기능 요구사항에 *오류 발생 시 첫 번째 로또부터 다시 입력*이 요구되어야 한다면, 첫 번째 방법을 채택해야 겠네요. 현업에서 기능을 구현하다 보면 *개발에서의 논리와 현실 세계에서의 논리가 충돌*하는 경우가 종종 있습니다."
|
|
117
|
+
|
|
118
|
+
## 리뷰어 의견 요지
|
|
119
|
+
|
|
120
|
+
1. **언어 기능 변경은 *이유*도 함께** — value class → class는 *왜*가 동반되어야.
|
|
121
|
+
2. **setter 패턴은 *시간 결합*** — 객체 생성 시점과 사용 시점 사이에 *순서*가 필요해짐.
|
|
122
|
+
3. **검증 + 변환은 대상 객체의 자기 책임** — Controller에서 직접 toInt + Validator + 생성하는 흐름은 *모든 검증 책임*을 Controller로 끌어옴.
|
|
123
|
+
4. **null vs Exception은 *원인 종류*에 따라** — *비논리적*(형식 X) = null + 재입력, *논리적*(범위 X) = 예외.
|
|
124
|
+
5. **sealed class는 *분기별 다른 동작*이 있을 때 가치** — 동일 동작이면 `runCatching.getOrElse`로 충분.
|
|
125
|
+
6. **예외 발생은 *나쁜 것*이 아니라 *의도된 도구*** — 카드 결제 잔액부족 같은 *비즈니스 오류*에 예외는 적합.
|
|
126
|
+
7. **테스트명 = 의도, 본문 = 의도의 직접 검증** — *예외 발생*은 *수단*, *0원 이상*이 *목적*.
|
|
127
|
+
8. **자연어 객체(`LottoTicket`)가 *반복되는 추상*을 흡수** — Auto/Manual Generator가 거의 같은 코드면 *Lotto 묶음*이라는 더 자연스러운 객체로.
|
|
128
|
+
9. **현실 세계와 코드의 논리가 충돌할 때 = 케이스별 트레이드오프 명시화** — 양쪽 모두 옳을 수 있음.
|
|
129
|
+
|
|
130
|
+
- **대표 인용:**
|
|
131
|
+
> 현재 Controller에서 변환을 직접 담당하고 있는데, `ManualLottoAmount` 객체 스스로가 input에 대해 검증하고, 논리적 오류가 존재하면 예외 처리, 논리 오류가 아니라면 예외 발생을 시키는 게 아닌 다양한 방법으로 대처가 가능할 것 같아요. `String.toInt()`와 `String.toIntOrNull()` 존재가 그 이유입니다.
|
|
132
|
+
> — @KwonDae on `src/main/kotlin/controller/LottoController.kt`
|
|
133
|
+
|
|
134
|
+
> `도메인을 테스트할 때 예외 발생하는 것`이 중요할까요? 아니면 `구입 금액은 0원 이상`이 의도였을까요?
|
|
135
|
+
> — @KwonDae on `src/test/kotlin/domain/model/PurchasePriceTest.kt`
|
|
136
|
+
|
|
137
|
+
> 현재 LottoGenerator를 구현하는 AutoLottoGenerator, ManualLottoGenerator의 구현 부분이 정확히 같습니다. … 예를 들어, LottoTicket이라는 객체가 존재하여 해당 객체가 Lotto를 관리할 수 있다면 어떨까요?
|
|
138
|
+
> — @KwonDae on `src/main/kotlin/domain/service/AutoLottoGenerator.kt`
|
|
139
|
+
|
|
140
|
+
> Exception은 좋지 않으니 발생시키지 말자 ❌ 적절한 예외 발생은 필요합니다(ex. 카드 결제시 잔액부족, 잔액 거스름돈)
|
|
141
|
+
> — @KwonDae on `src/main/kotlin/domain/model/PurchasePrice.kt`
|
|
142
|
+
|
|
143
|
+
## 얻은 교훈
|
|
144
|
+
|
|
145
|
+
- **언어 기능 *변경 이유*는 PR/주석에 남기기**. value class → class는 *왜*가 동반되어야 미래의 동료가 의도 추적 가능.
|
|
146
|
+
- **setter 패턴 = *시간 결합***. 생성 시점에 완성되지 않은 객체는 *언제 set 되었는지*에 의존 — 호출자가 *순서*를 보장해야 함.
|
|
147
|
+
- **검증 + 변환은 *대상 객체의 자기 책임***. `PurchasePrice.from(input)`이 `Result`를 반환하면 Controller는 *분기*만 함.
|
|
148
|
+
- ***비논리적 오류*(형식)는 null + 재입력, *논리적 오류*(범위)는 예외**. 둘을 한 함수에서 같이 처리하면 호출자가 무엇을 받는지 모름.
|
|
149
|
+
- **sealed의 가치는 *분기별 다른 행동*** — 모든 케이스가 같은 동작을 한다면 *runCatching 또는 예외*가 더 가벼움.
|
|
150
|
+
- **예외는 *의도된 도구*** — *과도하게 회피*하면 *비즈니스 오류*도 무리해서 결과 타입으로 만들게 됨.
|
|
151
|
+
- **테스트명은 *의도*, 본문은 *그 의도의 직접 검증*** — *예외*는 *수단*, *0원 이상*이 *목적*.
|
|
152
|
+
- **자연어 객체가 *반복되는 추상*을 흡수** — Auto/Manual Generator 구현이 99% 같으면 *Lotto 묶음(LottoTicket)*이 한 단계 위 추상.
|
|
153
|
+
- **현실 세계 vs 코드 논리** — *충돌* 자체가 *설계 의사결정 지점*. 양쪽 가능성을 *명시적으로* 평가하면 *케이스에 따른 정답*이 보임.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# PR #3 — [써니] 1단계 로또 (초창기 PR)
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@inseonyun](https://github.com/inseonyun)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-lotto/pull/3
|
|
5
|
+
- **단계:** 1단계
|
|
6
|
+
- **리뷰어:** @namjackson (잭슨)
|
|
7
|
+
- **라인 코멘트:** 39 (리뷰어 33 + 학생 6)
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **테스트 케이스 구체** — 리뷰어 칭찬: "구체적인 테스트 케이스 👍".
|
|
12
|
+
- **팩토리 메소드 활용** — 칭찬: "팩토리 메소드 👍 생성자와 같은 역할을 하고 있네요."
|
|
13
|
+
- **자가 질문 풍부** — *InputView 책임*, *원시값 포장 위치*.
|
|
14
|
+
|
|
15
|
+
## 못한 점 (설계 관점)
|
|
16
|
+
|
|
17
|
+
### 1. `World` Controller — *god-naming*
|
|
18
|
+
|
|
19
|
+
```kotlin
|
|
20
|
+
class World(.) {
|
|
21
|
+
fun processLotto() {. }
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
→ *"World"는 god-naming*. *책임이 무엇이든* 들어갈 수 있음. PR #2 (DYGames)와 같은 초창기 학생 패턴.
|
|
26
|
+
|
|
27
|
+
리뷰어: "*makeWinStatistics라는 함수명이지만, 내부 동작은 lotto를 구매하여, 생성하고, 당첨 숫자를 입력받아서, 결과를 리턴하고 있어요! makeWinStatistics에 너무 많은 책임이 있는 것 같아요! 역할마다 분리*해 보면 어떨까요?" + "*써니님이 생각하시는 world 클래스의 역할은 무엇인가요*?"
|
|
28
|
+
|
|
29
|
+
### 2. *함수 순서* — 코드 읽기 흐름
|
|
30
|
+
|
|
31
|
+
리뷰어: "함수 순서에 대한 이야기입니다! *개발자들은 보통 코드를 작성하는 시간보다 작성을 위해 코드를 읽는 시간이 훨씬 많다고* 해요! *코드를 읽는 사람의 가독성을 위해, 위에서 아래로 흐름이 흐르도록 순서*를 바꿔 보면 어떨까요? 코틀린 *공식 컨벤션*을 가볍게 읽어 봐도 좋을 거 같아요! https://kotlinlang.org/docs/coding-conventions.html#class-layout"
|
|
32
|
+
|
|
33
|
+
### 3. `Lotto`의 *범위 + 중복 검증 부재*
|
|
34
|
+
|
|
35
|
+
```kotlin
|
|
36
|
+
class Lotto(val numbers: List<Int>) {. } // ⚠
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
리뷰어 (각각): "*numbers에 1~45 범위가 아닌 수가 들어올 수 있는 구조*네요!" + "*numbers에 중복된 숫자가 들어오는 케이스도 고려*해 보면 좋을 것 같아요!" + "*Lotto, Lottos에서 번호가 일치하는지는 중요한 로직*인 거 같아요! 해당 테스트도 작성해 주시면 좋을 거 같아요!"
|
|
40
|
+
|
|
41
|
+
### 4. *몇 장 살지 Controller가 결정*
|
|
42
|
+
|
|
43
|
+
리뷰어: "*정해진 Money에서 몇 장의 로또를 살지를 결정하는 것 또한 모델의 있어야 하는 로직*이 아닐까요? *(View와 도메인을 연결하는 작업 이외의 로직은 최소화로 해 보면 어떨까요?) Lottos 클래스 내의 중복된 로직 또한 있는 것으로 보여요*!"
|
|
44
|
+
|
|
45
|
+
### 5. `WinNumber` vs `Lotto` *책임 중복*
|
|
46
|
+
|
|
47
|
+
리뷰어: "*WinNumber와 Lotto와의 책임의 차이는 무엇인가요? 비슷한 책임을 가지고 있는 것 같*아요!"
|
|
48
|
+
|
|
49
|
+
### 6. `Rank` *bonus 정보 부재* — 2등/3등 구별 불가
|
|
50
|
+
|
|
51
|
+
```kotlin
|
|
52
|
+
enum class Rank(val countOfMatch: Int,.) {. }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
리뷰어: "*2등과 3등은 countOfMatch가 같은데, 어떻게 구별할 수 있을까요? Rank의 가지는 책임이 무엇일까요? bonus에 대한 정보가 없어서 모호*한 것 같아요!"
|
|
56
|
+
|
|
57
|
+
리뷰어: 기본값으로 노출 최소화
|
|
58
|
+
```kotlin
|
|
59
|
+
enum class Rank(val countOfMatch: Int, val winningMoney: Int, val matchBonus: Boolean = false) {
|
|
60
|
+
FIRST(6, 2_000_000_000),
|
|
61
|
+
SECOND(5, 30_000_000, matchBonus = true),
|
|
62
|
+
THIRD(5, 1_500_000),
|
|
63
|
+
FOURTH(4, 50_000),
|
|
64
|
+
FIFTH(3, 5_000),
|
|
65
|
+
MISS(0, 0);
|
|
66
|
+
```
|
|
67
|
+
"*기본값을 지정해 주면 불필요한 matchBonus를 노출하지 않아도 되서 좋아요*!"
|
|
68
|
+
|
|
69
|
+
### 7. *싱글턴 = 강한 커플링*
|
|
70
|
+
|
|
71
|
+
리뷰어: "*싱글턴 인스턴스로 접근하게 되면, 강한 커플링이 생겨서 결합도가 높아져요*! *싱글턴 인스턴스가 아닌 프로퍼티로 선언하고 참조*하면 어떨까요?"
|
|
72
|
+
|
|
73
|
+
### 8. `tryAndRerun` 의도와 위험성 — *비입력 코드에 적용*
|
|
74
|
+
|
|
75
|
+
리뷰어: "*tryAndRerun의 의도는 알겠지만, 조금 위험할 수도 있을 것 같*아요! *bonus볼을 추첨했는데, 이후 로직에서 문제가 생기면, 보너스 볼을 다시 받아야 하는 케이스가 생길 것* 같아요, *의도하지 않은 로직이 중복되어 실행되지 않도록 하는 게 좋지 않을까요*?" + "*tryAndRerun은 잘못된 입력을 다시 받기 위한 로직인 것* 같아요! *입력과 관련된 로직이라면, InputView에서 처리되어야 하지 않을까요*? 특히 이 부분은 *Domain에서 발생하는 로직을 처리하고 있어서, 의도하지 않은 에러 또한 처리*되고 있어요. *의도하지 않은 에러라면 다시 실행되기 보다, 에러를 처리하도록 전달해 줘야 하지 않을까요*?"
|
|
76
|
+
|
|
77
|
+
### 9. *Controller가 Lotto 결과로 WinStatistics 조립* — Tell-Don't-Ask
|
|
78
|
+
|
|
79
|
+
```kotlin
|
|
80
|
+
val statistics = WinStatistics(lottos.value, winNumber) // ⚠
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
리뷰어: "*lottos의 value를 받아와서, determine을 통해 WinStatistics 객체를 생성해 주는 동작을 하고 있*네요! *객체에게 메시지를 보내고, 책임을 주어, 서로 협력하는 구조를 만들어 보면* 어떨까요?" + "*lottos의 결과값을 받아와서, WinStatistics을 생성해 주기보단, WinStatistics를 리턴해 주면* 어떨까요? *객체끼리 협력할 수 있도록 작업해 보아요*!"
|
|
84
|
+
|
|
85
|
+
### 10. *Interface 분리 기준* — YAGNI 원칙
|
|
86
|
+
|
|
87
|
+
```kotlin
|
|
88
|
+
interface RankDeterminer {. }
|
|
89
|
+
interface ProfitRateCalculator {. }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
리뷰어: "RankDeterminer와 *ProfitRateCalculator 인터페이스를 분리하셨네요! 어떤 기준으로 인터페이스를 분리하셨는지 의견이 궁금*합니다!" + "*YAGNI라고, '실제로 필요할 때 무조건 구현하되, 그저 필요할 것이라고 예상할 때에는 절대 구현하지 말라'라는 소프트웨어 원칙을 말하는 의견도* 있어요 :), *예상했던 부분과 다르게 요구사항이 변경될 때, 오히려 예상하여 구현된 부분은 독이 될 수도 있기 때문*인데요, 그렇기 때문에 *예상을 통해 구현하기보다, 객체의 역할과 책임을 분리하여 관리*하도록 하면 좋을 거 같아요! 위 부분의 구현이 잘못되었다고 생각하진 않지만, *인터페이스를 통해 추상화를 하였지만, 구현체만 사용하고 인터페이스는 사용하지 않는 구조*라서 *스타일에 따라서, 인터페이스가 필요한가?라는 의견도 있을 것* 같다는 생각이 들어요!" — *추상화의 정당화*.
|
|
93
|
+
|
|
94
|
+
### 11. *Set 사용 + 원시값 포장*
|
|
95
|
+
|
|
96
|
+
리뷰어: "*로또번호인 Int의 원시값을 포장*해 보면 어떨까요?" + "*Bonus로 분리하셨네요! Bonus 또한 하나의 로또 번호라고 볼 수 있지 않을까요*?" + "*로또 번호를 set으로 관리하는 방법도 있는 것* 같아요 :)"
|
|
97
|
+
|
|
98
|
+
### 12. `Lottos`의 *복합 책임* — *관리 + 생성 + 가격*
|
|
99
|
+
|
|
100
|
+
리뷰어: "*Lottos에는 로또들을 관리하는 것뿐만 아니라, 로또를 생성해 주는 책임 또한 있는 것 같*아요! *로또 가격을 관리하고, 돈을 받아, 로또를 생성해 주는 책임은 다른 클래스로 나누는 것*도 고민해 보면 좋을 거 같아요!"
|
|
101
|
+
|
|
102
|
+
### 13. `LottoPrice`의 *음수 가능성*
|
|
103
|
+
|
|
104
|
+
```kotlin
|
|
105
|
+
class LottoPrice(val value: Int) // ⚠ 검증 부재
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
리뷰어: "*원시값 포장의 장점을 고민해 보시면 좋을 것* 같아요! *LottoPrice에 음수가 들어갈 수 있을까요*?"
|
|
109
|
+
|
|
110
|
+
### 14. *방어적 코드 vs 미래 팀원*
|
|
111
|
+
|
|
112
|
+
리뷰어: "*생성을 막았더라도, 이후 팀원들 등으로의 인해 의도치 않은 코드가 들어올 수 있다고* 생각해요! *당장의 구조에는 검증의 필요성이 없을지라도, 방어적 코드가 있으면 좋을 거 같*아요!"
|
|
113
|
+
|
|
114
|
+
### 15. `RankTest`이지만 *LottoRankDeterminer 테스트*
|
|
115
|
+
|
|
116
|
+
리뷰어: "*RankTest이지만, 실제로는 LottoRankDeterminer의 테스트로 보여지네요*!"
|
|
117
|
+
|
|
118
|
+
### 16. *테스트 중복 초기화*
|
|
119
|
+
|
|
120
|
+
리뷰어: "*중복된 초기화 작업이 보이*네요! *@before을 통해 테스트 초기화 작업을 할 수 있*습니다!"
|
|
121
|
+
|
|
122
|
+
### 17. *given/when/then 테스트 구조*
|
|
123
|
+
|
|
124
|
+
```kotlin
|
|
125
|
+
@Test
|
|
126
|
+
fun `로또 번호와 당첨 번호의 일치 개수를 반환한다`() {
|
|
127
|
+
val lotto =.
|
|
128
|
+
val winLotto = WinLotto(.)
|
|
129
|
+
val result = lotto.determineCountOfMatch(winLotto.winNumber)
|
|
130
|
+
assertThat(result).isEqualTo(6)
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
리뷰어:
|
|
135
|
+
```kotlin
|
|
136
|
+
// given
|
|
137
|
+
val lotto = Lotto.from(.)
|
|
138
|
+
val winLotto = WinLotto(.)
|
|
139
|
+
// when
|
|
140
|
+
val result = lotto.determineCountOfMatch(winLotto.winNumber)
|
|
141
|
+
// then
|
|
142
|
+
assertThat(result).isEqualTo(6)
|
|
143
|
+
```
|
|
144
|
+
"*테스트 코드의 가독성과 관리를 위해 준비/실행/검증부를 나눠 보면* 어떨까요? *무엇을 테스트하는지, 무엇을 검증하는지 명확*해질 수 있을 것 같아요!" — PR #123 (Gyuil-Hwnag).
|
|
145
|
+
|
|
146
|
+
### 18. `List(lottoCount) Builder`
|
|
147
|
+
|
|
148
|
+
리뷰어: "*List(lottoCount) Builder를 사용해 보셔도* 좋을 것 같아요!".
|
|
149
|
+
|
|
150
|
+
### 19. *팩토리 함수에 `List<Int>` 받기*
|
|
151
|
+
|
|
152
|
+
리뷰어: "팩토리 메소드 👍 *생성자와 같은 역할*을 하고 있네요. *List<Int>를 받아서 변환*해 보면 어떨까요?"
|
|
153
|
+
|
|
154
|
+
### 20. 학생 *반복 입력 자가 의문* + 잭슨 답
|
|
155
|
+
|
|
156
|
+
학생: "InputView에 관해 *질문드리고 싶은 게 있*습니다! 사실 *요구사항에는 '입력에 대한 예외 발생 시 다시 입력을 받아야 한다'라는 말이 없*어 항상 해당 로직을 구성할 때 의문점이 생기곤 합니다! 크루들 사이에도 이와 관련해서 *말이 많이 오가고*, 대게는 '*나중에 이러한 요구사항이 생길 때를 대비하자*'라는 말이 오간 것을 들었는데, *요구사항에는 없는 반복 입력을 계속 냅두는 게 맞는 것일까요.?* 아니면 *예외 처리를 해 프로그램 동작이 멈추게 하는 것이 맞을까요*."
|
|
157
|
+
|
|
158
|
+
잭슨 답: "사실이 *요구사항에 존재 없기 때문에, 구현하지 않아도 되지만, 사용성을 고려하는 부분은 좋은 거 같*아요! 현업에서도 *요구사항에 없는 부분도 고려하여, 다른 관계자들과 적극적으로 커뮤니케이션*하기도 합니다. 하지만, *예측하지 못한 에러의 경우에는 의도치 못한 동작을 하게 되는데요, input에 대한 에러뿐 아니라, 다양한 에러에서도 tryRerun이 동작하기 때문에 의도하지 않은 동작의 가능성도 있지 않을까요*?" — PR #49 (잭슨, 써니 2단계)와 *직접 연결*.
|
|
159
|
+
|
|
160
|
+
### 21. 학생 *InputView 책임 자가 의문* + 잭슨 답
|
|
161
|
+
|
|
162
|
+
학생: "또, *InputView에서 입력 받은 원시값을 넘겨주는 것이 아닌 포장된 PurchaseMoney나 Lotto, LottoNumber를 넘겨주는 것과 입력에 대한 검증을 수행하는 것이 올바른 InputView의 책임인지 의문*이 듭니다!"
|
|
163
|
+
|
|
164
|
+
잭슨 답: "*입력값 검증에 대한 부분은 View에도 있어도 되지만, 입력 시 검증하더라도 도메인에서 처리될 부분*이라고 생각이 들어요! *원시값을 포장 또한 도메인 영역에서 진행되어야 책임이 있지 않을까* 생각합니다!"
|
|
165
|
+
|
|
166
|
+
### 22. *책임 분리 전반 평가*
|
|
167
|
+
|
|
168
|
+
리뷰어 (전반 코멘트): "*구현에는 정답이 없기 때문에, 다양한 구조가 될 수 있*어요! 다양한 구조 들 중 *각각의 구현 방법 중 장단점을 비교해서, 써니님 만의 우선순위나 규칙, 코딩 철학을 고민*해 보시면 좋을 거 같아요! 저의 개인적인 생각으로는, *makeWinStatistics에 당첨에 대한 로직이 모두 있었지만, makeWinStatistics는 컨트롤러 내에 구현되어 있기 때문에, 테스트로 검증하기 힘들뿐더러, 컨트롤러에서 View 관련 코드와 도메인 로직들이 다양하게 실행되고 있었던 거 같*아요! 각 *모델들에게 책임을 나누었기 때문에, 테스트할 수 있는 구조가 된 것 같아서 개선되었다고 생각이 들어요*!"
|
|
169
|
+
|
|
170
|
+
## 리뷰어 의견 요지
|
|
171
|
+
|
|
172
|
+
- ***"World" god-naming***. 책임 모호.
|
|
173
|
+
- **함수 순서 = *호출 흐름*** (Kotlin 컨벤션).
|
|
174
|
+
- **`Lotto` *범위/중복/개수* 검증 셋 다**.
|
|
175
|
+
- **장수 결정 = *도메인 책임***.
|
|
176
|
+
- **`WinNumber` vs `Lotto` *책임 중복*** 정리.
|
|
177
|
+
- **`Rank` *bonus 정보*** + *기본값으로 노출 최소화*.
|
|
178
|
+
- **싱글턴 = *강한 커플링*** — *프로퍼티 주입*.
|
|
179
|
+
- **`tryAndRerun` *Domain 적용 위험***.
|
|
180
|
+
- **Tell, Don't Ask** — `lottos.determine(winningLotto)`.
|
|
181
|
+
- **YAGNI** — *구현체만 쓰는 인터페이스*.
|
|
182
|
+
- **원시값 포장 + Set**.
|
|
183
|
+
- **`Lottos` *복합 책임* 분리**.
|
|
184
|
+
- **`LottoPrice` 음수 검증**.
|
|
185
|
+
- **방어적 코드 *미래 팀원*** 고려.
|
|
186
|
+
- **테스트 이름 = *실제 테스트 대상*과 일치**.
|
|
187
|
+
- **`@BeforeEach` 중복 제거**.
|
|
188
|
+
- **given/when/then**.
|
|
189
|
+
- **`List(n) { }` Builder**.
|
|
190
|
+
|
|
191
|
+
- **대표 인용:**
|
|
192
|
+
> 개발자들은 보통 *코드를 작성하는 시간보다 작성을 위해 코드를 읽는 시간이 훨씬 많다고* 해요!
|
|
193
|
+
> — @namjackson on `src/main/kotlin/lotto/controller/World.kt`
|
|
194
|
+
|
|
195
|
+
> YAGNI라고, *"실제로 필요할 때 무조건 구현하되, 그저 필요할 것이라고 예상할 때에는 절대 구현하지 말라"*라는 소프트웨어 원칙을 말하는 의견도 있어요.
|
|
196
|
+
> — @namjackson on `src/main/kotlin/lotto/domain/RankDeterminer.kt`
|
|
197
|
+
|
|
198
|
+
> 싱글턴 인스턴스로 접근하게 되면, *강한 커플링이 생겨서 결합도가 높아져*요!
|
|
199
|
+
> — @namjackson on `src/main/kotlin/lotto/domain/LottoMachine.kt`
|
|
200
|
+
|
|
201
|
+
> 다양한 구조 들 중 각각의 구현 방법 중 장단점을 비교해서, *써니님 만의 우선순위나 규칙, 코딩 철학을 고민*해 보시면 좋을 거 같아요!
|
|
202
|
+
> — @namjackson (PR 전반 평가)
|
|
203
|
+
|
|
204
|
+
## 얻은 교훈
|
|
205
|
+
|
|
206
|
+
- **"World" god-naming = lotto 초창기 (#2, #3) 공통 안티** — *책임 무경계*. *Application/Controller* 같은 *기능 단어*가 자연.
|
|
207
|
+
- **함수 *호출 순서대로 배치* (코틀린 컨벤션)** — *읽기 시간 >>> 쓰기 시간*. 위에서 아래로.
|
|
208
|
+
- **`Lotto` 도메인 invariant = *3개* (개수/범위/중복)** — 모두 *init*에서. *원시값 포장 + Set*은 *invariant 일부를 타입으로 표현*.
|
|
209
|
+
- **장수 결정 = *도메인 책임*** — `purchaseMoney.getLottoCount()`. Controller에 두면 *Tell-Don't-Ask 위반*.
|
|
210
|
+
- **`Rank` 기본값 매개변수로 *노출 최소화*** — `matchBonus: Boolean = false`로 *MISS/FIRST/THIRD/FOURTH/FIFTH*에 noise 제거.
|
|
211
|
+
- **싱글턴 = *강한 커플링*** — *프로퍼티 주입*이 *대체 구현체 가능*.
|
|
212
|
+
- **`tryAndRerun` *적용 영역*** — *입력 경계*에만. *도메인 영역에 적용*하면 *의도 외 에러*까지 재실행.
|
|
213
|
+
- **Tell, Don't Ask** — `lotto.determine(winLotto)`. `controller.organize(lotto.value,.)` 안티.
|
|
214
|
+
- **YAGNI** — *예상으로 인터페이스* 도입 시 *구현체만 사용*하면 부담. *변경 가능성이 실제*일 때만.
|
|
215
|
+
- **`Set` = *중복 방지 invariant***.
|
|
216
|
+
- **`Lottos` *복합 책임* (관리 + 생성 + 가격)** = 분리.
|
|
217
|
+
- **`LottoPrice` 음수 검증** — *원시값 포장의 본질*은 *invariant*. 검증 없으면 wrapper.
|
|
218
|
+
- **방어적 코드 *미래 팀원* 고려** — *현재는 안 깨지더라도* *수정 시 깨질 가능성*.
|
|
219
|
+
- **테스트명 = *실제 SUT*** — `RankTest`이지만 *LottoRankDeterminer 테스트*면 *오해 유발*.
|
|
220
|
+
- **`@BeforeEach` 중복 제거**.
|
|
221
|
+
- **`given/when/then`** — *3구역 분리*가 *유기적 객체 테스트* 가독성.
|
|
222
|
+
- **`List(n) { gen() }`** — Kotlin idiom.
|