---
# System prepended metadata

title: Untitled

---

안녕하세요 라자냐 @wonhee009
**탑킴, 허황** 입니다😊

STEP 1 구현이 끝나 PR 드립니다😁
잘 부탁드립니다🤩

### STEP 1 UML
![](https://i.imgur.com/yF3Umm3.jpg)

### 구현 내용
- 과일의 종류를 표현하는 FruitType 타입 정의
    - 딸기, 바나나, 파인애플, 키위, 망고

- 과일의 재고를 관리하는 FruitStore 타입 정의
    - 각 과일의 초기 재고 : 10개
    - 각 과일의 수량 n개를 변경하는 기능

- 과일 쥬스를 제조하는 JuiceRecipes 타입 정의
    - 딸기쥬스 : 딸기 16개 소모
    - 바나나쥬스 : 바나나 2개 소모
    - 키위쥬스 : 키위 3개 소모
    - 파인애플 쥬스 : 파인애플 2개 소모
    - 딸바쥬스 : 딸기 10개 + 바나나 1개 소모
    - 망고 쥬스 : 망고 3개 소모
    - 망고키위 쥬스 : 망고 2개 + 키위 1개 소모

- FruitStore 과일을 사용해 과일쥬스를 제조하는 JuiceMaker 타입 정의
    - 과일의 재고가 부족하면 과일쥬스를 제조 불가


### 고민했던 점
- 확장에 용의한 코드
    >  쥬스의 종류를 구현할 때 처음에는 열거형으로 구현했지만, 나중에 쥬스가 추가 될 경우 열거형을 수정해야하기 때문에 쥬스 별로 RecipeProtocol 프로토콜을 채택한 struct를 구현했습니다.
    >  struct로 구현할 경우 쥬스가 추가될 때마다 새로운 쥬스 타입을 생성해주면 되기 때문에 확장에 용의한 코드라 판단하고 진행했습니다.
    >  라자냐의 생각이 궁금합니다🧐

- FruitStore 타입 struct VS class
    > struct로 구현 할 경우 immutable하게 값을 사용 할 수 있을 것이라 판단하여, 진행 하였으나, 테스트 코드 작성 시 이로 인해 오히려 혼선이 생기게 되어 class로 전환 하게 되었습니다.

    ![](https://i.imgur.com/HnP1BV8.png)



### 조언을 얻고 싶은 부분
- 테스트 파일의 위치
    > Unit Test를 진행할 때 Tests 타겟을 추가하고 그 하위에 Unit Test 파일을 생성해서 사용하게 되는데 Unit Test 파일과 프로덕션 코드가 한 그룹에 있는게 어떤 프로덕션 코드가 테스트 진행되었는지 명확하게 알 수 있는 것 같습니다.
    > Unit test 파일을 위 상황 같이 배치해도 괜찮을까요??
    > 배치하게 된다면 Tests 타겟은 추가하지 않고 Unit test 파일만 생성해서 테스트를 진행해도 괜찮은지 궁금합니다🧐
    > 예시) 킥스타터 github 참고 이미지 [링크](https://github.com/kickstarter/ios-oss/tree/main/Kickstarter-iOS/DataSources)
    >  ![](https://i.imgur.com/4TbRXWc.png)


- 문서화 주석
    > 함수의 로직을 문서화 주석으로 남겨도 괜찮은지 궁금합니다🧐
    > 부연설명 드리자면 과일의 개수가 부족한지 확인하는 메서드 내부에서 Dictionary 메서드 중 [merging](https://developer.apple.com/documentation/swift/dictionary/3127173-merging)을 사용했습니다. 
    > merging을 사용해서 두 딕셔너리의 value의 차이를 구하고
    > filter를 이용해서 value가 음수인 key의 개수를 구하고 
    > value가 음수인 key의 개수가 0보다 크다면 .failure를 반환
    > 하게 구현했는데 이러한 로직은 코드를 보고 파악하는 것 보다 문서화 주석을 사용하는게 다른 사람이나, 본인이 봤을 때 코드를 파악하기 수월하겠다고 생각했습니다.


- Result 타입 캐스팅
    > Result<Void, Error> <-> Result<Void, CustomError> 사이의 캐스팅이 불가능 한 이유가 궁금 합니다.
    > CustomError는 Error 프로토콜을 채택 하고 있습니다.
    >  오류 문구 : Cannot convert return expression of type 'Result<Void, CustomError>' to return type 'Result<Void, Error>'


--------------------
## 리뷰 답변

### 확장에 용이한 코드
해당 부분은 확장보다는 유지보수 면에서 좀 더 의미가 있지 않나?라는 생각이 들었습니다.
주스가 추가 되었을때 열거형을 수정(케이스 추가)하는 부분이나 주스 struct를 추가하는 부분이나 저는 비용이 비슷한거 같거든요.
물론, 주스별로 뭔가 다른 기능이 추가되는거라면 확장면에서는 좀 더 좋은 코드라고 생각합니다.
그럼 과일에 대해서는 열거형을 채택하신 이유는 무엇일까용?.?🤔
> 코드에 통일성을 유지하려면 과일도 별도의 타입으로 생성하는게 맞다고 판단됩니다😭
> 라자냐께서 말씀해주신 과일도 별도의 타입으로 생성할 고민해봤지만,
> 열거형을 사용하게되면 FruitStore 타입의 Inventory 프로퍼티의 타입이 [FruitType: Int]을 사용하기 때문에 과일의 초기수량을 넣어줄 때 `CaseIterable`를 채택한 열거형을 사용하면 간편하게 초기수량을 넣어줄 수 있다고 판단해서 열거형을 사용했습니다.


### Result 타입 캐스팅
현재 FruitStoreError에서는 Error를 채택하지 않는거로 보이는데용?.?

> FruitStoreError는 LocalizedError를 채택하며 이는 Error를 상속 받습니다.
> JuiceMaker의 make 함수를 소스 1과 같이 작성하고 싶었는데요.
> 캐스팅이 안되는 문제로 소스 2와 같이 작성되었습니다. 이유가 무엇일까요?

소스 1
```swift=
mutating func make(with recipe: RecipeProtocol) -> Result<Void, Error> {
    return fruitStore.use(of: recipe.items) // return type Result<Void, FruitStoreError>
}
```

소스 2
```swift=    
mutating func make(with recipe: RecipeProtocol) -> Result<Void, Error> {
    let result = fruitStore.use(of: recipe.items)
    switch result {
    case .success():
        return .success(Void())
    case .failure(let error):
        return .failure(error)
    }
}
```

의존성을 줄이고 테스트가 쉬운 구조를 만들기 위해 작성 했습니다.
예를 들면 FruitStoreMock을 주입하는 경우 입니다.

