AsyncSwift Seminar 002 정리

rbw·2022년 9월 22일
2

TIL

목록 보기
45/98

20220922 어싱크 스위푸투 커뮤니티 2회

Core를 잘 다루는 타다의 상태관리 기술 - 김남현(타다)

RIBs : 타다 아키텍처, RIB : Router, Interactor Builder 의 약어

RIB은 필수로 들어가고 View, Presenter도 포함한다. (Presenter, 변환하는 로직 ? )

State tree를 사용한다.

RIBs 에 대해서 더 알고 싶으면 레츠스위프트2018의 강연연상이 있으~

  • 상태관리의 어려운 점 : 타다 사례

문제 1 : 복잡한 상태에 얽힌 도메인 로직

미리배차 라는 기능을 사용하면 평가 없이 바로 진행 되는 플로우가 생김

다음 주변콜 이라는 기능을 사용하면 앞의 플로우는 같지만, 새로운 상태가 하나 생김

상태 추가에 따른 고민

  • 다양한 도메인 맥락을 고려해야함
    • 현재의 요구 조건만 고려한 업데이트의 부작용
      • 미리배차 로직에 대한 이해도 없이 새로운 콜 업데이트하기
    • 상태 전이시 참고해야할 데이터가 많음
  • 대전제를 건드리는 변경 사항이 생기면 너무 많은 변경 발생
  • 서버와 클라이언트 간 상태가 다를 때 동기화 하는 방식

-> State Tree 에서 RideDroppedOff 컴포넌트안에서 하차하는 걸 관리해라 ! 라고 구현함. 나머진 알 필요 x

그래도 고민은 계속

  • 상태를 반영하는 코드가 분산되어 있음
    • 도메인 지식 파악의 어려움
    • 상태 변경 이벤트가 Propagate (자식 컴포넌트인 RideDroppedOff가 변하니 위의 부모 컴포넌트로 전파된다.)
    • 여러 RIB 에서 수정

문제 2 : 상태 변경 과정의 문제 상황들

순서 보정

  • 타다에서 사용하는 서버 통신 : HTTP, gRPC
  • 상태 업데이트용 순서 보정 코드 필요
    • DTO 객체 Versioning
    • 상태 업데이트 중 변경 이벤트 무시하기 (A로 변환하는 과정이 끝나지 않았다면 그 사이에 B로 바꾸는 신호는 무시하기, 이 부분은 트랜잭션과 좀 관련이 있어보이기도함 개인적으론 ?)

동시성 문제

  • 한 번에 발생해야 하는 상태 업데이트가 개별로 발생
  • 이로 인해 Event Emit이 불필요하게 여러번 발생
  • 각각의 상태 업데이트간 간섭으로 생기는 미묘한 동시성 버그 해결을 위한 코드 존재
    • 의도적인 Filter 로직

문제를 해결해보자 😎

문제 해결을 위한 가설

  • 상태 변화에 대한 테스트를 작성하여 변경에 대한 안정성을 만들면 복잡한 상태로 인한 버그가 줄어들 것이다.
  • 상태 관리에서 반복적으로 나타나는 패턴을 추출하여 개발을 할 수 있도록 하면 중복 코드 / 중복 버그를 줄일 수 있을 것이다.
  • 상태 변화에 대한 모니터링을 쉽게할 수 있는 방법을 만들면 디버깅 효율성을 높일 수 있을 것이다.

-> 상태 관리 책임을 독립된 모듈로 분리

  • 상태 변화 코드를 한곳에 응집
    • 수많은 메서드를 갖는 거대한 모듈의 탄생

TODO : 거대한 모듈 -> 책임 분리나 확장에 용이한 모듈

-> 안정적이고 확장에 유리한 모듈로 개선

이 고민을 하기에 앞서 다른 생태계에선 ?

Redux

  • 단방향 데이터 흐름으로 상태를 변경 및 구독
  • Action 처리에 대한 Middleware를 제공
  • MVI 아키텍처와 유사

타다 앱에 Redux를 끼얹으면 ?

  • State Mutation / Subscription 등 리덕스의 단방향 데이터 흐름 개념은 이미 익숙한 사용성
  • 액션과 스테이트에 대한 미들웨어의 도입을 통한 관점 지향 개발 가능
  • 중앙집중화된 상태관리를 제공
    • 커다란 State Tree를 가지는 프로덕트 요구사항에 적합

