사소하지만 개선이 필요했던 사항들

배준형·2023년 12월 21일
0

서문

기획에 따라 서비스를 개발하기만 하지 실제로 유저로써 사용하지는 않기에 개발하는 부분과 코드 리뷰를 진행했던 곳 외의 서비스 기능들은 잘 알지 못하거나 어떻게 동작하는지 정도만 알고 있습니다. 이런 상황에서 우연히 내가 개발하지 않는 곳이더라도 문제가 될만한 부분을 종종 볼 수 있는데요. 이번 글에서는 잡다 서비스를 개발하면서 기획되지 않은 사항 중 아주 사소하고, 변경되었다 하더라도 눈치채기 어려울 수도 있는 부분들이지만 개선한 것들에 대해 정리해 보려 합니다.


1. 작은 화면에서 모달 컨텐츠 잘림

잡다 서비스 내부에는 모달을 많이 사용합니다. 저는 PC 페이지에 맞게 개발을 하고 있고, 모바일 개발은 모바일 개발팀이 따로 작업하는데, 그래서인지 대부분의 코드가 반응형으로 개발되어 있지 않고 PC 중심적으로 코드가 작성되어 있습니다.

대부분의 경우 그냥 PC 화면이 작게 보이는 정도이고, 태블릿 등으로 보았을 때 스크롤 하거나 확대해서 서비스를 그대로 이용할 수 있는데요. 일부 모달의 경우 상, 하단이 잘리는 문제가 발생하고 있었습니다.


정상 모달 화면


작은 Screen으로 봤을 때 모달 화면

PC 화면으로 봤을 때는 대부분 문제가 없습니다. 다만, 노트북 화면이나 태블릿 PC 등으로 봤을 때 상단, 하단이 잘려 버린다면 큰 문제입니다.

잡다 서비스 내 대부분의 모달에서 우측 상단에 X 버튼이 존재하고, 하단 부분엔 Action 버튼이 위치하며 중앙 정렬되어 있습니다. 만약 Screen Height의 크기가 모달 Height 보다 작은 경우 위 캡쳐본처럼 X 버튼을 누를 수 없어 모달창을 닫을 수조차 없게 되는데요. 모바일 URL을 통해 접근하면 모달을 사용하지 않기에 PC에서만 문제가 되는 상황입니다.


해결 방법

해결 방법은 간단합니다.

CSS 미디어 쿼리 + min-height 조건을 사용하여 모달 사이즈를 조절하였습니다.

// 모달 Container
height: calc(100vh - 10px); // 10px: 임시 Margin 값

@media (min-height: $MODAL_CONTAINER_HEIGHT) {
  // 모달 전체의 Height
  height: $MODAL_CONTAINER_HEIGHT;
}

// 모달 Content
overflow-y: scroll;
height: 100%;
max-height: $CONTENT_HEIGHT; // 모달 Contents 영역의 Height

위와 같이 CSS Style을 적용한 후 다시 확인해보면

Screen Height 크기가 점점 작아짐에 따라 알맞게 조절됩니다.

모달 Container 영역에 Scroll을 주지 않고 Contents 영역에 Scroll을 부여한 이유는 X 또는 Action 버튼이 있는 모달에서 버튼들의 영역도 Scroll 되는 것은 자연스럽지 않게 느껴집니다. 작은 Screen Height 화면으로 보았을 때 Contents를 보다가 상단, 하단의 버튼들을 누르기 위해 스크롤 하여 올리거나 내릴 필요 없이 바로 누를 수 있도록 Contents 영역만 Scroll을 적용했습니다.


2. 포지션 더보기 시 깜빡임

잡다 서비스 내의 채용 포지션을 보는 페이지가 존재합니다. 일정량만 보여준 후 최하단까지 스크롤 하면 더 보기 버튼이 있는데요. 해당 버튼을 누르면 추가로 포지션들을 보여줍니다.


이때, 새로운 요소들을 렌더링 하면서 기존에 이미 렌더링 된 요소들이 깜빡입니다.

렌더링 된 요소들은 그대로 두고 새로 추가된 요소들만 렌더링 되면 될 텐데 왜 이런 현상이 발생할까요?? Chrome 브라우저의 React Developer Tools Extention을 사용해 알아보겠습니다.


원인

개발자 도구 → React Developer Tools Components 탭 → 옵션 톱니바퀴 → Highlight updates when components render. 옵션을 활성화해 줍니다.

이후 다시 포지션 더 보기 버튼을 눌러보겠습니다.

