Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

자판기 미션 기능 요구 사항을 개선한다. - 8월 11일 #91

Closed
woowahan-pjs opened this issue Aug 9, 2021 · 6 comments
Closed

Comments

@woowahan-pjs
Copy link
Contributor

woowahan-pjs commented Aug 9, 2021

#55 (comment)

@unluckyjung
Copy link

unluckyjung commented Aug 9, 2021

요구사항의 모호성, 문제가 발생할 가능성이 있는 부분들

입력한 금액으로 동전을 무작위로 생성하는 기능에 대한 문제

2단계 - 돈통
기능 요구 사항
입력한 금액으로 동전을 무작위로 생성한다.
  • 입력한 금액으로 동전을 무작위로 생성한다.
  • 최초 자판기가 보유한 금액으로 만드는것인지
  • 최초 자판기가 보유한 금액 + 투입 금액으로 만드는것인지 에 대한 명확한 정의가 필요해보인다.
    • 일단은 후자로 생각하고 구현을 진행했다.
    • 전자인 경우 바로 아래에서 이야기하는 문제점에 대한 코멘트가 필요하다.

투입 금액에 대한 문제

실행 결과
자판기가 보유하고 있는 금액을 입력해 주세요.
10000

상품명과 수량, 금액을 입력해 주세요.
[콜라,1,1000]

투입 금액을 입력해 주세요.
100000000
  • 자판기가 보유하고 있는 금액보다, 더 큰 투입 금액이 들어오는 경우에 대한 코멘트가 필요해보인다.

  • 만약 돈통에서 입력한 금액으로 동전을 무작위로 생성한다. 기능이 최초 자판기가 보유한 금액이 기준이라면

    • 자판기 보유금액 1만원 / 투입금액 1억원
    • 이런 상황에 대해 불가능하다고 예외처리가 필요해보인다.
      • 위처럼 입금을 완료한뒤, 9000원짜리 물건을 샀다고 가정해보자.
      • 돈을 반환하면 최초 자판기가 보유한 금액이 기준 일경우 1만원 기준으로 동전을 생성한지라, (1억-9000원)을 기대하는 상황에서 최대 1만원으로 랜덤하게 생성된 동전밖에 돌려주지 못하게된다.
        • 지원자가 충분히 혼란을 가질 수 있는 부분인것 같다.
  • 개인적으로는 최초 자판기가 보유한 금액 + 투입 금액 으로 동전을 만들게하고, 그에 대한 코멘트가 필요해보인다.


동전을 반환하는 순서에 대한 문제

1단계 - 잔돈 계산 모듈
기능 요구 사항
그저 반환되는 동전이 최소한이 되는 자판기 잔돈 계산 모듈을 구현해서 제공하면 충분하다.

최소 개수의 동전으로 잔돈을 돌려준다. 예) 1000원 넣고 650원짜리 음료를 선택했다면, 잔돈은 100, 100, 100, 50원으로 반환한다.
지폐를 잔돈으로 반환하는 경우는 없다고 가정한다.

잔돈은 100, 100, 100, 50원으로 반환한다. 내림차순이 간접적으로만 표시되어있다.

  • 동전의 가치를 내림차순으로 하길 원한다면, 내림차순으로 반환한다라는 조건 명시가 필요해 보인다.

사용자가 입력한 금액에 대한 잔돈을 반환할 수없는 경우에 대한 모호함

2단계 - 돈통
기능 요구 사항
...
...
사용자가 입력한 금액에 대한 잔돈을 반환할 수없는 경우 입력한 금액을 그대로 반환한다.
  • 사용자가 입력한 금액에 대한 잔돈을 반환할 수없는 경우 입력한 금액을 그대로 반환한다

최소 단위에 대한 제약이 필요해보인다.

10원단위로 넣을수 있다는 제약조건이 현재 없다.

  • 만약 5원을 넣은경우(사용자가 입력한 금액), 동전의 최소가치인 10원보다 아래라서 잔돈을 동전으로 반환할 수 없다.(잔돈을 반환할 수없는 경우)
    • 이런경우 넣은 5원을 바로 반환하고 끝인지 혼란스럽다.
    • 일반적으로 자판기엔 1원단위를 넣지 못하지만, 일반적인것을 기대하기보다 조건명시를 확실히 해주어야 한다고 생각한다.

