기술 포스트

유지보수 가능한 퍼블리싱 구조란 무엇인가


Article

프로젝트가 끝나고 6개월 뒤, 클라이언트가 수정을 요청합니다. 이때 코드를 열었을 때 구조가 바로 파악되느냐—이게 유지보수 가능한 구조의 기준입니다.

솔직히 저도 예전에 만든 코드를 3개월 뒤에 열어보고 "이게 뭐였지?" 했던 적이 있습니다. 그 경험 이후로 구조에 대한 생각이 좀 바뀌었습니다.


문제가 되는 패턴들

실제로 자주 보는 안 좋은 예시들입니다:

의미 없는 클래스 네이밍

/* 이건 3개월 뒤에 아무도 이해 못 한다 */
.box1 { padding: 20px; background: #fff; }
.box2 { padding: 16px; background: #f5f5f5; }
.box3 { padding: 20px; background: #fff; border: 1px solid #ddd; }
.tt { font-size: 18px; font-weight: bold; }
.desc { font-size: 14px; color: #666; }

.box1이 뭐고 .box2가 뭔지, 만든 사람도 한 달 뒤면 기억 못 합니다. .tt가 title인지 tooltip인지도 모호합니다.

BEM으로 바꾸면

/* 컴포넌트와 역할이 이름에 드러난다 */
.service-card { padding: 20px; background: #fff; }
.service-card__title { font-size: 18px; font-weight: bold; }
.service-card__desc { font-size: 14px; color: #666; }

.feature-card { padding: 16px; background: #f5f5f5; }
.feature-card__title { font-size: 18px; font-weight: bold; }
.feature-card__desc { font-size: 14px; color: #666; }

파일을 열자마자 "서비스 카드의 제목"인지 "기능 카드의 설명"인지 바로 알 수 있습니다.

Tailwind를 쓴다면

// 클래스 네이밍 고민 자체가 사라진다
function ServiceCard({ title, description }: ServiceCardProps) {
  return (
    <div className="bg-white p-5">
      <h3 className="text-lg font-bold">{title}</h3>
      <p className="mt-2 text-sm text-stone-600">{description}</p>
    </div>
  );
}

Tailwind의 장점은 유틸리티 클래스 자체가 스타일의 설명이라는 점입니다. text-lg font-bold를 보면 바로 "큰 볼드 텍스트"라는 걸 압니다. 커스텀 클래스 이름의 모호함이 없습니다.


같은 UI인데 마크업이 다른 문제

프로젝트 안에서 카드 UI가 5군데에 나온다고 치겠습니다. 근데 각각 마크업이 다릅니다:

<!-- 메인 페이지 -->
<div class="main-card">
  <strong>제목</strong>
  <span>설명</span>
</div>

<!-- 서브 페이지 -->
<article class="sub-item">
  <h3 class="sub-item-title">제목</h3>
  <p class="sub-item-text">설명</p>
</article>

<!-- 목록 페이지 -->
<li class="list-card">
  <div class="list-card-head">제목</div>
  <div class="list-card-body">설명</div>
</li>

같은 역할인데 태그도 다르고, 클래스 규칙도 다르고, 구조도 다릅니다. 나중에 "카드 디자인 전체를 바꿔주세요"라는 요청이 오면 5군데를 다 찾아서 각각 수정해야 합니다.

컴포넌트로 통일하면

// Card.tsx — 이 하나만 수정하면 전체가 바뀐다
interface CardProps {
  title: string;
  description: string;
  variant?: "default" | "outlined";
}

export default function Card({ title, description, variant = "default" }: CardProps) {
  return (
    <article
      className={`p-5 ${
        variant === "outlined"
          ? "border border-stone-200 bg-white"
          : "bg-stone-50"
      }`}
    >
      <h3 className="text-base font-semibold text-stone-900">{title}</h3>
      <p className="mt-2 text-sm leading-relaxed text-stone-600">{description}</p>
    </article>
  );
}
// 어디서든 이렇게 쓴다
<Card title="서비스 소개" description="..." />
<Card title="포트폴리오" description="..." variant="outlined" />

수정 사항이 생기면 Card.tsx 하나만 고치면 됩니다. 5군데를 돌아다닐 필요가 없습니다.


파일 구조도 중요합니다

# 이건 나중에 찾기 어렵다
styles/
  style.css          ← 모든 스타일이 여기에 1000줄
pages/
  index.html
  about.html
  contact.html
# 이게 훨씬 낫다
components/
  Card/
    Card.tsx
  Navigation/
    Navigation.tsx
  Footer/
    Footer.tsx
app/
  page.tsx
  about/
    page.tsx
  contact/
    page.tsx

컴포넌트별로 파일이 나뉘어 있으면, "카드 수정"이라는 요청이 왔을 때 Card.tsx만 열면 됩니다. 1000줄짜리 CSS 파일에서 .card를 검색하며 헤매지 않아도 됩니다.


결국 핵심은 하나입니다

예측 가능성.

파일을 열기 전에 "이건 아마 여기 있을 거다"라고 추측할 수 있는 구조. 코드를 읽기 전에 "이건 아마 이런 역할일 거다"라고 짐작할 수 있는 네이밍. 이게 유지보수 가능한 구조의 전부입니다.

고급 기술이 아닙니다. 처음에 규칙을 정하고, 끝까지 일관되게 지키는 것. 이 습관 하나가 프로젝트 6개월 뒤의 수정 비용을 결정합니다.

에이전시에서 다시 찾는 퍼블리셔는 대체로 이 부분이 강한 사람들이라는 걸, 여러 현장을 보면서 점점 더 확실하게 느낍니다.