해당 옵션을 사용하면 렌더링 된 요소들은 위처럼 테두리로 표시해 줍니다. 포지션 더 보기 버튼을 클릭했을 때 새로 추가될 아래 요소들은 당연히 첫 렌더링이므로 테두리 표시가 이해가 되지만, 이미 렌더링 된 요소에 테두리가 칠해지면서 다시 렌더링 된 것은 개발자가 의도한 것은 아닐 것입니다.

해당 내용을 이해하기 위해선 React의 리렌더링 조건을 알아야 하는데요. 잘 정리된 블로그 글이 많으니 링크로 대체하겠습니다.

React re-renders guide: why React components re-render https://dev.to/adevnadia/react-re-renders-guide-why-components-re-render-4ml

리렌더링 조건으로는 아래 5가지 이유가 있습니다.

  • State 변경
  • Props 변경
  • Context Provider로 전달해준 Context의 변경
  • hooks 변경
  • 부모 요소의 리렌더링

이 5가지 사항 중 여기선 부모 요소의 리렌더링으로 인해 기존 요소들도 리렌더링되는 것으로 판단됩니다.

// 더보기 버튼 누르기 전
<ul>
	<li>list 1</li>
	<li>list 2</li>
	<li>list 3</li>
	<li>list 4</li>
</ul>
<button onClick={fetchPositionList}>포지션 더보기</button>

// 더보기 버튼 누른 후
<ul>
	<li>list 1</li>
	<li>list 2</li>
	<li>list 3</li>
	<li>list 4</li>
	<li>list 5</li>
	<li>list 6</li>
	<li>list 7</li>
	<li>list 8</li>
</ul>
<button onClick={fetchPositionList}>포지션 더보기</button>

여기서 각각의 li 요소는 Component로 분리되어 있지만, 보기 쉽게 li 요소로 표기하였습니다. 버튼을 누르기 전 1~4까지의 list만 렌더링 되어 있었는데, 버튼을 누르면 5~8 요소가 추가됩니다. 그러면, 위에 작성한 요소를 감싸는 컴포넌트는 리렌더링 됩니다.

이때 li 각각의 Component의 state, props, context, hooks는 변경되지 않았으나 부모 요소의 리렌더링으로 인해 불필요하게 렌더링이 이루어졌습니다.


해결 방법

이것도 해결 방법은 간단합니다. List 요소의 컴포넌트를 React.memo로 감싸주면 됩니다.

// 수정 전
export default PositionListItem;

// 수정 후
export default React.memo(PositionListItem);

이렇게 전달해 주면 PositionListItem 컴포넌트의 Props가 변경되지 않았다면 부모 요소가 리렌더링 되었다 할지라도 리렌더링은 이루어지지 않습니다.

수정 후 다시 확인해 보면,

새로운 요소가 추가되면서 전체 요소가 리렌더링 되지만, 이미 렌더링 되어있던 자식 요소들은 리렌더링되지 않는 모습입니다.

일단, 전체 요소가 렌더링 되지 않으므로 각 리스트가 깜빡이는 현상은 사라졌습니다. React.memo가 주는 이점도 확실히 알겠습니다. 다만, React.memo는 항상 좋은 방향일까요??

React에서 메모이제이션을 해주는 hook은 React.memo 말고도 useCallback, useMemo 등이 있습니다. 저는 처음 위 내용들을 알게 되었을 때 적절히 사용하면 사용하는 것이 항상 더 좋다고 생각했었는데요. 이를 이용해 성능 측정한 글들을 찾아보면 꼭 그렇지만도 않은 것 같습니다. 대표적으로 useMemo에 대한 블로그 글 링크를 남겨드립니다.

(번역) useMemo를 사용하는 것을 당장 멈추세요! https://velog.io/@lky5697/stop-using-usememo-now

요약하자면 useMemo를 사용하는 것이 상황에 따라 사용하지 않는 것보다 느려질 수도 있다는 것. 언제나 좋지는 않다는 점입니다.


성능 측정하기

일단 새로운 포지션을 불러올 때마다 모든 요소들이 깜빡이는 현상은 유저 경험 상 안 좋은 경험으로 남을 가능성이 있고, 해결하고 가는 것이 무조건 옳은 방향이라고 생각합니다만, 이것이 성능에 영향을 주어 느려지게 만든다면 그것도 좋은 방법은 아닐 것입니다.

단순히 React.memo 한 줄만 추가해 줬는데요. 이것이 실제로 성능에도 영향을 주는지 확인해 보고 넘어가면 좋을 것 같습니다.

아까 사용했던 React Developer Tools Extention에서 이번에는 Profiler 탭을 사용해 보겠습니다.

개발자 도구 → Profiler 탭 → 파란색 원 버튼을 누르면 Profiling이 시작되고, 다시 한번 누르면 Profiling이 종료됩니다. 해당 기능을 사용하여 이전 과정을 반복해 봅시다.

