Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[team-10][Dumba, Min] MVVM 구조설계와 첫 번째 화면(Main) 구성 #16

Merged
merged 44 commits into from
Apr 29, 2021

Conversation

youngminshim-de
Copy link

작업내용

  • MVVM 패턴을 적용하여 클린 아키텍쳐 구조를 지키려 노력하며 설계했습니다.
  • UICollectionViewDiffableDataSource를 이용하여 CollectionView를 구성했습니다.
  • Combine을 이용하여 View - ViewModel 간의 Data를 Binding 했습니다.
  • Alamofire를 이용하여 Network 통신을 구현했습니다.
  • Toast를 이용하여 Title을 터치하면 상품의 개수를 띄우도록 구현했습니다.

고민거리

  • Title을 누르면 Toast를 띄워야하는 요구사항이 있어, BanchanCustomCellHeader(UICollectionReusableView) 에
    TapGestureRecognizer 를 추가해줌으로써, Action을 연결해 주었는데, 여기서 Cell의 개수가 필요하기에 cellCount라는 property를 선언해줌으로써 해결해주었습니다.

  • 네트워크 통신 주체인 NetworkService Class가 현재 MVVM 패턴에서 Repository 미구현으로 Network 접근이 viewModel, view에서 등 여러곳에서 접근되어 지향하고 싶지만 어쩔 수 없이 싱글톤으로 구현하였는데 Repository의 윤곽이 잡히게 되면 싱글톤 방식에서 벗어날 수 있는지 고민하고 있습니다.

kihyuk-sung and others added 30 commits April 19, 2021 14:34
- README.md에 팀 브랜치 전략 추가.
- 커밋 규약 추가
- 팀명 추가
- 팀원 추가
반찬 컬렉션뷰를 나타낼 BanchanListViewController 와 상세페이지를 나타내는 DetailBanchanViewController 추가
MVVM 패턴적용을 위한 폴더 그룹핑 & 주석제거
반찬 모델 생성
상세반찬모델 생성
BanchanCustomCell.xib 파일에 Cell Layout 작성

issue: #12
반찬컬렉션 뷰의 헤더파일 추가
섹션별로 업데이트를 하기위해 UICollectionViewDiffableDataSource를 도입하였습니다.
이에 따른 NSDiffableDataSourceSnapshot을 적용해 주었고 가독성을 높이기 위해 typealias를 통하여 재정의 해주었습니다.
DataSource에 정보를 주기 위한 BanchanListViewModel을 정의해주었습니다.

issue: #13
반찬커스텀셀, 반찬커스템셀 헤더 다른 폴더로 이동
Cell Autolayout 수정

issue: #12
Section 클래스를 만들어 기존 BanchanListViewModel 의 역할을 대신함
Toaster 패키지 cocoapod으로 설치
BanchanListViewModel Refactoring & Install Toaster
네트워크 프레임워크인 Almofire을 사용하기위해 Cocoapod을 통하여 설치하였습니다

issue: #16
HTTPMethod를 통한 네트워크 통신을 Alamofire를 사용하여 작동하는 NetworkService Class의 초안을 구현하였습니다.

issue: #16
네트워크와 통신할 DTO 객체를 구현하였습니다.
DTO 자체에서 toDomain() 메소드를 두어 Entity를 바로 생성해줄 수 있도록 하였습니다.

issue: # 16
네트워크와 통신할 DTO 객체를 구현하였습니다.
DTO 자체에서 toDomain() 메소드를 두어 Entity를 바로 생성해줄 수 있도록 하였습니다.

issue: # 16
네트워크와 통신하여 반찬리스트를 받아올 UseCase를 작성하였습니다

issue: #16
String URL로 부터 Image를 불러오기 위한 UseCase를 작성하였습니다.
UIKit을 모르게 하기 위해 가공된 Data에 대한 completion을 제공하여 Image생성하게 끔 하였습니다.

issue: #16
DiffableDataSource를 이용한 Section Update 가능하도록 구현하였습니다.
Notification을 이용하였지만 Combine으로 구현해볼 예정입니다.

issue: #13, #16
feat: Mod BanchanListViewMdoel, BanchanListViewController
Notification을 이용하여 collectionView를 업데이트 하던 방식에서 Combine을 활용한 방식으로 변경
토스터를 이용하여 제목을 누르면 상품의 개수가 화면에 나오도록 구현
issue:#15
이미지를 가져와 앱에 뿌려지도록 구현

