Featured image of post 14. 컴포넌트 결합

14. 컴포넌트 결합

4부 - 컴포넌트 원칙

지금부터 다룰 세 가지 원칙은 컴포넌트 사이의 관계를 설명한다.

컴포넌트 사이의 관계는 응집도와 마찬가지로 개발 가능성과 논리적 설계 사이의 균형을 다룬다.

컴포넌트 구조와 관련된 아키텍처를 침범하는 힘은 기술적이며, 정치적이고, 가변적이다.

ADP: 의존성 비순환 원칙

컴포넌트 의존성 그래프에 순환(Cycle)이 있어서는 안된다.

숙취 증후군 The morning after syndrome
무언가를 작동하게 만들놓았는데, 무언가를 의존하고 있던 무언가를 다른 사람이 수정하여 동작하지 않는 현상을 저자는 숙취 증후군이라 부른다.


숙취 증후군은 많은 개발자가 동일한 소스 파일을 수정하는 환경에서 발생한다.

소수의 개발자로 구성된 작은 프로젝트에서는 큰 문제가 되지 않지만, 프로젝트와 개발팀 규모가 커지면 큰 문제로 다가온다.

지난 수십 년 동안 이 문제의 해결책으로 두 가지 방법이 발전되어 왔다.

  • 주 단위 빌드(Weekly build)
  • 의존성 비순환 원칙(Acyclic Dependencies Principle)

주 단위 빌드

중간 규모의 프로젝트에서는 흔하게 사용되는 방법으로 일주일의 첫 4일 동안은 각자 작업한 후 금요일이 되면 변경된 코드를 모두 통합하여 시스템을 빌드한다.

이 접근법은 5일 중 4일 동안 개발자가 걱정없이 개발할 수 있다는 장점이 있지만, 금요일에 통합과 관련된 막대한 업보를 치러야한다는 단점을 가진다.

  1. 프로젝트가 커질수록 통합은 하루만에 끝마치는게 불가능해진다.
    • 통합 일정이 길어진다.
  2. 개발보다 통합에 드는 시간이 늘어나면서 팀의 효율성도 서서히 나빠진다.
    • 빌드 주기가 길어진다.

이러한 과정이 반복되며 효율성을 유지하기 위해 빌드 일정을 계속 늘려야 하고, 빌드 주기가 늦어질수록 프로젝트가 감수할 위험은 더 커지게된다.

  • 통합과 테스트를 수행하기가 점점 어려워진다.
  • 빠른 피드백이 주는 장점을 잃는다.

순환 의존성 제거하기

이 문제의 해결책은 개발 환경을 릴리스 가능한 컴포넌트 단위로 분리하는 것이다.

이를 통해 컴포넌트는 개별 개발자 또는 단일 개발팀이 책임질 수 있는 작업 단위가 된다.

  1. 개발자가 해당 컴호넌트가 동작하도록 만든 후, 해당 컴포넌트를 릴리스하여 다른 개발자가 사용할 수 있도록 만든다.
  2. 컴포넌트에 릴리스 번호를 부여하고, 다른팀에서 사용할 수 있는 디렉터리로 이동시킨다.
  3. 개발자는 자신만의 공간에서 해당 컴포넌트를 지속적으로 수정한다.
  4. 나머지 개발자는 릴리스된 버전을 사용한다.
  5. 컴포넌트가 새로 릴리스되어 사용할 수 있게 되면, 다른팀에서는 새 릴리스를 적용할 지 결정한다.

특정 컴포넌트가 변경 되더라도 다른 팀에 영향을 즉각 영향을 주지는 않으므로 어떤 팀도 다른 팀에 의해 좌우되지 않는다.

  • 각 팀은 특정 컴포넌트가 새로 릴리스되면 자신의 컴포넌트를 해당 컴포넌트에 맞게 수정할 시기를 스스로 결정할 수 있다.
  • 통합은 작고 점진적으로 이뤄진다.

이 같은 작업 절차는 단순하며 합리적이여서 널리 사용되는 방식이나, 성공적으로 동작하려면 컴포넌트 사이의 의존성 구조를 반드시 관리해야한다.

