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,145 @@
|
|
|
1
|
+
# PR #85 — [로또] 꼬상 2단계 미션 제출합니다
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@kkosang](https://github.com/kkosang)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-lotto/pull/85
|
|
5
|
+
- **단계:** 2단계 (수동 로또 추가)
|
|
6
|
+
- **리뷰어:** @Gyuil-Hwnag
|
|
7
|
+
- **라인 코멘트:** 132 (가장 많은 코멘트)
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **`LottoNumber` 값 객체 도입** — 원시 강박 탈출 (1단계 → 2단계 리팩토링의 핵심).
|
|
12
|
+
- **`Rank` enum** — 등수 + 상금을 enum으로 묶음.
|
|
13
|
+
- **`InputValidator` object로 검증 집중** — Validation 한 곳에 모음.
|
|
14
|
+
- **`InputException` enum** — 에러 케이스를 enum으로 정형화.
|
|
15
|
+
- **`require()` 활용** — 도메인 무결성.
|
|
16
|
+
- **`ParameterizedTest + CsvSource`** — 케이스 풍부.
|
|
17
|
+
|
|
18
|
+
## 못한 점 (설계 관점)
|
|
19
|
+
|
|
20
|
+
### 1. `Buyer`가 mutable `var lottos: Lottos` 보유
|
|
21
|
+
|
|
22
|
+
```kotlin
|
|
23
|
+
class Buyer(private val purchaseAmount: Int) {
|
|
24
|
+
val numberOfLotto: Int = calculateNumberOfLotto()
|
|
25
|
+
var purchasedLotto: Lottos = Lottos(emptyList()) // ⚠ 초기엔 비어있다가 나중에 채워짐
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
생성자에서 모두 채우지 않고 외부에서 `buyLottos(lottos)` 메서드를 통해 나중에 채움 → invariant ("Buyer는 구매한 로또를 가진다")가 시간차로 깨짐.
|
|
30
|
+
|
|
31
|
+
### 2. `Controller`에 `var winningStatistics` 같은 lateinit 패턴 잔존
|
|
32
|
+
|
|
33
|
+
```kotlin
|
|
34
|
+
fun run() {
|
|
35
|
+
val purchaseAmount = InputView.inputPurchaseAmount()
|
|
36
|
+
buyer = Buyer(purchaseAmount)
|
|
37
|
+
val numberOfManualLotto = InputView.inputPurchaseSizeOfManualLotto(purchaseAmount)
|
|
38
|
+
publishLottos(numberOfManualLotto) // buyer 멤버에 side-effect
|
|
39
|
+
val winningLotto = drawWinningLotto()
|
|
40
|
+
winningStatistics = makeWinningStatics(buyer.purchasedLotto, winningLotto)
|
|
41
|
+
displayWinningStatistics(purchaseAmount)
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`run()`이 너무 많은 단계를 직접 조율. 각 단계가 *Controller 멤버 변수*에 부수효과로 결과 저장.
|
|
46
|
+
|
|
47
|
+
### 3. `INVALID_INPUT = -1`로 magic sentinel 값 사용
|
|
48
|
+
|
|
49
|
+
```kotlin
|
|
50
|
+
private const val INVALID_INPUT = -1
|
|
51
|
+
|
|
52
|
+
fun validatePurchaseAmount(input: String): Int {
|
|
53
|
+
val purchaseAmount = input.toIntOrNull() ?: INVALID_INPUT // ⚠ -1을 정상 흐름에 흘림
|
|
54
|
+
validatePurchaseAmountRange(purchaseAmount)
|
|
55
|
+
return purchaseAmount
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`null`이 의미하는 "변환 실패"를 `-1`이라는 정상 정수 자리에 끼워 넣음. 호출자가 검증을 안 하면 `-1`이 그대로 도메인에 들어감.
|
|
60
|
+
|
|
61
|
+
### 4. View 안에서 try-catch + 재귀로 재입력
|
|
62
|
+
|
|
63
|
+
```kotlin
|
|
64
|
+
fun inputPurchaseSizeOfManualLotto(purchaseAmount: Int): Int {
|
|
65
|
+
val numberOfManualLotto = br.readLine()
|
|
66
|
+
return try {
|
|
67
|
+
InputValidator.validatePurchaseSizeOfManualLotto(numberOfManualLotto, purchaseAmount)
|
|
68
|
+
} catch (exception: IllegalArgumentException) {
|
|
69
|
+
println(exception.message)
|
|
70
|
+
inputPurchaseSizeOfManualLotto(purchaseAmount) // ⚠ View가 재시도 흐름까지 보유
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
InputView가 재시도 정책을 결정 — 입력 받기 책임 초과.
|
|
76
|
+
|
|
77
|
+
### 5. `Constant.kt` 단일 파일에 모든 상수
|
|
78
|
+
|
|
79
|
+
```kotlin
|
|
80
|
+
object Constant {
|
|
81
|
+
// 모든 상수를 한 파일에.
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
→ 리뷰어 지적: "`Constant`라는 네이밍은 무엇을 담당하는 것인지 혼란을 줄 수 있다. `LottoNumberConstants` 등으로."
|
|
86
|
+
|
|
87
|
+
### 6. `Lotto.toString()`에 표현 형식
|
|
88
|
+
|
|
89
|
+
```kotlin
|
|
90
|
+
open class Lotto(val numbers: List<LottoNumber>) {
|
|
91
|
+
override fun toString(): String {
|
|
92
|
+
return numbers.map { it.number }.sorted().joinToString(", ", "[", "]")
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
도메인 객체가 출력 형식 (`", "`, `"["`, `"]"`)을 직접 결정 → OutputView 책임 침범.
|
|
98
|
+
|
|
99
|
+
### 7. `WinningStatistic`가 `Pair<Rank, Int>` 보유
|
|
100
|
+
|
|
101
|
+
```kotlin
|
|
102
|
+
class WinningStatistic(val result: Pair<Rank, Int>) {. }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`first`/`second`가 무엇인지 모름. data class 또는 명시적 필드 필요.
|
|
106
|
+
|
|
107
|
+
## 리뷰어 의견 요지
|
|
108
|
+
|
|
109
|
+
리뷰어 @Gyuil-Hwnag의 핵심 가르침:
|
|
110
|
+
|
|
111
|
+
1. **모호한 이름 = 책임 모호** — `Constant`, `WinningStatistic.result` 등 일반 어휘 회피.
|
|
112
|
+
|
|
113
|
+
2. **try-catch + 재귀 회피** — `runCatching` 또는 `toIntOrNull() ?: return inputXxx()` 같은 코틀린 idiom.
|
|
114
|
+
|
|
115
|
+
3. **표현 형식의 자리 = OutputView** — `joinToString(", ", "[", "]")`이 도메인에 있으면 표현 변경 시 도메인 변경.
|
|
116
|
+
|
|
117
|
+
4. **`INVALID_INPUT = -1` 같은 sentinel 값은 위험** — null/Optional/Either 등 *타입으로 실패를 표현*.
|
|
118
|
+
|
|
119
|
+
5. **mutable lateinit 패턴 회피** — `Buyer`가 생성 시점에 구매한 로또까지 받거나, 별도 팩토리 메서드 사용.
|
|
120
|
+
|
|
121
|
+
- **대표 인용:**
|
|
122
|
+
> purchasedLotto를 mutable한 변수가 아닌 초기에 생성해서 사용하는 방법도 고민해보면 좋을 것 같습니다!
|
|
123
|
+
>
|
|
124
|
+
> — @Gyuil-Hwnag on `src/main/kotlin/model/Buyer.kt`
|
|
125
|
+
|
|
126
|
+
> 자칫하면 Constant라는 네이밍은 어떤 것을 담당하는 것인지에 대해서 혼란을 줄 수도 있겠다는 생각이 듭니다. LottoNumberConstants 등으로 수정하는 것도
|
|
127
|
+
>
|
|
128
|
+
> — @Gyuil-Hwnag on `src/main/kotlin/util/Constant.kt`
|
|
129
|
+
|
|
130
|
+
> INVALID_INPUT = -1으로 지정하신 이유가 있을까요??
|
|
131
|
+
>
|
|
132
|
+
> — @Gyuil-Hwnag on `src/main/kotlin/util/InputValidator.kt`
|
|
133
|
+
|
|
134
|
+
> 해당 내용을 try-catch를 사용안하는 방법으로 수정해보는 것도 고민해보면 좋을 것 같습니다!
|
|
135
|
+
>
|
|
136
|
+
> — @Gyuil-Hwnag on `src/main/kotlin/view/InputView.kt`
|
|
137
|
+
|
|
138
|
+
## 얻은 교훈
|
|
139
|
+
|
|
140
|
+
- **mutable lateinit 패턴 = invariant의 시간차 파괴**. 객체가 생성 시점부터 *완성된 상태*를 갖도록 설계. "나중에 채워진다"는 곧 "잠시 동안은 깨진 상태"라는 뜻.
|
|
141
|
+
- **sentinel 값 (`-1`, `""`)은 타입 시스템의 함정**. `null` 또는 sealed class로 *실패를 타입으로* 표현해야 호출자가 강제로 처리.
|
|
142
|
+
- **재시도 흐름의 자리 = Coordinator(Controller)**. View는 입력 받기만, 검증 실패 시 재시도 결정은 Controller가.
|
|
143
|
+
- **표현 형식은 OutputView로**. `Lotto.toString()`이 표현을 결정하면 출력 변경이 도메인 변경. lotto 미션 특히 출력 포맷 변경 잦음.
|
|
144
|
+
- **`Pair`는 일회용**. `WinningStatistic`처럼 영구적으로 들고 다니는 자료는 data class 또는 명시적 객체로.
|
|
145
|
+
- **`Constant.kt`는 god-folder**. 어떤 상수든 다 들어가 응집도 0. 의미별 분리 (`LottoConstants`, `MoneyConstants`).
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# PR #70 — [로또 1단계] 케이엠
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@kmkim2689](https://github.com/kmkim2689)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-lotto/pull/70
|
|
5
|
+
- **단계:** 1단계
|
|
6
|
+
- **리뷰어:** @ghojeong (파이로)
|
|
7
|
+
- **라인 코멘트:** 20
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **`Rank` enum 도입 + `(countOfMatch, winningMoney)`** — 등수/상금 한 곳.
|
|
12
|
+
- **`LottoNumber` `value class` + `private const val MIN/MAX` + 메시지에 *상수 참조***.
|
|
13
|
+
- **`fun interface LottoGenerator`** — 테스트 가능 구조.
|
|
14
|
+
- **`runCatching + onFailure { return retry() }`** — 재시도 흐름.
|
|
15
|
+
- **README에 기능 요구사항 + 명세 잘 정리**.
|
|
16
|
+
|
|
17
|
+
## 못한 점 (설계 관점)
|
|
18
|
+
|
|
19
|
+
### 1. `Rank.valueOf`의 *복잡한 분기*
|
|
20
|
+
|
|
21
|
+
```kotlin
|
|
22
|
+
companion object {
|
|
23
|
+
private const val MIN_COUNT = 0
|
|
24
|
+
private const val MISS_MAX_THRESHOLD = 2
|
|
25
|
+
private val NON_BONUS_COUNTS = listOf(3, 4, 6)
|
|
26
|
+
fun valueOf(countOfMatch: Int, matchBonus: Boolean): Rank = when {
|
|
27
|
+
countOfMatch in MISS_RANGE -> MISS
|
|
28
|
+
countOfMatch == SECOND.countOfMatch && matchBonus -> SECOND
|
|
29
|
+
countOfMatch == THIRD.countOfMatch -> THIRD
|
|
30
|
+
countOfMatch in NON_BONUS_COUNTS -> entries.first { it.countOfMatch == countOfMatch }
|
|
31
|
+
else -> throw IllegalArgumentException(.)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
학생 자가 정리: "Rank 객체에 대해 어디까지 책임을 부여해야 할 것인가에 대해 논의. 한 의견은 *발행된 로또와 비교까지* 부여, 다른 의견은 *상수로만 활용*. 결국 Rank라는 명사의 의미(*순위라는 정보*)에 초점을 맞추어, 상수로만 활용." 리뷰어: "이미 고민에 대해 *훌륭한 결론*. … 한눈에 각각이 무슨 값을 가지고 있는지 들어오는 Rank에 비해, Rank1이 더 많은 코드를 읽어야 하기 때문입니다."
|
|
37
|
+
|
|
38
|
+
### 2. `runCatching + onFailure { return retry() }` — 무한 루프 + indentation 깊이
|
|
39
|
+
|
|
40
|
+
```kotlin
|
|
41
|
+
private fun getPurchaseExpense(): Int =
|
|
42
|
+
runCatching {
|
|
43
|
+
lottoGameInputView.inputPurchaseExpense()
|
|
44
|
+
}.onFailure {
|
|
45
|
+
if (it is IllegalArgumentException) return getPurchaseExpense()
|
|
46
|
+
}.getOrThrow()
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
리뷰어: "runCatching을 활용해 onFailure 처리를 해주시는 점 멋집니다. 하지만 예외 처리는 근본적으로 *if-else 처리와 다를 바 없다*는 점을 명심하세요. *만약 이러한 예외가 발생한다면, 이러한 로직을 처리한다*라는 조건문입니다. 즉 위와 같은 상황에서는 *조건문이 중첩되어 indentation depth가 깊어진 것*과 동일한 상황입니다. 로직을 더 작은 단위로 쪼갤 필요가 있어 보입니다. 뿐만 아니라 *조건문이 들어갔다는 것은, 곧 테스트할 로직이 있다는 의미*. Controller에 있는 로직들을 model로 옮겨서 테스트 용이하도록." + "만약 `inputPurchaseExpense()`에서 IllegalArgumentException이 계속 발생하면 *무한 루프*를 돌아야 하나요? 언제 탈출할 수 있을지에 관해서는 *조건*을 생각하면 좋을 것 같습니다. 안드로이드 개발에서 *폰이 갑자기 뜨거워지면서 벽돌*."
|
|
50
|
+
|
|
51
|
+
### 3. 예외 메시지가 *사용자 안내*가 아님
|
|
52
|
+
|
|
53
|
+
```kotlin
|
|
54
|
+
private const val EXCEPTION_PURCHASE_EXPENSE = "로또 구매 금액은 정수여야 합니다."
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
리뷰어: "보통 예외상황에 따른 메시지를 사용자에게 던질 때는, *사용자가 무엇을 잘못했는지 어떻게 하면 제대로 프로그램을 사용할 수 있는지* 알려주는 게 좋습니다. 가령, *음수인 -1도 정수*입니다." — *정수 입력*만으로는 *양수 + 1000원 단위*를 의미하지 않음.
|
|
58
|
+
|
|
59
|
+
### 4. `lottie`라는 별난 명명
|
|
60
|
+
|
|
61
|
+
```kotlin
|
|
62
|
+
val lottie: List<Lotto> = purchaseLottie(purchaseExpense)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
리뷰어 농담: "Lotto의 복수형이 Lottie였나요? 신기하군요." — *Lottos*가 더 자연스러움.
|
|
66
|
+
|
|
67
|
+
### 5. `value class LottoNumber` — 학생 기준 묻기
|
|
68
|
+
|
|
69
|
+
리뷰어: "LottoNumber에서는 value class로 해주셨는데, 케이엠 님이 *value class를 언제 써야겠다*고 생각하는 본인만의 기준이 있으시나요?" — 기준 명시화 학습 유도.
|
|
70
|
+
|
|
71
|
+
## 리뷰어 의견 요지
|
|
72
|
+
|
|
73
|
+
- **runCatching = if-else** — *indentation depth*는 *조건문 중첩*과 같음. 로직 분리 + 테스트.
|
|
74
|
+
- **`return retry()`는 *무한 루프* 위험** — *탈출 조건* 또는 *최대 시도 횟수* 고려.
|
|
75
|
+
- **사용자 메시지 = *행동 안내*** — *정수여야 합니다*는 *너무 좁음*.
|
|
76
|
+
- **명사형 명명 = 자연어 따라가기** — `Lottie` → `Lottos`.
|
|
77
|
+
- **상수 + 메시지 = *상수 참조***로 변경 동기화.
|
|
78
|
+
- **value class 도입의 *기준* 명시화**.
|
|
79
|
+
|
|
80
|
+
- **대표 인용:**
|
|
81
|
+
> 예외 처리는 근본적으로 if-else 처리와 다를 바 없다는 점을 명심하세요. 즉 위와 같은 상황에서는 조건문이 중첩되어 indentation depth가 깊어진 것과 동일한 상황입니다.
|
|
82
|
+
> — @ghojeong on `src/main/kotlin/controller/LottoGameController.kt`
|
|
83
|
+
|
|
84
|
+
> 만약 `inputPurchaseExpense()`에서 IllegalArgumentException이 계속 발생하면 무한 루프를 돌아야 하나요? 안드로이드 개발에서 폰이 갑자기 뜨거워지면서 벽돌이 되는 현상.
|
|
85
|
+
> — @ghojeong on `src/main/kotlin/controller/LottoGameController.kt`
|
|
86
|
+
|
|
87
|
+
> 가령, 음수인 -1도 정수입니다. 안드로이드 개발자 관점에서 사용자 경험에 관련된 피드백.
|
|
88
|
+
> — @ghojeong on `src/main/kotlin/view/ConsoleLottoGameInputView.kt`
|
|
89
|
+
|
|
90
|
+
## 얻은 교훈
|
|
91
|
+
|
|
92
|
+
- ***runCatching은 if-else의 다른 표현*** — indentation은 같음, 테스트 가능성도 같음.
|
|
93
|
+
- **재시도 = 탈출 조건 필요** — *무한 루프*는 *벽돌화 위험*.
|
|
94
|
+
- **사용자 메시지 = *행동 안내*** — 도메인 invariant를 *행동으로 옮길 수 있게* 표현.
|
|
95
|
+
- **명사형은 자연어 따라가기** — *Lottie* 같이 *별난 변형*은 *읽는 부담*.
|
|
96
|
+
- **상수 + 메시지 = 상수 참조** — 변경 동기화.
|
|
97
|
+
- **value class 도입은 *명시적 기준*** — 호출자에게 *왜 이 클래스가 value class인지* 보여야 함.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# PR #82 — [로또 2단계] 케이엠
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@kmkim2689](https://github.com/kmkim2689)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-lotto/pull/82
|
|
5
|
+
- **단계:** 2단계 (수동 로또 추가)
|
|
6
|
+
- **리뷰어:** @ghojeong (파이로)
|
|
7
|
+
- **라인 코멘트:** 19
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **`fun interface LotteriesGenerator { fun generate(): List<Lotto> }`** + `AutoLotteriesGenerator`/`ManualLotteriesGenerator` 구현체 — 인터페이스로 깔끔히 추상화.
|
|
12
|
+
- **`ManualLotteriesGenerator(manualCount, onReceiveNumbers: () -> List<Int>)`** — *View 의존성 차단*하면서 *수동 번호 입력 시점*을 람다로 주입.
|
|
13
|
+
- **`Count` 원시값 포장**으로 수동 검증 응집.
|
|
14
|
+
- **`LottoMachine`을 *상태 보유 객체*로** — `availableCount`, `currentLotteries` 등 진행 상태 명시화.
|
|
15
|
+
- **수동 로또 generator의 테스트 — `trial` 카운터로 *시나리오 검증***.
|
|
16
|
+
- **자가 의문 PR에 풍부히 명시** — *MatchCount 원시값 포장 기준*, *view 테스트 생략의 의미*, *Manager의 추상 깊이* 등.
|
|
17
|
+
|
|
18
|
+
## 못한 점 (설계 관점)
|
|
19
|
+
|
|
20
|
+
### 1. `Lottie` vs `lotteries` 용어 혼용
|
|
21
|
+
|
|
22
|
+
```kotlin
|
|
23
|
+
private fun purchaseLottie(.) =.
|
|
24
|
+
fun showPurchasedLottie(lottos: List<Lotto>) =.
|
|
25
|
+
val lotteries = randomLottoGameManager.generateLotteries(.)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
리뷰어: "어떨 때는 Lottie라는 용어를 쓰고 어떨 때는 lotteries라는 용어를 쓰는 것처럼 보이는군요. 이 둘을 *다른 의미로 쓰고 있나요? 아니면 같은 의미*로 쓰고 있나요?" 학생: "같은 의미의 변수들을 *다른 용어로 활용*하면 읽는 입장에서 혼란이 있을 것이라는 것을 알게 되었습니다. 통일성을 위하여 lotteries라는 용어로 변경하였습니다!" — 같은 개념은 *한 용어로 고정*.
|
|
29
|
+
|
|
30
|
+
### 2. `RandomLottoGameManager` — *Random*이 어디서 나오는가
|
|
31
|
+
|
|
32
|
+
```kotlin
|
|
33
|
+
class RandomLottoGameManager(private val lottoGenerator: LottoGenerator) : LottoGameManager {
|
|
34
|
+
override fun generateLotteries(purchaseExpense: Int) = lottoGenerator.generate(Money(purchaseExpense))
|
|
35
|
+
override fun generateWinningLotto(winningNumbers: List<Int>) = Lotto(*(winningNumbers.toIntArray()))
|
|
36
|
+
override fun generateBonusLottoNumber(bonusNumber: Int, winningLotto: Lotto) = LottoNumber(bonusNumber, winningLotto)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
리뷰어: "솔직히 RandomLottoGameManager의 *어디가 Random*한 것인지, 코드를 처음 보는 사람 입장이라고 가정하면 *파악하기 어렵습니다*. 실제 랜덤을 담당하는 코드는 LotteryGenerator 중 AutoLottoGenerator 안의, NumbersGenerator 중 RandomNumbersGenerator까지로 이어지게 됩니다. 결국 *랜덤 요소를 가지고 있어 테스트하기 어려운 model*이 `RandomNumbersGenerator`, `AutoLottoGenerator`, `RandomLottoGameManager` *3개나 되어 버리게* 되었습니다. 이런 구조로는 프로젝트가 커질수록 (*Manager를 관리하는 Manager가 생기는 경우*가 많습니다), 점점 테스트 불가능한 model들이 많아지리라 생각됩니다." — *추상화 단계*가 *테스트 불가 영역*을 *3중*으로 늘림. 후속 라운드에서 학생: "랜덤적인 요소를 가진 클래스(RandomNumbersGenerator)를 controller에서 *직접 의존*하도록 함으로써 나머지 클래스들의 *테스트가 가능*하도록 변경." — *국소화*.
|
|
41
|
+
|
|
42
|
+
### 3. `RandomLottoGameManager` 명명 — "*Wrapper 클래스를 가져오기 위한 용도*"
|
|
43
|
+
|
|
44
|
+
학생 PR 설명: "입력값을 바탕으로 Wrapper 클래스를 가져오기 위한 용도의 객체 추가." 리뷰어: "model에 새로 추가된 것은 LottoGameManager 인터페이스와 RandomLottoGameManager가 유일한데 이것이 '*Wrapper 클래스를 가져오기 위한 용도의 객체*'인 건가요? 아마 `List<Lotto>`와 `LottoNumber`를 *원시값 '포장(wrapper)' 클래스*라고 표현하시는 것 같고, 입력받은 숫자들을 원시값으로 포장 객체들로 바꾸어 반환하시기 때문에 그렇게 하신 것 같습니다. 그냥 LottoGameManager라고 하면 *좀더 코드를 읽기 쉬웠을* 듯합니다. 혹시 다른 클래스가 있나, *다시 한 번 체크하며 읽어야* 했습니다." — *PR 설명 어휘*가 코드 이해를 어렵게 함.
|
|
45
|
+
|
|
46
|
+
### 4. 랜덤 generator의 테스트 — `assertDoesNotThrow` 한정
|
|
47
|
+
|
|
48
|
+
```kotlin
|
|
49
|
+
@Test
|
|
50
|
+
fun `유효한 금액이 입력되었다면, 금액에 맞는 개수의 로또가 생성된다`() {
|
|
51
|
+
val expectedSize = 6
|
|
52
|
+
val actualSize = randomLottoGameManager.generateLotteries(6100).size
|
|
53
|
+
assertThat(actualSize).isEqualTo(expectedSize)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@Test
|
|
57
|
+
fun `유효한 우승 로또의 번호와 우승 번호와 중복되지 않는 보너스 번호가 입력되었다면, 보너스 번호를 위한 로또 숫자 객체가 생성된다`() {
|
|
58
|
+
assertDoesNotThrow {
|
|
59
|
+
randomLottoGameManager.generateBonusLottoNumber(7, Lotto(1, 2, 3, 4, 5, 6))
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
리뷰어: "랜덤 요소 때문에 구체적인 아웃풋을 테스트하지 못하고, *assertDoesNotThrow*만을 테스트하고 있습니다. 사실 *모든 종류의 아웃풋을 검증하는 assertThat 테스트는 당연하게도 assertDoesNotThrow를 포함하는 테스트*입니다. 이 테스트 이름이 좀 더 *유의미해질 수 있도록 단순한 assertDoesNotThrow 말고* 더 좋은 테스트를 작성해 주시면 좋을 것 같습니다." — *결과 검증이 안 되는 테스트*는 *함수 이름*의 약속을 못 지킴.
|
|
65
|
+
|
|
66
|
+
### 5. `ExceptionHandler` 인터페이스 도입의 의문
|
|
67
|
+
|
|
68
|
+
```kotlin
|
|
69
|
+
interface ExceptionHandler {
|
|
70
|
+
fun <T> handleInputValue(action: () -> T): T
|
|
71
|
+
fun handleOutputValue(action: () -> Unit)
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
리뷰어: "ExceptionHandler를 *별도의 인터페이스로 선언*하신 이유가 궁금합니다. input을 콘솔 입력이 아니라, 안드로이드를 통한 입력, 블루투스를 통한 입력 등등을 가정하셨기에 추상화하신 건가요? 그렇다면 *입력받는 부분이 아닌 입력 값에 대한 검증이 왜 여러 개가 필요한 경우*가 있는지 궁금해서 여쭈어봅니다. 입력값 검증의 요구사항이 *바뀌었을 때를 대비*하기 위함이라면, 요구사항이 바뀌기 전의 *과거의 로직은 레거시 취급*받아 *없어지도록* 저는 구조를 짤 것 같아서요." — 추상화는 *현재의 다양성*이 있을 때 비로소 정당화.
|
|
76
|
+
|
|
77
|
+
### 6. View 테스트 생략 — 학생 자가 의문
|
|
78
|
+
|
|
79
|
+
학생: "view에 대한 테스트를 생략한다는 것이 *문제가 된다는 것으로 배우거나 들어본 바는 없었습니다*. 미션에서도 *UI 로직은 제외*하고 테스트를 진행하라는 요구 조건. 다만 *입력값이 null인지 여부를 검증*한다는 것이 저에게는 중요한 것으로 느껴졌던 것 같습니다." 후속: "수동 로또의 요구사항을 확인하면서 *논리적 오류에 대해서만 예외*를 던져야 한다는 Kotlin의 예외 처리 방식을 알게 되었습니다. 크루들과 이야기를 나누어 보았을 때, *사용자로부터 입력을 받는 부분은 논리적인 오류가 아니라는 결론*을 얻을 수 있었는데 이것으로 *입력값이 null일 때 예외를 던지는지 여부를 테스트로 확인할 필요가 없어*지게 되었다고 생각하였습니다."
|
|
80
|
+
|
|
81
|
+
### 7. `LottoNumber(number: Int, winningLotto: Lotto)` 부생성자 — 보너스 검증
|
|
82
|
+
|
|
83
|
+
```kotlin
|
|
84
|
+
constructor(number: Int, winningLotto: Lotto) : this(number) {
|
|
85
|
+
val winningLottoNumbers = winningLotto.numbers.map { it.number }
|
|
86
|
+
require(number !in winningLottoNumbers) { EXCEPTION_DUPLICATE_BONUS_NUMBER_FORMAT }
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
리뷰어: "로직의 일부를 domain으로 옮겼다는 게 이 부분을 말씀하시는 건가요? 하지만 *관련해서 추가된 테스트 코드는 보이지를 않*아서 여쭈어봅니다." 학생: "보너스 번호가 우승 번호와 중복될 때 예외를 던지는지에 관한 *테스트 케이스를 추가*하였습니다. 사실 미션 수행 과정에서 *TDD를 원활히 진행하지 못하여*, 도메인에서 들어가는 모든 로직에 대한 테스트 케이스를 작성하지 못하고 일부 로직에 대한 *테스트를 생략*하게 된 것 같습니다."
|
|
91
|
+
|
|
92
|
+
### 8. `NumbersGenerator` → `LotteriesGenerator` 추상화 단계 상향
|
|
93
|
+
|
|
94
|
+
리뷰어 제안: "기왕 NumbersGenerator라는 인터페이스를 선언해 주신 것처럼, *더 큰 단위로 Lotteries 그 자체를 만드는 인터페이스*를 선언해 보면 어떨까 제안해 봅니다. `fun interface LotteriesGenerator { fun generate(): List<Lotto> }`" — *추상의 단위*를 *Number*에서 *Lottery*로 한 단계 올림. 학생 후속 라운드에서 정확히 그렇게 구현:
|
|
95
|
+
|
|
96
|
+
```kotlin
|
|
97
|
+
class ManualLotteriesGenerator(
|
|
98
|
+
private val manualCount: Count,
|
|
99
|
+
private val onReceiveNumbers: () -> List<Int>,
|
|
100
|
+
) : LotteriesGenerator {
|
|
101
|
+
override fun generate(): List<Lotto> = List(manualCount.value) { Lotto(*onReceiveNumbers().toIntArray()) }
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
리뷰어 평가: "제 의도와 일치합니다. 수동 로또를 *무척 훌륭하게* 구현해 주셨습니다."
|
|
106
|
+
|
|
107
|
+
### 9. `MatchCount` 원시값 포장 vs 단순 Int
|
|
108
|
+
|
|
109
|
+
학생 README에서 *MatchCount 원시값 포장*을 TODO로 남김. 리뷰어: "Lotto 클래스의 `getMatchCount(other: Lotto): Int`에서 말하는 MatchCount를 말하는 것 같은데, *케이엠이 생각하는 원시값 포장을 해야 하는 값과 하지 말아야 하는 값을 구분하는 기준*이 있나요?" — *원시값 포장의 기준*을 학생 스스로 정리하도록.
|
|
110
|
+
|
|
111
|
+
### 10. `LottoMachine`에 *발행된 lotteries 보관 + 추가* 패턴
|
|
112
|
+
|
|
113
|
+
리뷰어: "lottoMachine에 *생성된 로또 번호를 넘겨주는 게 아니라*, 추상화된 LotteriesGenerator 자체를 넘겨서, *lottoMachine을 테스트*하는 것이었습니다. LotteriesGenerator가 인터페이스로 추상화되어 있기 때문에, *언제든 정해진 시나리오의 로또 번호를 생성하도록 강제*할 수 있고, 그렇게 하면 *LottoMachine의 상태가 어떻게 변하고 어떻게 동작하는지 그 결과를 예측*할 수 있게 됩니다." — `LottoMachine(generator: LotteriesGenerator)`이 더 깊은 추상.
|
|
114
|
+
|
|
115
|
+
### 11. `LottoGameController` — 리뷰어 칭찬
|
|
116
|
+
|
|
117
|
+
리뷰어: "저는 컨트롤러 코드가 비대하다고 생각하지 않습니다. 첫째로 컨트롤러의 *코드의 줄 수가 100줄 이하로 충분히 작고*, 둘째로 컨트롤러의 *그 어떤 메서드에서도 조건문과 반복문이 존재하지 않고*, 무슨 역할을 하는지 메서드가 충분히 작고 직관적입니다. 저는 *더 이상 분리하기 어려울 만큼* 정말 잘 분리를 해 주신 것 같습니다!"
|
|
118
|
+
|
|
119
|
+
## 리뷰어 의견 요지
|
|
120
|
+
|
|
121
|
+
- **용어 일관성** — 같은 개념은 한 용어로.
|
|
122
|
+
- **랜덤은 *최외곽 1곳에 가두기*** — Random* Manager → Manager → Generator 3중은 *테스트 불가 영역 확장*.
|
|
123
|
+
- **클래스명에 *역할이 명시*** — `RandomLottoGameManager`는 *랜덤*이 어디서 들어오는지 코드에서 안 보임.
|
|
124
|
+
- **추상화 단위 상향** — `NumbersGenerator`(List<Int>)보다 `LotteriesGenerator`(List<Lotto>)가 *책임의 자연 단위*.
|
|
125
|
+
- **`assertDoesNotThrow`는 *함수명*에만**, 본문은 *결과 검증* 포함.
|
|
126
|
+
- **인터페이스 추상화의 정당화** = *현재의 다양성*. 미래 변경 대비 추상화는 *레거시 회피*가 더 자연.
|
|
127
|
+
- **수동 로또 generator의 *람다 주입*** — `onReceiveNumbers: () -> List<Int>`로 View 의존 차단.
|
|
128
|
+
- **LottoMachine에 *Generator 자체*를 주입** — 시나리오 강제 테스트.
|
|
129
|
+
|
|
130
|
+
- **대표 인용:**
|
|
131
|
+
> 랜덤 요소를 가지고 있어 테스트 하기 어려운 model이 `RandomNumbersGenerator`, `AutoLottoGenerator`, `RandomLottoGameManager` *3개나 되어버리게* 되었습니다. … 점점 *테스트 불가능한 model*들이 많아지리라 생각됩니다.
|
|
132
|
+
> — @ghojeong on `src/main/kotlin/model/RandomLottoGameManager.kt`
|
|
133
|
+
|
|
134
|
+
> 솔직히 RandomLottoGameManager의 *어디가 Random*한 것인지, 코드를 처음 보는 사람 입장이라고 가정하면 파악하기 어렵습니다.
|
|
135
|
+
> — @ghojeong on `src/main/kotlin/model/RandomLottoGameManager.kt`
|
|
136
|
+
|
|
137
|
+
> 모든 종류의 아웃풋을 검증하는 assertThat 테스트는 *당연하게도 assertDoesNotThrow를 포함하는 테스트*입니다.
|
|
138
|
+
> — @ghojeong on `src/test/kotlin/model/RandomLottoGameManagerTest.kt`
|
|
139
|
+
|
|
140
|
+
> 기왕 NumbersGenerator라는 인터페이스를 선언해 주신 것처럼, *더 큰 단위로 Lotteries 그 자체를 만드는 인터페이스*를 선언해 보면 어떨까 제안해 봅니다.
|
|
141
|
+
> — @ghojeong on `src/main/kotlin/lotto/model/NumbersGenerator.kt`
|
|
142
|
+
|
|
143
|
+
> LotteriesGenerator가 인터페이스로 추상화되어 있기 때문에, 언제든 *정해진 시나리오의 로또 번호를 생성*하도록 강제할 수 있고, 그렇게 하면 *LottoMachine의 상태가 어떻게 변하고 어떻게 동작하는지 그 결과를 예측*할 수 있게 됩니다.
|
|
144
|
+
> — @ghojeong on `src/main/kotlin/lotto/controller/LottoGameController.kt`
|
|
145
|
+
|
|
146
|
+
## 얻은 교훈
|
|
147
|
+
|
|
148
|
+
- **용어 일관성 = 협업 비용 감소** — `Lottie`/`lotteries`처럼 같은 개념을 두 용어로 부르면 *읽는 사람이 매번 확인*.
|
|
149
|
+
- **랜덤은 *최외곽 1곳*에 가두기** — Random Manager → Manager → Generator 같은 *3중 추상*은 *테스트 불가 영역을 확장*. Controller가 *직접 RandomNumbersGenerator만* 의존하고 나머지 도메인은 *번호를 받아 처리*.
|
|
150
|
+
- **클래스명에 *역할의 핵심***이 노출되어야 함 — `RandomLottoGameManager`의 *Random*이 코드에서 안 보이면 *부정확한 이름*.
|
|
151
|
+
- **추상화 단위는 *책임의 자연 단위*** — `List<Int>`보다 `List<Lotto>`가 도메인 책임의 단위. 추상이 *작은 단위*에 머무르면 *호출자가 한 번 더 변환* 필요.
|
|
152
|
+
- **추상화의 정당화 = *현재의 다양성*** — 미래 변경 대비 추상화는 *과설계*. 요구 변경 시 *레거시 교체*가 더 자연.
|
|
153
|
+
- **`assertDoesNotThrow`는 *함수 이름의 약속*만 지킬 뿐**, 본문은 *결과 검증*까지 포함해야 *함수명이 의미*를 가짐.
|
|
154
|
+
- **수동 generator의 *람다 주입*** — `onReceiveNumbers: () -> List<Int>` 같이 *View 의존을 람다로 추출*하면 *도메인 단위 테스트* 가능 + 시나리오 제어.
|
|
155
|
+
- **LottoMachine에 *Generator 자체*를 주입** — *로또 번호를 직접 받기*보다 *생성 정책*을 받으면, *상태 전이 시나리오*를 외부에서 강제할 수 있어 *기계 전체*를 단위 테스트 가능.
|
|
156
|
+
- **MatchCount 원시값 포장의 *기준*** — *행위가 있어야* 정당화. Int 반환에 머무르면 *wrapping 비용*만.
|
|
157
|
+
- **TDD 보존** — *일부 로직 테스트 생략*은 *후속 라운드에서 추가*되어야 하며, *변경 의도*가 PR에 명시되어야 함.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# PR #19 — [끄롱] 1단계 로또
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@krrong](https://github.com/krrong)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-lotto/pull/19
|
|
5
|
+
- **단계:** 1단계
|
|
6
|
+
- **리뷰어:** @laco-dev
|
|
7
|
+
- **라인 코멘트:** 79
|
|
8
|
+
|
|
9
|
+
## 잘한 점 (설계 관점)
|
|
10
|
+
|
|
11
|
+
- **`WinningLotto`가 `Lotto`와 `BonusNumber`를 보유** — 역할 표현 잘됨.
|
|
12
|
+
- **`RandomGenerator` 인터페이스** — 테스트 가능성.
|
|
13
|
+
- **`Rank` enum + `valueOf(match, bonus)`** 팩토리.
|
|
14
|
+
- **`InputViewInterface` 도입** — View 의존성 분리 시도.
|
|
15
|
+
|
|
16
|
+
## 못한 점 (설계 관점)
|
|
17
|
+
|
|
18
|
+
### 1. `LottoNumber` 도메인 누락 → `Set<Int>` 그대로 노출
|
|
19
|
+
|
|
20
|
+
```kotlin
|
|
21
|
+
class Lotto(val numbers: Set<Int>) {. }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
리뷰어 핵심 지적:
|
|
25
|
+
|
|
26
|
+
> 로또에서 사용하는 숫자는 결국 Int 타입이라고 볼 수 있겠습니다. 그렇다면 외부에서 가져온 이 숫자들이 로또 번호라는 것을 어떻게 알 수 있을까요
|
|
27
|
+
> ```kotlin
|
|
28
|
+
> val lotto = Lotto(.)
|
|
29
|
+
> val number = lotto.numbers.first()
|
|
30
|
+
> foo(number)
|
|
31
|
+
>
|
|
32
|
+
> fun foo(number: Int) {
|
|
33
|
+
> // number가 로또 번호인가? 그럼 또 검증해야되나?
|
|
34
|
+
> }
|
|
35
|
+
> ```
|
|
36
|
+
|
|
37
|
+
→ `LottoNumber` 값 객체로 추출하면 타입 시스템이 검증을 보장.
|
|
38
|
+
|
|
39
|
+
### 2. `RandomGenerator` 이름의 모호함
|
|
40
|
+
|
|
41
|
+
```kotlin
|
|
42
|
+
interface RandomGenerator {
|
|
43
|
+
fun generate(): Set<Int>
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> 단순히 RandomGenerator라는 이름이 1부터 45 사이의 중복되지 않은 숫자 6개를 반환한다는 것을 알 수 있을까요?
|
|
48
|
+
|
|
49
|
+
→ `LottoNumberGenerator`처럼 *무엇을* 생성하는지 명시. 인터페이스 계약을 시그니처/이름으로 드러내기.
|
|
50
|
+
|
|
51
|
+
### 3. `LottoStatistics`의 `compareNumbers`/`compareBonusNumber`가 public — 테스트만 위해 노출
|
|
52
|
+
|
|
53
|
+
```kotlin
|
|
54
|
+
class LottoStatistics(val winningLotto: WinningLotto) {
|
|
55
|
+
fun compareNumbers(lotto: Lotto): Int {. } // ⚠ 테스트만 호출
|
|
56
|
+
fun compareBonusNumber(lotto: Lotto): Boolean {. } // ⚠ 테스트만 호출
|
|
57
|
+
fun compare(lotto: Lotto): Rank =.
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> 이 함수들은 테스트 코드에서만 사용되고 있어요. 테스트 코드를 위해 구현 코드가 public으로 노출되어서는 안됩니다.
|
|
62
|
+
|
|
63
|
+
### 4. 함수 이름 모호 — `compare()`, `yield()`
|
|
64
|
+
|
|
65
|
+
```kotlin
|
|
66
|
+
fun compare(lotto: Lotto): Rank =.
|
|
67
|
+
fun yield(): Double =.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> compare(), yield()라는 함수 이름으로 하여금, 어떤 결과를 반환하는지 알 수 있을까요?
|
|
71
|
+
|
|
72
|
+
`compare`는 일반적으로 `-1/0/1` 반환을 시사. 도메인 어휘로 `match(lotto): Rank`, `profitRate(): Double`이 더 명확.
|
|
73
|
+
|
|
74
|
+
### 5. **Tell-Don't-Ask 위반 — Statistics가 외부 객체의 정보로 직접 비교**
|
|
75
|
+
|
|
76
|
+
```kotlin
|
|
77
|
+
class LottoStatistics(val winningLotto: WinningLotto) {
|
|
78
|
+
fun compareNumbers(lotto: Lotto): Int {
|
|
79
|
+
val winningNumbers = winningLotto.getWinningNumbers() // ⚠ winningLotto의 정보를 꺼냄
|
|
80
|
+
return lotto.numbers.filter { number -> // ⚠ lotto의 정보도 꺼냄
|
|
81
|
+
winningNumbers.contains(number)
|
|
82
|
+
}.size
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
리뷰어 가이드 (Tell-Don't-Ask의 모범):
|
|
88
|
+
|
|
89
|
+
> 몇개가 일치하는지 요청해서 결과를 받아오도록 해보세요. 객체지향 프로그래밍에서는 이 개념을 메시지를 보낸다 라고 표현합니다.
|
|
90
|
+
> ```kotlin
|
|
91
|
+
> val matchedRank: Rank = winningLotto.match(lotto)
|
|
92
|
+
> ```
|
|
93
|
+
|
|
94
|
+
→ Statistics가 직접 계산하지 말고 WinningLotto에게 메시지 전달.
|
|
95
|
+
|
|
96
|
+
### 6. Rank 집계 자료구조 부재
|
|
97
|
+
|
|
98
|
+
```kotlin
|
|
99
|
+
fun compare(lotto: Lotto): Rank = Rank.valueOf(.)
|
|
100
|
+
// ⚠ 각 Rank에 몇 개 일치하는지를 어떻게 셀까?
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
> Rank에 해당하는 값에 총 몇개의 당첨 갯수가 있는지를 확인하는 방법으로 적절한 자료구조는 무엇일까요?
|
|
104
|
+
|
|
105
|
+
→ `Map<Rank, Int>` 또는 더 깔끔하게 `groupingBy { it }.eachCount()`.
|
|
106
|
+
|
|
107
|
+
### 7. `WinningLotto`가 1~45 범위 검증 직접 수행 (중복)
|
|
108
|
+
|
|
109
|
+
```kotlin
|
|
110
|
+
class WinningLotto(val lotto: Lotto, val bonusNumber: Int) {
|
|
111
|
+
init {
|
|
112
|
+
require(!lotto.numbers.contains(bonusNumber)) { ERROR_CONTAIN_BONUS_NUMBER_IN_LOTTO }
|
|
113
|
+
require(bonusNumber in MINIMUM_LOTTO_RANGE..MAXIMUM_LOTTO_RANGE) { ERROR_BONUS_NUMBER_RANGE }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`Lotto` 내부에서도 `numbers in 1..45` 검증. `LottoNumber` 값 객체가 있으면 양쪽에서 사라짐.
|
|
119
|
+
|
|
120
|
+
### 8. `let` 오용
|
|
121
|
+
|
|
122
|
+
```kotlin
|
|
123
|
+
fun valueOf(countOfMatch: Int, matchBonus: Boolean): Rank {
|
|
124
|
+
return values().find { it.countOfMatch == countOfMatch }.let { matchResult ->
|
|
125
|
+
if (matchResult == SECOND && !matchBonus) return@let.
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
> let에 대한 올바른 사용방법이 아닙니다. when 문을 이용해서 표현 해 보도록 하세요.
|
|
131
|
+
|
|
132
|
+
## 리뷰어 의견 요지
|
|
133
|
+
|
|
134
|
+
리뷰어 @laco-dev의 메시지:
|
|
135
|
+
|
|
136
|
+
1. **`LottoNumber` 도메인 추출**이 모든 안티패턴의 출발점 — 범위 검증 중복, 일반 Int 노출, "이 Int가 로또 번호인가?" 의문 모두 해결.
|
|
137
|
+
|
|
138
|
+
2. **Tell-Don't-Ask = 메시지 전달**. Statistics가 두 객체의 정보를 꺼내서 비교 = feature-envy. `winningLotto.match(lotto): Rank` 한 메시지.
|
|
139
|
+
|
|
140
|
+
3. **함수명 = 도메인 어휘**. `compare`처럼 일반 어휘 회피, `match`, `profitRate` 등.
|
|
141
|
+
|
|
142
|
+
4. **테스트만을 위한 public 노출 금지** — racingcar에서도 반복 등장.
|
|
143
|
+
|
|
144
|
+
5. **인터페이스 이름이 *계약*을 드러내야** — `RandomGenerator`만으로는 "무엇을 생성하는지" 모름.
|
|
145
|
+
|
|
146
|
+
- **대표 인용:**
|
|
147
|
+
> 몇개가 일치하는지 요청해서 결과를 받아오도록 해보세요. 객체지향 프로그래밍에서는 이 개념을 메시지를 보낸다 라고 표현합니다. `val matchedRank: Rank = winningLotto.match(lotto)`
|
|
148
|
+
>
|
|
149
|
+
> — @laco-dev on `src/main/kotlin/domain/LottoStatistics.kt`
|
|
150
|
+
|
|
151
|
+
> 로또 번호라는 역할을 만들어서 가지도록 해 보면 어떨까요? 마찬가지로 로또 번호를 최대 6개 까지만 가져야 한다면, 그러한 역할을 가지는 객체를 만들어 볼 수 있겠습니다.
|
|
152
|
+
>
|
|
153
|
+
> — @laco-dev on `src/main/kotlin/domain/Lotto.kt`
|
|
154
|
+
|
|
155
|
+
## 얻은 교훈
|
|
156
|
+
|
|
157
|
+
- **`LottoNumber`는 lotto 미션의 *마스터 키***. 1-45 범위, 중복 검증, 보너스 비교 모두 이 한 값 객체로 해결.
|
|
158
|
+
- **Tell-Don't-Ask의 lotto 적용** = `winningLotto.match(lotto): Rank`. Statistics 같은 외부 객체가 비교 로직을 갖지 말고, 도메인 소유자(WinningLotto)에게 메시지.
|
|
159
|
+
- **함수명 컨벤션 차이**: `compare()` = 비교(-1/0/1), `match()` = 일치 확인. 도메인 어휘를 신중히.
|
|
160
|
+
- **인터페이스 이름 = 계약 요약**. `RandomGenerator`보다 `LottoNumberGenerator`가 의도 명확.
|
|
161
|
+
- **`Map<Rank, Int>` 자료구조** = lotto 통계의 표준. 등수별 개수를 한 자료구조로.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# PR #41 — [크롱] 2단계 로또
|
|
2
|
+
|
|
3
|
+
- **Reviewee:** [@krrong](https://github.com/krrong)
|
|
4
|
+
- **PR:** https://github.com/woowacourse/kotlin-lotto/pull/41
|
|
5
|
+
- **단계:** 2단계
|
|
6
|
+
- **리뷰어:** @laco-dev
|
|
7
|
+
- **라인 코멘트:** 45
|
|
8
|
+
|
|
9
|
+
## 못한 점 + 핵심 지적
|
|
10
|
+
|
|
11
|
+
### 1. 함수명 `makeMoney()` vs `Money(.)`
|
|
12
|
+
|
|
13
|
+
```kotlin
|
|
14
|
+
fun makeMoney(input: String): Money =.
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
> 마이너한 내용인데, Money는 왜 makeMoney()가 아닐까요?
|
|
18
|
+
|
|
19
|
+
→ 팩토리는 보통 `Money.of(input)` 또는 `Money(value)` 직접. `makeXxx` 패턴은 일관성 떨어짐.
|
|
20
|
+
|
|
21
|
+
### 2. 0 이상 검증을 Controller에서
|
|
22
|
+
|
|
23
|
+
```kotlin
|
|
24
|
+
class LottoController {
|
|
25
|
+
fun run() {
|
|
26
|
+
val count = readManualCount()
|
|
27
|
+
require(count >= 0) {. } // ⚠ Controller에서 비즈니스 로직
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> 항상 0 이상의 숫자를 받아야 한다는 것도 객체를 만들어서 처리해보세요. (비즈니스 로직을 도메인 모델로 옮긴다는 의미입니다)
|
|
33
|
+
|
|
34
|
+
### 3. `runCatching` 중복 — Controller + UI
|
|
35
|
+
|
|
36
|
+
```kotlin
|
|
37
|
+
// Controller
|
|
38
|
+
runCatching {. }.getOrElse {. }
|
|
39
|
+
// UI
|
|
40
|
+
runCatching {. }.getOrElse {. }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> `runCatching {. }` 로직이 컨트롤러, UI 두군데에 중복해서 있습니다. 올바르지 않은 값으로 Money를 만들었을때 누구의 잘못이 된다고 볼 수 있을까요?
|
|
44
|
+
|
|
45
|
+
### 4. 수익률 계산이 Controller에
|
|
46
|
+
|
|
47
|
+
```kotlin
|
|
48
|
+
val profitRate = totalPrize.toDouble() / money.value // ⚠ Controller가 계산
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
> 수익률을 계산하는 로직도 도메인 로직으로 분리해보세요.
|
|
52
|
+
|
|
53
|
+
### 5. 로또 가격 1000원을 Controller가 앎
|
|
54
|
+
|
|
55
|
+
```kotlin
|
|
56
|
+
val count = money.value / 1000 // ⚠ Controller 안에 1000원
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
> 로또 한장의 가격을 컨트롤러가 알아야 할 필요가 있을까요?
|
|
60
|
+
|
|
61
|
+
### 6. Lotto.toList 반환 타입
|
|
62
|
+
|
|
63
|
+
```kotlin
|
|
64
|
+
fun toList(): List<Int> =. // ⚠ List<LottoNumber>여야 하지 않나?
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
> toList()는 `List<LottoNumber>`를 반환해야 하지 않을까요?
|
|
68
|
+
|
|
69
|
+
## 얻은 교훈
|
|
70
|
+
|
|
71
|
+
- **도메인 객체로 검증/계산 이동** — Controller에 0 이상, 1000원, 수익률 같은 *비즈니스 로직*이 모이면 god-controller.
|
|
72
|
+
- **`runCatching` 중복 = 책임 위치 결정 필요**. Money 생성 실패는 *Money의 책임*. Controller/UI는 결과만.
|
|
73
|
+
- **`toList()` 타입 — 도메인 타입 유지**.
|