본문 바로가기

Insight

ResizeObserver로 반응형 구현하기 (feat. 첫 PM 체험기)

반응형

지난 4월, 고객사 측에서 대규모 프로젝트 통합에 앞서 반응형 동작에 대한 요구사항이 생겨 갑작스럽게 데드라인성 프로젝트를 진행하게 되었다.

 

성능 최적화를 위해 절대 좌표로 구현되어 있는 내부 컴포넌트 구조에서 특정 모바일 브라우저의 인앱 기능을 통해 글꼴 크기 비율(%)을 변경하면 컨텐츠가 잘리지 않고 반응형처럼 동작해야 하는 요구사항이었다. 실제로 브라우저에서 글꼴 크기를 변경했을 때 computed style의 font size는 변경해주지만 notify event를 따로 내어주지 않기 때문에 내부 프레임워크의 event flow를 태울 수 없기에 적절한 대안이 필요했다.

 

애초에 컴포넌트가 상대 좌표로 구현되어 있었다면 간단히 flex 를 통해 반응형 레이아웃을 구축할 수 있었겠지만 기존 제품의 구조를 변경할 수 없기에 이를 위한 레퍼런스 자료들을 취합하던 중 resizeObserver  API를 통해 size 변경을 감지하고 이에 맞는 callback 함수 수행을 통해 적절한 position 변경이 가능할 것 같았다.

 

사내 코드이므로 구체적인 코드를 공유할 수는 없지만 전체적인 동작 flow는 다음과 같다.

 

반응형 컴포넌트 Sequence

1. ResizeObserver의 .observe() 메소드를 통해 특정 dummy node element를 탐지

2. 탐지 대상 element의 fontSize가 변경되면 detect trigger가 발동해 resizeObserver의 callback 함수를 호출

 - text 유무에 따른 observer 처리

3. callback 내에서 fontSize의 변경 비율 값 추출

 - initialScale 을 지정하여 변경 비율 계산

 - 브라우저에서 설정한 값과 같이 5% 단위 scale 계산 패턴 사용

4. Application의 component에 해당 근사치 값을 parameter로 전달하여 resize event를 notify

5. 각 Component의 size를 fontSize 비율과 같이 재조정하여 반응형처럼 동작하도록 구현

 

 

 

 

이 때 callback는 entries 라는 ResizeObserverEntry DOMRectReadOnly 개체를 반환하고 .contentRect라는 속성을 통해 요소의 Content Box 정보를 가져온다. (Border Box - Padding = Content Box)

 

적용해본 것

  • 실시간 상태 관리를 위한 wrapper 패턴 함수 정의
  • wrapper 패턴 함수를 통한 모듈 메소드 custom
  • 콜백함수 내 this 스코프 유지를 위해 함수 객체화
  • wrapper 함수를 전역변수화 하기위한 메모리 할당(new) -> 스크립트 언어가 어려운 이유
  • 함수의 객체화를 위한 prototype chain 설정
  • 객체 재사용 패턴과 prototype chain으로 구현한 객체 상속

 

결과

최종 시연 및 1차 사업을 성공적으로 마무리했다.(이후 고객사가 만족해 2차 사업까지 확장할 것이라는 피드백을 받았다.) 프로젝트를 끝내고 며칠 동안 고생한 팀원들이 모여 회고를 진행하면서 서로를 북돋아주기도 하고, 부족했던 점들을 다같이 모여 터 놓고 이야기하기도 하면서 진정 "애자일" 스럽게 일하고 있구나. 라는 생각이 들기도 했다.

 

개인적인 회고

창사 이래 가장 큰 규모의 프로젝트였기에 실패하면 안된다는 정신적인 부담과 스트레스가 있었다. 첫 메인 역할을 도맡아 진행하면서 팀장님이 나를 믿고 맡긴 일을 잘 끝내야겠다는 욕심도 굉장했다.

 

업무 공수를 조정하고, 회의를 진행하는 과정도 그렇지만 제품의 스펙을 고려하며 직접 공통 Core 단 API 기능을 설계하고 구현하는 것이 쉽지만은 않았다. 내가 공통 단 업무를 선행하면 그에 맞게 컴포넌트 기능 구현을 맡은 팀원들이 작업을 수행해야 했기 때문에 최대한 일찍 끝내야 한다는 압박감에 시달리기도 했다. 혹여 설계가 잘못되거나 스펙이 변경되어 공통 단을 수정하게 되면 컴포넌트 구현자들의 재작업 가능성도 있기에 매우 조심스러운 작업이었다.

 