React.memo 추가 전

React.memo 추가 후

결과

  1. 전체 렌더링 시간이 증가
    • 사용 전: 89.5ms
    • 사용 후: 159.2ms
  2. PositionList 컴포넌트의 렌더링 시간도 증가
    • 사용 전: 0.5ms
    • 사용 후: 1.1ms
  3. 전체 렌더링 시간 대비 PositionList 컴포넌트가 차지하는 비중이 증가
    • 사용 전: 89.5ms 중 0.5ms (0.56%)
    • 사용 후: 159.2ms 중 1.1ms (0.69%)

React.memo를 사용하여 컴포넌트 리렌더링 최적화에 의해 일부 성능 개선 효과가 있을 수 있지만, 불필요한 리렌더링을 방지하는 대신 메모이제이션 비교 로직이 추가되어 오히려 성능이 나빠질 수 있음을 보여줍니다.

결과는 성능 수치상으로는 약간 느려졌다고 해석할 수 있습니다. 다만, 실제 사용자가 체감할 정도의 성능 저하는 아니라고 생각합니다. 89.5ms에서 159.2ms로 약 1.8배 정도 늘어났지만, 이 정도의 차이는 사용자가 실제로 느끼기 어려운 수준일 것입니다. 따라서 리스트 아이템의 깜빡임 현상을 해결하기 위해 React.memo를 사용하는 것이 더 중요하다고 판단하여 수정하였습니다.


3. 매칭제안 거절 안티패턴

위 캡쳐는 매칭 제안을 거절할 때 사용하는 모달입니다. 저는 위 모달이 안티 패턴이라고 생각했습니다.

  • 제안을 거절하시겠어요? 라는 의문문 타이틀로 인해 예, 아니오 버튼이 있어야 할 것 같고, 선택안함 버튼이 아니오의 역할을 할 것 같지만 아님.
  • 선택안함 버튼을 누르면 선택안함 선택지로 제안이 거절됨.

이 모달을 본 사용자는 제안에 거절하기보단 기업을 더 자세히 확인하고 거절한다던지, 지금 당장은 거절할 생각이 없다던지 하는 이유로 해당 모달창을 닫은 후 생각의 시간을 갖고 다시 제안에 응답할 수 있을 것 같습니다.

그런데, 사용자는 제안에 거절하시겠어요? 의 대답으로 아니오라고 답한 후 모달을 닫고 싶었는데 선택안함 버튼을 눌러서 제안을 거절해버리는 경우가 분명히 발생할 것입니다. 우측 상단에 X 버튼이 있지만 의문문으로 물어보는 제목이 있으므로 그것과는 별개라 생각합니다.


해결 방법

사실 이 부분은 개발과 관련 있는 부분은 아니고, 기획적으로 수정되어야 하는 내용이라 데일리 스크럼이나 기획 리뷰 시간에 의견을 말씀드렸고, 기획자 확인 후 아래와 같이 수정되었습니다.

선택안함 버튼 대신 라디오 버튼으로 수정 되었습니다.

사실 완전히 개선되었다고 생각하지는 않습니다. 개인적인 생각으로 아래 요소들도 개선되어야 한다고 생각합니다.

  • 제안을 거절하시겠어요? 라고 물어봤으면 버튼이 2개였으면 좋겠습니다. 물어봐놓고 하나의 버튼만 존재한다면 답정너같은 느낌을 주는 것 같습니다.
  • 제안에 거절하려는 이유는 여러 가지가 있을 수 있을 것 같습니다. 사실 라디오일 필요가 있나 하는 생각도 듭니다.

정리

위에 정리한 내용 외에도 자잘 자잘 한 개선은 많았습니다. 폰트를 다운받을 때 전체 폰트를 받는 것 대신 필요한 subset 폰트만 다운받도록 수정한다던지, 이미지를 다운받을 때 On-demand Image Resizing이 적용된 이미지를 다운받도록 하는 것 등 코드 상 수정은 별로 없지만 실제로 효과는 있었던 개선은 더 있었습니다.

아직도 더 많은 개선이 필요하다고 생각하지만, 앞으로 추가될 기능을 개발하거나 각종 행사 등으로 개선만을 위한 시간은 사실 많지 않습니다. 그리고 제가 더 나은 방향이라고 생각했던 것들도 사실은 더 안 좋은 방향으로 가는 방향일 수도 있습니다. 그렇기에 지속적으로 확인하고 고민하면서 성능 측정 등을 활용하여 기획 외 내용 중 개선할 수 있는 부분들은 개선해나갈 생각입니다.

profile
프론트엔드 개발자 배준형입니다.

0개의 댓글