issue:#12
Copy link

@pay-napster-x pay-napster-x left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요! Napster라고합니다 :) 반갑습니다.
부족하지만 최선을 다해 리뷰를 해보려합니다.

팀원을 이루어서 작성한 코드이지만 코드 컨벤션이 잘 지켜진것 같습니다. 의도하신건가요? :)
Clean Architecture 의 도입은 아주 좋습니다. 다만,
모든 건 왜 사용하는지에 대한 나름의 기준이 분명히 있어야합니다.
배웠으니까, 모두 하니까 적용해봤습니다는 타당한 이유가 되지 않습니다. 😙
나름의 기준을 세워보세요.

ViewModel의 역할은 어디까지일까요?
BancanListViewController에 데이터를 바인딩해서 보여주고있지만,
applySnapshot 메소드가 하는 역할이 ViewModel의 역할과 조금 겹쳐보입니다.
CollectionViewDataSource와 View의 바인딩은 정말 이방법 밖에 없을까요?
Combine을 사용했다면 좀 더 명확한 표현의 바인딩이 있을 것 같습니다.
코드에 Combine을 도입이 되었는데 되도록이면 Closure사용을 줄이고 Event로 바꿔보세요!

😄 잘 알고 계신 것 같지만 싱글톤의 사용을 최소한으로 줄여보세요.
NetworkService에 대한 고민이 필요해보입니다.
Swift Network Layer를 키워드로 자료를 찾아보세요.

수고하셨습니다!!
화이팅합시다!

let salePrice: String
let badge: [String]?

private enum CodingKeys: String, CodingKey {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodingKey를 따로 사용하신 이유가 있을까요?
없다면 카멜케이스로 Decoding할 수 있는 옵션이 있습니다. 😀

Copy link
Collaborator

@ghis22130 ghis22130 Apr 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

카멜케이스로 Deconding 하고자 하는 의도로 도입했었는데 convertFromSnakeCase 가 존재 하는것을 알았네요.
적용하면 불필요한 enum을 줄일 수 있어 코드가 더욱 깔끔해질 것 같습니다! 감사합니다.😀


import Foundation

struct BanchanListDTO: Codable {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codable은 Encoding과 Decoding이 함께 채택되어있는 프로토콜입니다.
해당 구조체가 Decoding만 한다면 Decodable만 채택하는게 다른사람이 봤을때
이 객체는 Decoding만 하는구나 라고 명시적으로 알 수 있습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 DTO는 Decoding만 하고있으니 Decodable을 채택하도록 수정하겠습니다.
Encoding, Decoding에 대한 명시적 구분도 중요하다는 것을 배웠습니다. 🧐

}
}