내가 생각한 구조가 하위 호환성을 지키며 문제 없이 동작할 수 있는 스펙인지 가늠이 불가능한 부분은 수석님들께 여쭤보며 바쁘신 와중에 굉장히 귀찮게 굴었기 때문에 죄송한 마음이 컸다. 무엇보다 작업 기한이 2주 정도로 극단적으로 짧다보니 무던한 내 성격에도 일을 하면서 예민해지는 순간이 오기도 했다.

 

특히 이번 프로젝트는 내게 굉장히 특별한 키워드들로 남겨졌다.

 

1. 커리어 성찰

일태기를 느끼던 와중에 정말 짧은 시간 내 협업을 진행하면서 나의 역량을 돌이켜보고, 나는 5년 뒤 그리고 10년 뒤에 어떤 방향성을 가지고 시니어 개발자, 역량이 닿는다면 어떤 테크 리더로 성장하고 싶은지 성찰해보는 계기가 되었다.

잘 짜여진 코드 패턴을 따라 치는 건 아무 의미가 없다. 결국 내 스스로 코드를 짜보고 고민하고, 실패하더라도 부딪혀봐야 실력이 는다. 개발이라는 게 어찌보면 이보다 더 명백하고 정직할 수가 없는 일이다. 오롯이 내가 몰입하고 집요하게 파고드는 연습을 해야하는 것이다. 이런 부분들에 대해 내 스스로 증명해내고, 또 그런 과정들을 슬기롭게 보여주는 것이 주니어 개발자가 보여줘야 하는 역량인 것 같다.

 

개발을 레고에 비유한다면?

실제 현업에서 요구하는 것은 고객이 요구하는 기존 조립서에는 없었던 새로운 것을 만들어내는 과정이다. 혼자서 하는게 아니라 대규모 헙업인 것이다. 그동안 만들어진 것들 가운데서 필요한 것들을 적절히 재조립해서 만들어야 하고 이것들이 html css js 외에도 라이브러리나 프레임워크등을 계속 찾고 익혀야 하는 이유다.

물론 조립만 할 줄 아는 능력만 요구하는 곳도 있다. 조립서는 위에서 만들어주고 그대로 만들줄 아는 인력도 부족한 상황이니 보통 우리가 코더라고 불리는 그런 개발자 유형이며 개발을 공부하는 사람들이 이상적으로 꿈꾸는 유형은 아닐 것이다.

만들고 싶은 것을 하나 정하고 강의나 책 클론에서 배운 것들을 변형해서 내것에다가 적용을 해보는 연습이 필요하다. 공부가 아니라 연습이라고 적은 이유는 학습의 영역이 아니라 경험과 숙달의 영역이기 때문이다. 대부분의 경우는 필요한 것을 검색하고 시도해보고 버그를 수정하고 하는 문제해결의 반복이기 때문이다.

이것을 잘하는 것은 재능의 영역일 수도 있으나 몇몇의 소수 개발자들을 제외하고는 엉덩이를 붙이고 끝까지 문제를 파고 들고 해내는 책임감과 해냈을때 즐거움을 느끼는 사람이라면 충분히 이 업계에서 살아남을 수 있다고 생각한다. 그러니 공부를 할 때 코드를 따라서 치고 있을 때 꼭 한번씩 내것에 붙여보거나 응용을 하는 연습을 해보거나 작게라도 내가 만들고 싶은 것들을(혹은 남들이 부탁하는 무언가든) 만들어가면서 필요한것을 찾아가며 공부하는 과정을 꼭 함께 하길 권한다. - teo

 

2. 팀이 성공하는 법

타이트한 협업을 진행하면서 나만 잘해서는 안되고 팀원 모두가 생각의 싱크를 맞추고 같은 방향성으로 나아가는 것이 팀 프로젝트 성공의 핵심이라는 것을 알게 되었다. 이를 깨닫는 과정은 진정 경험을 통해서만 느낄 수 있는 "업무적 성장"을 체감하는 경험이었다. 

 

