ShoppingProject + 회고

ShoppingProject

2차 과제로 구현한 앱입니다.

네이버 쇼핑 API를 이용하여 상품 검색 및 페이지네이션 기능을 구현했고, 모든 화면에서 좋아요 추가 / 제거가 가능합니다.

추후 기술할 기능과 환경에 대한 최소 요구 사항을 바탕으로 제작하였으며 아이패드나 macOS에서는 대응하지 않습니다. 추가적으로 라이트모드 / 다크 모드를 처리해 주었습니다.

라이브러리는 Kingfisher, Realm, SnapKit을 이용하였으며, Kingfisher의 경우에는 이미지 캐싱 기능이 내장되어 있어 실제로 구현하는 것보다 간단히 임포트하여 사용하는 것이 효율적일 것 같기에 사용하였습니다.

 

요구사항 및 최소 요구 사항은 해당 프로젝트 README에 따로 기술해 놓았고, 혹시 모를 스포일러 및 교육 내용 누출이 될 수도 있을 것 같아 앱 동작 화면으로 대체합니다.

 

 

 

 

 

 

트러블 슈팅

API 통신 관련

이미지를 어떤 식으로 가져오는 것이 효율적일지에 대한 고민했습니다.

기존의 가져오는 방식은 좋아요 했을 때도 URL을 통해서 저장하는 방식이었습니다. 그렇다 보니 네트워크가 연결되어 있지 않으면 검색 화면과 좋아요 화면 모두 작동하지 않았습니다.

이후, 해당 방식에서 좋아요한 데이터를 도큐먼트에 저장하는 형식으로 변경하여 네트워크에 연결되지 않아도 좋아요 목록을 가져올 수 있게 구현하였습니다. 또한, 사진 전체를 저장하는 것이 아니라 자체적으로 이미지를 줄여 저장하여 앱의 크기가 과도하게 커지지 않도록 하였습니다.

UX 관련

사용자가 이 앱을 사용할 때, 어떤 부분에서 불편함을 느낄지, 어떻게 하면 더 편리하게 사용할 수 있을지에 대하여 고민했습니다.

기존에 찾은 문제와 해결한 방법은 다음과 같습니다.

  • 검색어 관련 대응
    • 영어 대소문자의 경우에는 API에서 자체적으로 처리해 주어 관련으로는 구현할 필요가 없었습니다.
    • 다만, 사용자가 문자 자동 완성을 사용할 경우에 단어 끝에 띄어쓰기 한 번이 필수적으로 들어가게 되는데 이 부분에 대해서 띄어쓰기 없이 검색될 수 있도록 구현해 주었습니다.
  • 검색 관련 처리
    • mallName 관련 처리
      • 간혹 몰 이름이 mallName이 아니라 brand에 적혀 있는 경우가 있었습니다. 해당 경우에는 mallName이 네이버가 적혀 있고, 실제 몰 이름은 brand에 있어 빈 화면으로 해당 내용에 관련하여 브랜드에 몰 이름이 적혀 있을 경우에 반영되도록 하였습니다.
    • 사용자가 검색어를 잘못 입력하여 데이터 결과가 없을 경우와 데이터 통신이 불안정할 때를 다르게 처리함
      • 기존의 요구사항에서는 빈 화면으로 구현해도 괜찮다고 했지만, 위와 같은 경우에 동일한 빈 화면을 띄워준다면 해당 데이터가 없는 것일지 아니면 네트워크 오류가 난 것일지 알 수 없을 것입니다.
      • 네트워크 오류가 난 경우에는 Alert을 이용하여 네트워크 통신이 안 되고 있다는 것을 사용자에게 직접적으로 알려 주었습니다. 네트워크 통신 시 오류 메세지를 받아 어떤 이유로 네트워크 통신이 되지 않고 있는지 사용자가 알 수 있도록 하였습니다.
      • 검색어를 잘못 입력한 경우에는 검색 결과가 나와야 하는 화면에 이미지와 검색어를 가져올 수 없다는 문구를 띄워 주면서 다른 검색어로 검색하게끔 유도했습니다.

회고

전체적으로 기본적인 요구사항을 만족하고 있는 앱을 제작하려고 노력했습니다. 회고를 잘한 부분과 아쉬운 부분으로 나눠보자면, 다음과 같습니다.

먼저, 잘한 부분으로는 전체적으로 요구사항을 확인한 이후에 좋아요 버튼과 네트워크가 동작하지 않을 때를 사용자가 알기 쉽게 처리해 준 부분이 만족스럽습니다. UI 또한 제시된 이미지와 유사한 형태로 제작하였고, 다크모드와 라이트모드 처리를 따로 해 준 것이 만족스럽습니다.