컴포넌트 다이어그램에서는 컴포넌트를 조립하여 애플리케이션을 만드는 다소 전형적인 구조로, 중요한 점은 컴포넌트 간의 의존성 구조이다.

  • 의존성 관계는 일방향이다.
  • 어느 컴포넌트에서 시작하더라도, 의존성 관계를 따라가면서 최초의 컴포넌트로 되돌아갈 수 없다.
  • 어떠한 컴포넌트의 새로운 릴리스를 만들게 되면 영향을 받는 컴포넌트는 의존성 화살표를 거꾸로 따라가면 알 수 있다.
    • Presenters > View, Main
    • Main은 새로 릴리스되더라도 영향을 받는 컴포넌트가 전혀 없다.

Presenters 컴포넌트를 만드는 개발자가 이 컴포넌트를 테스트하려고 한다면, 현재 사용중인 버전의 InteractorsEntities를 이용해서 Presenters 자체 버전을 빌드하면 그만이다.

  • 테스트를 구성할 때 대체로 적은 노력이 든다.
  • 고려해야 할 변수도 상대적으로 적다.

시스템 전체를 릴리스해야 할 때가 오면 릴리스 절차는 상향식으로 진행된다.

  1. Entities 컴포넌트를 컴파일하고, 테스트하고, 릴리스한다.
  2. DatabaseInteractors에서도 동일한 과정을 거친다.
  3. Presenters, Views, Controllers, Authorizer 순으로 진행한다.
  4. 마지막으로 Main을 처리한다.

구성요소 간 의존성을 파악하고 있으면 시스템을 빌드하는 방법을 알 수 있다.

순환이 컴포넌트 의존성 그래프에 미치는 영향

요구사항 발생으로 EntitiesUser 클래스가 AuthorizerPermissions 클래스를 사용한다고 가정하면, 아래와 같이 순환 의존성이 발생한다.

Database 컴포넌트를 릴리스하려면 Entities와의 호환되어야 하므로 Authorizer과 확인도 필요하며, AuthorizerInteractors와도 의존하므로 세 개의 컴포넌트가 사실상 하나의 거대한 컴포넌트가되어 릴리스 하기 어려워진다.

해당 컴포넌트의 개발자들은 항상 정확하게 동일한 릴리스를 사용해야하므로 모두 서로에게 얽매이게 된다.

Entites 컴포넌트를 테스트할 때도 AuthorizerInteractors 까지도 반드시 빌드하고 통합해야한다.

이처럼 순환이 생기면 컴포넌트를 분리하기가 상당히 어려워진다.

  • 단위테스트를 하고 릴리스를 하는 일도 굉장히 어려워진다. 에러가 쉽게 발생한다.
  • 모듈의 개수가 많아짐에 따라 빌드 관련 이슈는 기하급수적으로 증가한다.
  • 컴포넌트를 어떤 순서로 빌드해야 올바를지 파악하기가 상당히 힘들어진다.
    • 순환이 생기면 올바른 순서라는 것 자체가 없을 수 있다.

순환 끊기

컴포넌트 사이의 순환을 끊고 의존성을 다시 DAG로 원상복구하는 일은 언제라도 가능하다.

의존성 역전 원칙 적용

  1. User가 필요로하는 메서드를 제공하는 인터페이스를 생성한다.
  2. 이 인터페이스를 Entities에 위치시키고, Authorizer에서 이 인터페이스를 상속받는다.

이를 통해 EntitiesAuthorizer 사이의 의존성을 역전시킬 수 있고, 이를 통해 순환을 끊을 수 있다.

새로운 컴포넌트

  1. EntitiesAuthorizer가 모두 의존하는 새로운 컴포넌트를 만든다.
  2. 두 컴포넌트가 모두 의존하는 클래스들을 새로운 컴포넌트로 이동시킨다.

흐트러짐(Jitters)

새로운 컴포넌트를 생성하는 두 번째 해결책에서 시사하는 바는 요구사항이 변경되면 컴포넌트 구조도 변경될 수 있다는 사실이다.

애플리케이션이 성장함에 따라 컴포넌트 의존성 구조는 서서히 흐트러지며 또 성장하므로, 의존성 구조에 순환이 발생하는지를 항상 관찰하여 순환이 발생하면 어떤 식으로든 끊어야 한다.

이로인해 새로운 컴포넌트를 생성하거나 의존성 구조가 더 커질수도 있다.

하향식(Top-down) 설계

지금까지 논의로 컴포넌트 구조는 하향식으로 설계될 수 없다는 결론에 다다른다.

컴포넌트는 시스템에서 가장 먼저 설계할 수 있는 대상이 아니며, 오히려 시스템이 성장하고 변경될 때 함께 진화한다.


컴포넌트와 같이 큰 단위로 분해된 구조는 고수준의 기능적인 구조로 다시 분해할 수 있다고 기대하기 때문에 동의하지 않을 수 있지만, 컴포넌트 의존성 다이어그램은 애플리케이션의 기능을 기술하는 일과는 거의 관련이 없다.

컴포넌트 의존성 다이어그램은 애플리케이션의 빌드 가능성과 유지보수성을 보여주는 지도이므로 빌드하거나 유지보수할 소프트웨어가 없다면 빌드와 유지보수에 관한 지도 도한 필요 없기 때문에 컴포넌트 구조는 프로젝트 초기에 설계할 수 없다.

하지만 프로젝트가 진행되고 발전함에 따라 의존성관리, 영향범위 최소화, 안정적인 컴포넌트, 재사용성 등의 대한 요구로 점점 아키텍처를 새로 만들고 가다듬게 되어 컴포넌트 의존성 그래프는 조금씩 흐트러지고 성장한다.


이처럼 아직 아무런 클래스도 설계하지 않은 상태에서 컴포넌트 의존성 구조를 설계하려고 시도한다면 큰 실패를 맛볼 수 있다.

  • 공통 폐쇄에 대해 파악할 수 없다.
  • 재사용 가능한 요소도 알 수 없다.
  • 컴포넌트 생성 시 대부분 순환 의존성이 발생하게된다.

따라서 컴포넌트 의존성 구조는 시스템의 논리적인 설계에 발맞춰 성장하며 또 진화해야한다.

SDP: 안정된 의존성 원칙

안정성의 방향으로(더 안정된 쪽에) 의존하라.

설계를 유지하다 보면 변경은 불가피하므로 결코 정적일 수 없다.

공통 폐쇄 원칙을 준수함으로써 컴포넌트가 다른 유형의 변경에는 영향받지 않으면서도 특정 유형의 변경에만 민감하게 만들 수 있으며, 이에 맞추어 특정 컴포넌트는 변동성을 지니도록 설계한다.

변동성이 높은(변동이 예상되는) 컴포넌트에 한번 의존하게 되면 변동성이 큰 컴포넌트도 결국 변경이 어려워지므로 변경이 쉽지 않은 컴포넌트가 변동이 예상되는 컴포넌트에 의존하게 만들어서는 절대 안된다.

  • 모듈을 만들 때는 변경하기 쉽도록 설계했지만, 그 모듈에 의존성을 매달아 버리면 해당 모듈도 변경하기 어려워진다.
  • 만든 모듈에서는 한 줄의 코드도 변경되지 않았더라도 변경하는 일이 상당히 도전적인 일이 되어버린다.

안정된 의존성 원칙을 준수하면 변경하기 어려운 모듈이 변경하기 쉽게 만들어진 모듈에 의존하지 않도록 만들 수 있다.

안정성

동전을 세로로 세우면 안정성이 떨어지지만 건드리지 않으면 넘어지지 않는 것 처럼, 안정성은 변화가 발생하는 빈도와는 직접적인 관련이 없다.

웹스터 사전에서는 안정성을 ‘쉽게 움직이지 않는’이라고 정의하는데 이는 변경을 만들기 위해 필요한 작업량과 관련된다.

  • 변경을 위해 필요한 작업량이 많으면 안정적이다.

소프트웨어 컴포넌트를 변경하기 어렵게 만드는 데는 크기, 복잡도, 간결함 등 많은 요인이 있지만, 변경하기 어렵게 만드는 확실한 방법 중 하나는 수 많은 컴포넌트가 해당 컴포넌트에 의존하게 만드는 것이다.

  • 컴포넌트 안쪽으로 들어오는 의존성이 많아지면, 사소한 변경이라도 의존하는 모든 컴포넌트를 만족시키면서 변경하기 위해 많은 노력이 들기 때문에 상당히 안정적이다.

안정된 컴포넌트

  • X는 세 컴포넌트를 책임 responsible진다
    • X에 3개 컴포넌트가 의존하기 때문에 X를 변경하지 말아야할 이유는 3가지이다.
  • X는 독립적이다.
    • 어디에도 의존하지 않으므로 변경되도록 만들 수 있는 외적인 영향이 전혀 없다.

불안정한 컴포넌트

  • 책임성이 없다.
    • 어떤 컴포넌트도 Y에 의존하지 않는다.
  • 의존적이다.
    • 3개 컴포넌트에 의존하므로 변경이 발생할 수 있는 외부 요인이 3가지이다.

안정성 지표

컴포넌트로 들어오고 나가는 의존성의 개수를 세어 컴포넌트가 위치상(Positional) 어느 정도의 안정성을 가지는지 계산할 수 있다.

  • Fan-in: 안으로 들어오는 의존성
    • 컴포넌트 내부의 클래스에 의존하는 컴포넌트 외부의 클래수 개수
  • Fan-out: 바깥으로 나가는 의존성
    • 컴포넌트 외부의 크래스에 의존하는 컴포넌트 내부의 클래수 개수
  • I(불안정성): I = Fan-out / (Fan-in + Fan-out)
    • 0 ~ 1
    • 0이면 최고로 안정된 컴포넌트
    • 1이면 최고로 불안정한 컴포넌트

Fan-inFan-out 지표는 특정 컴포넌트 내부의 클래스에 의존하는, 컴포넌트 외부에 위치한 클래스의 개수를 세어서 계산할 수 있다.

  • I 값이 1이면 어떤 컴포넌트도 해당 컴포넌트에 의존하지 않지만, 해당 컴포넌트는 다른 컴포넌트에 의존한다는 뜻이다.
    • 최고로 불안정한 상태, 책임이 없으며 의존적이다.
    • 자신에게 의존하는 컴포넌트가 없으므로 변경하지 말아야 할 이유가 없다.
    • 다른 컴포넌트에 의존하기 때문에 언젠가는 해당 컴포넌트를 변경해야 할 이유가 있다.
  • I 값이 0이면 해당 컴포넌트에 의존하는 다른 컴포넌트가 있지만, 해당 컴포넌트 자체는 다른 컴포넌트에 의존하지 않는다는 뜻이다.
    • 최고로 안정된 상태, 다른 컴포넌트를 책임지면서 독립적이다.
    • 자신에게 의존하는 컴포넌트가 있으므로 변경하기가 어렵다.
    • 해당 컴포넌트를 변경하도록 강제하는 의존성은 같지 않는다.

SDP에서 컴포넌트 I 지표는 그 컴포넌느가 의존하는 다른 컴포넌트들의 I보다 커야한다고 말한다.

즉, 의존성 방향으로 갈수록 I 지표 값이 감소해야한다.

모든 컴포넌트가 안정적이어야 하는 것은 아니다.

모든 컴포넌트가 최고로 안정적인 시스템이라면 변경이 불가능하다.

이는 바람직한 상황은 아니며, 컴포넌트 구조를 설계할 때 기대하는 것은 불안정한 컴포넌트와 안정된 컴포넌트가 공존하는 상태다.

위 다이어그램은 세 컴포넌트로 구성된 이상적인 구조이다.

추상 컴포넌트

인터페이스만을 포함하는 추상 컴포넌트는 상당히 안정적이므로, 덜 안정적인 컴포넌트가 의존할 수 있는 이상적인 대상이다.

안정적인 Stable의 내부 클래스 U가 불안정한 Flexible의 내부 클래스 C를 사용해야한다면, DIP를 도입해 문제를 해결할 수 있다.

US라는 인터페이스를 생성한 수 UServer 컴포넌트에 넣고, 해당 인터페이스를 구현하도록 하면 StableFlexible에 대한 의존성을 끊을 수 있고, UServer 자체는 어디에도 의존하지 않으므로 안정된 상태이므로, 모든 의존성이 감소하는 방향으로 개선할 수 있다.

SAP: 안정된 추상화 원칙

컴포넌트는 안정된 정도만큼만 추상화되어야 한다.

고수준 정책을 어디에 위치시켜야 하는가?

고수준 아키텍처가 정책 결정과 관련된 소프트웨어는 자주 변경되서는 절대로 안되는 소프트웨어이다.

따라서 시스템에서 고수준 정책을 캡슐화하는 소프트웨어는 반드시 안정된 컴포넌트(I = 0)에 위치해야 한다.

불안정한 컴포넌트(I = 1)는 반드시 변동성이 큰 소프트웨어, 즉 쉽고 바르게 변경할 수 있는 소프트웨어만을 포함해야 한다.

하지만 고수준 정책을 안정된 컴포넌트에 위치시키면, 그 정책을 포함하는 소스코드는 수정하기 어려워져 시스템 전체 아키텍쳐가 유연성을 잃게 된다.

개방 폐쇄 원칙의 추상화를 통해 컴포넌트가 최고로 안정된 상태이면서도 동시에 변경에 충분히 대응할 수 있을 정도로 유연하게 만들 수 있다.

안정된 추상화 원칙

안정된 추상화 원칙은 안정성과 추상화 정도 사이의 관계를 정의한다.

  • 안정된 컴포넌트는 추상 컴포넌트여야한다.
  • 이를 통해 안정성이 컴포넌트를 확장하는 일을 방해해서는 안된다.
  • 불안정한 컴포넌트는 반드시 구체 컴포넌트여야한다.
    • 컴포넌트 내부의 구체적인 코드를 쉽게 변경할 수 있어야 하므로

따라서 안정적인 컴포넌트라면 반드시 인터페이스와 추상 클래스로 구성되어 쉽게 확장할 수 있어야 한다.

안정된 컴포넌트가 확장 가능해지면 유연성을 얻게 되고 아키텍처를 과도하게 제약하지 않게 된다.

SDP에서는 의존성이 반드시 안정성의 방향으로 향해야 한다고 말하며, SAP에서는 안정성이 결국 추상화를 의미한다고 말하기 때문에 SAP와 SDP를 결합하면 컴포넌트에 대한 DIP와 같다.

  • 따라서 의존성은 추상화의 방향으로 향하게 된다.

추상화 정도 측정하기

SDP + SPA 조합이 컴포넌트에 대한 DIP라고 언급했었지만, DIP는 클래스에 대한 원칙이므로 추상적이거나 그렇지 않거나 둘중 하나이다.

하지만 SDP + SAP 조합은 컴포넌트에 대한 원칙이므로 컴포넌트의 어떤 부분은 추상적이면서 다른 부분은 안정적일 수 있다.

A 지표는 컴포넌트의 클래스 총 수 대비 인터페이스와 추상 클래스의 개수를 단순히 계산하여 컴포넌트의 추상화 정도를 측정한 값이다.

  • Nc: 컴포넌트의 클래스 개수
  • Na: 컴포넌트의 추상 클래스와 인터페이스 개수
  • A: 추상화 정도
    • A = Na / Nc

A지표는 0과 1 사이의 값을 가지며, 0이면 추상 클래스가 하나도 없다는 뜻, 1이면 추상클래스만 포함한다는 뜻이다.

주계열: Main Sequence

  • 최고로 안정적이며 추상화된 컴포넌트는 (0, 1)
  • 최고로 불안정하며 구체화된 컴포넌트는 (1, 0)

컴포넌트는 추상화와 안정화 정도가 다양하므로 두 지점에만 분포할 수는 없다.

따라서 A/I 그래프 상에서 컴포넌트가 위치할 수 있는 합리적인 지점을 정의하는 궤적이 있을 것이라 가정해 볼 수 있으며, 이 궤적은 컴포넌트가 절대로 위치해서는 안 되는 영역(배제할 구역)을 찾는 방식으로 추론할 수 있다.

고통의 구역: Zone of Pain

(0, 0) 주변 구역에 위치한 컴포넌트는 매우 안정적이며 구체적이므로 굉장히 뻣뻣한 상태로 바람직한 상태는 아니다.

  • 추상적이지 않으므로 확장할 수 없다.
  • 안정적이므로 변경하기 어렵다.

제대로 설계된 컴포넌트라면 (0, 0) 근처에는 위치하지 않을 것이라 보는게 일반적이다.

일부 소프트웨어 엔티티는 고통의 구역에 위치한다.

  • 데이터베이스 스키마
    • 변동성이 매우 높다.
    • 극단적으로 구체적이다.
    • 많은 컴포넌트가 의존한다.
    • OO 애플리케이션과 데이터베이스 사이에 위치한 인터페이스는 관리하기 굉장히 어렵다.
    • 스키마가 변경되면 대체로 고통을 수반한다.
  • 유틸리티 라이브러리(String 컴포넌트)
    • I가 1일지라도, 실제로는 변동성이 거의 없다.
    • 속한 클래스가 모두 구체 클래스이다.
    • 광범위하게 사용되어 수정하면 혼란을 초래할 수 있다.

변동될 가능성이 거의 없는 컴포넌트는 (0, 0)에 위치했더라도 해롭지 않다.

고통의 구역에서 문제가 되는 경우는 변동성이 있는 소프트웨어 컴포넌트이다.

쓸모없는 구역: Zone of Uselessness

(1, 1)에 위치한 컴포넌트는 최고로 추상적이지만 누구도 그 컴포넌트에 의존하지 않기 때문에 쓸모없는 컴포넌트이며 이로인해 쓸모없는 구역이라 부른다.

이 영역에 존재하는 소프트웨어 엔티티는 폐기물과도 같다.

  • 대부분 누구도 구현하지 않은 채 남겨진 추상 클래스

쓸모없는 구역 내부 깊숙이 자리잡은 컴포넌트는 이러한 엔티티의 상당 부분을 포함할 가능성이 높다.

배제 구역 벗어나기

변동성이 큰 컴포넌트 대부분은 두 배제 구역으로부터 가능한 멀리 떨어뜨려야 한다.

주계열에 위치한 컴포넌트는 자신의 안정성에 비해 너무 추상적이지도 않고, 추상화 정도에 비해 너무 불안정하지도 않다.

  • 쓸모없지 않으면서 고통을 안겨 주지도 않는다.
  • 추상화된 수준에 어울릴 정도로만 다른 컴포넌트가 의존한다.
  • 구체화된 수준에 어울릴 정로로만 다른 컴포넌트에 의존한다.

컴포넌트가 위치할 수 있는 가장 바람직한 지점은 주계열의 두 종점이다.

하지만 대규모 시스템에서 일부 컴포넌트는 완벽히 추상적이거나 완전하게 안정적일 수 없으므로, 이러한 컴포넌트는 주 계열 바로 위에 또는 가깝게 위치하게 설계하는 것이 이상적이다.

주계열과의 거리

추상화 정도를 측정하는 A/I 그래프에서 (1, 0), (0, 1)를 연결하는 직선인 주계열을 기준으로 해당 컴포넌트가 얼마나 떨어져있는지 거리를 측정하여 지표으로 사용할 수 있다.

  • D: 거리, D = |A + I - 1|
    • 유효범위: [0, 1]
    • 0이면 주계열 바로 위에 위치, 1이면 주계열로부터 가정 멀리 위치

이 지표를 통해 컴포넌트가 주계열에 대체로 일치하도록 설계되었는지(추상화, 구체화 수준에 어울리는 의존성을 갖는지) 분석하고, 거리가 먼 컴포넌트들을 개선할 수 있다.

통계적 활용

값으로 계산할 수 있으므로 통계적으로 분석 가능해진다.

설계에 포함된 컴포넌트들의 D를 계산하고 이들의 평균과 분산을 측정하였을때, 주계열에 일치하도록 설계되었다면 평균과 분산은 0에 가까워진다.

  • 분산을 통해 다른 컴포넌트에 비해 극히 예외적인 컴포넌트르 식별할 수 있으므로 관리 한계를 결정하는데 유용할 수 있다.

시간에 따른 변화 확인

각 컴포넌트의 D 값을 시간의 흐름에 따라 확인해보면, 해당 컴포넌트가 시간이 지남에 따라 의존성이 어떻게 변화하는지 확인할 수 있다.

이를 통해 주계열에서 멀리 벗어난 컴포넌트들을 분석하여 인사이트를 얻는 것도 가능하다.

결론

의존성 관리 지표는 설계의 의존성과 추상화 정도가 휼륭한 패턴이라고 생각하는 수준에 얼마나 잘 부합하는지를 측정한다.

하지만 지표는 임의로 결정된 표준을 기초로 한 측정값이므로 진리가 아니며, 의존성의 좋고 나쁨을 지표로만 판단해서는 안된다.

그러나 이러한 지표를 통해 이상을 확인할 여지가 충분하고, 이를 상세하게 분석하여 아키텍처 개선에 유용하게 사용될 수 있다.