ELI5: 종속성 주입

"Dependency Injection에 대해 알려주세요"... 이것은 취업 면접에서 제가 받은 첫 번째 기술적인 질문이었습니다. 당시 신입 코딩 부트캠프 졸업생으로서 저는 솔직히 전혀 몰랐습니다... 저는 즉시 바보가 된 것 같은 느낌이 들었고 제가 그것에 대해 아무것도 모른다는 것을 인정해야 했습니다. 면접관이 친절하게 설명해 주었지만 그 시점에서 나는 거의 듣지 않았고 이미 내가 일자리를 얻지 못할 것이라는 것을 알고 있었습니다. 몇 년 후 나는 개념을 이해하고 솔직히 말해서 사람들이 그것에 대해 말할 때 사용하는 모든 멋진 컴퓨터 과학 용어에도 불구하고 실제로는 그렇게 복잡한 생각이 아닙니다.

이게 뭐야?



종속성부터 시작하겠습니다. 종속성은 코드 조각이 제대로 작동하기 위해 의존하는 것입니다. 종속성 주입은 단순히 내부에 기능을 구축하는 것이 아니라 외부에서 해당 기능을 전달(주입)하는 것입니다. 책임의 분리입니다.

예시



사용자 테이블이 있는 데이터베이스가 있고 서버에서 ID로 해당 사용자 중 한 명을 GET하려고 한다고 가정합니다. 종속성 주입 전에 해당 코드는 다음과 같을 수 있습니다.

// imports database functionality
import dbConnection from 'dbConnection'

// router code
router.get('/:id', (request) => {

  // connects to our database
  const mockDatabaseConnection = new dbConnection({
    user: 'mockUsername',
    host: 'mockHost',
    database: 'mockDatabase',
    password: 'mockPassword',
    port: 'mockPort'
})

  // grabs the id from our request
  const { id } = request.params

  // builds a query object
  const query = `SELECT * FROM users WHERE id = ${id}`

  // queries our database
  mockDatabaseConnection.query(query)
    .then((response) => {
      // handles response
    })
})


여기에서 꽤 많은 일이 벌어지는 것을 볼 수 있습니다. 그리고 이 아키텍처를 사용하여 다른 테이블에 대한 또 다른 경로를 만들려면 이 코드를 많이 복제해야 합니다. 그렇다면 이 코드를 분할하여 더 모듈화할 수 있는 방법이 있을까요? 코드를 보면 우리가 만들 수 있는 몇 가지 다른 그룹이 있습니다.
  • 요청을 처리하고 요청에서 쿼리 개체를 빌드하는 코드
  • 데이터베이스와 관련된 모든 것을 처리하는 코드(연결 및 쿼리)
  • 반환된 응답 또는 오류로 수행할 작업을 처리하는 코드

  • 모든 요청에서 공유할 수 있도록 데이터베이스 코드를 다른 파일로 추출해 보겠습니다.

    DATABASE FILE
    
    // imports database functionality
    import dbConnection from 'dbConnection'
    
    // connects to our database
    const mockDatabaseConnection = new dbConnection({
        user: 'mockUsername',
        host: 'mockHost',
        database: 'mockDatabase',
        password: 'mockPassword',
        port: 'mockPort'
    })
    
    // a simple query function that we can export
    const queryFunction = (query) => {
      return mockDatabaseConnection.query()
    }
    
    export default queryFunction
    


    이제 해당 코드를 내부에 구축하는 대신 라우팅 함수에 삽입할 수 있습니다.

    // imports database functionality
    import queryFunction from 'DatabaseFile'
    
    // GET user by id
    router.get('/:id', (request) => {
    
      // grabs the id from our request
      const { id } = request.params
    
      // builds a query object
      const query = `SELECT * FROM users WHERE id = ${id}`
    
      // queries our database
      queryFunction(query)
        .then((response) => {
          //handles response
        })
    })
    
    


    훨씬 깔끔해 보이는군요... 의존성 주입의 예입니다! 경로 코드가 의존하는 경로 코드에 데이터베이스 코드를 주입하고 있습니다. 시각적으로 더 깔끔해지는 것 외에도 이것의 이점은 무엇입니까?
  • 모듈식이며 재사용이 가능합니다. 이제 새 경로를 작성할 때마다 데이터베이스를 매번 다시 작성하지 않고 경로에 간단히 주입할 수 있습니다.
  • 테스트하기가 훨씬 더 깨끗하고 쉽습니다. 우리의 데이터베이스 코드는 하나의 파일에 있으며 한 번에 모두 테스트할 수 있습니다. 모든 경로에서 데이터베이스 코드를 테스트해야 하기 전에! (단위 테스트 작성을 싫어하는 사람으로서 이것은 엄청납니다.)
  • 논리적으로 분리되어 각 부분이 서로 독립적으로 필요한 작업을 수행합니다. 라우터 코드가 데이터베이스 연결과 관련되어야 하는 이유는 무엇입니까? 데이터베이스를 변경하려면 어떻게 해야 합니까? 종속성 주입을 사용하여 데이터베이스 파일을 업데이트하기만 하면 됩니다. 모든 단일 경로에서 변경해야 하기 전에... 이런.
  • 코드는 DRY입니다(반복하지 마세요)

  • TL; DR



    종속성 주입은 코드를 더 작은 재사용 가능한 클래스/객체로 분리한 다음 매번 다시 빌드하지 않고 해당 기능을 다른 객체에 주입할 때 발생합니다. 이것은 코드를 재사용, 테스트 및 유지 관리하기 쉽게 만듭니다.

    좋은 웹페이지 즐겨찾기