아쉬운 부분은 전체적인 구조가 깔끔하지 못한 것과 생각했던 추가 기능을 구현하지 못한 것입니다. 전체적인 구조를 충분히 생각하면서 제작했음에도 전체적으로 세부화된 함수 사용이나 반복되는 함수들을 하나로 리팩토링하지 못했다고 생각합니다. 후반에 테스트를 계속 하면서 고려해야 할 예외 사항이 자꾸 추가되다 보니 후반에는 코드가 조금 난잡해지지 않았나 합니다.

또, 상세 화면에서 웹뷰에 툴바를 활용하여 이전 화면 / 이후 화면을 넣어 주고, 네비게이션바에 새로고침 버튼을 넣어줬으면 사용자 입장에서 더 편리했을 것 같은데 이 점을 구현하지 못하여 아쉽습니다. 또, 다른 화면에서는 네트워크 처리를 했으나, 상세 화면에 들어갔을 때, 네트워크 통신이 불가능하다면 Alert을 띄워주는 부분을 구현하지 못하였습니다.

다음에는 부족한 부분들을 보충하여 더욱 효율적으로, 깔끔하게 구현하고 싶습니다. 간단한 것 같아 보였지만 막상 해 보니 생각할 게 많아 즐거운 과제였습니다. 감사합니다!

 

 

 

 

 

 


 

 

 

요기까지가 리드미.

이제부터는 개인적인 회고이다.

 

사실 이걸 쓰기로 했던 건 이번 주 월욜? (약 5일 전...) 이었는데 영 컨디션이 좋지 않다 보니 조금 미루게 되었다.

 

초반에는 엥? 빨리 끝나겠는데?! 했다가 후반에 가서는 시간이 더 있었으면 하는 마음 반 그냥 빨리 제출하고 싶은 마음 반 울고 싶은 마음 20 도합 120%의 맘으로 코드만 쳤던 것 같다...

같이 스터디하는 멤버들끼리 모여서 주말에 과제를 하기로 하고 모였는데 막상 밤샘 모각코를 하게 돼서 웃기고... 즐거웠다... ^___^ 

그치만 후유증이 너무 심해서 다음에는 딱!!!! 빠르게 하고 넘기는 걸루.

 

 

과제를 해 보니 내가 그럭저럭 잘하는 부분과 못하는 부분이 확연하게 차이났다.

나는... ... 귀찮은 걸 정말 싫어하드라. (사실 누구나 그렇겠지만)

좋아요 버튼을 구현하는 건 생각보다 빨리 끝났는데 (말그대로 구현!!) 정렬 버튼은 조금 오래 걸렸다.

좀 짜보지도 않고 이게 좋을까? 저게 좋을까? 이건 괜찮을까? 저건 어떨까? 생각하다가 막상 짜는 시간이 더 늦어지고 어영부영 넘기는 시간이 꽤 있는 것 같다. 이건 개인적으로 반성해야 하고 고쳐야 함.

수업 시간에 멘토님께서 그랬듯이 5가지의 방법이 생각나면 머가 조을까? 하는 것보다 그냥 그 시간에 다섯 가지를 모두 구현해 보자.

앞으로는 조금 더 부지런하게 그러는 걸루.

 

또, 데이터 전달이나 화면 구성 관련해서는 즐거웠다. 어떤 식으로 보내지? 하면 대부분 빠르게 답이 떠올랐고 화면간의 데이터 이동이나 뷰를 짜는 것에 있어서는 그래도 전보다 훨씬 나아진 것 같다.

 

흠... 근데 문제는 역시 오류 처리였는데, 네트워크가 되지 않는 부분을 하나하나 생각해서 각자 처리해 주는 방식이 비효율적이었다.

무엇보다 웹뷰에서 타임아웃으로 오류처리를하자! 고 생각하고서 엄청 찾아봤는데 타임아웃으로 처리하는 방법은 진짜 11년 전? 8년 전? 이때 방식이 나와서 (ㅠㅠ) 멘토님께도 여쭤봤는데 따로 타이머를 이용해서 구현하거나 하는 수밖에는 없을 것 같다. 아쉬움

 

여기저기 오류처리를 어케 하셨나 물어보고 다녔는데 그 중에서 S님 방법이 인상적이었다. 담에는 나도 이렇게 해 봐야지!! 싶음.