입금단위, 물품가격이 1원단위인 경우

  • 3단계에서 콜라가 1원이고, 입금을 5원 했다고 해보자.
    • 이런경우는 동전보다 낮은 숫자라서 바로 반환해야할지, 아니면 물품을 사는 작업을 진행해야할지 혼란스럽다.

동전 단위로 반환하는 경우

사용자가 입력한 금액에 대한 잔돈을 반환할 수 없는 경우 입력한 금액을 그대로 반환한다 : 모호성

  • 자판기 보유 금액(600) + 사용자 투입금액(400) = 1000 을 가지고, 동전이 랜덤하게 생성되었는데
    • 500x2 가 생성되었다고 가정해보자.
    • 이런경우 사용자가 입력한 금액에 대한 잔돈을 반환할 수 없는 경우 라는 조건에 충족한다. (400원(투입금액) < 500원(동전))
    • 사용자는 400원을 바로 돌려받게 되는것인지 혼란스럽다.
잔돈
500원 - 1개
  • 그런데 위와 같이 동전과 같은 형태로 반환하는 것을 기대한다면,
잔돈
  • 사용자는 돈 400원을 허공에 날린 상황이 된다.
  • 이부분에 있어서 혼란을 가질 수 있어보인다.

잔돈 금액이 최소 상품금액보다 적은경우 잔돈을 동전으로 변환해 돌려주는 기능

2단계 - 돈통
기능 요구 사항
...
...
사용자가 입력한 금액에 대한 잔돈을 반환할 수없는 경우 입력한 금액을 그대로 반환한다.
자판기가 보유하고 있는 금액을 입력해 주세요.
100000000

상품명과 수량, 금액을 입력해 주세요.
[콜라,1,1000]

투입 금액을 입력해 주세요.
100000000

투입 금액: 100000000원
구매할 상품명을 입력해 주세요.
콜라

// 이후 99999000원이 남아있다.
  • 만약 상품을 다 구매해버린 상황이고, 돈이 남은경우는 잔돈을 반환해주어야 하는가?
    • 예시) 자판기 초기 투입금액 1억원입금, 사용자 투입금액 1억원 입금, 1000원짜리 콜라가 1개 있었고, 콜라를 전부 다 구매한상황
    • 어찌됏던 잔돈은 남아있으나, 최소 상품금액보다 더 많은 잔액이 남아있고, 더이상 잔돈을 소모할 수 없는 상황이다.
    • 이런 경우 잔돈을 돌려주는가? 상식적으로는 그래야하나, 이부분에 대한 코멘트가 요구사항에 없다.
    • 이런 상황에 대한 규칙이 추가적으로 필요해보인다.

상품 가격에 대한 문제

  • 상품가격이 0원인 경우를 없게 해야할것으로 보인다.
    • 가격이 0원짜리가 있다고 가정시, 모든 상품을 구매해도 잔돈 금액이 최소 상품금액보다 적은경우 잔돈 반환 의 조건은 항상 만족할 수 없게된다.
    • 위에서 언급한 ## 잔돈 금액이 최소 상품금액보다 적은경우 잔돈을 동전으로 변환해 돌려주는 기능 와 이어지는 논의 거리이다.

반환하지 못하는 경우에 대한 문제

  • 1000원으로 동전을 만드는것을 시도하고, (500x2) 가 생성, 최소 상품가격이 600원
    • 물품을 구매하고 금액이 400원이면, 보유하고 있는 500원짜리로 반환이 불가능하다.
    • 반환되는 돈은 0원일텐데, 이부분에 대해 명시해주면 지원자들이 덜 혼란스러울것 같다.

상품명, 수량, 금액 입력에 대한 문제

상품명과 수량, 금액을 입력해 주세요.
[콜라,20,1500],[사이다,10,1000]
  • 파싱이 상당히 까다롭다. 파싱연습을 의도한게 아니면 수정했으면 한다.
    • 대괄호를 벗겨내고 하는작업이 간단하지 않았다.
// 대괄호 벗겨내기
private static final Pattern GET_PRODUCT_INFO = Pattern.compile("(?<=\\[)(.*?)(?=\\])");

