728x90

실제 코드 구현 기간 : 11/30~12/6

 

실질적으로 기능을 구현하기 시작한 지 2주차부터 썬나 일을 하는 시간 외에는 내내 프로젝트에만 몰두했었다. first project와는 달리 우리가 할 수 있는 것인지에 대한 고려보다는 이 기능이 필요한 지에 더 집중하여, 모르는 부분에 대해서 찾아서 공부하는 시간도 많이 필요 했기 때문이다. 

 

프로젝트 Sprint 2주차

2주차의 주요 이슈 사항은 단연 일정 등록/수정이었다. 여기서 가장 메인은 일정을 등록 할 때 약 정보가 촬영되고

이에 대한 1. 예측결과가 처리되어야 하고

2. 이에 대한 이미지를 client에서 캐싱처리 하여 가상 저장소에 가지고 있다가

3. server에 전달한 후, S3에 이미지를 업로드 하고 그 링크를 DB에 저장하는 것이었다. 

이와 관련하여 한 주 동안 내가 진행한 이슈들을 정리하니 아래와 같다. (저 많은 것들을 일주일동안 했다는 사실이 믿겨지지 않지만) 

 

해당 글은 주차별 이슈 정리 및 회고가 목적이고, 각 기능들 중에서 블로그에 별도로 정리할 내용들은 추후에 정리하여서 링크로 남겨둘 예정이다.

1. [Client+Server]  촬영 Image 처리 하기
  -> [Client] image caching
  -> [Client + Server] 촬영된 카메라 이미지 가공
  -> [Server] flask -> S3 이미지 업로드
2. [Client + Server] 일정 수정 기능 구현
  -> [Client + Server] 일정 수정 screen에 기등록 일정 정보 get -> rendering
  -> [Client + Server] 일정 수정 기능 구현
  -> [Server] 일정 등록 코드 수정(중복 데이터 저장 방지)
3. [Server] 일정 삭제 기능 구현
4. 서버 및 클라이언트 코드 리팩토링 -> 코드리뷰
5. 배포테스트/연동테스트 -> 에러 핸들링

ToDo 1 : 촬영 Image 처리 하기

 

해당 기능 구현을 설명하기 전에 아래의 gif를 보면 일정 등록 과정에서 약이 등록된다는 부분에 대해서 이해가 쉬울 것이다.

 

** 일정등록기능 예시

촬영이 진행되는 screen과 이미지와 예측된 약 이름을 함께 보여주는 screen은 별도의 구분된 screen이다. 이말인 즉슨, 카메라로 촬영된 이미지를 어딘가에 저장해서 다음 screen에 넘겨주지 않는다면, 카메라 촬영 스크린에서만 볼 수 있다는 의미이다. 

물론 이는 이미지 데이터에만 국한된 것은 아니다. 화면이나 component 간에 state 전달 및 관리는 매우 중요한 이슈이고, 그래서 상태관리 차원에서 redux, react hook이 사용되고 있는 것일 것이다.(이는 react hook에 대해 정리하며 좀 더 다뤄보기로 하고)

 

[Client] image caching

 

그렇다면 이미지 데이터를 어떻게 다음 화면으로 전달줄 수 있을까?

간단하게 카메라 스크린에서 post API를 날려서 이미지를 서버의 DB에 저장하고, 이미지 확인 화면에서 get API를 통해서 서버에 요청하여 이미지를 불러오면 되지 않을까라고 생각할 수도있다. 하지만 위의 로직에는 두가지의 큰 맹점이 존재한다.

1. 카메라 화면 -> 이미지 확인, 이 두 개의 통신과정에서 아직 우리는 약 정보를 모른다. 이미지 확인 화면에서 예측 결과에 대해 사용자에게 물어보고, 그 다음에 약 정보가 확정되기 때문이다. 즉, 이미지 확인 화면 이후에 약정보와 이미지가 대응된다. 

 => 이 때문에 DB에 단순 약정보를 저장하기 위한 테이블을 만드는 것은 너무 비효율적이다.

2. 이미지 데이터 하나로 인해 서버와 통신 하는 코스트가 2번이나 들어간다. 효율적인 서비스를 위해서는 최대한 통신 코스트를 줄일 필요가 있다.

 

이에 따라 우리는 client 단에서 이미지를 캐싱처리하여, 즉 임시 저장소에 저장하고 잠깐 불러오는 방법을 선택했다. 

이를 위해서 첫 번째로 client에서 이미지를 캐싱처리하는 방법에 대해서 공부하고 처리했다.

자연스레 react native에 사용할 수 있는 라이브러리가 있는지 탐색했다. 그런데 expo 환경에서는 사용할 수 없는 라이브러리가 많았고, 다시 expo 공식 문서를 공부하면서 캐싱저장소 라이브러리에 대해서 공부했다. 

 

자세한 기능 구현에 대해선 하 단의 블로그 글을 참고하면 된다.

expo 환경 react native에서 image caching 처리하기 (후에 블로그 정리할 예정)

 

[Client + Server] 촬영된 카메라 이미지 가공

 

