의존성 주입 : 판매 방법 [폐쇄] 컨테이너를 작성했습니다.

나는 의존성 주입 (DI) 및 자동화 된 테스트 의 큰 팬이라는 것을 알게되었습니다 . 나는 하루 종일 그것에 대해 이야기 할 수 있습니다.

배경

최근에 우리 팀은이 큰 프로젝트를 처음부터 새로 만들었습니다. 복잡한 비즈니스 요구 사항이있는 전략적 응용 프로그램입니다. 물론, 나는 그것이 깨끗하고 깨끗하기를 원했습니다. DI를 사용하고 싶었습니다.

저항

문제는 우리 팀에 있었고 DI는 금기입니다. 그것은 몇 번 제기되었지만 신들은 승인하지 않았습니다. 그러나 그것은 나를 낙담시키지 않았습니다.

나의 움직임

이상하게 들릴 수 있지만 타사 라이브러리는 일반적으로 건축가 팀에서 승인하지 않습니다 ( ” , 손가락을 자르지 않도록 Unity , Ninject , NHibernate , Moq 또는 NUnit에 대해 이야기해서는 안됩니다 “). 그래서 기존의 DI 컨테이너를 사용하는 대신 매우 간단한 컨테이너를 작성했습니다. 기본적으로 시작에 대한 모든 종속성을 연결하고 종속성 (생성자 / 속성)을 주입하고 웹 요청 끝에 일회용 객체를 배치합니다. 그것은 매우 가볍고 우리가 필요로하는 것을했습니다. 그런 다음 검토를 요청했습니다.

응답

글쎄요. 나는 강한 저항에 부딪쳤다. 주요 논쟁은 “이 복잡한 계층을 이미 복잡한 프로젝트에 추가 할 필요는 없다”는 것이었다. 또한 “다른 컴포넌트 구현을 연결하는 것과는 다릅니다”. 그리고 “가능한 한 모든 것을 하나의 어셈블리에 넣는 것만으로 간단하게 유지하고 싶습니다. DI는 이점이없는 불필요한 복잡성입니다.”

마지막으로, 내 질문

내 상황을 어떻게 처리하겠습니까? 저는 아이디어를 잘 표현하지 못하며 사람들이 자신의 주장을 어떻게 표현할 것인지 알고 싶습니다.

물론, 나는 나처럼 DI를 선호한다고 가정합니다. 동의하지 않으면 동전의 다른 쪽을 볼 수 있도록 이유를 말하십시오. 동의하지 않는 사람의 관점을 보는 것이 정말 흥미로울 것입니다.

최신 정보

모든 사람의 답변에 감사드립니다. 그것은 실제로 사물을 원근법에 넣습니다. 당신에게 피드백을 줄 다른 눈을 가지고 있으면 충분합니다 .15는 정말 굉장합니다! 이것은 정말 훌륭한 답변이며 다른 측면에서 문제를 볼 수 있도록 도와 주지만 한 가지 답변 만 선택할 수 있으므로 가장 인기있는 답변을 선택합니다. 시간을내어 답변 해 주셔서 감사합니다.

DI를 구현하기에 가장 좋은시기는 아니라고 판단했으며 아직 준비가되지 않았습니다. 대신, 나는 디자인을 테스트 할 수있게 만들고 자동 단위 테스트를 제시하기 위해 노력할 것이다. 필자는 테스트 작성이 추가 오버 헤드이며 추가 오버 헤드가 가치가 없다고 결정되면 개인적으로 디자인을 테스트 할 수 있기 때문에 여전히 승리 상황으로 간주합니다. 그리고 만약 테스트 나 DI가 미래에 선택된다면, 디자인은 쉽게 처리 할 수 ​​있습니다.



답변

반론의 몇 가지를 취하는 것 :

“우리는 가능한 한 모든 것을 하나의 어셈블리에 넣는 것만으로 간단하게 유지하려고합니다. DI는 이점이없는 불필요한 복잡성입니다.”

“우리는 다른 컴포넌트 구현을 연결하는 것을 좋아하지 않습니다”.

원하는 것은 시스템을 테스트 할 수있는 것입니다. 쉽게 테스트 가능하려면 프로젝트 (데이터베이스, 통신 등)의 다양한 계층을 조롱보고 할이 경우 당신이 필요 합니다 구성 요소의 다른 구현에 연결된다.

제공하는 테스트 혜택에 대해 DI를 판매하십시오. 프로젝트가 복잡한 경우에는 우수하고 견고한 단위 테스트가 필요합니다.