private void inputProducts() {
    List<String> productInfos = new ArrayList<>();
    Matcher matcher = GET_PRODUCT_INFO.matcher(InputView.getProductInfo());

    while (matcher.find()) {
        productInfos.add(matcher.group());
    }
    vendingMachine.addProducts(productInfos);
}
// 콤마로 split
public void addProducts(final List<String> productInfos) {
    if(productInfos.isEmpty()){
        throw new IllegalArgumentException("입력형식이 잘못되었습니다.");
    }

    for (String productInfo : productInfos) {
        String[] splitProductInfo = productInfo.split(",");
        products.add(new Product(splitProductInfo[PRODUCT_NAME], splitProductInfo[PRODUCT_QUANTITY], splitProductInfo[PRODUCT_PRICE]));
    }
}
  • 현재는 위와 같은 방법으로 파싱해두긴 했는데, 프리코스 난이도로는 적절치 않아보인다.

추가

밑에 코멘트로 언급해주신 부분들 외

잔돈을 반환해주는 경우에 대한 명세가 확실히 필요할꺼 같습니다.
동전을 무작위로 생성한다. 라는 조건 때문에

물건을 다 구매한뒤 혹은 잔돈이 상품 최소 금액보다 적어 남아있는 상품을 더이상 구매하지 못하는경우
잔돈이 반환된다고 가정할시

사례
무작위로 생성된 동전 = {500,500,500}
남은 잔돈 value = 900 
  • 잔돈을 동전으로만 반환할지, 혹은 동전 외 단위로도 반환하게 할 수 있을지를 고민해보아야 할것 같습니다.
    • 동전으로만 반환된다면, 남은 잔돈이 자판기에 먹히게 될텐데, 이를 위해서 남은 잔돈이 얼마있고 생성된 동전이 몇개 있는지 보여주어야 지원자가 혼란스럽지 않을것 같습니다.
    • 하지만 이 경우 출력문을 구현 하는데 공수가 들어가는 트레이드 오프가 있습니다.
자판기가 보유중인 동전 - 500, 500
잔돈 - 400원

500원 - 1개

@woowahan-pjs
Copy link
Contributor Author

  • 자판기가 보유하고 있는 금액에 따라 동전을 무작위로 생성한다.
  • 투입 금액이 자판기가 보유하고 있는 금액보다 많을 경우는 입력한 금액을 그대로 반환한다.
  • 사용자가 입력한 금액에 대한 잔돈을 반환할 수 없는 경우 입력한 금액을 그대로 반환한다.
  • 잔돈이 상품 최소 금액보다 적은 경우 바로 잔돈을 돌려준다.
  • 상품의 최소 금액은 100원이며, 10원으로 나누어 떨어져야 한다.
  • 다른 모든 예외에 대해 예외가 발생해야 한다.

입력한 금액으로 동전을 무작위로 생성하는 기능에 대한 문제

  • 자판기가 보유하고 있는 금액에 따라 동전을 무작위로 생성한다.
  • 투입 금액이 자판기가 보유하고 있는 금액보다 많을 경우는 입력한 금액을 그대로 반환한다.

동전을 반환하는 순서에 대한 문제

  • 반환하는 순서는 채점에 큰 문제가 없어 보인다.

사용자가 입력한 금액에 대한 잔돈을 반환할 수없는 경우에 대한 모호함

  • 상품의 최소 금액은 100원이며, 10원으로 나누어 떨어져야 한다.
  • 사용자가 입력한 금액에 대한 잔돈을 반환할 수 없는 경우 입력한 금액을 그대로 반환한다.

잔돈 금액이 최소 상품금액보다 적은 경우 잔돈을 동전으로 변환해 돌려주는 기능

  • 모든 상품이 소진된 경우에는 잔돈을 돌려준다.
  • 잔돈을 반환할 수 없는 경우 예외가 발생해야 한다.

상품 가격에 대한 문제

  • 상품의 최소 금액은 10원이며, 10원으로 나누어 떨어져야 한다.

반환하지 못하는 경우에 대한 문제

  • 사용자가 입력한 금액에 대한 잔돈을 반환할 수 없는 경우 입력한 금액을 그대로 반환한다.

