리팩토링- 간단한 단일 태그 UI, 태그로만 관리해도 괜찮을까?

김철준·2024년 12월 9일
0

리팩토링

목록 보기
1/9
post-thumbnail

프로젝트 기능 개발이 끝나 리팩토링을 진행해보려합니다.

처음에는 무엇부터 시작을 해야하나.. 막막했지만 코드를 한참 들여다보니 할 수 있는 부분들이 보입니다.

리팩토링을 하기에 앞서, 목적이 먼저 있어야할텐데요.

저는 최적화와 가독성 및 유지보수에 두었습니다.

  • 최적화
  • 가독성 및 유지보수

제 코드들을 위 기준에 맞춰 리팩토링하는 과정을 이 시리즈에 담아보려합니다.

우선, 이 글에서는 가독성과 유지보수에 초점을 맞춰보려합니다.

간단한 단일 태그 UI, 태그로만 관리해도 괜찮을까?

코드를 바라보다가, 아래와 같은 생각이 들었어요.

간단하게 이루어진, 하나의 태그로 있는 UI를 컴포넌트로 관리하지 않고 그냥 태그로 둬도 괜찮을까?

코드와 화면을 구경해보시죠.

"use client"

// 퀴즈 상세 컴포넌트
const QuizDetails = ({
                         quizData
                     }:{quizData:QuizItem}) => {

....

    return (
        <>
            {/*퀴즈 제목*/}
            <h1 className={"lg:text-title1 md:text-title2Bold sm:text-title2Bold"}>{quizData.metaTitle}</h1>
        	{/*퀴즈 질문*/}
            <p
                className={"text-menu"}
            >{quizData.title}</p>

            {/*퀴즈 내용*/}
            <div
                className={"prose w-full"}
                dangerouslySetInnerHTML={{__html: quizData.content}}
            ></div>

   ....

        </>
    );
};

export default QuizDetails;

일부분의 코드는 생략했어요. 제가 말하고 싶은 부분에 대한 코드만 적어봤습니다.

QuizDetails 컴포넌트는 ...으로 생략한 부분까지 100줄 가량의 코드들이 있는 퀴즈 상세 UI 컴포넌트입니다.

위 코드를 확인해보면 h1 태그가 나타내는 UI는 퀴즈 제목, p태그가 나타내는 UI는 퀴즈 질문,.div 태그에 dangerouslySetInnerHTML을 통해 퀴즈 내용을 나타내고 있습니다.

  • h1 -> 퀴즈 제목
  • p -> 퀴즈 질문
  • div -> 퀴즈 내용

물론 주석도 잘 달아놨죠.

초기에 개발할 때, UI가 복잡하지 않으니 단일 태그로로 충분할거야라는 생각에 위처럼 UI를 작성하였어요.

하지만 이대로 충분한가?라는 의문이 들었어요.

의문의 이유는 다음과 같았어요.

  • 주석을 달았을지언정, 해당 UI를 보았을 때 어떤 UI인지 단번에 파악하는 것이 더 좋지 않을까?

  • tailwind className으로 인해 코드가 길어져서 가독성이 좋지 않다.

  • 추후에 퀴즈 제목,질문,내용에 대한 className을 수정하거나 태그를 수정할 때, QuizDetails 컴포넌트를 건드려야한다.

  • QuizDetails 컴포넌트는 많은 역할들을 하고 있다.

주로 가독성관점에서 이유를 바라본 것 같습니다.

QuizDetails 컴포넌트 100줄 가량 된다고 했었죠. 코드를 오랫동안 보다보면 알겠지만, 코드를 파악하는 것이 누적되면 꽤나 피곤합니다.

때문에 보자마자 바로 파악가능하게 하는 것이 개발 피로 누적을 방지할 수 있는 생각이 들었어요.

만약 위 단일 태그로 감싸진 UI들을 컴포넌트로 만들면

  • 컴포넌트명으로 어떤 역할을 하는지 단번에 파악할 수 있다고 생각했고

  • className은 굳이 눈으로 볼 필요가 없습니다.

  • 위 UI들을 수정할 때, QuizDetails 컴포넌트도 건드릴 필요가 없죠.

  • 또한 SOLID 원칙의 단일 책임 원칙을 완전히 지키진 못하겠지만 QuizDetails 컴포넌트의 역할을 줄일 수 있게 해주죠.

그래서 위와 같은 이유로 간단한 태그로 감싸진 UI지만 컴포넌트로 분리하려고 합니다.

데이터를 props로 전달할까? children으로 전달할까?

그렇다면 위 UI들에 대해서 컴포넌트를 만들면 컴포넌트로 데이터를 전달해야할텐데요.