또 다른 이점은 인터페이스로 코딩 할 때 구성 요소 중 하나의 더 나은 구현 (빠르고 적은 메모리 부족 등)을 구현할 경우 DI를 사용하면 이전 구현을 교체하기가 훨씬 쉽다는 것입니다. 새로운.

여기서 말하는 것은 DI를 위해 DI를 주장하는 대신 DI가 가져 오는 이점을 해결해야한다는 것입니다. 사람들이 진술에 동의하도록함으로써 :

“X, Y 및 Z가 필요합니다”

그런 다음 문제를 이동하십시오. DI가이 진술에 대한 답변인지 확인해야합니다. 그렇게함으로써 동료들은 자신에게 부과 된 느낌보다 솔루션을 소유하게됩니다.


답변

당신이 쓰고있는 것에서 DI 자체는 금기가 아니지만 DI 컨테이너의 사용은 다릅니다. 예를 들어 생성자에 의해 전달되어야하는 다른 구성 요소를 얻는 독립적 인 구성 요소를 작성하면 팀에 아무런 문제가 없을 것입니다. “DI”라고 부르지 마십시오.

이러한 구성 요소는 DI 컨테이너를 사용하지 않는 것이 지루하다고 생각할 수 있지만 옳습니다. 그러나 팀이 스스로 알아낼 수있는 시간을주십시오.


답변

당신이 요청한 이후로, 나는 당신 팀의 DI를 반대 할 것입니다.

의존성 주입에 대한 사례

내가 “에너지 절약”이라는 물리학의 규칙과 유사한 규칙 인 “복잡성 보존”이라고합니다. 그것은 엔지니어링의 양이 문제에 대한 최적의 솔루션의 총 복잡성을 줄일 수 없다고 말하며, 그 복잡성을 주변으로 옮기기 만하면됩니다. 애플의 제품은 마이크로 소프트보다 덜 복잡하지 않고 단순히 사용자 공간에서 엔지니어링 공간으로 복잡성을 이동시킨다. (하지만 결함이있는 유추입니다. 에너지를 만들 수는 없지만 엔지니어는 매번 복잡성을 만드는 습관이 있습니다. 실제로 많은 프로그래머가 복잡성을 더하고 마술을 사용하는 것을 좋아 합니다이는 프로그래머가 완전히 이해하지 못하는 정의상의 복잡성입니다. 일반적으로 복잡성을 줄이는 것처럼 보이는 것은 복잡성을 다른 곳, 일반적으로 라이브러리로 옮기는 것입니다.

마찬가지로 DI는 클라이언트 개체를 서버 개체와 연결하는 복잡성을 줄이지 않습니다. 그것이하는 일은 Java에서 가져 와서 XML로 옮기는 것입니다. 그것은 모든 것을 하나의 XML 파일로 중앙 집중화하여 진행중인 모든 것을 쉽게 볼 수 있고 코드를 다시 컴파일하지 않고 변경 할 수있는 곳에서 좋습니다. 반면에 XML 파일은 Java가 아니므로 Java 툴링에 사용할 수 없기 때문에 좋지 않습니다. 디버거에서 디버깅 할 수 없으며 정적 분석을 사용하여 호출 계층을 추적 할 수 없습니다. 특히, DI 프레임 워크의 버그는 감지, 식별 및 수정이 매우 어렵습니다.

따라서 DI를 사용할 때 프로그램이 올바른지 증명하기가 훨씬 어렵습니다. 많은 사람들이 DI를 사용하는 프로그램은 테스트 하기가 더 쉽다고 주장 하지만 프로그램 테스트는 버그가 없다는 것을 증명할 수 없습니다 . (연계 된 논문은 약 40 년이되었으며, 일부 참고 문헌이 있고 일부 오래된 관행을 인용하지만, 많은 기본 진술은 여전히 ​​유효합니다. 특히 P <= p ^ n, 여기서 P 시스템에 버그가 없을 확률, p는 시스템 구성 요소에 버그가 없을 확률, n은 구성 요소의 수입니다. 물론이 방정식은 지나치게 단순화되었지만 중요한 사실을 가리 킵니다.) Facebook IPO 중 NASDAQ 충돌이 최근의 예입니다.그들은 코드를 테스트하는 데 1,000 시간을 소비 했지만 여전히 충돌을 일으킨 버그를 발견하지 않았다고 주장했다 . 1,000 시간은 1 년 반이므로 테스트를 밟는 것과 같지 않습니다.

사실, 코드를 공식적으로 증명하는 작업을 수행하는 사람은 거의 없습니다 (완전히 완료하지는 못함). 그러나 증거에 대한 약한 시도조차도 버그를 찾기위한 대부분의 테스트 체제를 능가합니다. L4.verified 와 같은 강력한 증거 시도 는 테스터가 이미 버그의 정확한 특성을 이미 알고 있지 않은 한 테스트하지 않았거나 발견하지 못한 많은 양의 버그를 발견합니다. 검사로 코드를 확인하기 어렵게 만드는 것은 테스트 능력이 향상 되더라도 버그가 발견 될 가능성을 줄이는 것으로 볼 수 있습니다 .

또한 테스트에는 DI가 필요하지 않습니다 . 대체 테스트 버전이 아닌 시스템의 실제 소프트웨어에 대해 시스템을 테스트하는 것을 선호하기 때문에 그 용도로는 거의 사용하지 않습니다. 테스트에서 변경 한 모든 내용은 프로그램을 프로덕션 환경이 아닌 테스트 환경의 리소스로 보내는 속성 파일에 저장됩니다. 프로덕션 데이터베이스 문제를 추적 할 수 있기 때문에 모의 데이터베이스를 코딩하는 데 시간을 소비하는 것보다 프로덕션 데이터베이스의 사본으로 테스트 데이터베이스 서버를 설정하는 데 시간이 많이 걸립니다. 문자 인코딩 문제는 하나의 예일뿐입니다. ) 및 시스템 통합 버그 및 나머지 코드의 버그.