extension BanchanListDTO.BanchanListItemDTO {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 Extension은 꼭 Extension으로 빼야할까요?
BancanListItemDTO 내부에 있는게 읽기 편해보입니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DTO 내부 property들만 명시적으로 먼저 보여주는 것이 중요하다 생각했습니다!

DTO 안에 property, enum, method 가 들어가게되다 보니 번잡해 보여서 toDomain() 메소드 들은 extension 으로 빼서 모아 주는것이 깔끔하다 여겼는데,
위에서 리뷰해주신 Coding Key 관련 enum을 사용하지 않게 되면 내부로 들어가는게 더 좋을것 같군요!

guard let url = URL(string: strUrl) else { return }

AF.request(url, method: httpMethod).validate().responseData { data in
completion(data)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

항상 API는 성공만 하지 않습니다.
Error에대한 처리를 잊지 말아주세요 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error에 대한 처리 ... 명심하겠습니다! 👍

iOS/SideDish/SideDish/Domain/Entities/Banchan.swift Outdated Show resolved Hide resolved
break
}
}, receiveValue: { (value) in
self.applySnapshot()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

순환참조를 방지하기위해 캡쳐리스트를 사용해주세요
value는 사용하지 않는다면 _ 로 바꿔주시는게 더 좋겠죠? 😌

import Foundation

enum Delivery {
static let dawn = "새벽배송"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum으로 사용하셨다면 case의 이점을 이용하는게 좋지 않을까요? 😃

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 enum들에 대한 처리가 아주 고민이였습니다 😥
case의 이점 인지하고 개선해보겠습니다!


import Foundation

struct FetchImageUseCase {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단순히 이미지만 받아오는 건 Use Case가 아닌 것 같아요.
:) 다른 클래스에서 설명드린대로 한번 살펴보세요.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도 향후 구현할 Repository, Persistent Storage와 함께 깊게 고민해봐야할 것 같습니다.
저도 구현하면서 아리송 했었는데 역시 였군요..ㅎ

MVVM에 대한 이해가 더 필요한 것 같습니다 😮

loadImages(imgURL: banchan?.image ?? "")
titleLabel.text = banchan?.title
descriptionLabel.text = banchan?.description
netPriceLabel.text = "1000"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

가격은 고정인가요?
반찬속성에 값이 set될때 고정된 값이 보일 것같습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI 구현이 완전하지 않아 우선 고정적으로 두었으나 개선할 예정입니다!


import Foundation

struct DetailBanchan {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

왠지 느낌일지 모르지만 BanchanDetail이 더 익숙합니다.

youngminshim-de and others added 11 commits April 23, 2021 11:55
반찬리스트DTO 클래스의 코딩키 삭제 & ConvertfromSnakeCase 적용 및 변수명 변경

issue: #27
클래스 내부의 속성 접근 제한자 설정

issue:#27
반찬 커스텀셀에 특가 배지 넣기위해 BadgeStaciView를 추가하였습니다.

issue: #12
섹션이 순서대로 나오지 않는 버그 수정
변수명 수정 및 불필요한 함수 제거

issue: #27
기존에 헤더에서 불리워지던 토스터를 ViewController에서 불리워지도록 수정
issue: #27
변수명 및 클래스명 변경

issue: #27
컴바인을 이용하여 네트워크 리퀘스트를 받아오도록 변경하였고, FetchBanchanUseCase 또한 컴바인을 이용하도록 변경하였다.
KingFisher와 ImageView Extension을 이용하여 Cell의 imageView의 image Update 하는 부분 변경
URL을 ViewModel에서 UseCase로 주입해주는 형태로 변경하였고, UseCase에서 static method를 쓰던 방식에서 ViewModel이 UseCase를 가지고 있는 형태로 변경
Refacotring: FeedBack 내용 수정 및 Network Combine으로 변경
Malloc72P pushed a commit that referenced this pull request Apr 27, 2021
ksundong pushed a commit that referenced this pull request Apr 28, 2021
…pi-course

Revert "[BE] Course 반찬 추가"
sallyjellyy pushed a commit that referenced this pull request Apr 29, 2021
@ghis22130 ghis22130 merged commit c32d5e2 into codesquad-members-2021:team10 Apr 29, 2021
wheejuni pushed a commit that referenced this pull request Apr 29, 2021
ksundong pushed a commit that referenced this pull request May 1, 2021
- 도메인 생성
ksundong pushed a commit that referenced this pull request May 1, 2021
- Best 테이블과 매핑되는 Best 엔티티 클래스 생성
ksundong pushed a commit that referenced this pull request May 1, 2021
- 배포 시 jar을 빌드하기 위해, gradle-wrapper.jar 파일 origin으로 커밋
ksundong pushed a commit that referenced this pull request May 1, 2021
- DB에서 이벤트 테이블을 삭제
- DB 테이블 변경 사항을 클래스와 커스텀 쿼리에 적용
ksundong pushed a commit that referenced this pull request May 1, 2021
- dish_best 테이블을 추가하면서 data.sql과 schema.sql에도 변경사항을 반영
ksundong pushed a commit that referenced this pull request May 1, 2021
- 클라이언트가 요청한 json 데이터 형식에 맞춰 BestDTO 구현
ksundong pushed a commit that referenced this pull request May 1, 2021
- 추가한 DishBest 테이블과 매핑되는 클래스 구현
ksundong pushed a commit that referenced this pull request May 1, 2021
- best API와 관련된 기능 구현
  - /best -> 모든 best 목록 가져오기
  - /best/{category_id} -> 특정 best 정보 가져오기
crongro pushed a commit that referenced this pull request May 4, 2021
* [#1] init: 🎉 개발 환경 구축

* [#3] feat: ✨ Header 만들기

* [#5] feat: ✨ BestTab UI 구현

- BestTab UI
- 상수 파일
    - const.js
- 재사용 컴포넌트
    - Label.jsx
    - ItemCard.jsx

* [#7] feat: ✨ Slide UI 구현

- App.jsx
    - SlideContainer import
- BestItem.jsx
    - 삭제 (미사용)
- BestItems.jsx
    - ItemCard prop 추가
- BestTab.jsx
    - 스타일 수정
- SlideContainer.jsx
    - UI 구현
- SlideItems.jsx
    - UI 구현
- SlideArrowBtn.jsx
    - UI 구현
- ItemCard.jsx
    - 스타일 수정
    - prop 추가
- Label.jsx
    - prop 추가
    - 기본 값 추가

* [#8] feat: ✨ ShowMoreBtn UI 구현

- App.js
    - ShowMoreBtn import
- ShowMoreBtn.jsx
    - UI 구현

* [#10] feat: ✨ Header Dropdown 구현

- App.js
    - Header 경로 수정
- Header.jsx
    - 경로 변경
    - HeaderLeft & Right 분리
- HeaderLeft.jsx
    - 컴포넌트화
    - Navigations 컴포넌트화
- HeaderRight.jsx
    - 컴포넌트화
- Navigations.jsx
    - 컴포넌트화
    - Dropdown 구현

* [#13] feat: ✨ API에 fetch 요청 로직 구현

* [#13] feat: ✨ API 요청, 베스트 기능구현
- BestItems.jsx
   - API 데이터 동기화
- BestTab.jsx
   - useState, useEffect, API 요청
- BestTabContainer.jsx
   - API 데이터 동기화
- BestTabNavigator.jsx
   - API 데이터 동기화
- ItemCard.jsx
   - prop 변경
- Label.jsx
  - COLOR변수 추가

* [#15] feat: ✨ 상세 modal 페이지 UI 구현
- App.js
   - PopUpContainer import
-  PopUpContainer.jsx
   - UI 구현
- PopUpImages.jsx
   - UI 구현
- PopUpInformations.jsx
   - UI 구현

* [#16] feat: ✨ 모달 페이지 이벤트 구현중

* [#16] feat: ✨ 수량정보 컴포넌트 분리

* [#19] refactor: 🔨 리팩토링, 부족한 부분 추가 구현
- 파일 및 폴더 구조 변경
   - common 폴더 생성
- Context.jsx
   - useContext 사용하여 prop drilling 개선
- 팝업 이벤트 구현
   - 수량 변경
   - 주문하기
   - 주문결과 안내 메시지 UI

* [#19] refactor: 🔨 리팩토링

* [#17] feat: ✨ dj-slider 폴더구조 구축

* [#17] feat: ✨ 슬라이드 1/2 구현 중

* [#23] refactor: 🔨 코드 리뷰 코멘트 반영 및 개선

* [#17] feat: ✨ 슬라이드 구현중/일부사항 수정
- util.js
   - price에 comma 붙이는 기능 구현
- PopUpItemCountContainer.jsx
   - price에 comma 붙이는 기능 import
- ItemCard.jsx
   - price에 comma 붙이는 기능 import
   - 이미지 background로 수정
- Label.jsx
   - 라벨 배경색상 적용

* [#17] feat: ✨ 슬라이드 구현중

- 모듈화
   - 시연을 위한 기능 구현을 위해 보류

* [#25] feat: ✨ 슬라이드 2/2 구현, API 데이터 동기화

- 슬라이드 명칭을 캐로셀로 변경
- API 데이터 동기화
- 캐로셀의 ItemCard를 children으로 변경
   - 모듈화를 위함!
- 아이템카드 mini, large 프로퍼티 추가
- 상세모달 캐로셀 추가
- 상세모달 스크롤 추가
- 모든 카테고리 보기 기능 구현

* [#27] feat: ✨ BestTab Skeleton UI 만들기

- Main.jsx
   - 시연을 위한 loop 설정 추가
- BestTab.jsx
   - SkeletonTab import
- BestTabNavigator.jsx
   - 주석 제거
- SkeletonTab.jsx
   - Skeleton UI 구현
- DicoJsonCarousel.jsx
   - Carousel 구현중

* [#29] feat: ✨ PopUp Skeleton UI 만들기

- Context.jsx
   - 주석 제거
- BestTab.jsx
   - 주석 제거
- PopUpContainer.jsx
   - Skeleton import
- PopUpItemsSlide.jsx
   - 주석 제거
- SkeletonPopUpContainerBody.jsx
   - Skeleton UI 구현

* feat: ✨ carousel loop 기능 구현

* [#31] feat: ✨ README.md 작성완료

Co-authored-by: kowoohyuk <kowoohyuk91@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
review-iOS iOS 리뷰
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants