본문 바로가기

FrontEnd

리액트 프로젝트의 결합도를 관리하는 방법

반응형

리액트 프로젝트의 결합도와 응집도를 관리하는 방법에 대해 알아봅니다.

결합도 분석 단위는 모듈(폴더, 패키지)이라 볼 수 있습니다.

응집도 분석 단위는 라인 입니다.

같이 보면 좋은 글 !

https://itchallenger.tistory.com/644

 

리액트 컴포넌트의 응집도를 관리하는 방법

같이 보면 좋은 글! : https://itchallenger.tistory.com/646 리액트 프로젝트의 결합도를 관리하는 방법 원문 : https://betterprogramming.pub/coupling-cohesion-552b022492b2 Organizing Modules in React Pro..

itchallenger.tistory.com

https://ui.toast.com/weekly-pick/ko_20150522

 

Javascript의 커플링 측정

이 글은 커플링을 Javascript기반 예제를 통해 설명한다. 먼저 커플링이란 서로 다른 객체 또는 모듈간의 관계를 뜻한다. 그리고 그 관계의 방법은 조금씩은 다르지만 거의 유사한 패턴이므로 측정

ui.toast.com

원문 : https://betterprogramming.pub/coupling-cohesion-552b022492b2

 

Organizing Modules in React Project — Low Coupling and High Cohesion

Design robust applications

betterprogramming.pub

서로 분리되어있지만 각각은 응집력 있는 방식으로 시스템 요소를 구성합니다. 즉, 낮은 결합도과 높은 응집도를 선호합니다.
이 규칙은 이미 들어보셨을 것입니다.
이 규칙이 무엇을 의미하며 실제로 어떤 이익을 가져다 줄까요?

TLDR

  • 응집도를 논하는 각 모듈(디렉터리) 범위에서 요소들은 같이 변해도 무관합니다.
  • 결합도는 의존대상의 변경이 의존중인 모듈의 변경을 유발함을 의미합니다.
    • 의존하는 모듈의 변경이 의존하고 있는 모듈의 변경을 유발하지 않도록 결합도를 관리해야 합니다.
    • 양뱡향 결합은 피해야 합니다.
  • 결합도를 낮추기 위해선 먼저 모듈 간의 응집도를 높여야 합니다.
  • 응집도를 높이기 위해선 같이 사용하는 것들, 변하는 것들을 하나의 모듈로 묶습니다.
    • Place code as close to where it's relevant as possible
    • Things that change together should be located as close as reasonable.

결합도 (coupling)

커플링은 시스템 요소 간의 연결과 같습니다.
높은 결합도는 시스템의 요소간에 혼란스러운 연결이 있는 경우입니다.
 
기술적으로 커플링의 정도를 측정할 수 있습니다.
이것은 시스템 요소(함수, 객체, 모듈 등) 간의 연결 수입니다.
이 규칙은 시스템이 가능한 가장 적은 수의 연결을 가져야 한다고 명시하고 있습니다.
이 경우 예상되는 연결만 있는지 확인할 수 있으며 이를 효과적으로 관리할 수 있습니다.
결합도

 

사실, 연결 수를 계산하는 쉬운 방법이 있는지 확실하지 않습니다.
또한 나는 이 숫자를 계산하는 것이 유용하다고 생각하지도 않습니다.
예를 들어 어떤 식으로든 연결 수를 계산했는데 이  수치가 "100"이라고 가정해 보겠습니다.
많은가요? 적은가요?
기존 시스템을 개선하기 위해 이 수치를 어떻게 사용할 수 있나요?
저는 여기에 어떻게 대답해야 할지 잘 모르겠습니다.
그렇다면 기존 시스템을 어떻게 개선할 것인가?

단 하나의 가장 적절한 방법은 이후 논의할 기술을 따르는 것입니다.


응집도 (cohesion)

응집도는 시스템의 요소가 몇 가지 기준에 따라 함께 그룹화되는 경우입니다.
응집도가 낮다는 것은 앱 요소에 명확한 경계가 없다는 것을 의미합니다.
이것은 엉망으로 보일 수 있습니다.

 

우리가 "그룹"이라고 부를 수 있는 많은 것들이 있습니다:
  • module
  • class
  • React component (both class and functional)
  • namespace
  • service
  • 등등,,,

응집도

그런데 이것이 왜 유용한가요?
  • 응집력 있는 시스템에서는 요소 간의 연결이 훨씬 적기 때문입니다.
  • "결합"과 "응집"이라는 용어는 항상 함께 사용됩니다.
  • 높은 응집도는 연결 수를 줄이고 시스템을 보다 쉽게 관리하고 확장할 수 있도록 합니다.

응집도와 결합도

다양한 사례를 살펴보겠습니다.
아래에서 "결합"과 "응집" 사이의 연결을 설명하는 다이어그램을 찾을 수 있습니다.
이는 응용 프로그램을 분석하고 개선 계획을 만드는 데 유용할 수 있습니다.

 

1. 이상적(Ideal) : 낮은 결합도, 높은 응집도

응집도를 논하는 범위에서 요소들은 같이 변해도 무관합니다.
결합도는 의존대상의 변경이 의존중인 모듈의 변경을 유발하는 것을 의미힙니다.
의존하는 모듈의 변경이 의존하고 있는 모듈의 변경을 유발하지 않도록 결합도를 관리해야 합니다.
또한 양뱡향 결합은 피해야 합니다.
 
우리의 목표입니다.
유지보수가 쉽고 확장하기 쉽습니다.
대부분의 경우 개발자는 논리적 부분으로 나눌 수 있는 시스템의 한 부분을 작업하는 것을 좋아합니다.
이것은 개발 과정에서 더 낮은 정신적 압박으로 이어집니다.
이 경우 요소 간의 연결이 어떻게 보이는지 아래에서 볼 수 있습니다.

Ideal: low coupling, high cohesion

이 규칙을 따르는 방법은 어렵지 않습니다.
관련 있는 요소를 그룹으로 구성하고(위 참조) 그룹 간의 연결을 설정합니다.
  • 같이 쓰이는 요소
  • 같이 변하는 요소

프로젝트 구조는 아래와 같이 보일 것입니다.

이와 관련하여 참고할 문서가 있습니다.
https://kentcdodds.com/blog/colocation

 

Colocation

Maintainability through colocation

kentcdodds.com

https://kentcdodds.com/blog/state-colocation-will-make-your-react-app-faster

 

State Colocation will make your React app faster

How state colocation makes your app not only more maintainable but also faster.

kentcdodds.com

같이 변하는 것들을 같은 모듈로 관리합니다.
같이 사용하는 것들을 같은 모듈로 관리합니다.
app
├── components
│   ├── dropdown
│   .   ├── container.js
│       ├── component.js
│       ├── utils.js
│       ├── use-options-search.js
│       └── index.js
├── utils
│   ├── find-tree-items
│   .   ├── find-tree-items.js
│       ├── find-tree-items.test.js
│       └── index.js
├── hooks
│   ├── use-previous
│   .   ├── use-previous.js
│       ├── use-previous.test.js
│       └── index.js
├── index.js
.
이제 인위적인 코드 예제를 살펴보겠습니다.
// app/index.js

import usePrevious from 'hooks/use-previous';
import Dropdown from 'components/dropdown';

const App = () => {
  const [value, setValue] = useState('');
  const previousValue = usePrevious(provalue);

  const handleChange = useCallback((event) => {
    setValue(event.value);
  }, []);

  return (
    <>
      <span>Pevious value: {previousValue}</span>
      <Dropdown
        onChange={handleChange}
        options={[/*...*/]} />
    </>
  );
};

// ...

2. God Module (갓 모듈) : 높은 결합도, 높은 응집도

최악의 경우이며 모든 팀이 피해야합니다.
이러한 시스템은 관리하기 어렵고 적절한 방식으로 확장될 수 없습니다.

God module: high coupling, high cohesion

이 상황에서는 시스템 요소가 엉망입니다. 이것이 코드 구조에서 어떻게 보일지 상상해 봅시다.
app
├── components
│   ├── dropdown
│   .   ├── container.js
│       ├── component.js
│       ├── utils.js
│       ├── use-options-search.js
│       ├── use-user-options-data.js
│       ├── use-language-options-data.js
│       └── index.js
├── index.js
.

코드 예제는 다음과 같습니다.

// app/component/dropdown/container

import useOptionsSearch from './use-options-search';
import useUserOptionsData from './use-user-options-data';
import useLanguageOptionsData from './use-language-options-data';
import * as utils from './utils';
import Dropdown from './component';

const DropdownContainer = (props) => {
  const optionsSearch = useOptionsSearch(/*...*/);
  const userOptionsData = useUserOptionsData(/*...*/);
  const langageOptionsData = useLanguageOptionsData(/*...*/);

  const optionsData = useMemo(() => {
    switch (props.dataType) {
      case 'user':
        return userOptionsData;
      case 'language':
        return languageOptionsData;
      default:
        return [];
    }
  }, [props.dataType]);

  return (
    <Dropdown {/*...*/} />
  );
};

DropdownContainer.propTypes = {
  onChange: PropTypes.func.isRequired,
  dataType: PropTypes.oneOf(['user', 'language']).isRequired,
};

export default DropdownContainer;
여기서 문제는 공유 컴포넌트에 데이터 논리가 내장되어 있다는 것입니다.
이 컴포넌트는 재사용할 수 있어야 하며 새 데이터 타입이 영향을 주어서는 안 됩니다.
이러한 설계를 피하고 모든 특정 논리를 재사용 가능한 컴포넌트 외부에 보관하십시오.
주 : 렌더링 (반복, 조건부 렌더링, 스타일) 관련 로직만 View Asset Component에 넣음

3. Wrong Boundaries (잘못된 경계) : 높은 결합도, 낮은 응집도

가장 흔하게 볼 수 있는 프로젝트 구조입니다.
추가 설명 없이 다이어그램과 예제를 살펴보겠습니다.

Wrong boundaries: high coupling, low cohesion

프로젝트 구조입니다.

app
├── components
│   ├── dropdown
│   .   ├── container.js
│       ├── component.js
│       └── index.js
├── utils
│   ├── find-tree-items
│   │   ├── find-tree-items.js
│   │   ├── find-tree-items.test.js
│   │   └── index.js
│   ├── dropdown-utils
│   .   ├── ...
│       .
├── hooks
│   ├── use-previous
│   │   ├── use-previous.js
│   │   ├── use-previous.test.js
│   │   └── index.js
│   ├── use-dropdown-options-search
│   .   ├── use-dropdown-options-search.js
│       ├── use-dropdown-options-search.test.js
│       └── index.js
├── index.js
.


경계가 잘못되었음을 분명히 이해하시기 바랍니다. 이러한 앱은 첫 번째 예와 같이 재설계되어야 합니다.

4. Destructive Decoupling (파괴적 결합 분해): 낮은 결합도, 낮은 응집도

이번에도 자세한 설명은 생략하고 그림을 보겠습니다.

Destructive Decoupling: low coupling, low cohesion

프로젝트 구조는 다음과 같습니다.

app
├── dropdown.js
├── find-tree-items.js
├── find-tree-items.test.js
├── dropdown-utils.js
├── use-previous.js
├── use-previous.test.js
├── use-dropdown-options-search.js
├── use-dropdown-options-search.test.js
├── index.js
.

 

코드 예제입니다.
// app/index.js

import usePrevious from './use-previous';
import Dropdown from './dropdown';

const App = () => {
  const [value, setValue] = useState('');
  const previousValue = usePrevious(provalue);

  const handleChange = useCallback((event) => {
    setValue(event.value);
  }, []);

  return (
    <>
      <span>Pevious value: {previousValue}</span>
      <Dropdown
        onChange={handleChange}
        options={[/*...*/]} />
    </>
  );
};

// ...
  • 모듈(파일)의 사용 범위를 파악하기가 다소 어렵습니다.
  • 같은 파일에 위치한 정보가 너무 많습니다.

이 콘텐츠가 마음에 드셨기를 바라며 강력한 애플리케이션을 설계하는 데 도움이 되기를 바랍니다!

좀 더 디테일하게 코드 레벨에서 결합도 살펴보기

https://itchallenger.tistory.com/651?category=0 

 

자바로 알아보는 결합도(커플링)

https://www.linkedin.com/pulse/types-coupling-ahmed-adel/ Types of Coupling As our Software grows, and the communication between it's Modules gets more complex, we come to the point where "Coupling"..

itchallenger.tistory.com

 

반응형