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

발표자료 초안 발표

피드백

도표처럼 두번째 이슈도 비동기 이슈니까 비슷하게 설명할 수 있지 않을까

  • 맥락없는 사람은 이해하기 힘들어보임
  • 다른 팀들 한테 이해되는지 물어보기

네트워킹 어떻게 되는지 물어보심

  • 풀 온라인
  • 기술적 문제가 많으면 좋음
    • 문제가 발생했다는거보단 어떻게 해결했고
    • 아키텍쳐 MVVM-C를 왜 선택했는지
  • 기능은 영상보여주고 간단하기 구조 설명하기
    • MVVM-C가 중요한 아키텍처링이고
    • CoreData는 굳이 설명안해도 될것같음
      • 문제가 생기지 않는 이상
    • MVVM-C 관련 모듈구조나 폴더링이 어떻게 되었는지 그려서 설명
    • 프로젝트 전체 구성이 어떻게 되어있는지 설명하면 좋아보임
    • 개발자가 보는거라 기술 스택을 사용해서 어떻게 도식화했고
    • 어떤 문제를 만나서 어떻게 해결했다
    • 더 궁금하면 우리 부스로 오세용!

더 디테일한 구조는 이력서나 Wiki에 UML 그린거 넣으면 좋아보임

질문

15분정도 분량을 채워야하는데 지금은 완성이 안되었는데 15분에 못미칠거같음

  • 기술 스택을 더 추가할지 트러블 슈팅을 더 추가할지
  • 비중을 어떻게 맞출지 고민입니다.

답변

서비스 개발 설명하기가 힘들다. 근데 엔지니어들이 보는거라 기획을 궁금해하진 않는다. 어떤 기능을 만들었는지는 중요할거임. 영상으로 보여주겠지만 어떤 기능, 어떤 앱이다 설명 하나정도 추가되어도 좋아보임

  • 기능 명세나 리스트...? 독특한 개념이 들어갔으니 (백그라운드 태스크로 기록하기) 이걸 명시적으로 써주면 우리는 다르다는걸 보여줄 수 있음
  • 서비스 배경이나 설명 + 영상 + 강조할 기능 몇개 + 프로젝트 구조 + 문제해결 나오면 15분은 충분해보임

온라인이라 우리 이력서를 파는게 중요함

  • 시간이 없으니 우리 부스에 오게 만드는게 중요함
  • 그런 점에서 문제 해결은 좋아보임

질문

reuse 문제나 이런것들이 현업 개발자 관점에선 별거아닌 문제일 수 있어보였음

  • 나름 시간이 많이 소요되고 골치도 많이 아팠는데 걱정임

답변

엄청나게 대단해보이진 않을 것 같음

  • 빠르게 스크롤했을때 생기는 문제에서 킹피셔 빼니까 문제가 생겼고 그걸 해결하는 과정이 더 중요했음
  • 바로 응답이 나오셨는데 어떻게 유추해냈는가가 더 중요해보임
  • 해결하는 과정에서 킹피셔 구현을 봤다. 어떻게 동작하는데 우리는 이렇게 동작하니까 어디가 문제인지를 찾아냈다.
    • 어떻게 해결했는지 과정이 더 중요함
    • 문제에 직면해서 어떻게 해결했는지가 중요함
    • 간단한 앱 만드는데 얼마나 생기겠음
      • 전체적 데이터 sink를 맞추는 것 같이 큰 문제가 아니니까...
    • 문제가 많았는데 (10개정도 되어보였음) 과정에 더 초점을 맞추자!
  • 현업에서 잘 안쓰는 기술을 썼다는게 신선하고
  • 권한도 좋고
  • 보이스오버도 안한 팀이 있을 수 있으니 접근성, 모바일/프론트엔드 엔지니어니까 접근성을 많이 개선했다는걸 보여주는게 중요
  • 위트있게 하는게 좋음
  • 5개 문제해결을 보여주는것도 중요한데 개판인걸 보여주고 이렇게 개선된걸 보여준다던지
  • before after를 보여주는거지
  • 이팀이 특수했던건 다 iOS가 처음인데 팀소개할때 넣어도 좋아보임
    • 강조하고 싶은게 우리는 성장곡선이 빠르다
    • 소개할때도 그런 옵션을 주는게 좋아보임
  • 채용을 위한 거니까 어떤 경험을 통해 만들어가는 과정을 설명하는 자리라서
    • 아니면 고민에 대한걸 안넣었겠지
    • 팀이 어떻게 만들었는지를 PR하는게 목적이면 어떤 결과물이 나왔는지 보여주고 그 와중에 만난 문제를 소개하기
      • 사실 잘 못적음

