esoby 님의 상세페이지[4팀 김소희] Chapter 2-1. 클린코드와 리팩토링

과제 배포링크

esoby.github.io/front_6th_chapter2-1/

과제 체크포인트

기본과제

  • 코드가 Prettier를 통해 일관된 포맷팅이 적용되어 있는가?
  • 적절한 줄바꿈과 주석을 사용하여 코드의 논리적 단위를 명확히 구분했는가?
  • 변수명과 함수명이 그 역할을 명확히 나타내며, 일관된 네이밍 규칙을 따르는가?
  • 매직 넘버와 문자열을 의미 있는 상수로 추출했는가?
  • 중복 코드를 제거하고 재사용 가능한 형태로 리팩토링했는가?
  • 함수가 단일 책임 원칙을 따르며, 한 가지 작업만 수행하는가?
  • 조건문과 반복문이 간결하고 명확한가? 복잡한 조건을 함수로 추출했는가?
  • 코드의 배치가 의존성과 실행 흐름에 따라 논리적으로 구성되어 있는가?
  • 연관된 코드를 의미 있는 함수나 모듈로 그룹화했는가?
  • ES6+ 문법을 활용하여 코드를 더 간결하고 명확하게 작성했는가?
  • 전역 상태와 부수 효과(side effects)를 최소화했는가?
  • 에러 처리와 예외 상황을 명확히 고려하고 처리했는가?
  • 코드 자체가 자기 문서화되어 있어, 주석 없이도 의도를 파악할 수 있는가?
  • 비즈니스 로직과 UI 로직이 적절히 분리되어 있는가?
  • 코드의 각 부분이 테스트 가능하도록 구조화되어 있는가?
  • 성능 개선을 위해 불필요한 연산이나 렌더링을 제거했는가?
  • 새로운 기능 추가나 변경이 기존 코드에 미치는 영향을 최소화했는가?
  • 코드 리뷰를 통해 다른 개발자들의 피드백을 반영하고 개선했는가?
  • (핵심!) 리팩토링 시 기존 기능을 그대로 유지하면서 점진적으로 개선했는가?

심화과제

  • 변경한 구조와 코드가 기존의 코드보다 가독성이 높고 이해하기 쉬운가?
  • 변경한 구조와 코드가 기존의 코드보다 기능을 수정하거나 확장하기에 용이한가?
  • 변경한 구조와 코드가 기존의 코드보다 테스트를 하기에 더 용이한가?
  • 변경한 구조와 코드가 기존의 모든 기능은 그대로 유지했는가?
  • (핵심!) 변경한 구조와 코드를 한번에 새로 만들지 않고 점진적으로 개선했는가?

과제 셀프회고

과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?

클린 코드 첫 과제! 멘토링 때도 말씀드렸지만, (정말)(정말) 재밌었어요!

업무로 개발을 하다 보면 코드의 질적인 개선보다 기능 구현에 집중하게 되기도 하고, 이미 구현된 틀 안에서 유지 보수를 조금씩 해나가는 경험을 많이 하는 것 같습니다. 그런데 오랜만에 구조까지 갈아엎을 수 있는 리팩토링 과제라 .. 아주 짜릿했습니다.

과제를 처음 받았을 때는 무슨 수단을 써서라도 완벽한 코드를 만들어 보자! 다짐 했었는데요. 그렇게 맘 먹고 시작해보니 막막하기도 하고 부담도 돼서 ai한테 자꾸 시키게 되더라고요. 파일부터 냅다 나누면서 중복 코드 제거하다가 결국 원상복구 하고 main에서 뚝딱뚝딱 했습니다.

과제를 마저 진행하면서 저는 결과보단 과정에 집중하기로 했어요. 아주아주 완벽한 코드라는 게 뭔지도 모르겠고! 그러기엔 나는 아직 부족하니까! 적어도 바로 전보다는 나은 코드를 만들어가잔 마음으로 차근차근 임했습니다.

기본 과제의 큰 방향성은 리액트스러움(?)으로 잡았습니다! 심화 과제로 빠르게 전환하고 싶기도 했고 확실히 깔끔한 흐름인 것 같아요. 처음부터 store에서 dispatch - subscribe - notify를 구현해 데이터 변동을 관리하고 컴포넌트 단위로 ui 코드를 분리해놨더니 리액트 전환이 아주 수월했습니다. 뿌듯.

앗 과제 초반 팀원들과 eslint와 prettier rule을 적용하기 위한 팀 컨벤션도 정해보았는데요! 다른 분들 코드 스타일도 엿볼 수 있고~ 합의해가려 서로를 설득하는 과정도 재밌었읍니다. 학메 송이님 조언으로 평소보다 빡빡하게 규칙을 넣어서 작업했는데 덕분에 가독성이 좋아져쒀요