StateMachine 동작 과정

  • StateMachine은 스테이트에 대한 Mutation 을 액션이라는 데이터를 디스패치하여 진행
  • Mutation 을 발생 시키는 과정에서는 미들웨어를 도입
  • 최종적으로 State의 Mutation을 시키는 도메인 로직은 리듀서가 책임

도입 후 효과들

효과 1 상태 관리 모듈 분리

  • 상태 관리 책임이 한 곳으로 집중
    • 도메인 지식 파악 용이
    • 비슷한 맥락의 중복된 코드 제거
    • 놓치는 로직 개선

-> 전반적인 버그 감소

효과 2 Middleware

  • 관점 지향 개발 (AOP ?)
  • 비즈니스 로직에 영향을 미치지 않는 동작들 추가 가능

효과 3 UnitTest

  • StateMachine에 대한 유닛 테스트 기능
  • 다양한 앱 기능을 실행하면서 StateTrackerMiddleware 를 통해 각 테케를 수집하여 보다 쉽게 테스트 생성 가능

추가로 자랑하고 싶은 부분은

FlipperMiddleware (의도하지는 않았찌만 ...)

  • 원활한 디버깅을 위한 시각화 툴
    • State의 diff 비교
    • Dispatch된 액션 순서
    • 임의로 액션 디스패치 하기

정리

  • 상태관리의 어려운 점
  • 안정성 : 올바른 상태 관리를 위해서 다양한 도메인 지식 필요
  • 생산성 : 변화에 유연함 필요
  • 해결방식
    • 상태관리 책임 모듈 분리
    • 안정적이고 확장에 유리한 모듈로 개선 - Redux style

이 발표는 상태관리 모듈 분리, 유연하고 안정성 있는 상태관리 모듈 만들기 이고 아키텍쳐 발표가 아닙니다 ~


Why? MVVM (권문범 - 쿠팡 iOS 9년차)

MVVM에 관한 주제로 얘기를 하실 예정

MVC

Model - View - Controller

Controller -> Model == Model Life cycle / write
Model -> Controller == Model life-cycle / read

Controller -> View == View LifeCycle / update
View -> Controller == Handle user events

Model : 데이터 상태를 관리
View : 사용자와 직접 상호작용한다.
Controller :

장점 : 각 모듈의 결합도 약화, 역할에 따른 코드 기반한 구별

단점

  • 컨트롤러에 API 코드들이 모여 단위 테스트가 어렵
  • 상대적으로 Model-Contoller 결합도가 강함
  • 유지보수 과정에서 Controller의 비대화

MVP

장점

  • View 별로 분리 구현된 비지니스 로직에 의해 뷰별 단위 테스트용이
  • 뷰컨트롤러는 라이프사이클에 집중 가능

단점

  • 각 뷰컨은 가벼워지지만 뷰와 프레젠터 사이의 수작업이 늘어난다
  • 각 뷰별로 분리되어 경량화된 프레젠터도 유지보수 과정에서 무거워질 수 있따.

MVVM

View Model -> Model == Data Binding / write
Model -> View Model == Data bindings

나머진 비슷한듯 데이터 바인딩이라는 부분이 좀 다른 느김 ~

ViewModel : 옵저버 패턴등을 사용하여 뷰 모델 사이에 연관성을 완전히 분리, (Rx or KVO 등을 활용하면 편리, 이제는 Combine)

장점

  • 각 모듈의 결합도를 낮춰준다.

단점

  • Binding을 구현하기 위한 난이도가 있다
  • 위의 방법을 쉽게 하기 위해서 사용하는 라이브러리들의 디버깅이 다소 어렵다

좀 더 추가하자면

  • Interactable : Protocl로 ViewModel과 View의 바인딩 역할
  • Contatiner: Interactable 같은 바인딩을 위한 component를 담는 역할

Why MVVM

1. 각 코드의 역할과 책임을 분명히 한다

  • UI component
  • 사용자의 이벤트 출력
  • 데이터 출력

뷰 컨트롤러

  • 뷰의 라이프 사이클 관리
  • 뷰이벤트 따라 비지니스 로직 정의
  • ex) viewDidLoad에서 뷰모델 바인딩

모델

  • 데이터 저장 및 관리
  • API 호출과 같은 remote data 로딩도 수행

