JS용 클래스와 CSS용 클래스는 명확히 분리돼야 합니다(관심사 분리 원칙 사례)

, , ,

유지보수 용이성

개발자 대부분은 신규 개발보다는 유지보수를 합니다. 유지보수 용이성을 확보하는 개발이 매우 중요한 이유입니다.

그런 관점에서 볼 때 프론트엔드 개발에서 중요한 한 측면은 CSS와 JS의 관심사를 주의깊게 분리하는 것입니다. 서로 연동되는 것을 최대한 차단해야 하는 것이죠.

그중 손쉽게 실천 가능하면서도 매우 중요한 것은 CSS용 클래스와 JS에서 사용하는 클래스를 분리하는 것입니다. 보통 JS 전용 클래스명에는 js-라는 접두어를 붙여 CSS와는 무관하고 JS에서만 사용하는 클래스라는 표시를 합니다.

CSS용 클래스와 JS용 클래스를 분리하는 것은 코드 유지보수성을 높이는 핵심적인 방법 중 하나입니다. 둘을 구분하지 않고 사용하면 스타일용 클래스의 이름을 변경했을 때 JS의 동작이 깨지게 되는 경우가 발생합니다.

그러면 유지보수가 힘들어지고 최악의 경우에는 클래스명을 변경하는 것이 두려워지는 지경에 이르게 됩니다.

최악의 시나리오

한 번 최악의 시나리오를 상상해 봅시다.

한 JS 팀이 Vue의 드래거블 라이브러리를 사용하면서 아래와 같은 코드를 작성했습니다.

<draggable ... handle=".my-handler-class">
<div class="item">
<div class="my-handler-class">≡</div>
...
</div>
...
</draggable>

여기서 드래그용 핸들러로 지정한 요소는 .my-handler-class 클래스를 가진 요소입니다.

그런데 이 클래스는 이름에서도 알 수 있듯 CSS 스타일링을 위해 사용되고 있는 클래스입니다. 이 JS 개발자는 이미 있는 클래스를 활용하는 것이 HTML 코드의 클래스 글자를 늘리지 않는 비용 효율적인 방법이라고 생각했던 거죠.

일단 이 코드는 문제없이 잘 동작합니다.

그런데 1년 후, 다른 개발자가 HTML을 살펴 보다가 클래스명을 수정하기로 결심합니다. my-라는 접두사와 -class라는 접미사가 굳이 필요하지 않다는 생각을 한 것이죠. 그래서 이 개발자는 .handler라고 심플한 이름으로 클래스명을 수정했습니다. 이 개발자는 스타일이 깨지지 않는다는 것을 확인하고 수정을 제품단에 적용했습니다.

하루가 지나고 드래그 앤 드롭 기능이 작동하지 않는다는 연락이 JS 팀에 가게 됩니다. 클래스명을 수정한 CSS팀 개발자는 이를 알지도 못합니다. JS 팀은 한참 동안 JS쪽 코드 오류를 찾아 헤매다가 결국 .my-handler-class라는 클래스가 더이상 존재하지 않는 것이 문제의 원인이라는 것을 깨닫게 됩니다.

JS 팀은 허탈한 마음과 짜증(다른 팀이 한 짓이라는) 속에 CSS 팀에게 컴플레인을 넣습니다. JS 이벤트가 걸려 있을지 모르니 앞으로는 함부로 CSS 클래스명을 변경하거나 클래스의 위치를 옮기지 말라고 말입니다.

이제 CSS 팀은 더이상 기존의 CSS 클래스명을 변경할 수 없게 됩니다. 심지어 클래스를 다른 HTML로 옮기지도 못하게 됐습니다. 옮기면 JS 동작이 달라질 수도 있으니 말입니다. 이러다 보니 목록의 모양이 더이상 카드 모양이 아닌데도 클래스명은 card라는 이름을 달고 있게 되는 경우도 발생합니다. CSS 클래스명을 함부로 고치면 안 되기 때문이죠. JS를 넘어 CSS 작성 그 자체에까지 대혼란이 준비되고 있습니다.

이 모든 것이 JS용 클래스와 CSS 클래스를 분리하지 않은 탓입니다. 몇몇 사람들은 분리를 해야 한다는 생각을 하게 됩니다만 이미 프로젝트 전체에 걸쳐 이런 결합이 퍼져 있기 때문에 어떻게 할 방법이 없습니다.

대대적인 리팩토링을 하지 않는 이상 CSS팀은 거대한 고통 속에 유지보수를 지속해야 할 것입니다. 그런데 앞선 일처리가 아주 관료적이었다는 것에 비춰 보면 대대적인 리팩토링은 요원해 보입니다.

프로그래밍 원칙의 관점에서 살펴 본다면, 이 모든 것은 관심사 분리 원칙을 위반한 대가입니다.