질문

마지막 주여서 코드에 대한 관심도가 떨어지고 있음. 작성해서 많이 늦었지만 테스트 코드를 리뷰해주실 수 있을까요

유즈케이스 로직이 거의 없어서 레포지토리 테스트가 중요하다고 판단함

  • 코어데이터 테스트를 해보려고 했는데 코어데이터 모델을 쓰는데 충돌도 나고 TravelMO랑 RecordMO를 사용하려고 했는데 재선언된다고 에러가 떴음
  • 그걸 포함 안시키니까 없다고 뜸
  • 결국 레포지토리는 테스트 못하고 넘어갔음

유즈케이스는 대부분이 레포지토리 함수를 1:1로 호출해주는 역할을 하는거라 로직이라고 있는게 타이틀 검증하는정도?

  • 목 객체를 만들어서 테스트했음
  • 유즈케이스에서 레포지토리로 요청 보낼때 아무 의미없는애를 리턴하도록 작성함
  • 타이틀 검증, 날짜 검증, 위치 검증 로직 3개가 있어서 함수 3개를 작성함
  • viewModel 테스트가 주였음
    • 비동기 작업들이 좀 있어서 cancellable을 선언해주고 expectation을 선언해서 비동기 작업이 끝났을때 리턴되도록 wait 활용함
    • 결과가 제대로 나왔는지 비동기가 끝나면 확인할 수 있도록 구성

대부분 테스트코드가 엄청 많았는데 우리는 뷰모델 프로퍼티가 다 private 처리가 되어있어서 확인 가능한 함수만 했는데 이렇게 하는게 괜찮을까요

답변

private 함수는 테스트 안하는게 맞음

test_관광명소_초기설정에서 // given when then 적어주는게 좋다 각각 주어진 상황, 액션, 결과(검증)를 의미함

나는 저거 적었음

코드레벨에선 저렇게 작성함

저 함수에서 landmarks를 지역함수로 뺀다

이름도 test_관광명소_뷰가_로드되었을때_뭐한다() 이런 느낌

private 변수는 구현을 위해 많이 작성하고 노출되는건 publisher잖아

  • 일반적으로는 Input, Output으로 쪼갬

사실 유즈케이스도 주입받는거라 안중요함

  • 목으로 만드는것보단 UsecaseStub으로 만들고
var executeFetchStub: Result<[Landmark], Error> = .failure(JSONError.fileError)

패칭을 해야한다면 given 상황에서 usecase.executeFetchStub

func test_fetch에_성공했을떄_랜드마크_목록을_변경합니다()
// given
usecase.executeFetchStub = .success([])

// when
viewModel.fetch()

// then
viewModel.landmarks == [] 검증

이 테스트를 쪼개면 호출하는지 테스트하고 성공했을때와 실패했을때로 나누기

  • 호출하는지는 안중요하고 성공했을때와 실패했을때가 중요
  • 은닉화된 정보에 대한 테스트는 구현체에 대한 테스트가 됨
  • 주입하는 의존체에 대한 설정은 변경해주면 됨
  • 이름은 초기설정보단 given_when_then이 드러나도록 하자!