우리가 촬영으로 받은 이미지를 그냥 그대로 저장하고 활용할 수 있을까? 에 대해서도 이번 프로젝트를 하면서 많은 공부가 되었다. 

결론적으로는 이미지를 저장하든, 혹은 학습 모델과 대응하여 예측하는 과정이든 해당 이미지는 가공되어야 한다. 

심지어 안드로이드와 아이폰 환경에서 촬영되는 이미지는 다른 방식으로 출력되기 때문에 이에 대해서 이미지 가공 코드가 좀 더 추가 되기도 했다. 

 

자세한 기능 구현에 대해선 하 단의 블로그 글을 참고하면 된다.

image 데이터를 활용할 수 있도록 가공하기(후에 블로그 정리할 예정)


[Server] flask -> S3 이미지 업로드

 

이렇게 가공도 하고, 예측도 한 이미지 데이터를 저장하기로 결정이 된다면, 이제는 진짜 DB에 저장해야 할 것이다. 그렇다면 이미지 데이터는 어떻게 DB에 저장할까? 이에 대해서 고민한다면 Database에 대한 이해도 조금 필요한 것을 느꼈다.

first project 회고록에서 정리한 바 있는데, 나는 database가 굉장히 동적인 하나의 프로그램이라 오해했었다. 하지만 프로젝트를 하고 공부를 하며 database 또한 하나의 파일형태일 뿐이며 이는 또한 매우 무겁다. 그래서 최대한 비효율적인 공간을 차지하지 않고 데이터가 잘 저장될 수 있도록 관리해 주어야 한다. 그런 면에서 이미지 데이터도 무거운 축에 속하므로 이미지를 그대로 저장할 수 없다. 

(또한 SQL 의 대표격인 mySQL에서는 이미지 데이터 자체를 저장할 수도 없다고 한다.)

 

이를 해결하기 위해서 존재하는 것이 클라우드 저장소이다. 그리고 이를 위해 우리는 가장 대표격인 AWS S3 서비스를 사용했다. S3에 대해서는 매우 익숙할 것이다. 웹앱 배포 시에 client를 빌드하고 배포하는 과정에서 S3가 사용되기 때문이다. 

S3는 하나의 파일 서버로서, 다양한 데이터들을 관리해주는 클라우드 저장소 개념에 가깝다. 

이 곳에 어떤 데이터를 저장하면 각 데이터에 대해 링크가 나오게 되고, 그 링크로 해당 데이터에 접근할 수 있게 된다. 따라서 우리는 client에서 server로 이미지를 전달 주면, 이를 server에서 S3에 업로드할 수 있는 형태로 가공 후에, S3와 연결하여 데이터를 저장한 후, 

링크를 S3로 부터 전달받아서 이를 약 이미지에 해당하는 칼럼에 데이터로 저장했다.

 

자세한 기능 구현에 대해선 하 단의 블로그 글을 참고하면 된다.

S3를 활용하여 image 데이터를 저장하기(후에 블로그 정리할 예정)

 

이미지 데이터를 저장하기 위한 로직을 정리해보면 (C: Client, S:Server)

[C] 이미지 촬영 -> [C] 이미지 캐싱처리 -> [C] 이미지 확인 화면에서 캐싱 저장소에서 해당하는 약 이미지 불러오기 / 해당 이미지 server로 전달 -> [S]이미지 예측 후 결과값 client 전달 ->[C] 캐싱된 이미지 + 예측값 렌더링 -> [C] 약 이미지 server에 전달 ->
[S] 이미지 S3 업로드 후에 링크 값 전달 -> [C] 최총 약정보와 이미지 링크 대응/ 서버에 약정보 create 요청

 

ToDo 2 : 일정 수정 기능 구현

 

**일정 수정 기능

 

일정 수정 페이지가 일정 등록 페이지와 비슷해 보이지만, 가장 큰 차이점은

1. 기존 데이터를 get 해와서 렌더링 해야 한다는 점에서 통신이 하나 더 늘어난 점

2. 모든 일정을 수정하지는 않을 것이므로 중복 데이터가 db에 저장되는 것을 방지 해야 한다는 점이었다. 

 

일정 등록 기능을 구현할 때 까지만 해도, 전체적으로 아무것도 없는 상태에서 등록하는 경우라 문제점을 크게 발견하지 못했으나, 일정 수정 기능을 구현하면서, 기존 로직의 허점을 많이 발견하게 되었다. 

단순 기능 구현 뿐 아니라 통신 효율성이라던가 코드의 논리성 더해져서 rest API에 대해서도 다시 공부하고 고민했었다.

 

1. 중복된 데이터를 방지하자.

실제로 일정 수정 기능에서 table 내에서 칼럼이 수정되는 데이터는 schedules 이지, 만약에 약정보를 수정한다면 약기준에서는 create 이다. 즉, 일정 수정 시에 약 정보를 새로 등록하고자 한다면/ 혹은 기존에 등록한 약정보를 가지고 와서 일정에 새로 연결하고자 하는 경우가 있을 것이다. 이 경우에는 server의 service 파일 즉, 서버와 db가 직접적으로 통신하는 쿼리 코드에서 create 코드를 재사용해야 했었다. 

