회사 개발 업무 온보딩을 진행하면서 앞으로 기능 추가를 해야 할 때가 있으면 프론트엔드의 코드를 알고 있어야 하고, 사내 프로젝트 코드를 좀 더 유지보수가 쉽도록 설계 하고자 유림님의 클린 코드 강연을 듣게 되었다. 기술적인 성장과 함께 후에 나와 함께 협업하게 될 분을 위해서도 이런 작업은 매우 중요하기도 하고, 미래의 걱정이 될 수 있을 요소들을 해결하지 않으면 편하게 두발 뻗고 잠을 잘 수 없는 나의 성향 때문에도 그렇다.
"그 코드는 안 건드리는게 좋으실 거예요. 일단 제가 만질게요.^^;;;"
모든 회사의 프로젝트마다 존재하는 이런 지뢰 코드의 특징.
솔루션 : 유지보수 시간의 단축 (코드 파악/디버깅/코드리뷰) 을 해줄 수 있는 코드 → 클린 코드!
긴장의 끈을 놓치면 코드가 들쑥 날쑥해짐을 경험할 수 있다.
안일한 코드 추가의 함정
기능 추가 요청이 새롭게 들어왔다.
예시) 보험에 대한 질문을 입력하는 페이지가 있는데, 내 설계사가 있는 경우 그 설계사 사진이 들어간 팝업을 먼저 띄워달라는 기능 요청 이였다.
아래의 기존 코드를 보자.
function QuestionPage() {
async function handleQuestionSubmit() {
const 약관동의 = await 약관동의_받아오기();
if (!약관동의){
await 약관동의_팝업열기();
}
await 질문전송(questionValue);
alert("질문이 등록되었어요.");
}
return (
<main>
<form>
<textarea placeholder="어떤 내용이 궁금한가요?"/>
<Button onClick={handleQuestionSubmit}>질문하기</Button>
</form>
</main>
);
질문하기
버튼을 클릭하면, 유저의 약관동의 여부를 검사하고 필요시 팝업을 띄운다. 그 후에 질문을 전송하고 질문이 등록되었다는 알림을 띄우는 기능이다.
이 코드를 위의 요구사항과 함께 어떻게 리팩토링할까?
그래서, 이 기존의 클릭함수에서 연결 중인 전문가가 있는지 확인하는 코드를 넣고 있으면 팝업을 띄우는 팝업 컴포넌트를 추가 해야겠다! (우리의 생각!)
버튼 컴포넌트 아래에 넣고 처음엔 숨겨두고, 필요할때 보여줘야겠어! (모두의 바람)
그래서, 이 생각의 흐름대로 다음과 같이 코드를 추가했다고 하자.
function QuestionPage() {
const [popupOpened, setPopupOpened] = useState(false); // 팝업 상태를 확인하는 코드
async function handleQuestionSubmit() {
const 연결전문가 = await 연결전문가_받아오기();
if (연결전문가 !== null) {
setPopupOpened(true);
}
else {
const 약관동의 = await 약관동의_받아오기();
if (!약관동의){
await 약관동의_팝업열기();
}
}
await 질문전송(questionValue);
alert("질문이 등록되었어요.");
}
// 팝업 버튼 클릭 핸들러
async function handleMyExpertQuestionSubmit() {
await 연결전문가_질문전송(questionValue, 연결전문가.id);
alert('${연결전문가.name}에게 질문이 등록되었어요.');
}
return (
<main>
<form>
<textarea placeholder="어떤 내용이 궁금한가요?"/>
<Button onClick={handleQuestionSubmit}>질문하기</Button>
</form>
// 팝업 버튼 컴포넌트
{popupOpened && (
<연결전문가팝업 onSubmit={handleMyExpertQuestionSubmit}/>
)}
</main>
)
}
위의 코드를 하나하나 생각대로 설계했지만, 결과적으로 좋지 못한 코드가 되었다. 문제점은 무엇일까?
'연결중인 전문가 팝업 코드'
라는 점을 기억해야 한다.시간 == 자원
이기 때문이다.handleQuestionSubmit()
, handleMyExpertQuestionSubmit()
두 함수는 모두 이벤트 핸들링 함수 이다.handleQuestionSubmit()
함수는 질문 전송 외에도 여러가지 일을 수행 하는 함수이다.PR(Pull Request)의 상황만 보면, 어지러운 코드인지 파악하기 어렵다. 변경점 자체는 문제가 없기 때문이다.
handleNewExpertQuestionSubmit()
, handleMyExpertQuestionSubmit()
으로 위계를 맞췄다.== 원하는 로직을 빠르게 찾을 수 있는 코드
응집도 높이기
단일 책임 원칙 준수
추상화 단계를 조정해서 핵심 개념 추출하기
당장 몰라도 되는 디테일은 숨겨두기만 해도 코드의 목적을 빠르게 파악하는 작업이 용이해진다.
코드 파악에 필수적인 핵심 정보들을 분리하면 이를 파악하기 위해 모듈을 넘나드는 대참사가 발생한다.
리액트의 JSX에서 핫하게 쓰이는 선언형 프로그래밍, 그러나 때에 따라서는 명령형 프로그래밍도 유동적으로 사용할 수 있어야 가독성이 더 좋아질 수 있다. 코드의 목적을 빠르게 파악할 수 있기 때문에 그렇다.
중요 포인트가 모두 담겨 있지 않는 함수명 → 위험
이런 경우, 나중에 새롭게 다른 기능을 추가할 때 원하는 동작을 이끌어내기 어렵다. 또, 리팩토링할 때 들어가는 수고로움은 배가 될 것이다.
추상화 단계를 비슷하게 정리해서 추상화 수준이 같은 것 끼리 모으는 작업을 해 두자.
20분의 짧은 강연을 들으면서 많은 것을 배웠다. 그 중 가장 와닿았던 점들은 위의 열거한 원칙이 모두 지켜진다는 가정하에서, 기능을 설계할 때 개발자의 의견이 상대적으로 존중받기 쉬워지는 개발 환경이 된다는 점 이다.