test_두번째_리로드일때_fetch에_성공하면_랜드마크_목록을_초기화합니다() { // given viewModel.landmarks = [A()] }

동작들에 대해 유추할 수 있어야하고 동작이 구현체에 의존하면 좋지 않음

  • 테스트 많다고 좋진 않음 개수에 민감하게 반응하지 말자
  • 구현을 테스트하는게 아니라 원하는 명세대로 동작하는지를 테스트하는거!

질문2

@testable import OwnMyWay은 프로젝트 모든 파일에 대해 로드가 되어서 테스트 스킴에서 컴파일 소스를 일단 많이 넣긴 했는데 정확히 뭐하는지 모르겠음

답변2

이렇게 하면 안된다. Alamofire를 import하면

// Alamofire

class Foo {

} 이건 접근할 수 없음

이부분 이해가 안된다

질문3

일단 모든 파일을 로드한다는게 맞긴 한가요

의존성

답변3

프레임워크를 추가해서 다 프레임워크로 만든다

Something이라는 프레임워크가 생기고 이걸 import해도

final class Something {
    let name: String
}

Something.name을 사용할 수 없게됨. 왜냐? internal로 되어있기 때문임 public으로 지정하거나 해서... 그래서 프레임워크로 분리해서 적절히 오픈할걸 지정해주는 방식임

Something의 작업이 있고 앱 타겟에서 Something에 접근하게 하고싶지 않다면? public으로 만들지 않으면 앱에서 Something을 모르겠지 프로토콜만 노출시켜서 실제 구현 객체는 internal로 하면 된다.

근데 구현 객체에 대한 테스트를 할 수가 없잖아 @testable로 작성하면 구현 객체에 대해서도 접근할 수 있게 된다.

근데 public에 대한 접근만 허용하고 싶다면 무관함 @testable import로 자동으로 되는데 굳이 @testable은 안 붙여도 된다.

일반적인 방식은 아님. 원 타겟이 있으면 하나만 만드는게 일반적인 방식임. 쪼개진 레이어를 해보고 싶었을수도 있는데 프레젠테이션 레이어와 도메인 레이어가 프레임워크로 쪼개져야 가능한 방식임

질문4

아까 생긴 레포지토리 문제는 Entity를 만들어서 Add를 했는데 HostApplication을 끄고 테스트하니까 Persistance는 디바이스 안에 있는거라 실행환경에서의 context와 테스트 환경의 context에 동시접근해서 문제가 생긴걸로 파악함

답변4

context 자체를 모킹을 해야할것 같아보임 이런 객체를 만드는게 쉽지 않음

protocol NSMAnagedObjectContenxtProtocol {
    func fetch<T>()
    
    func fetch(_ request: NSFetchRequest<NSFetchRequestResult>) throws -> [Any]
}

extension NSMAnagedObjectContenxtProtocol

NSManaged 자체를 추상화하는것도 방법임

이해가 하나도 안됨

이런 느낌으로 하지 않았을까요 lazy하게 만들수 있으니까

오토 클로저??

함수 자체를 만들어서 넘기면 클로저 형태로 만들어줌 FirebaseAnalytics.shared()를

이해가 안돼ㅜ

컨텍스트 자체도 실제 객체가 아니라 모킹을 해서 테스트한다는 개념 내부 객체나 네트워킹 연결체, 퍼스트파티나 서드파티 연결체는 추상화를 다 해야해서 테스트하기 어려움

  • 도전해볼만 한데 복잡함
  • 뷰모델은 저수준임... 모든 파일에 의존하고 있고...

유즈케이스는 코어객체에 의존하지 않으니 ㄱㅊ 뷰모델도

이런거 먼저 해보고 레포지토리 객체에 참조하자

  • 추상화를 만들고 테스트하는 정도
  • 그게 힘들면 추상화하지 않고 코어데이터에 접근하는 서비스를 만들고 추상화시키고 하는 경우도 있음
  • 패쳐를 직접 참조하니까 어려우데 context를 가져오는걸 서비스로 밀어버리고 MO를 넘기면 값만 반환하는 형태로
    • 그런걸 추상화하는것도 방법이고
    • 퍼스트파티 자체를 추상화하는 것도 좋음

직접 컨택하는 경우도 있고 부스가 열리는 경우도 있음. 최소한의 이력서를 준비하고 CS 학습을 많이 하고 스타트업가려면 프로젝트 보여주고... 이력서를 self 드라이브 가능하게

  • 기술 고민해본거 -> 이런 구조로 설계했음 이런 문제를 해결했음
  • 스타트업은 1시간동안 내가 준비한대로 문제를 받을 수 있음
  • 이력서나 포폴 준비할때 상대방이 궁금할 요소를 만들어놓기
  • 그럼 내가 준비한 질문만 잘 답변하고 끝내면 되잖아
  • 큰 회사는 코테랑 CS 준비하기
  • 스타트업은 프로젝트에서 내가 해결했던 문제.. 캐시나 킹피셔 직접 만들기 등등을 구체화시키고 내가 했던걸 정리하기

끝나고 템포가 빠름. 면접이 동시에 잡히기도 함. 그런걸 참고해서 준비하자!

서비스 고민을 했다. 사용자에 관심이 많았다. 다 비슷한 이야기를 할거야. 여기서도 뾰족한게 중요하고... 부캠이 특별하다면 여기에 묻혀가는 것도 중요할지도

  • 엔지니어링 잘하는 사람? 서비스 잘 만드는 사람?
  • 컨셉을 잘 잡자!
  • 큰 회사 중심이라면 이런건 아마 필요 없을지도
  • 시장이 블루오션이라 ㄱㅊ음

1년 내내 채용이 있으니 이번에 모든 회사에 지원하기보단 면접하는데 필요한 스킬... 관심없는 회사 먼저 넣어서 스킬 쌓일때 원하는 회사에 지원하기! 관심 있는 회사를 너무 몰아서 지원하는 것도 안좋음

발표자료 최종본 만들면 슬랙에 올리기!

멘토링은 마지막이지만...! 우리의 인연은 여기서 끝나지 않음. 여기까지보다 뒤가 더 중요할 수도 있음!