이를 props로 전달할지, children으로 전달할지 고민이 되었어요.

  • props로 전달?

변경후 코드

import React from 'react';

// 퀴즈 제목
function QuizTitle({title}:{title:string}) {
    return (
        <h1 className={"lg:text-title1 md:text-title2Bold sm:text-title2Bold"}>{title}</h1>
    );
}

export default QuizTitle;
  • children으로 전달?
<QuizTitle>{quizData.metaTitle}</QuizTitle>

props와 children을 사용했을 때, 어떤 장단점들이 있는지 생각해볼게요.

props를 사용하는 경우

장점

  • 어떤 데이터를 전달해야 하는지 props 타입으로 명확하게 정의할 수 있습니다.
  • 호출하는 쪽에서 작성해야 할 코드가 짧아집니다.
  • 대부분 한 줄로 표현되는 데이터는 props로 전달하기 적합합니다.

단점

  • 만약 복잡한 구조나 HTML을 포함해야 한다면 제한이 있을 수 있어 유연성이 떨어질 수 있습니다.

children을 사용하는 경우

장점

  • children은 더 자유롭고 유연하게 데이터를 전달할 수 있습니다.텍스트뿐만 아니라, HTML 태그나 컴포넌트를 포함한 복잡한 구조를 전달할 수 있습니다.
  • 중첩 구조를 쉽게 표현 가능: 텍스트 외에도 태그들을 중첩해야하는 경우에도 표현가능합니다.

단점

  • 호출부의 코드가 길어질 수 있음: 데이터를 컴포넌트 내부에 작성해야 하므로 다소 지저분해질 수 있습니다.
  • 단순 데이터에는 과할 수 있음: 제목이나 질문처럼 단순한 문자열을 처리할 때는 불필요한 코드 복잡성을 초래할 수 있습니다.

그래서 어떤 방식 사용?

정리해본 장단점의 따라, 위 경우에는 단순한 데이터를 보여주는 것이기 때문에 props 방식을 사용해보려합니다.

추후를 생각해봐도 위 UI들을 중첩되지는 않을 것 같다는 판단이 들기도 하여서 props로 사용해도 괜찮다고 생각했습니다.

import React from 'react';

// 퀴즈 제목
function QuizTitle({title}:{title:string}) {
    return (
        <h1 className={"lg:text-title1 md:text-title2Bold sm:text-title2Bold"}>{title}</h1>
    );
}

export default QuizTitle;
...
<QuizTitle
  title ={quizData.metaTitle}
  />

변경전 코드,변경후 코드

그래서 변경된 코드는 다음과 같아요.

변경전 코드

"use client"

// 퀴즈 상세 컴포넌트
const QuizDetails = ({
                         quizData
                     }:{quizData:QuizItem}) => {

....

    return (
        <>
            {/*퀴즈 제목*/}
            <h1 className={"lg:text-title1 md:text-title2Bold sm:text-title2Bold"}>{quizData.metaTitle}</h1>
        	{/*퀴즈 질문*/}
            <p
                className={"text-menu"}
            >{quizData.title}</p>

            {/*퀴즈 내용*/}
            <div
                className={"prose w-full"}
                dangerouslySetInnerHTML={{__html: quizData.content}}
            ></div>

   ....

        </>
    );
};

export default QuizDetails;

변경후 코드

"use client"

// 퀴즈 상세 컴포넌트
const QuizDetails = ({
                         quizData
                     }:{quizData:QuizItem}) => {

....

    return (
        <>
          {/*퀴즈 제목*/}
            <QuizTitle
                title={quizData.metaTitle}
            />
            {/*퀴즈 문제*/}
           <QuizQuestion
               question={quizData.title}
           />

            {/*퀴즈 내용*/}
            <QuizContent
                content={quizData.content}
            />

   ....

        </>
    );
};

export default QuizDetails;

변경하니 제가 보기에는 훨씬 깔끔하고 가독성도 더 좋아졌네요. 주석은 있어야하지만 없어도 파악가능할 것 같아요.

위와 같이 처음 리팩토링해본 부분은

  • 가독성 및 유지보수

측면에서 리팩토링을 해보았어요.

  • 가독성측면에서는 className을 볼 필요없도록 하고 컴포넌트명을 적절히 지어 단번에 파악가능하게 하고

  • 유지보수측면에서는 추후 위 UI들을 수정할 때 관련 컴포넌트만 수정하면 된다는 관점에서 유지보수성이 늘었다고 생각할 수 있습니다.

이렇게 첫번째 리팩토링을 간단한 내용과 작업으로 마무리해봅니다.

profile
FE DEVELOPER

0개의 댓글