상품명, 수량, 금액 입력에 대한 문제

  • "[콜라,20,1500];[사이다,10,1000]"
  • "[콜라;20;1500],[사이다;10;1000]"
  • "콜라,20,1500;사이다,10,1000"
  • "콜라;20;1500,사이다;10;1000"

@2SOOY
Copy link

2SOOY commented Aug 10, 2021

이번 미션을 구현하면서 도출한 요구사항 목록

공통

  • 금액 충전상품 구매, 잔돈 반환을 하기 위한 메뉴 버튼의 id는 product-purchase-menu이다.
  • 자판기에 잔돈을 충전하기 위한 메뉴 버튼의 id는 vending-machine-manage-menu이다.
  • 자판기에 상품 추가를 위한 메뉴 버튼의 id는 product-manage-menu이다.

STEP1 - 잔돈 계산 모듈

금액 충전

  • 사용자는 금액 충전 입력란에 충전하고자 하는 금액을 입력할 수 있다.
    • 금액 충전 입력 요소의 id는 charge-input이다.
  • 입력하는 금액은 양의 정수여만 한다.
  • 충전 버튼을 클릭하면 입력한 금액을 충전할 수 있다.
    • 충전 버튼 요소의 id는 charge-button이다.
  • 사용자는 금액을 누적하여 충전이 가능하다.
  • 사용자는 충전한 금액을 확인할 수 있다.
    • 충전된 금액을 확인하는 요소의 id는 charge-amount이다.
  • 사용자가 충전한 금액 요소의 값은 숫자만을 갖는다.
    • 1000(o) / 1000원 (x)

잔돈 반환

  • 최소 개수의 동전으로 잔돈을 돌려준다. 예) 1000원 넣고 650원짜리 음료를 선택했다면, 잔돈은 100, 100, 100, 50원으로 반환한다.
  • 잔돈의 개수는 무한하다고 가정한다.
  • 지폐를 잔돈으로 반환하는 경우는 없다고 가정한다.
  • 반환하기 버튼을 클릭하면 충전된 금액을 바탕으로 최소 동전의 개수로 동전이 반환된다.
    • 반환하기 버튼 요소의 id는 coin-return-button이다.
  • 반환된 동전의 개수를 테이블 형태로 보여준다.
    • 각 동전의 개수에 해당하는 요소의 id는 다음과 같다.
    • 500원: coin-500-quantity
    • 100원: coin-100-quantity
    • 50원: coin-50-quantity
    • 10원: coin-10-quantity
  • 반환된 동전의 개수는 숫자만을 표현한다.
    • 예시
      • 500원: 1
      • 100원: 1
      • 50원: 1
      • 10원: 2

STEP2 - 돈통

  • 돈을 거슬러 주기 위해서 자판기가 보유하고 있는 금액을 충전할 수 있다.
    • 자판기가 보유할 금액을 충전할 input 요소의 id는 vending-machine-charge-input이다.
    • 충전 금액은 500 / 100 / 50 / 10의 배수 금액만 가능하다.
    • 예를 들어, 11원은 충전이 불가능하다.
  • 충전하기 버튼을 클릭하면 자판기에 금액을 충전할 수 있다.
    • 충전하기 버튼에 해당하는 요소의 id는 vending-machine-charge-button이다.
  • 입력한 금액으로 동전을 무작위로 생성한다.
    • 동전을 무작위로 생성하는 기능은 /lib/ 내부의 랜덤 유틸 중 Random.pick 메서드를 활용해서 구현해야한다.
    • 생성된 동전의 종류는 500원 / 100원 / 50원 / 10원만 존재할 수 있다.
  • 생성된 동전의 개수는 사용자가 확인할 수 있다.
    • 500원의 개수에 해당하는 td요소의 id는 vending-machine-coin-500-quantity이다.
    • 100원의 개수에 해당하는 td요소의 id는 vending-machine-coin-100-quantity이다.
    • 50원의 개수에 해당하는 td요소의 id는 vending-machine-coin-50-quantity이다.
    • 10원의 개수에 해당하는 td요소의 id는 vending-machine-coin-10-quantity이다.
  • 잔돈을 돌려줄 때 현재 보유한 최소 개수의 동전으로 잔돈을 돌려준다.
    • (예시) 500원 1개 / 100원 6개 보유 상황 => 1000원 : 500원 1개 + 100원 5개 반환
  • 보유한 동전으로 최대한 반환하고 반환할 수 없는 금액은 반환하지 않는다.
  • (예시) 500원 1개 / 100원 1개 보유 상황 => 1000원 반환: 500원 1개 + 100원 1개 반환 / 400원 반환 X

