2월 셋째 주 TWIL : 프로젝트 '초록 ChoLog' 마무리, 그리고 또 시작

윤슬기·2020년 2월 23일
1

TWIL

목록 보기
30/32
post-thumbnail

Immersive Course

Immersive Course(이하 IM)는 프로그래밍 교육기관 코드 스테이츠의 웹 개발 심화 코스이다. 아래 내용은 IM에서 배우고, 내가 찾아보고, 다른 수강생들이 전해 준 지식이다.


서비스 완성

사주 간 달려온 여정에 우선 마침표(사실은 쉼표!)를 찍었다. 목표로 한 지점까지 서비스를 완성해서 발표하고 이머시브 코스를 마무리했다. 기능 시연 GIF와 스택 정보, 서비스의 자세한 내용을 담은 소개 문서는 여기이다.

아래 스크린샷을 클릭하면 모바일 앱 '초록'을 개발한 팀 009900의 서비스 발표 영상(데모데이)을 확인할 수 있다.
Video Label

서비스 화면 스크린샷

로그인

식물 목록과 식물 추가하기

식물 정보 확인

식물 정보 검색

관리 일지 작성 및 확인

기록 달력과 일지 목록

관리 속성 선택 및 수정


발표 전 일주일간 겪고 느꼈던 일을 정리해본다.

마주친 문제들

  • 이전까지는 대부분 서버에서 보내주는 데이터를 그대로 화면에 랜더했지만, 이번에는 그 데이터를 가공하는 부분이 많았다. 이때 객체형 데이터의 불변성을 지키는 일이 상당히 어려웠다. 우선은 스프레드 연산자를 이용해서 객체의 변화를 방지하다가 라이브러리 Immer를 도입했다.

  • 안드로이드 가상 디바이스(AVD)와 실제 안드로이드 기기 간에 다른 점들이 있었다. 모바일 개발 시 테스트가 가능한 실제 기기가 무조건 필요하다.

    • 키패드를 number 스타일로 설정했을 경우, 내가 테스트하는 AVD에서는 '-' 를 입력할 수 있었으나 팀원의 휴대폰에서는 '-' 입력 패드가 보이지 않았다.
    • 실제 휴대폰의 화면을 막바지에 발표에 사용할 화면을 녹화할 때 확인했는데, 팀원의 휴대폰에서는 앱 내 글꼴이 테마로 설정한 글꼴이 아닌 휴대폰 기본 글꼴로 표시되었다. 이는 상당히 중요한 문제였는데 사실상 예상하지 못한 부분이었다.
  • 데이터를 서버에서 가공/수정할지, 프론트에서 가공해서 랜더할지 결정해야 하는 부분들이 있었다.

    • 데이터베이스에서 보내주는 데이터는 기본적으로 id순서인데, 식물일지는 과거 날짜 기록을 오늘 입력할 때가 있어서 id를 오름차순으로 화면에 랜더할 경우 일기 날짜가 오래된 순으로 보여지지 않았다.

      → 백엔드와 프론트엔드 중 데이터를 id순서가 아닌 날짜 순서로(createdAt) 정렬하는 데 드는 비용이 어디가 낮을지 검토했다. 일기화면을 랜더하는 컴포넌트에서는 이미 일기 뿐 만 아니라 다른 정보들을 가공하고 있었고, DB에서 날짜 순서로 데이터를 받아오는 메서드가 존재했기에 서버에서 날짜 순서로 데이터를 정렬하여 보내기로 했다.

    • 관리 속성에는 레벨을 고를 수 있는 타입과(e.g 물주기 : 조금/중간/듬뿍) 아닌 타입이 존재한다. 관리 속성 DB에는 미리 여러 가지 속성들을 저장해놓고 그 목록을 프론트에서 받아 화면에 랜더하였는데, id순서로 속성들을 랜더하면 type이 뒤섞여서 나타났다.

      → 속성은 이후에 추가될 수 있는 항목이다. 만약 중도에 type별로 데이터를 정렬하여 DB에 다시 저장할 경우, id가 변하므로 과거 기록에 영향을 미친다. 그래서 이 부분은 프론트에서 속성을 type별로 정렬하는 함수를 작성해 정보를 가공하여 랜더했다.

API 요청 타이밍 설정하기

가짜 데이터를 이용해 데이터 흐름을 잡은 후, 그 데이터들을 실제 API 요청으로 바꿔보니 스크린 생명주기에 따른 요청 타이밍과 자리를 고려해야 했다.

  • 내용이 연관이 있는 스크린들도, 서로 다른 navigation stack에 존재하는 경우가 많아 네비게이터 컴포넌트에서 API 요청을 한 후 그 데이터를 initialParameter로 스크린 컴포넌트들에 전달했다.
const Stack = createStackNavigator();

const MyPlantStack = () => {
  // 받아올 데이터를 state로 지정한다
  const [parametersData, setParametersData] = useState(null);
  // 로그인 시 사용하는 TokenContext에서 Bearer Token이 담긴 헤더 객체를 가져온다
  const { headers } = useContext(TokenContext);

  // 컴포넌트가 마운트될 때 데이터 GET 요청
  useEffect(() => {
    async function getParameters() {
      const response = await Parameters.getAllParameters(headers);
      if (response.data && response.status === 200) {
        setParametersData(response.data);
      }
    }
    getParameters();
  }, [headers]);

  // 데이터가 들어올 때까지 화면을 랜더하지 않는다
  if (!parametersData) return null;
  return (
    <Stack.Navigator>
      {/* 받은 데이터를 initialParams를 통해 MyPlants 컴포넌트로 전달한다 */}
      <Stack.Screen
        name="MyPlants"
        component={MyPlants}
        options={{ headerShown: false }}
        initialParams={{ parametersData }}
        />
      {/* ..다른 Screen 들.. */}
    </Stack.Navigator>
  );
};
  • 모바일 스크린은 현재 화면에서 보이지 않더라도 단순히 컴포넌트가 언마운트되지 않는다는 것을 알았다. 그래서 컴포넌트의 생명주기와 더불어 React Navigator에서 이야기하는 스크린 생명주기를 이해해야 했다. 스크린이 현재 화면에 보이는 순간은 focus, 사라지는 순간은 blur이며 이를 이용해 스크린이 focus 될 때 새로운 API 요청을 보내는 event를 몇몇 컴포넌트에 설정했다.
    [ Triggering an action with a 'focus' event listener ]
  • API 요청을 기다리는 동안 비어있는 화면을 보여주지 않기 위해서, 데이터가 state에 할당되지 않을 경우에는(데이터가 null인경우) 동그라미가 빙그르르 돌아가는 로딩 인디케이터를 랜더했다.

스타일링

  • 버튼과 인풋 스타일링 적용/수정을 쉽게 하기 위해서 스타일 객체를 따로 객체로 정의해 import하여 사용했다.
// 스타일과 컬러를 지정한 theme를 가져오기
import theme from '../../theme';

const buttonStyles = {
  buttonPosition: {
    marginBottom: 10,
  },
  contentStyle: {
    padding: 5,
  },
  lableStyle: {
    fontSize: 15,
    color: theme.colors.text,
  },
  // ... 스타일들 ...
};

export default buttonStyles;
  • 그래픽디자이너 출신인 백엔드 담당 팀원이 어플리케이션의 디폴트 이미지들을 그렸다. 오리지널 이미지들이 더해지자 화면 퀄리티가 훨씬 높아졌다!

마침표를 찍고 다시 시작하면서

아쉬운 점을 찾자면 한도 없었지만, 일정에 맞춰 발표 자료를 준비했다. 잘 만든 부분들을 제대로 보여줄 수 있게 발표자료와 대본 준비, 리허설까지 신경 썼다. 그렇게 준비한 만큼 자신 있게 발표했고, 큰 호응을 얻었다.

프로젝트를 마무리하면서 서비스 소개 문서도 꼼꼼하게 작성했다. 간단한 작업은 아니었지만, 서비스를 사람들에게 알리는 데 좋은 자료가 만들어져 만족스럽다.

이제는 아쉬웠던 부분들을 보충하고, 배포할 차례다. 발표 준비를 하면서 돌아보고, 코드를 점검하며 정리한 주요 개선점들은 다음과 같다.

  • state가 당초 예상보다 늘어나서 다루기 복잡해졌다. state 관리 라이브러리의 필요성을 느꼈다.
  • key 미수정, 입력 오타로 오류가 난 경우가 있었다. 보류했던 TypeScript를 다시 도입할 예정이다.
  • 없앨 수 있는 중복된 컴포넌트를 찾고 정리한다.
  • 라이브러리 Immer와 스크린 생명주기, Hooks를 사용하는 데 미숙한 부분이 많았다. 다시 꼼꼼히 문서를 익히고 테스트하며 코드를 다듬으려 한다.
  • 사용자에게 오류 이유를 알리거나 인풋 입력 제한을 하는 등 편의성을 위해 갖추어야 할 부분을 점검하고 보충해야겠다.
profile
👩🏻‍💻

0개의 댓글