person holding white and blue plastic blocks
관심사를 분리하지 않으면, 도미노처럼 이쪽의 코드 수정이 전혀 예기치 않은 저쪽 기능에 영향을 미치게 됩니다. (사진 Bradyn Trollip)

간단한 해결책

해결책은 간단했습니다. 애초 JS 개발자가 JS 이벤트 핸들러용 클래스를 별도로 만들어서 넣었으면 됩니다. .my-handler-class에 직접 이벤트 핸들링을 하지 않고, .js-drag-handler라는 클래스를 붙여서 사용했으면 됩니다.

<draggable ... handle=".js-drag-handler">
<div class="item">
<div class="handler js-drag-handler">≡</div>
...
</div>
...
</draggable>

이렇게 하면 CSS용 클래스명을 변경해도 JS 코드에는 전혀 영향을 미치지 않게 됩니다. HTML 구조가 변경돼도 CSS 개발자들은 이 클래스가 JS용 핸들러라는 사실을 쉽게 인지할 수 있기 때문에 JS 코드를 분석하지 않고도 적당한 요소에 이 클래스를 붙여줄 수 있습니다.

프로젝트 전반에서 이러한 일관성을 유지한다면 JS 동작이 깨질 것을 전혀 염려하지 않고 HTML, CSS 유지보수를 진행할 수 있게 됩니다.

즉, CSS용 클래스와 JS용 클래스를 분리하는 이 방법은 코드의 의도를 명확히 하고, 유지보수를 손쉽게 하도록 돕습니다. 이런 이점에 비한다면 HTML 클래스명에 몇 글자가 더해지는 것은 완전히 부차적인 일입니다.

이런 습관이 하나하나 쌓여 간다면 유지보수 작업이 두렵지 않게 되고, 신속하고 기민한 대응을 할 수 있게 되는 것입니다.

CSS용 클래스와 JS용 클래스를 꼭 분리하도록 합시다.

여러분은 어떤 경험을 갖고 있는지 공유해 주시겠어요? 👉 댓글 바로 가기


IDE의 힘을 빌린다면 어떨까

제가 사례로 든 클래스명 변경의 경우는 IDE에서 CSS 클래스명 리팩토링 기능을 이용하거나, 전체 찾기 바꾸기를 함으로써 해결이 가능할 수도 있습니다. CSS 클래스가 HTML 클래스 속성 안에만 들어 있고 JS에서 온전한 CSS 클래스명을 사용하고 있다면 확실히 리팩토링 기능으로 손쉽게 커버가 가능합니다.

그러나 js- 접두어를 사용한 클래스로 완전히 분리하는 것이 여전히 낫습니다. CSS를 수정할 때 JS까지 신경쓰는 것은 인지 부하를 낳기 때문입니다. 유지보수 용이성이라는 측면에서 볼 때 관심사 분리는 프로그램 자체뿐 아니라 사람에게도 도움이 되는 것이죠.

IDE로 깔끔히 해결되는 시나리오가 있는 것이 사실이지만, 반대로 IDE가 커버하지 못하거나 상당히 성가시게 하는 구체적인 시나리오를 여럿 상정할 수 있습니다.

  • CSS 쪽에서 클래스 리팩토링을 할 때 vue 파일 내의 handler 속성은 함께 변하지 않습니다(PhpStorm의 경우). Search in comments and strings(주석과 문자열에서도 찾기)를 켜도 마찬가지입니다.
  • 전체 찾기 바꾸기를 할 때 CSS 클래스명이 유니크하지 않고 매우 일반적인 경우(ex. handler) 상당히 오랜 노력을 들여야 하는 작업이 됩니다. 클래스명이 유니크하다면(예컨대 .c-sucject__handler 같은 것처럼) 다행이지요.
  • JS에서 핸들러용 클래스명을 전체 문자열로 갖고 있지 않고 변수로 처리한 경우(제가 든 사례를 예시로 든다면 "my-" + name + "-class" 식이 될 겁니다)엔 답이 없습니다. 그런 경우가 있겠나 싶을 수도 있겠지만 있습니다.
  • 클래스명을 바꾸지 않고 클래스를 다른 요소 쪽으로 옮겨 붙이는 경우. 드래그 핸들러는 이래도 돌아갈 가능성이 더 높겠지만 다른 경우에는 JS 동작이 완전히 깨질 수 있습니다.
  • 게다가 사례에서 든 것처럼 각 파트가 협력적이지 않다면 문제는 심각하겠죠. 어쩌면 JS쪽 소스코드에 CSS 팀이 접근하지 못할 수도 있습니다.

리팩토링을 도와주는 여러 도구가 발전해 있지만 역시나 문제 상황이 왔을 때 해결하는 것보다는 애초에 관심사를 분리해 문제 상황을 만들지 않는 것이 유리합니다.


트위터에서 관련한 토론이 벌어졌습니다. 보관합니다.

👇 카테고리 글 목록

, , ,

대표글

댓글 남기기