Post

더 나은 추상화 만들기 - 메뉴아이템

[번역] DRY - 잘못된 추상화의 일반적인 원인을 읽고 작성한 코드를 분석해본 글입니다.

위 포스트을 읽으며 DRY가 잘못되는 과정에 작성된 코드가 내가 작성한 코드와 비슷해서 생각해보게 되었습니다.

코드를 읽을 때 가장 좋은 코드는 아래의 그림 왼쪽처럼 위에서 아래로 쭉 읽어나가기만 하면 되는 코드입니다.

https://swizec.com/static/96961c7ae5eec58f69d9228861724008/e11e5/Reading-DRY-code-vs-simple-code-23f6a6.webp

하지만 내 코드는 오른쪽 그림만큼은 아니지만, 내가 작성한 메뉴 아이템을 확인하려면 위로 올라가서 읽어야합니다.

코드를 줄이기 위해 객체를 사용하여, 반복할 내용을 묶고 반복문을 사용해서 코드의 중복을 줄이는 방법을 사용하였기 때문입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const adminNav: IAdminNavItem[] = [
  {
    path: "/admin/users",
    name: "사용자 관리",
    icon: <UserIcon />
  },
  {
    path: "/admin/report-user",
    name: "신고된 사용자 관리",
    icon: <ReportIcon />
  },
  {
    path: "/admin/unverified-reviews",
    name: "미승인 후기 관리",
    icon: <DashboardUnapprovedReviewIcon />,
    $iconSize: 16
  }
];

function AdminSidebar() {
  const { pathname } = useLocation();
  return (
    <Container>
      <Logo>
        <NaedonnaesanTextLogo />
      </Logo>

      <LinkToService>
        <AdminNavItem
          path="/"
          icon={<DashboardLinkIcon />}
          name="사이트 바로가기"
        />
      </LinkToService>

      <div>
        <NavSectionTitle>사이트관리</NavSectionTitle>
        <nav>
          {adminNav.map((nav) => (
            <AdminNavItem
              isActive={pathname === nav.path}
              {...nav}
              key={nav.name}
            />
          ))}
        </nav>
      </div>
    </Container>
  );
}

그래서 포스트를 참고하여 작성해두었던 컴포넌트에 직접 인자를 전달하는 방법으로 변경해보았습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function AdminSidebar() {
  return (
    <Container>
      <Logo>
        <NaedonnaesanTextLogo />
      </Logo>

      <LinkToService>
        <AdminNavItem
          path="/"
          icon={<DashboardLinkIcon />}
          name="사이트 바로가기"
        />
      </LinkToService>

      <div>
        <NavSectionTitle>사이트관리</NavSectionTitle>
        <nav>
          <AdminNavItem
            path="/admin/users"
            name="사용자 관리"
            icon={<UserIcon />}
          />
          <AdminNavItem
            path="/admin/report-user"
            name="신고된 사용자 관리"
            icon={<ReportIcon />}
          />
          <AdminNavItem
            path="/admin/unverified-reviews"
            name="미승인 후기 관리"
            icon={<DashboardUnapprovedReviewIcon />}
            $iconSize={16}
          />
        </nav>
      </div>
    </Container>
  );
}

isActive 인자를 매번 전달하는 건 옳지 않다는 생각이 들어, AdminNavItem에서 주소를 비교하여 active 클래스를 추가하고 제거하도록 설정했습니다.

1
2
3
4
5
6
7
8
9
function AdminNavItem({ icon, name, path, $iconSize }: IAdminNavItem) {
  const { pathname } = useLocation();
  return (
    <NavItem to={path} className={pathname === path ? "active" : ""}>
      <Icon fill="#fff" icon={icon} width={20} $iconSize={$iconSize} />
      <Title>{name}</Title>
    </NavItem>
  );
}

변경하니 메뉴아이템의 정보를 확인하기 위해 코드를 다시 올려서 확인할 필요가 없어졌습니다.

비교

통합된 접근 방식

장점:

  • 코드의 중복을 줄여 유지보수가 용이
  • 메뉴 아이템이 많을 때 코드의 길이를 줄일 수 있음

단점:

  • 특정 메뉴 아이템을 수정하거나 내용을 확인할 때 스크롤해야 하기 때문에 불편할 수 있음
  • 구조가 복잡해져 가독성이 떨어짐

분리된 접근 방식

장점:

  • 각 메뉴의 아이템 정보를 한 눈에 확인할 수 있어 수정에 용이
  • 각 아이템 속성을 명확하게 관리할 수 있어 가독성이 높음

단점:

  • 코드가 길어질 수 있으며, 메뉴가 많아질 경우 관리가 복잡해질 수 있음
  • 새로운 메뉴 아이템을 추가할 때 여러 개의 코드를 수정해야할 수도 있음

결론

메뉴 아이템의 구조를 개선하는 방법을 고민하게 되었습니다. 분리된 접근 방식은 각 메뉴 아이템의 정보를 명확히 확인할 수 있어 유용했지만, 코드의 길이가 길어지는 단점도 있었습니다. 반면, 통합된 접근 방식은 중복을 줄여 코드 유지보수에 유리했으나, 가독성이 떨어지는 단점이 있었습니다.

이 포스트를 작성하며 좋은 코드란 이 포스트를 작성하며 좋은 코드란 단순히 코드의 중복을 줄이는 것이 아니라, 코드를 읽는 사람이 쉽게 이해할 수 있어야 한다는 것을 깨달았습니다. 앞으로는 이러한 교훈을 바탕으로, 코드의 가독성을 높이고 유지보수를 용이하게 할 수 있는 방법을 지속적으로 고민해야겠습니다.

This post is licensed under CC BY 4.0 by the author.