잡담이 경쟁력이다.

잡담은 신뢰를 만드는 원동력이다. 공동체의 유대감을 높이며 참여자의 마음 상태를 편안하게 만들어준다. 유대감은 신뢰로 발전한다. 잠담을 통해 커뮤니케이션의 벽이 낮아지면 더 편안한 분위기 속에서 보고가 이뤄질 수 있으며, 간혹 엉뚱해보이는 아이디어도 좀 더 자유롭게 개진될 수 있다. 이는 조직이 건강하게 성장할 수 있는 원동력이 된다.

 

3. 부끄러움을 통한 성장

팀 리드 역할이 처음이기도 했고, 메인 작업자로 5명의 TFT 구성원들의 업무 진행상황을 공유하고, 피드백하는 과정에서부터 누락사항이 생기기도 하면서 우여곡절이 많았다. 리더는 어떤 부분까지 고려해야 하지? 업무 딜레이를 어떻게 개선해야 하지? 내 스스로 고민하는 연습을 하고, 부족함을 느껴 부끄러움을 느끼고 조금 더 성장했구나 생각이 들었다.

 

내가 본질을 아나? 모순은 없나? 조금 더 본질적인 고민이 필요하다. 결국 큰 성장의 트리거는 부끄러움이다. 부끄러움이 선행되지 않으면 앞으로 나아갈 수 없다. 부끄러움을 느낀다는 건 내가 유의미하게 성장한다는 것이 아닐까.

 

4. 리더의 역할

지난 밤 이모와 참된 리더에 관해 이야기를 나눴다. 리더는 업무를 지시할 때 미리 파악하는 것이 당연하고, 혹여 프로젝트가 실패하더라도 그에 대한 책임은 리더가 지는 것이라는 것이다. 팀원이 계속 빠지거나, 업무 분위기가 흐린다면 그것은 팀원의 문제가 아니라 문제되는 상황을 미리 캐치하지 못하고 이에 대한 해결 방안을 고려하지 못한 리더의 문제라고.

 

팀장이 무슨죄야. 너무 안쓰럽잖아! -> 그러라고 팀장이 있는거야..(단호)

 

5. 장기 업무 플랜

장기적으로 나는 어떠한 일을 해보고 싶은 (개인적인) 꿈이 있다. 이를 위해서 기술적인 지식과 노련함이 필요하고, 전체적인 흐름을 읽는 것이 중요할 것이다. 이 가능성과 좋은 역량을 알아봐주고 응원해주는 좋은 사수가 있다는 것은 너무나도 큰 복이고, 지금 연차에 내가 얻을 수 있는 아주 값진 경험이라는 것을 늘 마음에 새기자. 연차가 쌓이면서 책임이 많아지긴 했지만 그만큼 견문을 넓혀가고 있는 듯 하다.

 

 

 

끝으로 내가 존경하는 뇌 과학자 정재승 교수님의 창의적인 뇌를 만드는 법에 대한 강연 내용을 첨부하며 2달이 지난 회고록을 마무리한다. 

 

창의적인 뇌 만드는법 - 정재승 교수

1. 코어타임 탐색
천재들은 자신이 일이 잘 되는 시간대를 안다.
→ 나만의 루틴 만들고 선택과 집중하기
→ 과도한 계획을 세우지 말 것
→ 다양한 시도를 통해 나 자신의 코어타임을 알고, 그 시간에는 창의적인 일을 하는 데 보낼 것

2. 멍 때리기

비목적성의 생각을 하는 멍 때릴 때 유레카 모먼트가 생겨난다. 창의적인 아이디어는 상관 없다고 느꼈던 분류들을 이어나갈 때 생겨난다.편견, 선입견을 깨지 않을수록 창의성이 떨어진다. 성공 가능성이 작다고 포기하면 불가능하다.

계속되는 실패에 좌절하지 않고 여러 번 도전하는 사람이 혁신적이고 창의적인 아이디어를 만든다.
즉, 끈기와 인내. 집요함이 필요하다.

 

 

 

 

 

 

Ref


ResizeObserver Interface by MDN

 

 

반응형