그런데 기존 약 등록 기능에서 중복에 대한 분기 설정이 안되어 있어서, 기존에 이미 등록한 약을 가지고 와서 등록하려는 경우에도 새로 등록하는 경우가 되어버려서 중복 약데이터가 계속 쌓여갔다. 

-> 이를 위해 약정보 create 관련 서버 코드들에 중복을 방지하기 위한 분기를 추가해주었다.

 

2. REST API란 무엇일까? 효율적인 통신이란 무엇일까?

사실 이 부분에서 가장 많은 고민을 했다. rest API란 하나의 기능 -  하나의 API라고 해서, first project 때는 client에서 하나의 큰 기능당 하나의 api를 연동하여 통신을 최소화했고, 서버에서 모든 복합적인 분기 및 JOIN을 진행했다.

그러나 이를 바탕으로 final project API를 짠 후에, 프로젝트를 관리해주는 코드스테이츠 관리자 분께서 rest API가 아니라고 하셨고, rest API에 대해서 다시 공부해보니(실질적 예는 없었다. 개념 설명이 많을 뿐) api uri는 접근하려는 테이블의 깊이로 짜고, 최대한 한 api 당 진짜 하나의 기능(우리는 여기서 하나의 쿼리로 이해했다) 을 구현하라고 했었다. (관련해서 블로그 정리 글

 

따라서 우리는 하나의 큰 기능(일정등록) 내에서 약등록/일정등록 등 세부적인 기능으로 나누어서 api를 쪼개서 구현했다.

하지만 기능이 쌓여가면서 이는 계속 오류를 일으켰다. JS는 비동기적 언어이지만, 해당 API들은 무조건 동기적으로 진행되어야 하는데, 상단의 API가 에러가 나더라도, 하단의 API가 실행되거나, 전체적인 일정수정/ 등록 API는 실패했지만 일부 성공한 세부적인 API들에 대해서는 데이터가 저장되어 버린 것이다. 

가령 약정보는 저장되었는데 이 약에 맞물린 일정정보는 저장이 안된 것이다.

(너무 큰 문제였다...)

 

다시 rest API에 대해서 고민했었다. 다시 first project처럼 진행한다면? 서버 코드들은 나름 쿼리 중복과 다중쿼리 사용이 없도록 (JOIN 가능한것은 다 해주었다.) 코드를 짜주었는데, DB와의 통신을 위한 쿼리를 다중으로 사용하거나 중복해야 할까? 하고 고민했었다,

 

다행히 썬나에서 일하면서 많은 해답을 찾을 수 있었다.

(따라서 효율적인 통신으로 리팩토링 중이다)

 

우선 이에 대해서도 정답은 없다. 서비스의 특성상 세부적인 기능으로 쪼개는 것이 낫다면(보통 큰 서비스, 에러 로깅과 핸들링이 쉽다) 세부적으로 구성하고 (그대신 통신 코스트는 부담해야한다) /  우리같이 작은 서비스로서 속도와 효율적인 통신이 더 중요하다면, client 기준에서는 진짜 최소한으로 API를 보내고, 서버에서 client을 맞이하는 controller라는 폴더에서 세부적으로 쿼리를 쪼개고 그 응답을 다시 합쳐서 client에 보내주면 되었다.

 

 

ToDo 3.  일정 삭제 기능 구현

 

** 일정 삭제 기능

약정보 삭제에 대해서는 hard delete로 구현했다. 이 부분에 대해서는 first project 때도 고민했던 부분이며 이때는 soft delete로 구현했다. 이번의 경우는 사람들간에 정보를 공유하는 커뮤니티적인 성향도 아니고, 삭제한 데이터에 대해서 다시 활용해야하는 경우가 없다고 판단했기 때문에 hard delete로 구현했다. 

 


ToDo 4. 서버 및 클라이언트 코드 리팩토링 / 배포&연동테스트 

 

어떻게 보면 가장 중요한 일이라고 생각한다. 단발적인 각 기능의 구현은 실질적으로 쉬울(?)수도 있다. 그러나 전체적으로 서비스를 구동해 가면서 기능들을 연결해보고, 다양한 경우의 수를 고려해야 상황이 더 복잡해지고 코드 리팩토링이 어려워지기 전에 문제를 파악하고 수정할 수 있을 것이다. 특히나 일정 등록/ 수정과 관련된 이슈는 프로젝트 진행하면서 빠르게 리팩토링하지는 못했지만, 문제파악을 빨리 한 덕분에 다른 기능은 최대한 이 부분을 고려하여 구현할 수 있었다.

 

또한 웹앱이나 모바일앱 공통적으로 배포는 최대한 가장 먼저 해두고 배포 테스트를 항상 하고 /  모바일 앱의 경우는 개발단에서는 좀더 편하게 웹으로 진행하지만 모바일 테스트를 항상 해야한다. 실제 구동되는 환경은 개발환경과 달리 더 복잡하기 때문에 문제들이 쌓이기 전에 최대한 빨리 발견하여 해결하는 것이 좋다. 

728x90

+ Recent posts