brunch

You can make anything
by writing

C.S.Lewis

by zwoo Jun 05. 2021

안전한 리팩토링을 위하여

버그가 두려워서 리팩토링을 못할 수는 없으니까!


팝업을 띄운다. 팝업에는 버튼이 있다. 버튼을 누르면 함수가 실행된다.


간단한 요구조건처럼 보이지만 얼마든지 복잡해질 수 있다. 여기, 몇가지 조건을 더 추가해보자.


A스크린에 있는 팝업을 B에서도 똑같이 띄워야 한다. 팝업 아래쪽에는 버튼이 좌우로 두개 있는데, 왼쪽 버튼을 누르면 휴대폰의 앨범을 열어 사진을 선택할 수 있고, 오른쪽 버튼을 누르면 사진촬영을 할 수 있다. 앨범접근이나 사진촬영을 하기 직전에 앨범 및 카메라 접근 권한에 동의했는지 체크하는 팝업들이 순차적으로 떠야 한다. 


이러한 요구조건을 받아 들고서 나는 가장 먼저, 리팩토링을 할지 말지 고민했다. 리팩토링을 한다면 공통 팝업 컴포넌트를 분리할 생각이었는데, 또다른 고민은 팝업 UI만 분리할지, 아니면 앨범 및 카메라로 접근시키는 메소드들도 팝업컴포넌트에 넣을 건지였다. 물론 리팩토링을 하지 않고도 A스크린에서 팝업과 메소드 부분만 그대로 긁어다 B에 넣어주어 요구조건을 맞출 수도 있었다. 똑같은 코드가 늘어나는 것은 좋지 않지만 그 분량이 겨우 스크린 하나에 해당하기에 부담스러울 정도의 코드 중복은 아니었다. 또한 오히려 팝업을 분리함으로 인해 버튼클릭 동작을 리덕스로 상태관리하게되면 복잡성이 늘어날 수도 있었다. 



판단의 근거


어느 쪽으로 구현하든, 방식은 머릿속에 그려졌다. 팀에 합류해서 리덕스를 처음 배운 이후, 리듀서를 타입스크립트로 전환하는 작업이나 수정하는 작업은 해봤지만 직접 액션을 생성하고 핸들링하는 작업은 처음 해보는 거였다. 만약 너무 막막하거나 어려웠다면 쉽게 포기했겠지만, 방법은 알고 있으나 사이드이펙트를 발생시킬까봐 겁이 나는 거여서 고민이 되었다. 


판단하기 어려웠다. 동료분께 양해를 구하고 질문했다. 그분이 한 말이 결정적이었다. '나중에 리팩토링을 할 기회가 올지 안올지 그건 모르는 일이다. 할 수 있을 때 하는 게 좋다.' 그래야 실력도 늘 거라고 덧붙이셨다. 

구더기가 무서워서 장을 못 담글 수는 없으니까, 리팩토링을 하기로 했다. 대신 최대한 안전하게! 



만들고, 테스트하고, 삽입하고, 테스트하기


먼저 A스크린에 있는 팝업 컴포넌트를 가지고 새로운 팝업을 만든다. 팝업에 있는 '앨범', 버튼과 '카메라' 버튼을 각각 클릭했을 때 호출될 onPressAlbum( ) , onPressCamera( ) 메소드는 각각 앨범 접근권한과 촬영권한 동의 팝업을 띄워야 하기 때문에, 이 메소드들은 A, B 스크린에 (동일하게 생긴 중복된 코드지만) 일단 놔두기로 한다. UI만 분리할 예정이다. 


플로우는 이렇다. A, B 스크린에서 '팝업 띄우기' 버튼을 클릭하면 리듀서 함수를 통해 팝업의 상태가 'true' 가 되고 팝업이 노출된다. 팝업의 앨범 , 카메라 버튼을 클릭하면 각각의 리듀서 함수를 통해 A스크린, B스크린의 componentDidUpdate() 함수에서 isAlbumOn, isCameraOn 이라는 이름의 state ( 리듀서 함수가 반환하는 state )를 감지하여 onPressAlbum,  onPressCamera 함수를 호출한다. 


새로 만든 팝업컴포넌트의 두 버튼이 잘 동작한다는 사실은 테스트코드를 작성하여 보장한다. 테스트코드는 테스팅 라이브러리* 를 이용해서 먼저 컴포넌트를 렌더시키고, 렌더된 컴포넌트의 버튼을 fireEvent 메소드로 클릭하여 예상한 액션과 실행된 액션이 서로 동일한지 비교한다. 


테스트코드가 성공하면, 이제 A 스크린과 B 스크린 각각에 팝업컴포넌트를 삽입한다. 가능하면 이때도 테스트코드를 작성한다. isAlbumOn, isCameraOn 변수가 담긴 스토어를 목업해서 A, B 스크린에 Provider 로 전달하면서 렌더링시키고, 각각의 리듀서 변수 상태에 따라 각 스크린의 onPressAlbum, onPressCamera 함수가 호출되었는지 테스트한다.  (이 부분은 아직 작성중이라 이렇게 테스트하는 게 맞는지 확실치 않음)


PR은 이렇게 네개로 분리하여 올린 후 팀원들과 같이 리뷰한다. 테스트코드까지 리뷰를 한 후에, 최신 브랜치로 리베이스 후 차례대로 머지한다. 


이렇게 하는데 이틀이 걸렸다. 팝업 하나를 수정하는 요구사항을 수행하는 데 이틀은 너무 길다. 더 신속하게 작업하되, 하지만 정확성은 유지해야 한다. 숙련되는 것 외에는 방법이 없을까?






테스팅 라이브러리 : https://testing-library.com/docs/dom-testing-library/api-events/



Photo by Ravi Roshan on Unsplash








TMI. 

이번 작업은 유난히 두려웠는데, 든든한 버팀목이 되어주시던 팀장님이 이제 안 계시기 때문이다. 물론 고민도, 일도, 성장도 스스로 해야 하는 것이지만, 그동안 리뷰를 꼼꼼히 해주셔서 더 많이 도전하며 PR을 올릴 수 있었던 것 같다. 


테스트 코드 시나리오를 설계하는 철학과 작성하는 방법, 자바스크립트의 실행컨텍스트 개념, 타입스크립트의 클래스와 인스턴스, 인터페이스의 다양한 활용방법, 객체지향적으로 코드를 작성하는 방법도 모두 팀장님께 배웠다. 회사는 학교가 아니라고 혼이 난 적이 있는데, 그 당시 나는 회사에서 매일같이 새로운 걸 배워서 홀린듯 공부하고 홀린듯 계속 질문을 했던 것 같다. 너무 재밌어서 미처 죄송하다는 생각도 못했다. 열정이 지나치면 남을 지치게 하는 법인데. 너무 이기적이었던 것 같다.  


내가 할 수 있는 건, 앞으로 오늘처럼 힘들더라도 포기하지 않고 이 일을 오래오래 해서 나중에 다른 사람에게도 좋은 도우미가 되어주는 것이다.  


그리고 팀장님께는 식사대접을 꼭 해드려야할 것 같다.






이전 11화 비전공 저연차 개발자가 할 수 있는 실수
brunch book
$magazine.title

현재 글은 이 브런치북에
소속되어 있습니다.

작품 선택

키워드 선택 0 / 3 0

댓글여부

afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari