11월 17일 (수) 멘토링 - boostcampwm-2021/iOS04-OwnMyWay GitHub Wiki

진행 상황

그동안 구현한것 보여드림

멘토님 질문

잔여 일감이 있나요

우리의 답변

  • 이번주까지 지난여행 완성하기까지 계획이었음
  • 자잘한 에러가 있었음
  • 다음주에는 슬라이드해서 카메라 띄워서 ML 이용 포즈 감지 해볼것

멘토님 재답변

지금 스펙적으로 많이 완성했음. 그러나 UI작업 자체가 덜 되어있음. 그러니 카메라 외에도 UI 디테일 챙기기

  • 지난 여행에서 Back이라는 텍스트
  • 텍스트 제거하기, 컬러 바꿔주기
  • 아래 영역도 버튼이랑 딱 붙어있는데 inset이 들어가면 좋을 것 (유저 친화적)
  • 글이 없으면 그냥 흰 화면인데 글 추가하기 버튼 누를 생각을 못할것
    • 액션을 유도하는 방법을 고민해보기
    • 추가하는 영역을 따로 뺀다던가 디테일들 추가하기만 조금 하면 될듯 기능적으로는 백그라운드도 되었고 완성도만 챙기면 이상태로 종료해도 될 정도 UI적 디테일과 코드 품질을 챙기자!
  • ML은 한 두명만 하고 공유하기
  • 나머지가 개선작업

디자인이 이쁠 필요는 없으니 사용성을 챙기자

  • 만든 사람이 아니어도 잘 사용할 수 있는가?

  • 디테일한 UI작업은 오래걸리지 않을테니 화면의 접근성을 어떻게 챙길지

  • 보이스오버 기능 제공하기

    • UIAccessiblity
    • 속성에 있는 것들만 해도 충분함
    • trait을 지정해줄 수도 있음 (??)
    • 유저들이 원하는 형태로 컨텐츠를 읽어주는지 확인하기
  • 다이나믹 타입

    • 폰트 사이즈를 변경하면 폰트 크기가 바뀌는 것들
    • 적용하기 오래걸리고 레이아웃 구조를 바꿔야 할 수도 있음
    • 이건 힘들수도

결론: 코드품질 올리고 사용성 올리고 접근성

질문

LocationManager ImageFileManager 매번 인스턴스를 생성할지 싱글톤으로 할지

  • 두 가지 다 싱글톤으로 되어있는데, 멘토님마다 의견이 다르다.
  • 유즈케이스, 테스트 가능한지를 기준으로 삼음
  • shared를 주입하는 방식으로 접근

답변

상황에 따라 다르다. 이미지 캐시를 사용한다고 했을때 킹피셔가 imageView.kf.setImage() 이런 방식이다. imageView.setImage()이게 더 좋다고 했지만

앱 자체에 하나만 존재하면 그게 싱글톤이지 static let shared = Some() 이렇게 선언해야지만 싱글톤은 아니다.

  • 멘토님은 천재인가?

Composition Root라는 개념

  • 앱의 맨 위에서 의존성을 연결시키는 개념
  • 앱의 맨위에서 하나만 생성해서 아래로 전달해주기
    • 네트워킹 요청하면 다 싱글톤일 수 있는데
    • 선언 방식이 static let인지 아닌지는 갈릴 수 있음
    • 주입받아서 사용하는게 코드 사용을 더 어렵게 만들 수 있다면 statis let 쓰는게 더 낫다
    • 특정 화면에서만 주입받아서 사용해야 한다면 싱글톤 객체가 맞고 상위 객체에서 주입해서 쓰는게 더 좋겠다.
struct AppDependency {
    let window: UIWindow
}

enum CompositionRoot {
    static func resolve() -> AppDependency {
        let locationManager = LocationManager(
            dependency1: .init()
        )
        
        return AppDependency(
            window: UIWindow()
        )
    }
}

@main
final class AppDelegate: ~~~ {

    let dependency: AppDependency
    
    init() {
        dependency = CompositionRoot.resolve()
    }
    
    didBecome {
        window = dependency.window
    }
}
// locationManager가 앱의 맨 위에 하나만 존재하니 싱글톤 객체임
// 싱글톤이 나쁜게 아니라 생성하고 주입할 수 없게 만드는 과정이 좋지 않은거고
// 싱글톤 자체는 괜찮다.
// static let으로 선언하면 그 안에 들어가는 의존관계들도 static let으로 선언해야하니...
// 멘토님 그는 천재인가?

