의존성 주입을 사용해야 하는 이유
11264 단어 injectiondependencietypescript
이 글에서 나는 몇 가지 기본 개념과 그것이 어떻게 당신의 삶을 더 쉽게 만들어줄지 설명할 것입니다.
먼저... 종속성이란 무엇입니까?
주변 세계에서 종속성은 다른 엔터티 또는 리소스에 의해 안정성이 결정되는 엔터티 또는 항목의 존재 상태입니다. 예를 들어, 아이들은 생존을 위해 부모에게 의존하고, 식물은 물과 햇빛에 의존하는 식입니다.
코딩 설정에서 종속성의 정의가 다소 변경됩니다.
클래스 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는 대부분의 경우에 필수적입니다.
더 공부
class SignUpController
constructor (
private readonly addAccount: AddAccount,
private readonly validation: Validation,
private readonly authentication: Authentication
) { }
...
}
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는 대부분의 경우에 필수적입니다.
더 공부
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
})
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는 대부분의 경우에 필수적입니다.
더 공부
Reference
이 문제에 관하여(의존성 주입을 사용해야 하는 이유), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/vitoraa/why-you-should-use-dependency-injection-31h9텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)