의존성 주입은 의존성 반전에도 필요하지 않습니다 . 정적 팩토리 메소드를 쉽게 사용하여 종속성 반전을 구현할 수 있습니다. 그것은 실제로 1990 년대에 어떻게 이루어 졌는가입니다.

사실, 10 년 동안 DI를 사용해 왔지만 다른 타사 라이브러리를 사용하도록 타사 라이브러리를 구성 할 수 있다는 것이 설득력있는 유일한 장점입니다 (예 : Spring에서 최대 절전 모드를 사용하도록 설정하고 Log4J를 사용하도록 설정) ) 및 프록시를 통한 IoC 활성화 타사 라이브러리를 사용하지 않고 IoC를 사용하지 않는 경우에는 그다지 중요하지 않으며 실제로 부당한 복잡성을 가중시킵니다.


답변

동료 직원이 귀하의 질문에서 말한 것을 고려할 때 귀하가 가진 문제는 기술적이 아니라 정치적인 것입니다. 명심해야 할 두 가지 진언이 있습니다.

  • “항상 사람들 문제입니다”
  • 변화 가 무섭다”

확실히, 당신은 확실한 기술적 이유와 이점으로 많은 반론을 제기 할 수 있지만, 그것은 회사의 다른 사람들과 나쁜 상황에 처하게 할 것입니다. 그들은 이미 원하지 않는 입장을 가지고 있습니다 (지금 상황이 편안해지기 때문에). 따라서 동료 직원과 지속적으로 관계를 유지하면 동료 동료와의 관계가 손상 될 수도 있습니다. 그것이 나에게 일어 났고 결국 몇 년 전에 해고 당했기 때문에 이것을 믿어 라. 이것은 당신이 들어가고 싶지 않은 상황입니다.

문제는 사람들이 현재의 업무 방식 을 변경 하기 전에 어느 정도 신뢰를 얻어야한다는 것입니다 . 건축 가나 기술 책임자의 역할을 맡는 등 신뢰를 많이 받거나 이런 종류의 일을 결정할 수 없다면, 동료를 돌이킬 수있는 일은 거의 없습니다. 회사 문화를 바꾸려면 신뢰를 얻기 위해 설득력과 노력을 기울이는 데 많은 시간이 걸릴 것입니다. 우리는 몇 달 또는 몇 년의 기간에 대해 이야기하고 있습니다.

현재 회사 문화가 당신과 함께 일하고 있지 않다는 것을 알게되면 적어도 다음 직장 인터뷰에서 물어볼 다른 것을 알고 있습니다. 😉


답변

DI를 사용하지 마십시오. 잊어 버려.

특정 종속성을 “만들거나”찾아서 객체에 전달 하는 GoF 팩토리 패턴 의 구현을 작성하십시오. 그러나 DI라고 부르지 말고 복잡한 일반 프레임 워크를 작성하지 마십시오. 간단하고 관련성을 유지하십시오. DI 로의 전환이 가능하도록 종속성과 클래스가 올바른지 확인하십시오. 그러나 공장을 마스터로 유지하고 범위를 극도로 제한하십시오.