STEP3 - 자판기

  • 상품명, 수량, 금액을 추가할 수 있다.
    • 상품 추가 입력 폼에 상품명, 가격, 수량을 차례로 입력한다.
    • 상품 추가 입력 폼의 상품명 input 태그의 id는 product-name-input이다.
    • 상품 추가 입력 폼의 상품 가격 input 태그의 id는 product-price-input이다.
    • 상품 추가 입력 폼의 수량 input 태그의 id는 product-quantity-input이다.
    • 상품 추가를 위한 추가 button 태그의 id는 product-add-button이다.
  • 같은 상품명의 데이터를 추가하면 기존의 상품에 해당하는 데이터는 새로운 상품으로 대체된다.
    • 콜라 / 1000원 / 12개(전) -> 콜라 / 1500원 / 10개(후) => 콜라 / 1500원 / 10개(결과)
  • 사용자는 추가한 상품을 확인할 수 있다.
    • 추가한 상품 목록의 이름에 해당하는 td요소의 class는 product-manage-name이다.
    • 추가한 상품 목록의 가격에 해당하는 td요소의 class는 product-manage-price이다.
    • 추가한 상품 목록의 수량에 해당하는 td요소의 class는 product-manage-quantity이다.
  • 사용자가 입력한 금액으로 상품 구매할 수 있다.
  • 사용자는 한 번에 한 가지의 상품만 구매할 수 있다.
  • 사용자는 자신의 충전 금액보다 높은 금액의 상품을 구매할 수 없다.
  • 사용자는 상품 목록들 중 특정 상품의 구매 버튼을 클릭하여 구매할 수 있다.
    • 각 상품의 구매 버튼에 해당하는 button의 class명은 purchase-button이다.
    • 각 상품 목록의 이름에 해당하는 td의 class명은 product-purchase-name이다.
    • 각 상품 목록의 가격에 해당하는 td의 class명은 product-purchase-price이다.
    • 각 상품 목록의 수량에 해당하는 td의 class명은 product-purchase-quantity이다.
    • 각 상품 목록의 가격은 dataset 속성에 data-price 형식으로 저장한다.
    • 각 상품 목록의 수량은 dataset 속성에 data-quantity 형식으로 저장한다.
  • 상품 구매에 성공한 경우 구매한 상품 목록이 화면에 보인다.
    • 구매한 항목을 나타낼 해당하는 li요소의 class명은 purchased-item이다.
    • lib/format 모듈에서 제공하는 createPurchasedResultContent함수를 이용하여 li 요소의 textContent 값을 채워넣는다.
  • 상품 구매에 성공할 때마다 해당 상품의 수량이 1개씩 감소한다.
  • 상품의 잔여 수량이 0일 경우 상품 구매 버튼을 disabled 처리한다.
  • 잔돈이 상품 최소 금액보다 적은 경우 바로 잔돈을 돌려준다.

논의해보면 좋을 것들

  1. 상품 추가
    • 기존에 등록된 상품에 동일한 이름의 상품이지만 다른 가격으로 추가하려 할 경우 처리
      (예 상품A, 1000원, 50개 + 상품A, 1500원, 10개)
    • 상품 추가할 때 이름과 가격이 동일하다면 수량을 누적시킨다. or 한 번 추가된 상품은 더 이상 추가할 수 없다.
  2. 금액 입력
    • 해당 범위: 상품을 구매하기 위한 금액 입력 & 돈통 충전을 위한 금액 입력 & 상품 추가를 위한 가격 입력
    • 금액의 상한선을 정하면 응시자들도 명확하게 인지할 수 있을 것 같습니다 + 테스트 코드 작성도 용이
    • 금액의 단위10의 배수만 가능하도록 제한하는 요구사항 추가하면 좋을 것 같습니다.
      • cf) FE의 경우 input의 step attribute를 지정한 응시자까지 테스트 코드로 커버 가능할지 고민 (HTML 자체에서 오류 띄움)
  3. 동전을 반환하지 않는 경우
    • 자판기가 동전을 꿀꺽 & 충전 or 금액 증발
    • 예시) 자판기 동전 보유 현황 (500원 1개 & 100원 3개) => 사용자에게 400원 반환 필요한 상황
      • 자판기에 400원 추가 및 무작위 동전 생성
      • 400원에 대한 금액 없어짐

