[React] SOLID 원칙 기반 클린 코딩 5 - DIP

olwooz·2023년 1월 6일
1

React

목록 보기
7/8

DIP - Dependency Inversion Principle

한국어로는 의존성 역전 원칙이라고 부른다.
고수준 모듈저수준 모듈에 의존해서는 안 되고, 둘 다 추상화에 의존해야 한다는 원칙이다.
고수준 모듈은 모듈의 본질적인 기능을 나타내고,
저수준 모듈은 고수준 모듈의 기능을 수행하기 위한 각각의 동작들을 나타낸다.

고수준 모듈보다는 저수준 모듈에서 변화가 더 빈번하게 일어나기 때문에 고수준 모듈저수준 모듈에 의존한다면 결국 고수준 모듈도 매번 저수준 모듈의 변화에 맞춰 같이 변화해야만 하는 상황이 발생한다.
따라서 DIP는 '자신보다 변하기 쉬운 것에 의존하면 안 된다는 원칙'으로도 이해할 수 있다.

로그인을 예로 들어 설명하자면 고수준 모듈은 로그인 기능 자체이고, 저수준 모듈은 로그인 방식, 즉 '로그인 요청 api를 호출해 응답을 받아오는 것'이라고 볼 수 있다.

import api from '~/common/api'

const LoginForm = () => {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

  const handleSubmit = async (evt) => {
    evt.preventDefault()
    await api.login(email, password)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" value={email} onChange={e => setEmail(e.target.value)} />
      <input type="password" value={password} onChange={e => setPassword(e.target.value)} />
      <button type="submit">Log in</button>
    </form>
  )
}

위 코드에선 고수준 모듈LoginForm저수준 모듈api에 의존하고 있다.
따라서 api에 변경이 생기거나 아예 다른 모듈을 사용하게 된다면 그에 맞춰 LoginForm도 변경돼야 할 것이다.
이를 개선하려면 LoginForm에서 직접적으로 api를 사용하는 대신, 추상화 컴포넌트를 만들어 그 안에 모듈을 정의한 후 LoginForm과 연결해주면 된다.

// ConnectedLoginForm.tsx

import api from '~/common/api'

const ConnectedLoginForm = () => {
  const handleSubmit = async (email, password) => {
    await api.login(email, password)
  }

  return (
    <LoginForm onSubmit={handleSubmit} />
  )
}
// LoginForm.tsx

type Props = {
  onSubmit: (email: string, password: string) => Promise<void>
}

const LoginForm = ({ onSubmit }: Props) => {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

  const handleSubmit = async (evt) => {
    evt.preventDefault()
    await onSubmit(email, password)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" value={email} onChange={e => setEmail(e.target.value)} />
      <input type="password" value={password} onChange={e => setPassword(e.target.value)} />
      <button type="submit">Log in</button>
    </form>
  )
}

ConnectedLoginForm이라는 추상화 컴포넌트로 인해 LoginFormapi에 직접적으로 의존하는 대신 '로그인 요청 api를 호출해 응답을 받아오는 것'을 추상화한onSubmit이라는 모듈에 의존하게 되면서 DIP를 준수하는 코드가 된다.
이는 결국 컴포넌트/모듈 간 결합도를 최소화하는 효과가 있어 OCP와도 밀접한 관계가 있다.

세 줄 요약

  1. DIP는 자신보다 변하기 쉬운 것에 의존하면 안 된다는 원칙이다.
  2. 추상화를 통해 고수준 모듈이 저수준 모듈에 의존하는 문제를 해결한다.
  3. DIP를 준수해 컴포넌트/모듈 간 결합도를 최소화한다.

참고 자료

0개의 댓글