의존성 주입을 사용해야 하는 이유

소프트웨어 개발자로서 나는 내가 원하는 것보다 더 오래 종속성 주입(DI)을 배웠습니다. 첫 만남 이후 그것은 첫사랑이었다.

이 글에서 나는 몇 가지 기본 개념과 그것이 어떻게 당신의 삶을 더 쉽게 만들어줄지 설명할 것입니다.

먼저... 종속성이란 무엇입니까?



주변 세계에서 종속성은 다른 엔터티 또는 리소스에 의해 안정성이 결정되는 엔터티 또는 항목의 존재 상태입니다. 예를 들어, 아이들은 생존을 위해 부모에게 의존하고, 식물은 물과 햇빛에 의존하는 식입니다.

코딩 설정에서 종속성의 정의가 다소 변경됩니다.

클래스 A가 클래스 B의 일부 기능을 사용할 때 클래스 A는 클래스 B의 종속성을 갖는다고 합니다. Typescript에서 다른 클래스의 메소드를 사용하려면 먼저 해당 클래스의 객체를 생성해야 합니다. 예를 들어 등록 요청을 수신하는 컨트롤러 클래스가 있습니다.

SignUp 컨트롤러 작업은 다음과 같습니다.
  • 요청에서 필드의 유효성을 검사합니다. 수신된 이름, 이메일, 비밀번호, 비밀번호 확인이 제대로 되었는지 확인하세요.
  • 사용자를 등록합니다. 사용자 데이터를 데이터베이스에 저장합니다.
  • 사용자를 인증하고 토큰을 보냅니다.

  • 이 예에서 우리는 가입 클래스에 최소한 세 개의 종속성이 있음을 분명히 알 수 있습니다. DI가 없으면 다음과 같이 클래스를 작성할 수 있습니다.

    class SignUpController{
      async handle (httpRequest: HttpRequest): Promise<HttpResponse> {
          const validation = new Validation() // First dependency
          const error = validation.validate(httpRequest.body)
          if (error) {
            .... return 400 Bad Request
          }
    
          const { name, email, password } = httpRequest.body
    
          const addAccount = new AddAccount() // Sencond dependency
          const account = await addAccount.add({ email, password, name })
    
          if (!account) {
            ... return 403 Forbidden
          }
    
          const authentication = new Authentication() // Third dependency
          const accessToken = await this.authentication.auth({ email, password })
          ...return 200 with a token JWT
      }
    }
    


    의존성 주입이란?



    종속성 주입은 클래스를 종속성에서 독립적으로 만드는 프로그래밍 기술입니다.

    위의 코드에서 종속성이 메서드 내에서 초기화되는 것을 볼 수 있습니다. 그것은 코드를 변경하기가 덜 쉽고(더 많은 결합) 테스트하기 더 어려워지기 때문에 좋은 코딩 방법이 아닙니다.

    다른 클래스의 개체를 만드는 대신 SignUp 클래스의 생성자에서 개체를 받을 수 있습니다. 따라서 이름: 종속성 주입. 클래스 내부에 객체를 주입합니다.

    class SignUpController
        constructor (
          private readonly addAccount: AddAccount,
          private readonly validation: Validation,
          private readonly authentication: Authentication
        ) { }
    
        ...
    
    }
    


    DI가 디커플링에 도움이 되는 이유는 무엇입니까?



    AddAccount 위의 코드에서 유효성 검사와 인증은 인터페이스입니다. 이것은 우리 클래스가 어떤 클래스가 각각의 메소드를 구현할 것인지에 대해 독립적으로 만들 수 있도록 합니다. 우리 클래스는 MongoDB나 Postgres를 사용하는지, 자체 클래스를 사용하여 유효성을 검사하는지 또는 타사 패키지를 사용하는지 상관하지 않습니다.

    따라서 인터페이스를 준수하는 한 종속성 구현의 일부를 변경하기로 결정한 경우 메서드를 변경할 필요가 없습니다.

    DI가 테스트에 도움이 되는 이유는 무엇입니까?



    예를 들어 설명하겠습니다.

    제공된 이메일이 이미 사용 중인 경우 메서드가 403을 반환하는지 테스트해야 한다고 상상해 보십시오.

    첫 번째 시나리오 - DI를 사용하지 않음

    test('Should return 403 if email is already in use', async () => {
        const signUpController = new SignUpController()
        await signUpController .handle(makeFakeRequest('[email protected]')) // Creating the first user with the email
        const httpResponse = await signUpController.handle(makeFakeRequest('[email protected]')) // Trying to create the second user with the same email
        expect(httpResponse).toEqual(forbidden(new FieldInUseError('Email'))) // Expect to receive 403
    })
    


    두 번째 시나리오 - DI 사용

    test('Should return 403 if AddAccount returns null', async () => {
        const addAccountStub = new AddAccountStub() // Creating a stub class that implements the AddAccount interface
        const signUpController = new SignUpController(addAccountStub, ...) // It has to send the others dependencies too
        jest.spyOn(addAccountStub, 'add').mockReturnValueOnce(null) // Setting a null return on the method add of the addAccountStub object
        const httpResponse = await sut.handle(makeFakeRequest('[email protected]')) // Creating the user with the email
        expect(httpResponse).toEqual(forbidden(new FieldInUseError('Email')))
    })
    


    코드의 양 측면에서 첫 번째 시나리오는 첫 번째 시나리오보다 짧은 것 같습니다. 맞아요!! DI를 사용하면 더 많은 코드를 작성해야 하지만 종속성의 반환을 제어할 수 있는 더 많은 권한이 있습니다. DI가 단위 테스트를 작성하는 데 도움이 되는 주된 이유는 종속성을 조롱하고 모든 것을 제어할 수 있기 때문입니다. 메소드에 대해 테스트하는 경우 테스트를 방해하지 않기 위해 다른 메소드의 반환을 조롱합니다.

    결론



    DI는 더 많은 코드를 작성하고 복잡성을 증가시키는 것이 직관적이지 않기 때문에 사용하지 않는 사람에게 첫눈에 이해하기가 쉽지 않지만 단위 테스트를 작성하기 시작하는 순간 DI가 얼마나 중요한지 분명합니다. 다른 클래스 종속성 구현의 각 세부 사항을 알아야 할 필요성이 줄어듭니다.
    변경을 허용하고 코드를 더 재사용할 수 있습니다. 내 관점에서 DI는 대부분의 경우에 필수적입니다.

    더 공부



  • https://www.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it-7578c84fa88f/
  • 좋은 웹페이지 즐겨찾기