@zereight
Copy link

zereight commented Aug 10, 2021

논의해보면 좋을 것들

(콜린꺼에 이어서)

  1. 상품 품절
    상품이 구매 후 수량이 0개가 되었다.
    그럼 상품을 자동으로 제거할 것인가? 품절표시를 해줄 것인가?

  2. 동전 반환 시, 반환결과는 매번 초기화 되는가?
    자판기가 보유한 금액과 동전보유현황과 유저가 보유한 금액은 반환결과만큼 차감되지만,
    반환결과는 누적되지 않음을 명시하는게 명확해보임

  3. 상품이름 길이 예외처리, 금액 최대값 예외처리 명시해야하는가?
    필요한가?


아래는 프론트엔드에서 논의할 부분

  1. 백엔드에서 "예외" 단어를 프론트엔드에서는 프로그램이 죽지않고 alert으로 대체하여 해석해야하는지?

  2. 백엔드에서는 자판기 금액 투입 -> 상품 추가 -> 사용자 금액 투입 -> 상품 구매 -> 반환
    으로 플로우가 정해져있는데, 프론트엔드도 해당 flow에서 해당 UI만 보이도록 구현되어야 하는지?
    지금은 모든 기능에 대한 UI가 한번에 보여서
    자판기 금액 투입 -> 상품 추가 -> 사용자 금액 투입 -> 상품추가 -> 상품 구매 -> 반환 등의 여러가지 플로우가 가능함.

@woowahanCU
Copy link

  1. 무작위 생성은 자판기가 보유하고 있는 금액, 투입 금액 각각 발생하면 위의 문제가 해결된다.
  2. 투입금액의 최소 단위, 최대 단위, 최대 투입할 수 있는 금액 제한, 상품가격의 최소 단위 등이 필요하다.
  3. 동전을 반환하는 순서가 필요없다면 불규칙적인 예시를, 필요하다면 명시하는 것이 좋다고 생각한다.
  4. 모두 구매 혹은 사용자의 구매완료 행동 후 잔돈을 반환해주는 기능이 필요하다.
  5. 반환하지 못하는 경우에 대한 문제 -> 구매가 불가능한 상태로 입력한 금액을 그대로 반환한다.

@woowapark
Copy link

woowapark commented Aug 13, 2021

@zereight @2SOOY

UI 제약사항 논의할 항목들 w/콜린,도비

  • input > step 프로퍼티 수준까지 요구사항으로 명시할 필요는 없을 것 같아요. 값을 조정한 결과만 테스트하고, 구현 자체는 자율적으로 해도 되지 않을까 합니다.
  • 백엔드와의 공통 요구사항에서 '예외' 발생 케이스는 프론트엔드에서는 alert을 띄우는 처리로 대체하면 될 것 같아요
    • 논의 예외 발생 이후 reset할 지, 상태 유지할 지 논의해봐요 :)
      -> 상태 유지
  • 플로우
    • 현재처럼 상태를 가지고, 여러 플로우를 가질 수 있도록 하는 것으로 유지해도 괜찮을 것 같아요
      • 탭이 있는 형식으로 지정
    • 이후 논의에 따라 난이도를 조금 낮춰야 할 경우 백엔드에서처럼 하나의 플로우로 수정
      • 이 경우 UI도 탭으로 나누지 않고 하나의 화면에서 모두 노출하도록 함께 수정
  • 스타일
    • 예시는 주되, 테스트를 위해서는 어차피 id를 사용할 예정이라 그 외에 스타일이나 사용하는 태그 등을 예시와 동일하게 해야 할 필요는 없을 것 같아요
    • 스타일 샘플은 필수 X
  • 추가로 있다면 논의 시간에 알려주세요~ :)

정리된 요구 사항

#86 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants