# STEP 1 ## 네트워크 관련 1. HealthChecker HealthChecker의 필요성 서버의 상태를 간편하게 확인할 수 있겠어요! 백엔드나 프론트엔드나 에러를 디버깅 할 때 일단 서버는 정상적으로 띄워져 있는지 간편하게 확인하는 용도로도 쓸 수 있을거 같아요! 좀 더 앱 로직 내에 활용해본다고 하면, 통신을 하기 전에 해당 API를 통해 서버의 상태를 확인하고 비정상적이라면 통신을 하지 않고 얼럿을 띄워두고, 서버가 정상적으로 돌아왔을 때 통신을 하도록하면 앱이 좀 더 효율적으로 동작할 수 있을 거 같습니다. 2. URLSession URLSession 공식문서를 확인해보면 URLSession을 싱글톤으로써 사용할 수 있는데요. custom하게 session을 사용하고 싶으신건가요? -> URLSession을 사용할 때 싱글턴 세션 사용하거나, 커스텀 세션을 만들어 사용 할 수 있습니다. 싱글턴 세션은 커스텀보다 기능이 제한적이지만 간단히 사용할 수 있고, 커스텀 세션은 더 세세한 설정을 할 수 있다. 이부분은 기능 확장시에 생각을 할 것 3. API 통신 코드(APIProvider)는 뷰모델이 소유하는게 더 자연스럽다(추후 적용하기) 4. 엔드포인트와 URL 관리에 관한 글 https://velog.io/@sookim-1/iOS-URL%EB%B0%8F-endpoint%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0 --- ## 테스트 관련 1. testDouble 목적에 따라 다양한 테스트 더블이 존재하는데요. Spy, Stub, Mock 등등. 이들에 대한 학습을 해보셨다면 간단하게 이해한 내용을 저에게 설명해주실 수 있으실까요? 우선, 각 테스트 더블 간 역할이 아주 명확하게 나뉘어 있지는 않다고 느꼈어요. 제가 이해한 바를 토대로 정리보겠습니다! Stub Mock에 비해 실제 객체의 더 작은 부분만을 구현합니다. 또한, 테스트 결과를 객체의 "상태"를 확인하여 결정하는 "상태검증 테스트"에 주로 사용됩니다. 예로, 현재 저희 코드의 StubURLSession처럼 호출되면 정해진 값(HTTP status code 등)을 반환하는 테스트 더블을 만들어야 하는 경우 Stub이 사용된다고 파악했습니다 Mock 실제 객체와 가장 유사한 수준으로 구현됩니다. Stub과는 달리 객체의 어떤 메서드가 호출되었는지 등의 "행위검증 테스트"에 사용됩니다. Dummy 가장 기본적인 테스트 더블로, 어떠한 기능도 구현되어 있지 않습니다. 테스트 코드에서 Dummy 객체에게는 어떠한 기능을 하길 바라지 않고 단순히 객체를 만들고, 넘기는 정도의 목적만 필요할 때 사용될 것 같습니다 Fake 실제 객체의 로직을 단순화하여 구현한 테스트 더블을 말합니다. 실제 로직과는 차이가 있기에 실제 앱에서는 제대로 동작하지 않음 Spy 기본적으로 Stub의 "상태검증 테스트"라는 목적을 가지면서, Mock의 "행위검증 테스트"를 위한 일부 로직(메서드 호출횟수를 기록한다던지)이 포함된 테스트 더블로 이해하였습니다. 2. 테스트시 코드에서의 강제 언래핑을 사용하는것에 대하여 저는 테스트 코드에서 캐싱을 위한 프로퍼티는 옵셔널 바인딩을 하지 않고 강제 언래핑을 해요. 굳이 필요하지 않은 코드 같거든요. 이미 setUpWithError메소드에서 매번 프로퍼티에 값을 할당해주고 있는 상황에서 sut_marketItemList가 nil이라면 테스트 자체가 성립이 안되니까요. 즉 테스트 코드에서 테스트가 반드시 성공한다면 그냥 !를 사용해서 테스트코드 가독성을 높이는 편이 나을수있다. 3. 네트워크와 무관한 유닛 테스트 코드 작성 관련 글 https://wodylikeios.notion.site/URLSession-Unit-Test-7a57917280b84a92b5a644adfac6246c 4. 네트워크 에러 케이스는 세분화 하기. 발생할 만한 에러 케이스를 Result Type을 활용해 세분화 하여 핸들링하도록 하자. 추가로 세분화 한 에러 케이스 각각에 대하여 테스트 코드를 작성하여 실패하는 코드에 대한 핸들링도 해야한다. > 코드 커버리지를 늘릴 수 있다. 5. 테스트 코드도 기능별로 분리를 잘 하는 것이 좋다. 결국 테스트 코드도 개발이므로 코드가 변경되면 바로바로 함께 수정해주어야 함. 테스트 타겟의 Host Application이라는 개념에 대해 알아볼까요? 이 테스트 타겟의 Host Application은 어떻게 지정해주는 것이 좋을지 논의해봅시다~! 아래 글부터 알아보기 시작하면 쉽게 시작할 수 있을거에요. --- ## 유틸리티 코드 및 구현 관련 1. JSONParser 데이터를 JSONParser 에서 처리함으로써, 외부에서 편하게 사용할 수 있고 중복 코드를 많이 줄일 수 있겠네요 👍 -> extension 하고 제네릭 쓰면 중복코드 및 범용성 증가 4. static 사용 static method는 피해주세요. Apple의 Foundation Framework에는 static util이 거의 없답니다. 구조체로 만드는 방향으로 수정해주세요. **static factory 패턴과 extension으로 확장하여 커스텀 이니셜라이저를 구현하는 방식의 차이** 기존에 static function 으로 구현했을 때 이점은 URLRequest 인스턴스 생성을 캡슐화 하고 이름을 좀더 구체적으로 지어서 가독성을 높여줄 수 있는 가능성을 가진다고 생각해요. 이번에 구현한 방식은 extension 을 통해 타입을 확장하는 Swift 만의 특성을 사용해서 initializer 를 통해 생성을 해줘서 좀더 해당 타입에 가깝고 연관된 방식을 제안해주셨네요. Swift 의 특성을 사용한 바꾼 방식과 이전 Static Factory Pattern 의 이점이 각각 명확히 있어서 어떤게 더 나을지는 두분의 판단에 맡길게요. 대신 기존의 방식이 왜 사용되는지 도움이 될 만한 글을 하나 가져왔어요! 개인적인 의견으로는 static factory pattern 을 사용하면 method 이름으로 생성하려는 인스턴스에 대한 구체적인 정보를 나타낼 수 있다는 점이 제일 큰 강점 같아요. 하지만 새로운 방식인 생성자를 통한 방식이 문맥에는 더 자연스러워 보이긴 하네요 3. codable 프로토콜 코더블 사용 지양 디코더블 인코더블로 사용. 안쓰는데도 쓰는걸 "오버 엔지니어링"이라 부름. 4. 전역으로 쓰이지 않는다면 enum은 각각 클래스가 내부에 존재하는게 좋다 5. 타입 사용에 관하여 전역으로 사용하는 상수의 경우 Namespace를 만들고 한곳에서 사용하는 경우 Extension으로 사용 보통 데이터를 가져올 때 - 외부 저장소(서버)에 접근하는 객체 - 이를 사용해 화면에서 사용되는 적절한 화면의 데이터로 매핑하는 객체 이렇게 두 가지 객체를 활용해요. 즉 1번 객체는 여러곳에서 재사용될 수 있고 2번 객체는 특정 화면에서만 사용 혹은 특정 도메인 안에서 재사용될 수 있겠죠! 그래서 보통 1번 객체는 제네릭을 활용하는 편이에요. (T: Decodable) 그리고 이를 사용하는 2번객체에선 원하는 모델(Network)로 매핑을 해서 다시 원하는 타입으로 사용하는 곳에 돌려주는 편이에요! 5. 이니셜라이저에서 xib파일로 인스턴스화 할 때 필요한 @Required 이니셜라이저의 경우 기본 구현이 fatalErro처리 되어있는데 논리적으로 실행이 안되더라도 굳이 강제종료시키는 이니셜라이저를 코드에 구현할 필요는 없다. 6. Alert를 남발하지 않도록 해야한다. 이는 HIG에 위배되는 동작 7. 기능 관련하여 중복이 일어난다면 프로토콜로 추상화를 진행해보자. 이는 제너럴한 코드를 작성하여 확장에 유용할 수 있다. 또한 재사용이 되지 않는 프로토콜이라 하더라도 단일 책임원칙에 의해 분리가 되어도 좋다. 네트워크 매니저, Json 파일 핸들링 인스턴스 등등. 프로토콜의 장점은 재사용성에 있다고 생각하는데, 현재는 네트워크를 담당하는 NetworkManager 타입에서만 채택해서 사용하고 있습니다. 현재로서는 NetworkManager가 할 일을 나누어 가지고 있기에 구조를 파악하기 용이하다는 점과 하나의 타입이 너무 많은 일을 담당하지 않게 되었다는 장점이 있다는 장점이 있는 것 같은데, 재사용하지 않더라도 이런 방식으로 프로토콜을 활용하는 것이 좋은 방식일까요? 재사용하지 않을 것이라면 NetworkManager과 같이 큰 타입을 관련된 메서드별로 묶어 여러 extension으로 분리하고 mark 주석을 이용해 정리해놓는 것은 어떤가요? (적다보니 분리하는 것이 좋은 이유를 알겠네요.. UML 구조를 통해 이해하기도 쉽다는 장점이 있겠군요!) https://github.com/yagom-academy/ios-open-market/pull/28 ---