그 방법이 뭐냐 한다믄~ 네트워크 상태가 연결되어 있는지 항상 체크해 주는 방법이다. 관련 링크는 요기 (https://qteveryday.tistory.com/m/314)

 

기존에 처리했던 방법은 내가 생각할 수 있는 오류나 예외 사항을 하나하나 처리해 줬다. 근데 요 방법은 그냥 네트워크가 끊기는지 아닌지 계속 보고 있다가(기존의 observer처럼!!) 끊겼을 때 Alert을 띄워주거나 화면을 전환해주어 지금 안 돼요! 하고 알려주는 방법이다.

 

첨에 듣고서 우와!! 했었다 ㅋㅋ 아니 누가봐도 일일이 처리해 주는 방법보다는 훨씬 효율적이지 않은가?!

근데 막상 이 방법이 정말 모든 걸 대체할 만큼 좋냐?! 한다면 또 아닌 것 같다. 혼자 고민한 부분도 있지만, K멘토님과 이야기하면서 깨닫게 된 건데 이렇게 처리를 해 줘도 인터넷이 연결되어 있지만 아주~~~ 느려서 거의 연결되지 않은 것과 다름 없는 상태도 있을 것이다.

만약에 이 모니터만 믿고 타임아웃을 처리해 주지 않는다면 이런 상태의 사용자는 당근 불편함을 느낄 것이다. 또, 상황에 따라서는 네트워크가 연결되지 않았습니다! 말고 연결은 되었지만 서버 상황에서 처리를 못하는 경우나 요청이 잘못되었을 경우에 대하여 처리를 해 주어야 사용자가 사용할 때 더욱 편리할 것이다.

최근에 이용하던 웹사이트가 갑자기 다운되는 경우가 있었는데, 이때 무조건 웹사이트가 연결되지 않습니다! 가 아니라 [404] 연결이 되지 않습니다나 [500] 연결이 되지 않습니다! 가 떠서 아~~ 내 네트워크 왜 이래!! 아님 ㅋㅋ 서버 문제구나 하구 그 상황을 대략적으로라도 이해하고? 넘어갈 수 있어서 좋았다.

이번에도 상태 코드에 대해서 처리를 하긴 했지만 다음에는 조금 더 꼼꼼히 하고 싶다! 네트워크 처리도 그렇구.

 

또 부족한 부분이 뭐가 있을까? 하고 생각해 보다 보니까 구조를 어떻게 짜야 할지, 특정 기준을 어떻게 잡아야 할지가 항상 고민인 것 같다.

baseViewController를 만들게 된다면 어느 정도까지를 base로 잡을지, baseView를 만들지 말지, 여러 군데에서 반복하여 사용하는 특정 method를 어떤 식으로 분리하여 사용할지, 이미지를 어떤 식으로 가져오는 것이 더 효율적이며 네트워크 통신에서 내가 사용하는 선에서는 URLSession과 Alamofire는 별 다른 기능 차이가 없는 것 같은데 alamofire를 쓴다면 왜 굳이 써야 하는지? 그런 의미에서 내가 사용한 snapKit과 Kingfisher는 그냥 편하다!! 가 아니라 왜 굳이? 사용을 하는지에 대해서 꾸준히 생각해 보게 된다.

고민했던 것들은 더 많았지만, 지금 생각난 건 대략 이정도이다. 나중에는 분명 생각이 안 날 테니 대략적으로 답변을 적어보자면...

  1. baseViewController를 만들게 된다면 어느 정도까지를 base로 잡을지
    • 이 부분이 정말 고민이었다!!! 사실 정말 공통되는 부분으로 한다면 서치뷰와 콜렉션뷰 / 오류 처리하는 부분까지 모두 베이스뷰컨으로 처리할 수 있었어서... 더 고민이었던 것 같다. 솔직히 베이스뷰컨을 그냥 홈뷰컨으로 삼고서 좋아요 버튼도 이거 그대로 상속받고 정렬 버튼만 hidden 처리하면 되는 거 아닌가?? 생각도 많이 했고...
    • 근데 만들 때 지금 과제만 생각하는 게 아니라 이후 다른 화면을 추가하게 되면 어떤 화면이 추가될까? 를 생각했을 때 무조건 가장 기본적인 서버 연결 이미지와 레이블만 넣어서 구성하는 게 더 좋을 것 같았다. 이후에는 생각이 달라질 수도 있겠지만 지금은 그랬음!!
  2. baseView를 만들지 말지
    • 만약에 들어가는 객체들이 많았다면 baseView를 만들었을 텐데 그렇게 많지 않아서 만들지 않았다.
    • 이래놓고 SearchViewController에서 정렬 버튼이 생각보다 길이를 많이 차지하는 바람에 ㅋㅋ 고민했다... 그래도 만들지 않은 건 잘한 것 같다 차라리 나중에 뷰모델로 구분해서 MVVM으로 한번 구현해 보고 싶당 ㅋ
  3. 여러 군데에서 반복하여 사용하는 특정 method를 어떤 식으로 분리하여 사용할지
    • 좋아요 버튼을 누르는 method가 계속 반복되었는데, 어떤 부분에서는 따로 반복되는 게 달라서 고민이었다. 리팩토링하기에는 시간이 없기도 했고, 자잘한 부분들이 달라서 고민을 했는데 지금 생각해 보면 이거 completionHandler(긍까 클로저)를 이용하면 해결대는 거 아닌가????? 싶다
    • 나중에 리팩토링하면댈듯..
  4. 이미지를 어떤 식으로 가져오는 것이 더 효율적일까?
    • 두 가지로 나누어 생각해야 했다. 검색창에서 데이터를 가져올 때와 내가 좋아요를 한 곳에서(그러니까, 해당 데이터가 데이터베이스에 저장되어 있을 경우에) 데이터를 가져올 경우를 생각해 봐야 한다.
    • 검색창에서 데이터를 가져오게 된다면 단순히 매번 데이터를 모두 불러오는 게 아니라 이전에 불러왔던 데이터들은 데이터 캐싱이 되도록 구현하여 같은 이미지를 불러올 때 더욱 빠르고 쉽게 불러오는 게 좋을 것이다.
    • 좋아요를 한 곳에서 데이터를 가져온다면 두 가지로 가져올 수 있을 것이다. 먼저, 해당 이미지의 url을 데이터베이스에 저장하여 매번 데이터통신을 하여 가져오는 방식과 document로 해당 파일을 저장하여 가져오는 방식으로! 원래는 document에 저장하는 방식이 만약에 좋아요를 만 개 정도 하게 된다면 너무 사진 데이터가 많은 용량을 차지하지 않나? 했는데 그렇다고 매번 좋아요를 로딩할 때마다 데이터를 통신하는 것도 그닥 효율적이지는 않은 것 같았다. 차라리 썸네일로 사용되는 데이터들은 정말 가볍게 해서 저장하는 게 더 효율적이지 않나?! 싶어서 저장했다.
  5. 네트워크 통신에서 내가 사용하는 선에서는 URLSession과 Alamofire는 별 다른 기능 차이가 없는 것 같은데 (왠지 잘못 사용하고 잇는듯?) alamofire를 쓴다면 왜 굳이 써야 하는지?
    • 기능 면에서는 차이가 없는 게 맞다! (Alamofire도 내부 구현은 URLSession으로 되어 있으니까.) 다만, alamofire를 사용하는 이유는 코드 간소화 / 가독성 향상 / 편리한 기능 구현 < 요 세 가지인 것 같다. URLSession으로 사용하는 것보다 alamofire가 일단 가시적인 코드량이 훨씬 적고, 보기 편리해서 글쿠나 싶다.
    • 근데 갠적으로는 오류 처리면에서 URLSession이 더 익숙하고 편리한듯?!
  6. 그런 의미에서 내가 사용한 SnapKit과 Kingfisher는 그냥 편하다!! 가 아니라 왜 굳이? 사용을 하는지
    • SnapKit의 경우에는 한번에 여러 개를 간편하게 잡아줄 수 있고, 기존의 NSLayoutConstraints를 이용하게 된다면 너무 길어지고 가독성도 떨어지는데 SnapKit은 어떤 객체에 어떻게 Constraints를 잡았는지 명확히 보여줄 수 있기 때문에 SnapKit을 사용했다 물론 편하기도 하궁
    • Kingfiser는 이미지캐싱이 자동으로 내장되어 있어 사용했다!! 아직 이미지캐싱 기술을 과제 기간 안에 스스로 구현하기에는 내 스스로 쪼렙이기때문에 ...... ㅋㅋ 구현햇다. 감사합니다.

 

개발은 명확한 답이 없다 보니 생각하면 할수록 더 즐거워지는 것 같다 ㅋ.ㅋ 나는 아직 많이 부족한 편이라 잘 구현하신 다른 분들을 보면 대단한 것 같다. 나두. 꼭. 짱이되고만다. 

 

아무튼 담 과제는 더 잘하고 싶다~~~!!!!!!

개인 프로젝트도 잼썻으면~~~!!!!!!!