예시로 들어주신 프로젝트에도 관련된 내용이 있음 AppDIContainer에 하나만 생성되는 객체가 있고 얘는 싱글톤임

  • 여기서 한번 만들고 다 주입시키는 방식

이미지는 애매할 수 있는데 이미지 뷰 하나당 의존성을 다 주입해야 하는데 이렇게 사용성을 해칠 수 있는 경우에는 의존성을 주입해주지 않는게 더욱 좋은 방식이겠죠. 킹피셔 kf같은 예시를 말씀하시는 것 같네요

질문

사용자가 볼 수 있게 Result 타입을 뷰컨까지 끌고와서 처리를 해야 할텐데 팁이 있을까요

답변

MVVM이니까 VM에서 에러타입을 넘겨주면,

HomeViewModel을 보심, 근데 에러처리가 유즈케이스에서 print하는 수준에서 끝남

일단 Result 타입을 밑으로 내리는게 우선이다

여기서 받아와서 travels가 아니라 results를 받아와서

에러를 여러개 선언해준다. 실제로 뷰컨트롤러에서 이벤트를 받아서 처리해야 하니까 에러가 일반적인 스위프트에서 주는 에러가 아니라 커스텀 에러를 반환시키는게 좋다.

enum OMWError: Error {
    case foo
    // case unknown일수도 있음
    case bar
}

// 특정 도메인에 맞는 에러는 아래와 같이 하기도 한다.
enum FooError: Error {
    
}
// 네트워크 에러는 아래와 같이 하기도 한다.
enum NetWorkError: Error {
    
}

final class Repository {
    func foo() -> Result<Foo> {
        return NSError() // 생성할 수 있는게 NSError밖에 없으니... 아니면 AFError.something같은거
        // 근데 일반적인 에러는 처리하기 힘드니 OWMError.unknown
    }
}

final class AUsecase {
    func execute() -> Result<Foo> {
        return .failure(OMWError.foo) // Swift.Error가 아니라 우리가 만든 에러를 넘김
    }
}

final class ViewModel {
    let fooError: Error
}

final class ViewController {

    init() {
        viewModel.error
            .subscribe(onNext: { error in
                case error as? FooError // 에러 자체를 분류할 수도 있음
                case error as? NetWorkError
                // a 에러면 a
                // b 에러면 b
                // 401 에러면 로그인 화면으로
                self.errorHandler.handle(with: error) // 토스트로 보여주거나처럼 추상적인 동작을 만들어줄 수도 있다.
            })
        // 이런 처리는 대부분 공통적이니까 이걸 처리하는 객체를 따로 만든다.
        // 객체의 이름을 errorHandler라고 하면 위와 같이 한다.
    }

}

질문

iOS 13+를 지원하기로 했는데 몇몇 라이브러리는 iOS 14+가 필요한 경우가 많았다. 일단 iOS 13은 지원해보려고 했는데 iOS 9까지 지원해야한다는 의견이 있었는데...

답변

높다면 높고 정상이라면 정상인데 지금 작업한다면 12 아니면 13을 하실 것 같음 (3개 버전은 지원하기) 금융권이나 모든 사람이 써야한다면 9까진 오바고 11정도? 당근마켓도 13으로 올라갔음 13정도면 될 것임 15로 만들어도 출시해서 제대로 사업할게 아니라면 괜찮아보임

세부 질문

게시물 작성할때 이미지 피커가 있었고 멀티셀렉션을 우선적으로 지원하자는 기준때문에 라이브러리나 PHPicker를 후보로 잡았습니다. ImagePicker는 곧 지원이 중단될거라고 해서. 이미지 피커를 직접 만들자는 의견도 있었는데 결국 PHPicker를 골랐습니다. 알고보니 PHPicker가 iOS 14+여서 저희가 세운 기준을 벗어나는데 오늘 배운 파편화 개념을 활용해서 iOS 14+라면 PHPicker를 열고 아니라면 다른 방식으로 처리하자고 헀는데

세부 답변

기술적 문제가 있다면 그 방향으로는 안갈 것. 우리의 경우 멀티셀렉션이 지원되지 않는다면 볼 필요가 없음. 전제가 약간 miss인게 iOS 13이 타겟인가 14가 타겟인지가 중요함. 13이라고 가정하면 3rd 파티를 먼저 고려할 것. 시간이 타이트하다면. 아니라면 직접 만들 것. if available을 쓸 일이 생기긴 함. 기능 차이가 아니라 방식의 차이라면 제공해야할 경우가 있음.

요구사항을 충족시키는가?를 먼저 따지고 3rd 파티가 문제가 생길지를 파악해서, 일정 등을 조율하면서 직접 만들지를 선택해야 함

질문

게시글을 작성하는 화면과 수정하는 화면이 있다. 같은 뷰를 재사용하고 있음. 옵셔널 타입으로 파라미터를 받아서 들어온 정보가 있냐/없냐에 따라 생성/수정을 판단해서 동작하도록 구현함. 뷰컨은 재사용하니까 내버려두고 뷰모델부터 나눠서 필요한 타이밍에 주입받아서 사용할까 고민중입니다. 재사용의 의미에 맞는지 궁금합니다.

답변

이런 경우는 유즈케이스 분기를 하는 경우도 있을 수 있다. new와 edit가 분명히 달라질 수 있다. 주입받는 이전 정보가 있느냐 없느냐도 중요할 수 있고 가독성이 중요하다면 enum 형태로 만들어서

enum Behavior {
    case new // new인 경우에도 draft가 제공되는 경우가 있을 수 있으니 받아야 할 수 있음
    case edit(Post)
}

기능 명세상 동일하다면 하나의 프로토콜로 추상화될 수 있다면 그렇게 할 수도 있지만 그렇게 추상화할만큼 두 개의 기능이 같아지는 경우가 많이 없어서 확장성을 고려한다면 저렇게 두지 않을까 싶음

연동 질문

여행을 수정하는 화면도 똑같은 화면을 사용하면 좋겠다는 의견 -> 다 똑같은데 마지막 화면의 기능 하나만 딱 다르다. 그래서 Bool 변수 받아서 편집인지 생성인지 구분헀음. 총 3개 화면을 넘어가야 하다보니 각 화면의 뷰모델과 유즈케이스를 만드는게 작업량이 너무 많아보였기 때문

연동 답변

그렇게 할 것 같음 유즈케이스도 마지막 전달하는 방법만 추상화할 수 있다면 그것만 추상화하면 될듯 근데 Boolean은 개발자 입장에서 사용성의 차이이지

요구사항이 분리되어서 유즈케이스를 쪼개던가 하는건 변경이 쉬우니까... 확장성과 팀원들의 가독성, 생성/수정/드래프트로 생성을 구분하는게 쉽다면 그렇게 할 것 같다.

질문

이미지 피커로 사진을 가져오는게 각 비동기이다보니 순서가 맞질 않았다. 이미지 첫번째의 메타데이터를 가져와야하는데 이미지 순서도 사용성에 영향을 주니까 순서가 중요할텐데 디스패치 그룹도 써봤는데 잘 해결되지 않았습니다.

답변

여러 방법이 있음

  • 인덱스 정보도 넘기는 방법
    • 나중에 재조합
  • 동시에 넘기는 선택도 있음

result 내부의 정보들이 인덱스가 있는 상황인데 비동기처리하면 당연히 순서보장이 안되니까 그렇게 처리할듯

  • 비동기처리 도와주는 도구를 사용할 수도 있음 인덱스 정보를 저장하고 다 완성된 시점에 전달하는게 일반적인 방법

6장을 올렸을때 ui상으로 셀을 미리 만들고 플레이스홀더로 로드되는 중이라는걸 보여줌

  • 특정 셀의 인덱스를 찾아가서 url을 설정해주면 됨

셀 구성을 먼저 해서 더미 ui를 보여주고 비동기처리가 끝나면 설정해주는게 사용자 입장에선 자연스러움

이해가 잘 안됨

전반적인 조언

머신러닝은 결과에 별로 영향이 없음

  • 완성도를 높이는 것이 더 중요함 -> 일반적인 코드를 더 잘 짜는게 중요할테니
  • 테스트 코드
    • 슬랙에 요청해주면 도움 주실 수 있음
  • 접근성 챙기기

개선작업이 우선이고 하고싶다면 ML을 하자

  • 기능 구현은 얼추되었으니, 완성도만 높이자!
⚠️ **GitHub.com Fallback** ⚠️