과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?

심화 과제를 시작하고, 기본 과제를 리액트 프로젝트 위로 어찌저찌 이식해두긴 했지만 뷰로만 작업하다가 리액트를 다시 써보려니 ,, 정말 기억이 하나도 안 나더라고요 ㅠ.ㅠ 깊이있는 내용은 머릿속에서 다 증발해 버려서 더 멋찐 코드를 짤 수 없었습니다. 이번 기회로 다시 친해져야 할 것 같고 계속 꾸준히 돌아봐야 할 것 같읍니다.

고쳐도 고쳐도 돌아보면 아쉬운 게 있다는 게 이 과제에 대한 아쉬운 점이겠습니다. 감각적으로다가 코드를 휘리릭 클린하게 짜는 사람이었다면 더 많은 부분을 캐치할 수 있었을텐데! 고런 부분에 대한 공부를 게을리 했다는 게 스스로 아숩게 느껴졌습니다~ 이제 하면 되지~ 헤헤

팀원들과 코드 리뷰를 더더더 적극적으로 해보지 못 한 것도 아쉽게 느껴져요! 다음주차 땐 더 많이 수다 떨고 더 많이 질문하고 더 많이 ...! 서로서로 귀찮게 하겠다 ,,! 다짐했습니다. 과제 제출 후에 늦게서야 다른 분들 코드를 훔쳐보았는데 진짜 기깔나더라고요 아 질투난다 💦

리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)

  • 화면을 그리는 코드와 계산에 필요한 코드를 자알 분리해보고 싶었는데, 혹시나 눈에 띄게 위반되는 지점이 있다면 꼬옥 알ㄹㅕ주세요!
  • 변수나 함수의 의미를 명확하게 하려고 하다보니 자꾸만 길어지는데 요런 경우 어떻게 하시는지 꿀팁! 아니면 규칙! 그런 게 궁금합니다!
  • basic 단계에서 현재 선택된 상품 값을 전역 변수로 관리하고 리렌더링 시 상태를 유지해주려고 했어요. 그래서 onChange 이벤트 핸들러를 걸어서 값이 바뀔 때마다 상태를 업데이트 하도록 했는데, 테스트 코드에서는 change 이벤트가 발생하지 않고 값이 직접 바뀌는 구조라 트리거가 안 되더라고요,, 최대한 핸들러에서 해결을 하고 싶었는데 아무리 생각해도 오직 테스트 통과만을 위한 못난 코드가(?) 되는 것 같아 결국 테스트 코드를 수정했습니다. 괜찮은 해결 방법이었을까요? 🥹🥹🥹
// select 값이 바뀌는 addItemsToCart 함수에 change 이벤트가 발생하도록 아래 내용을 추가했어요!
  sel.dispatchEvent(new Event('change', { bubbles: true })); 

과제 피드백

정말 정말 재밌었다니 과제 출제자로써 뿌듯하네요. 고맙습니다.

"..과제를 처음 받았을 때는 무슨 수단을 써서라도 완벽한 코드를 만들어 보자! 다짐 했었는데요." 맞아요. 개발자로써 뭔가 이상적이고 완벽한 코드를 만들고 싶어하는 바람들이 다들 있죠. 그렇지만 그런건 존재하지 않죠. 프로젝트가 성장하고 세상이 바뀌면서 코드는 바뀌기 마련이니까요.

"...적어도 바로 전보다는 나은 코드를 만들어가잔 마음으로 차근차근 임했습니다." 라는 인사이트를 느꼈다니 너무 멋지네요.

"..기본 과제의 큰 방향성은 리액트스러움(?)으로 잡았습니다!" 잘했습니다! 어쨌든 지난 10여년간 개발자 선배님들의 시행착오 끝에 합의가 된 방향인 만큼 분명 더 나은 무언가가 있을진 모르지만 지금까지 고민해온 결과의 이유들을 이해했기를 바랬요. 단순히 이렇게 해야한다가 아니라 더 좋은 코드의 고민의 결과물로써 리액트스러움을 이해했기를 바랍니다.

"감각적으로다가 코드를 휘리릭 클린하게 짜는 사람이었다면 더 많은 부분을 캐치할 수 있었을텐데!" 라는 의식을 가진다는 건 중요한 감각입니다. 전에 멘토링때 클린코드에 대한 감각은 패션센스? 혹은 정리정돈같은 감각인건데 신경안쓰면 신경이 안쓰이는데 신경쓰다보면 정리 안된거나 제대로 안된거 보면 불편하고 신경쓰게 되는 것 같은거요.

Q) 화면을 그리는 코드와 계산에 필요한 코드를 자알 분리해보고 싶었는데, 혹시나 눈에 띄게 위반되는 지점이 있다면 꼬옥 알ㄹㅕ주세요!

