

컴포넌트는(Component)는 소프트웨어 개발에서 재사용 가능하고 독립적인 기능 또는 모듈을 의미한다.
간단하게 말하면, 프론트엔드에서 컴포넌트는 인터렉션을 통해 필요한 비즈니스 로직을 실행하거나, 스타일, 애니메이션과 같은 시각적인 부분을 표현하는 UI를 적절하게 나눈 것이다.
컴포넌트는 다양한 분야에서 활용되며, 소프트웨어 개발에서는 사용자 인터페이스(UI) 컴포넌트, 데이터베이스 접근 컴포넌트, 네트워킹 컴포넌트 등 다양한 종류의 컴포넌트 등이 있다. 위 그림에서 볼 수 있듯이 사용자 인터페이스 컴포넌트를 기반으로 프로그래밍을 하면 이미 만들어둔 컴포넌트들을 조합하여 화면을 구성할 수 있다.
하드웨어 제품들은 각각 독립된 기능을 가진 모듈로 만들어지며, 회사 상관없이 서로 조합되어 하나의 제품으로 만들어진다. 때문에 문제가 발생할 경우 해당 부품만 교체하면 된다. 그러나 소프트웨어는 독립적으로 개발되지 않으며, 독립적으로 개발되었다고 해도 다른 모듈과의 호환을 생각하지 않는다면 재사용이 어렵고 유지보수 비용이 크게 증가한다. 때문에 소프트웨어 재사용의 중요성과 필요성을 위해 나온 기술이 컴포넌트 기술이다.
재사용성
컴포넌트는 특정 기능 또는 작업을 수행하는 독립적인 단위로, 이를 다른 프로젝트나 시스템에서 재사용할 수 있다. 이는 개발 생산성을 향상시키고 중복 코드를 줄이는 데 도움이 된다.
독립성
컴포넌트는 자체적으로 동작하고 필요한 데이터와 상태를 포함할 수 있다. 소프트웨어 시스템에서 독립적인 업무 또는 기능을 수행하는 모듈로서 이후 시스템을 유지보수하는데 있어 교체가 가능하다.
인터페이스
컴포넌트는 외부와 상호작용하기 위한 인터페이스를 제공한다. 이를 통해 다른 컴포넌트나 시스템은 해당 컴포넌트의 기능을 호출하거나 데이터를 주고받을 수 있다. 또한 컴포넌트 내의 정보는 외부로부터 모두 숨겨지기 때문에 외부에서 접근할 수 있도록 컴포넌트가 제공하는 서비스를 정의한 인터페이스만을 제공하고 컴포넌트를 사용하기 위해서는 어떤 인터페이스를 사용해야 하는지만을 알 수 있다. 이처럼 컴포넌트가 내부 정보를 숨기고 인터페이스만 제공함으로써 소프트웨어도 하드웨어처럼 조립 기반으로 갈 수 있게 되는 것이다.
추상화
컴포넌트는 내부 동작의 구체적인 세부 사항을 숨기고 필요한 기능만 외부에 노출함으로써 추상화의 원칙을 따른다. 이로써 컴포넌트 사용자는 내부 동작을 알 필요 없이 컴포넌트를 활용할 수 있다.
위에서 설명한 컴포넌트의 유래와 특징과 조금 겹치는 내용이지만, 컴포넌트를 분리의 장점을 통해 중요성을 설명하고자 한다.
컴포넌트 분리의 가장 설득력 있는 주장 중 하나는 유지보수성에서의 극적인 개선이다. 기능을 별개의 컴포넌트로 분리함으로써 한 부분의 변경이 의도치 않게 다른 부분에도 영향을 미치지 않도록 한다. 비슷한 맥락으로, 애플리케이션이 성장함에 따라 확장 가능한 구조를 유지하는 것은 점점 힘들어진다. 그러나 컴포넌트 분리는 모듈식 아키텍쳐를 장려함으로써 확장을 용이하게 만들어 쉽게 새로운 기능을 개발할 수 있다.
또한 이러한 분리는 업데이트와 디버깅을 단순화한다. 어떤 변경의 범위도 자연스럽게 수정되는 컴포넌트로 한정되기 때문이다.
동일한 구조의 버튼이나 입력 등이 프로젝트 내에서 여러 곳에 사용된다면 모든 컴포넌트에서 따로 작성하는 것보다는 따로 만들어두고 재사용하는 것이 훨씬 효율적이다. 이처럼 컴포넌트를 분리하면 자주 사용되는 컴포넌트를 분리해두고 편리하게 사용할 수 있다.
컴포넌트를 분리하게 되면 한 페이지에 어떤 요소들이 어떻게 배치될 것인가의 문제를 자연스레 해결할 수 있다. 이는 하나의 페이지 혹은 컴포넌트에서 하나의 문제만을 다룰 수 있기 때문에 자연스럽게 팀이 탐색하고 협업하기 쉬운 코드베이스로 이어진다. 또한 컴포넌트가 명확하게 정의되고 분리되어 있을 경우 여러 개발자가 애플리케이션의 다른 부분에서 동시에 작업할 수 있으며 서로의 작업에 방해되지 않는다.
컴포넌트 분리는 본질적으로 테스팅 과정을 단순화한다. 더 작고 잘 정의된 컴포넌트는 개별 기능에 초점을 맞춰 독립적으로 테스트 될 수 있어 애플리케이션의 신뢰성을 향상시킨다.
소프트웨어 테스트의 Unit Test를 실행한다고 생각해보자, 컴포넌트가 적절하게 분리되어 있다면 테스트를 실행하는 것도 아주 간편하다. 그렇지 않고 페이지 하나에 여러 기능과 UI들이 섞여있다면 Unit Test를 실시하기 이전에 각 요소들을 Unit 단위로 나누는 것부터 시작해야한다.
컴포넌트는 View를 추상화하는 것인데, 때문에 적절한 단위로 추상화를 잘하는 것이 컴포넌트를 잘 만드는 것이라고 볼 수 있다. 그렇다면 언제 컴포넌트를 나눠야 할까?
- 단일 책임 원칙: 각 컴포넌트는 하나의 명확한 역할을 수행
- 재사용 가능성: 비슷한 기능을 하는 부분은 독립된 컴포넌트로 분리하여 재사용성을 향상
- 가독성: 코드를 작고 독립적인 컴포넌트로 나누어 가독성 향상
상태와 라이프사이클: 컴포넌트가 관리하는 상태와 라이프사이클 메서드를 고려하여 분리- UI 요소: 서로 다른 UI 요소는 별도의 컴포넌트로 분리
일반적으로 컴포넌트를 나누는 기준 중 가장 많이 선택되는 이유는 재사용성과 복잡성이다. 코드가 재사용 될 가능성이 있을 경우 혹은 코드가 복잡할 경우 새로운 컴포넌트를 만들어 가독성을 개선하고 유지보수 할 수 있도록 만드는 것은 좋은 방식이다.
그러나 컴포넌트를 분리할 때도 주의해야 하는 것들이 있다.
아래의 설명들은 컴포넌트를 분리할 때 자주 발생하는 실수이다.
- 복잡한 컴포넌트 생성
- 하나의 컴포넌트에 여러 책임 추가
- 몇몇 동작하는 부분을 결합하여 컴포넌트 생성
- 비즈니스 로직을 컴포넌트에 추가
컴포넌트 분리의 가장 중요한 원칙은 하나의 컴포넌트는 하나의 기능만 수행하도록 하는 것이다. 때문에 복잡한 컴포넌트 또는 하나의 컴포넌트가 여러 책임을 지지 않도록 주의하여야 한다. 또한, 분리된 컴포넌트가 서로 의존성을 갖게 되면 컴포넌트를 분리한 의미가 없어지기 때문에 하나의 컴포넌트가 변화할 때 다른 컴포넌트가 영향을 받아서는 안 된다.
또한 컴포넌트 분리의 단점으로는 코드의 복잡성 증가, 성능 저하, 상태 관리의 어려움 증가 등이 있다.
컴포넌트를 분리하는 게 마냥 좋은 건 줄 알았는데, 성능 저하와 상태 관리의 어려움 증가 등의 단점도 있다는 것을 알게 되었다. 물론 분리하는 좋은 기준도 있지만,
처음 리액트 프로젝트를 진행할 때 딱히 '왜 컴포넌트를 분리하지?'라는 생각은 하지 못했었던 것 같다. 그냥 코드가 복잡해지니까 따로 관리하는 건가보다,,,~ 하고 넘어갔는데, 컴포넌트를 분리하는 데에는 여러 이유와 기준이 있다는 걸 알게 되었다. 이처럼 아티클을 정리하면서 별 생각 없이 하던 것들의 이유를 뒤늦게나마 알게 되는 것이 좋은 것 같다.
참고 자료
프론트엔드 아키텍처: 컴포넌트를 분리하는 기준과 방법
컴포넌트 분리, 3가지만 기억하자.
HANAMON-컴포넌트(Component)란?
React 컴포넌트 분리 기준