뷰 모델

  • 뷰 와 모델의 데이터와 이벤트 바인딩
  • 이벤트와 데이터의 경로 및 방향성 정의

2. 선언적 코드를 활용하여 동적인 코드를 통제함

  • 기존 MVVM이 아닌 방식에서는 함수를 호출하여 비지니스 로직 실행

  • 공유 변수 및 외부 변수가 참조되는 코드가 많아져서 동적인 코드가 다수

  • 런타임에 동작에서 예외 케이스 다수 발생

  • MVVM에서는 각 모델에 뷰 모델을 통하여 비지니스 로직을 바인드

  • 각 비지니스 로직은 모델에서 참조중인 데이터에 대해서만 태스크 수행

  • 클로져 형태로 바인드 되어 외부 변수 참조시에 context capturing을 통한 무결성 보장

3. 비지니스 로직의 방향성을 가시화하여 파악을 쉽게 만든다.

  • 뷰 - 뷰 모델 - 모델의 파이프라인과 방향성이 정해져 있어서 파악이 용이함

4. 동시성 프로그래밍에서 생기는 Side-Effect를 최소화한다.

이 부분이 크다고 생각하심

  • MVC 혹은 OOP에서 공유 자원에 대한 race condition 발생

마지막으로 연사님이 하고 싶은 말은

누구나 3개월 ~ 6개월 배우면 코딩은 할 수 있다고 함.

연사님은 그래서, 왜 쓰는지 그런 이유에 관한 것과 철학 까지 파악하는걸 중요시 여긴다고 하심

네이버나 쿠팡에 입사하면 들을 수 있는 더 자세한 MVVM 아키텍처 강연이 3~4시간 짜리가 있다고 하네여 ㅋㅌㅋ


코드리뷰 - 같이 성장하기 위한, 그리고 성공하는 팀이 되기 위한 도구 - 김우성(29cm iOS Lead)

연사님 소개

  • PR 리뷰를 기반으로 한 팀 협업 문화에 진심

  • 평범한 사람들이 팀으로 모여 비범한 결과를 내고 싶어함

  • 개발자는 회사 비즈니스 성공을 위해 존재해야 한다고 생각

  • 개발 문화는 회사와 팀의 성공을 위한 것이어야만 한다

1. 팀에 PR이 필요한 이유

연사님은 지식 아카이브로 사용하고 있다고 하심 .

신규 입사자분들도 이 훈련을 3~6개월 한다고 한다

Knowledge Archives (지식 아카이브)

업무와 관련된 히스토리, 의사결정, 일련의 활동등을 보관할 필요가 있다.

지라, Trello 등 칸반보드에 보관한다거나, 위키 서비스(Confluence)도 있으

노션으로 넘어가는 추세라고 함

PR as Knowledge Archives

변경사항 자체와, 이에 대한 맥락을 팀에 공유 하는 방식으로 PR 작성을 하도록 변함

2. 팀의 생산성을 낮추는 PR

PR을 단순히 코드리뷰를 위한 도구라고 생각하고 협업하면 오히려 생산성에 악영향을 미침

작성자 위주의 PR - 불친절한 설명, 맥락 부족

우성님은 머리를 크게 쓰지 않고도 리뷰할 수 있을 정도로 잘 읽히는 PR 을 지향함 (적어도 PR 제목 + 본문에 한해서는)

팀원 중에서 이 PR을 꼭 지금해야하나 이런 당위성에서 의문을 느껴 본인이 직접 자료를 찾아서 리뷰를 남긴 적이 있다. 이 부분도 PR을 요청하는 입장에서 자료를 주어야하지 않을까..?

PR에 너무 많은 내용이 있는것도 xxxx 조치아눔~ 그리고 테스트코드를 요청하는 리뷰 댓글이 많이 보였음 역시 테스트코드는 중요하다~

3. 좋은 PR 이란 ?

풀리퀘는 기본적으로 글이다. 그 중에서도 리뷰어가 읽는 요청서. 결국 잘 읽혀야 한다는 의미. (연사님은 잘 설득이 되어야 한다고 하심)

오픈소스에 기여하는 느낌으로 작성해보는걸 추천하심. RxSwift 머지된 리뷰들을 참고해보자 !