=> 잘했습니다. context를 이용해서 state와 dispatch를 분리하는 방식으로 잘 작성을 했네요! 이런 방식은 상태의 변화가 한군에 있고 어떤 동작을 통해 상태가 변화는지를 한눈에 볼 수 있어서 좋은 방식이죠. 지금과 같이 add, remove, inc등 다양한 액션이 있을 때 특히나 좋은 방식입니다.

Q) 변수나 함수의 의미를 명확하게 하려고 하다보니 자꾸만 길어지는데 요런 경우 어떻게 하시는지 꿀팁! 아니면 규칙! 그런 게 궁금합니다!

=> 자기만의 개발네이밍 사전등을 한번 갖춰보면 좋습니다. 어차피 개발에서 쓰이는 네이밍이라는건 도메인에서 쓰이는 특별한 용어를 제외하고는 대부분 비슷비슷하거든요. 그럴때마다 이런 이름을 뭐라고 지으면 좋지? 할때마다 좋은 기회를 삼아서 개발 어휘를 늘리기 위해서 여러가지를 비교하고 뉘앙스등을 면밀히 비교하는거죠.

=> 그리고 나만의 조립 법도 고민하면 좋습니다. 변수의 경우 가장 단순한 명사로 시작해서 맥락에 따라 형용사를 늘리는 식으로 index, selectedIndex, selectedProductIndex 중에서 주변 맥락을 통해 없어도 알 수 있을 것들은 안쓰고 적어주지 않으면 예측하기 어려운건 적어주는 편이 좋습니다.

=> 함수의 경우 동사, (형용사+)명사, (+전치사 명사) 와 같은 조립으로 대부분의 경우는 동사명사 2개의 조립이나 변수명처럼 findProduct() findSelectedProduct() 처럼 맥락을 더해야하는 경우와 indSelectedProductFromPoint() 입력값을 명확하게 해주기 위한 전치사를 더해주는 식 정도 입니다.

=> 컴포넌트나 다른 파일명등도 핵심이 되는 명사를 기준으로 얼마만큼 형용사로 맥락을 더해주어야 하나? 이런 방식들을 고민해보세요. 이러한 세세한 컨벤션등을 한번 나는 어떻게 하고 있나? 이런 고민들을 해보면 더 선명해지는 걸 느낄거에요

Q) basic 단계에서 현재 선택된 상품 값을 전역 변수로 관리하고 리렌더링 시 상태를 유지해주려고 했어요. 그래서 onChange 이벤트 핸들러를 걸어서 값이 바뀔 때마다 상태를 업데이트 하도록 했는데, 테스트 코드에서는 change 이벤트가 발생하지 않고 값이 직접 바뀌는 구조라 트리거가 안 되더라고요,, 최대한 핸들러에서 해결을 하고 싶었는데 아무리 생각해도 오직 테스트 통과만을 위한 못난 코드가(?) 되는 것 같아 결국 테스트 코드를 수정했습니다. 괜찮은 해결 방법이었을까요? 🥹🥹🥹

=> 테스트 코드와 실제 코드는 서로를 견제(?)하고 보강하기 위한 관계입니다. 테스트 코드로 하여금 실제 코드를 변경하더라도 문제가 없도록 할 수 있죠. 그렇지만 React로 넘어가고 나면 그 테스트 코드는 다시 쓰여져야 했을 거에요. 이 경우에는 실제 코드는 건들지 않고 테스트 코드를 다시 작성해야겠죠. 서로가 서로가 변하지 않을 거라는 전제로 의미가 생깁니다.

=> 이번에는 좋은 판단이었습니다. 해당 테스트 코드를 유지해야하는 이유가 사라지는 때였으니까요. 낡은 코드는 어느쪽이던간에 변경이 되어야 하죠. 내가 그 이유를 인지하고 변경하는 건 좋습니다. 우리가 경계해야 하는건 내 코드가 검증이 되지 않았는데 테스트 통과를 위해 코드를 변경하는 행위죠. 이건 경계가 뚜렷하지 않으므로 뭐라 딱 잘라 말하기는 어렵습니다만, 언젠가 폐기되거나 수정되어야 하는 코드는 수정이 되는게 맞습니다. 본인의 역할을 다 할 수 없는 코드라면 변경이 되어야 겠죠

이러한 고민 고민들이 쌓여서 본인의 감각으로 센스로 만들어지는 것이기에 지금의 과제가 그러한 의식을 가지는 계기가 되길 바라며 현업에서 만나는 코드에서도 조금만 더 시간을 들여서 클린코드를 만들고자 하는 생각들도 함께 가져가 보길 바래요. 수고했습니다! 5주차도 화이팅입니다!