시간이 지나면 언젠가 DI로 전환되기를 바랍니다. 리드는 제 시간에 결론에 도달하도록하고 푸시하지 마십시오. 그것에 도달하지 않더라도 최소한 코드는 DI의 장점 중 일부 (예 : 단위 테스트 가능 코드)를 갖습니다.


답변

개체를 단위 테스트하고 조롱하기 위해 DI를 극도로 끌어 올린 프로젝트를 보았습니다. DI 구성 자체가 프로그래밍 코드가되어 실제 코드처럼 시스템을 실행하는 데 필요한 구성이 많았습니다.

테스트 할 수없는 적절한 내부 API가 없기 때문에 시스템이 현재 어려움을 겪고 있습니까? 시스템을 DI 모델로 전환하면 유닛 테스트를 더 잘할 수 있기를 바라고 있습니까? 코드를 단위 테스트하기 위해 컨테이너가 필요하지 않습니다. DI 모델을 사용하면 Mock 객체로 단위 테스트를보다 쉽게 ​​수행 할 수 있지만 필수는 아닙니다.

전체 시스템을 한 번에 DI와 호환되도록 전환 할 필요는 없습니다. 단위 테스트를 임의로 작성해서는 안됩니다. 기능 및 버그 작업 티켓에서 코드를 발견 할 때 코드를 리팩터링하십시오. 그런 다음 터치 한 코드를 쉽게 테스트 할 수 있는지 확인하십시오.

CodeRot을 질병으로 생각하십시오. 임의로 해킹을 시작하고 싶지 않습니다. 환자가 있고 아픈 부위가 보이면 그 부위와 그 주위의 물건을 고치기 시작합니다. 해당 영역이 깨끗해지면 다음 영역으로 넘어갑니다. 조만간 코드의 대부분을 다루게 될 것이며이 “대규모”아키텍처 변경이 필요하지 않았습니다.

나는 DI와 Mock 테스트가 상호 배타적이라는 것을 좋아하지 않습니다. 그리고 DI를 사용하여 더 나은 단어가 부족하여 진행된 프로젝트를 본 후, 나는 혜택을 보지 않고 지칠 것입니다.

DI를 사용하는 것이 적합한 곳이 있습니다.

  • 스토리 데이터에 대한 전략을 교환하기위한 데이터 액세스 계층
  • 인증 및 권한 부여 계층.
  • 사용자 인터페이스 테마
  • 서비스
  • 자신의 시스템 또는 타사에서 사용할 수있는 플러그인 확장 점.

각 개발자가 DI 구성 파일의 위치를 ​​알도록 요구합니다 (컨테이너를 코드를 통해 인스턴스화 할 수는 있지만 실현하려는 이유는 무엇입니까?). RegEx를 수행하려고 할 때 실망 스럽습니다. 아 IRegExCompiler, DefaultRegExCompiler 및 SuperAwesomeRegExCompiler가 있습니다. 그러나 코드의 어디에서 Default를 사용하고 SuperAwesome을 사용하는지 분석 할 수는 없습니다.

누군가 나에게 더 나은 것을 보여 주면 내 말이 저를 설득하려고 하면 내 성격이 더 잘 반응 할 것입니다. 시스템을 개선하기 위해 시간과 노력을 기울일 누군가에 대해 할 말이 있습니다. 많은 개발자들이 제품을 진정으로 개선하기에 충분한 관심을 갖고있는 것은 아닙니다. 시스템을 실제로 변경하여 그들에게 갈 수 있고 그것이 더 쉽고 쉬운 방법을 보여줄 수 있다면, 그것은 온라인 조사보다 더 가치가 있습니다.

요약하면, 시스템 변경에 영향을 미치는 가장 좋은 방법은 각 패스에 대해 현재 만지고있는 코드를 천천히 개선하는 것입니다. 조만간 시스템을 더 나은 것으로 바꿀 수있게 될 것입니다.


답변

DI는 침입 컨트롤 컨테이너 또는 모의 프레임 워크를 필요로하지 않습니다. 간단한 설계를 통해 코드를 분리하고 DI를 허용 할 수 있습니다. 기본 제공 Visual Studio 기능을 통해 단위 테스트를 수행 할 수 있습니다.

공정하게 말하면, 동료들은 한 가지 지적 할 점이 있습니다. 이러한 라이브러리를 잘못 사용하면 (그리고 익숙하지 않기 때문에 학습에 어려움이있을 수 있음) 문제가 발생할 수 있습니다. 결국 코드가 중요합니다. 테스트를 위해 제품을 망치지 마십시오.

이러한 시나리오에서는 타협이 필요하다는 것을 기억하십시오.