다른 추천 방법으론 스마트폰으로도 리뷰할 수 있을정도로 최대한 작고 간결하게 작성하는걸 추천. (다만 PR 특성에 따라 프로젝트 내 기반이 갖춰져 있어야 할 수도 있다)

4. PR 중심으로 협업하는 팀이 되기 위한 기술들

Git - 꼭 알아둬야 할 기능들

Interactive Rebase, Fixup commit

Alfred Worflow * GitHub 알프레드에 PR을 찾는 기능이 있다고 하심

Git-Flow to Trunk-Based Development

코멘트 레벨 도입(From 뱅크샐러드)

PR 레이블 활용 - emergency, needs-healing 등

깃허브의 레이블 기능을 적극 활용 하시는 듯

5. 좋은 PR을 작성하는 방법

정리하는 목차라고 보면 될 듯

  • RxSwift에 기여하는 느낌으로
  • 스마트폰에서도 리뷰할 수 있는
  • 리뷰어는 언제나 바쁘다.
  • 리뷰어가 고민하지 않도록
  • 코드의 양은 적게, 본문은 많게

PR 작성 단위

  • 하나의 컨텍스트 만을 가진 최소 의미 단위 PR을 지향함
  • diff를 최소화한다. 리뷰에 방해가 안되는 선에서의 리네이밍, 리팩토링은 권장사항이나 많은 파일이 수정 혹은 추가되어 리뷰를 어렵게 만드는 변경은 별도의 PR로 작성하는 편
  • 에픽을 진행하고 있는 경우 한 PR 이 하나의 기능을 담도록 작성

참고 사진

추가로 테스트 코드로 확인하기 어려운 부분을 담기 !

6. PR 리뷰하기, 리뷰를 통해 서로 어떻게 성장할 것인가 ?

리뷰하기 & 승인하기

비동기로 효율적으로 커뮤니케이션하기

리뷰를 통해 성장하기

  • 글로 업무를 정확하게 표현하기
  • PR 리뷰하는 속도 높이기
  • PR 리뷰하는 깊이 더하기
  • 도메인/기술 지식 익히기

7. 실제 사례들

이런 분야에 대한 지식이 없는 사람이 봐도 이해가 될 수 있게 해당 분야에 대한 내용도 적당히 작성 해주는 것도 좋은 듯 하다.

자신의 고민 내용을 기록한 노트나, 사진 등등도 첨부하여 리뷰에 올리신것도 있었음


내일 지구가 멸망해도 테스트는 같게 동작해야 한다 - 김찬우(원티드랩 교육사업팀)

테스트가 필요한 이유 ?

  • 테스트를 함으로서 다음 기능을 추가할때 확신을 갖고 구현해 나갈 수 있다.

불확실한 상황에 대한 테스트는 어떻게 할ㄲ ㅏ ?

가짜 인스턴스를 만들어서 테스트를 진행하였음

이를 만들기 위해 프로토콜을 만들어서(추상화 진행) 가짜 인스턴스와 진짜 인스턴스에 채택을 시켜서 진행함.

그리고 무엇을 테스트하는지 파악을 잘 해야한다 !

Part2 대혼란의 Mock티버스

테스트가 중요한 부분은 아무래도 네트워킹 쪽인듯 하다.

우리의 데이터를 전송할 때 서버가 이상하다면 ? 또는 와이파이 연결이 불안정 하다면 등 이러한 경우엔 테스트 코드를 적극 활용하는게 좋아 보였다.

연사님이 설명한 URLSession의 가짜 인스턴스를 만드는 방법은 새로 프로토콜을 정의하고, URLSessionDataTask에 해당 프로토콜을 채택하였고, URLSession에서는 해당 프로토콜의 타입을 반환하는 함수로 새로 하나 더 작성하여서 만들었다.

여기서도 중요한건 네트워킹 이후의 과정을 테스트 한다는 점이다.

URLSession, URLSessionDataTask를 테스트 하는게 아니라 네트워킹 과정 이후 처리 과정을 테스트하는 것이다.

저 클래스들은 애플이 만든거기때문에 그건 우리가 테스트 하는게 아니라고 하심.

정리하자면, 기존에 존재하는 URLSession, URLSessionDataTask를 추상화해서 Mock을 만들고, 이를 통해 completionHandler를 테스트함.

profile
hi there 👋

0개의 댓글