-
"클린 코드" 는 "방어운전" 과 같다.ReactJS 2023. 10. 21. 07:20
사실 팀 프로젝트를 할 때마다 클린 코드의 중요성을 체감하고 있지만,
이번 프로젝트는 무려 디렉터, 기획팀, UI/UX 디자인 팀, 개발팀(프론트,백엔드), 운영팀이 함께 작업을 하는 내 인생 나름 대규모 프로젝트여서 클린 코드의 "필요성"을 아주 깊게 느끼는 중이다.
오히려 상대적으로 1인 프로젝트, 소규모 프로젝트에서 클린 코드가 그렇게 중요하지 않았기 때문에 내가 "재사용성" 높은 코드를 짜는 데 귀찮음을 느꼈다는 걸 깨달았다.
클린 코드의 정의
클린 코드는 일반적으로 유의미한 변수 이름, 한 개의 함수 당 하나의 역할, 이해하기 쉬운 로직 등을 합쳐 알아보기 쉬운 코드를 의미한다.
맞는 말이다. 나는 여기에, 협업을 하면서 느낀 React 에서의 클린 코드를, 중요도 순으로 개인적으로 정의하고 싶다.
클린 코드
- "재사용성" 높은 컴포넌트
- "디자인 패턴" 을 충실히 따르는 코드
- "순수 함수" 형 함수와 컴포넌트
- "컨벤션" 을 지키는 객체 이름과 디렉토리 구조
- "매크로" 변수 사용 (매직 넘버 사용 절대 금지)
이상이 내가 느낀 협업에 필요한 클린 코드이다.
사실 첫 번째 팀 프로젝트에서는 내가 너무 뉴비였고 개발 인원도 5명이었기 때문에 지금만큼 클린 코드에 대해 깊게 생각해 볼 일이 없었다.
지금은 생각이 다르다. 협업을 하는 개발자라면 클린 코드는 권장이 아닌 필수다.
클린 코드와 방어운전의 관계
클린 코드를 지키지 않으면 오늘은 효율이 높지만, 내일은 코드를 갈아엎고 새로 써야 한다.
- 도로에서 신호를 무시하고 과속하면 당장은 빠르지만, 얼마 안 가서 교통사고가 난다.
1인 프로젝트에서는 클린 코드를 지키지 않아도 문제 될 것이 없다. 어차피 모든 로직이 내 머리안에 있으니까.
- 서울에 사람이 나 혼자밖에 없으면 차선과 신호등을 지킬 필요가 없다.
클린 코드를 짜야 하는 이유는, 다른 사람들과의 협업에서 보다 작업 효율과 능률을 향상시키기 위함이다.
- 방어운전을 하는 이유는, 도로에 다른 차들과 함께 운전할 때 사고가 나지 않게 하기 위함이다.
= 내가 코드를 짤 때는 다음 내용을 명심해야 한다.
- 내가 만든 컴포넌트, 훅, 유틸리티 함수, 객체 등은 언제든 다른 사람이 사용할 수 있다.
- 시시각각 기획과 디자인과 백엔드의 데이터가 바뀌는 환경에서, 내 코드는 막강한 재사용성으로 모두 유연하게 대응할 수 있어야 한다.
사실상 이게 핵심이고, 이에 맞춰서 코딩을 하는 것이 바로 클린 코딩이라고 할 수 있겠다.
단적인 예시
여기서는 아주 간단하고 이해하기 쉬운 하나의 예시만 들어보도록 하겠다.
import { EachPortfoilo } from "./EachPortfoilo"; import { Title } from "./Title"; export const Portfolio = () => { return ( <main className="responsive min-h-full"> <Title titleName="PORTFOLIO" /> <div className="flex flex-col justify-center items-center m-20 xl:flex-row xl:flex-wrap"> <EachPortfoilo imageSrc="/transcendence/transcendence_1.png" title="transcendence" language="React / Nest.js" href="/transcendence" /> <EachPortfoilo imageSrc="/wakQuote/wakQuote_main.png" title="우왁굳 명언 아카이브" language="Next.js" href="/wakQuote" /> <EachPortfoilo imageSrc="/wakJot/wakJot_main.png" title="왁JOT" language="React Native" href="/wakJot" /> <EachPortfoilo imageSrc="/IsegyeUniverse/construction.svg" title="이세계 유니버스" language="Next.js / Express" href="/IsegyeUniverse" /> </div> <div id="blog" /> </main> ); };
위의 코드는 얼마 전에 개발한 포트폴리오 페이지에서, 포트폴리오 리스트 컴포넌트를 구현한 부분이다.
1인 개발 중에는 위의 코드가 아무런 문제가 없다.
이미 내 머릿속에 설계가 다 있고, 넣을 포트폴리오의 갯수도 내가 정할 수 있고, EachPortfolio 의 prop 에 인자를 넣어 주기만 하면 새로운 포트폴리오 배너를 만들 수 있게끔 하는 정도의 재사용성만 확보하면 충분했다.
하지만 백엔드에서 가져올 데이터의 배열의 길이가 시시각각 바뀌고, 각각의 컴포넌트 안에 일관성이 있을 지 없을 지 모르는 View 를 넣어야 한다면 어떨까?
아래의 코드는 아직 개발 중인 팀 프로젝트에서, 내가 구현 중인 코드의 일부분이다.
import { NewsMainBanner } from './NewsMainBanner' export const NewsMainBannerList = () => { return ( <div css={{ display: 'flex', gap: 10, overflowX: 'scroll', // temporary }} > {DUMMY_BANNER_LIST.map((banner) => ( <NewsMainBanner key={banner.id}> {banner.dummyInnerBanner} </NewsMainBanner> ))} </div> ) }
최신화가 계속 되는 뉴스들의 메인 배너를 x축을 따라 보여줘야 하는데,
몇 개의 뉴스가 들어올 지도 모르고, 메인 배너의 디자인과 내용에 일관성이 있을지 없을지도 모르는 상황이다.
따라서 가변적인 리스트의 길이에 대응하기 위해 map을 사용하고,
Inner Banner 의 내용에 뭐가 들어와도 대응할 수 있도록 NewsMainBanner 컴포넌트의 children 으로 넣어주었다.
이렇게 최대한 수비적으로 코드를 작성하면(방어운전 하듯이), 개발 중에 사양이 어떻게 변경되더라도 최소한의 리팩토링으로 대처할 수 있다.
이 외에도 같은 팀원이 사용하기 쉽도록 순수 함수형 공용 컴포넌트와 유틸리티 함수를 제작하고, 함수의 이름을 한 가지의 기능을 하는 동사형으로 선언하고, 하나의 feature 를 공동 작업한다던가, 내가 작업하던 feature 를 다른 사람이 맡게 될 경우(혹은 반대의 경우) 를 위해 파일 이름과 디렉토리 구조를 컨벤션에 맞게 쓰는 등 자잘한 것들이 매우 많다.
(모두 설명하면 아주 길고 지루한 포스트가 될 것이다)
하지만 클린 코딩의 핵심은 언제나, 다른 팀원이 사용할 것을 의식하고, 내 코드에 영향을 주는 외부 요인이 바뀔 수 있음을 의식하면서 코딩을 하는 것이다.
'ReactJS' 카테고리의 다른 글
React.memo, useMemo, useCallback 진짜로 언제 사용해야 할까? (0) 2023.10.14