SOLID / DI / IoC를 깨뜨릴 수있는 구실을 소위 "교차 관련 문제"라고합니까?


43

동료들은 "로깅 / 캐싱 / 등은 교차하는 문제"라고 말하고 어디에서나 해당하는 싱글 톤을 사용하여 진행합니다. 그러나 그들은 IoC와 DI를 좋아합니다.

SOLI D 원칙 을 어기는 것이 실제로 유효한 변명 입니까?


27
나는 SOLID 원칙이 어쨌든 자신도 모르게 따라가는 데 필요한 경험이있는 사람들에게만 유용하다는 것을 알게되었습니다.
svidgen

1
나는 "크로스 컷팅 관심사"라는 용어가 꽤 특정한 용어 (측면과 관련이 있음)이며 반드시 싱글 톤과 동의어 인 것은 아니라는 것을 알았습니다. 로깅은 동일한 방법으로 여러 위치에 일반 메시지를 기록하려는 경우 (예 : 전화를 건 사람 또는 다른 감사 유형 로깅과 함께 서비스 방법에 대한 모든 호출을 기록)한다는 점에서 교차 문제가 될 수 있습니다. 그러나 로깅 (일반적인 의미에서)은 모든 곳에서 사용되기 때문에 크로스 커팅 문제가 아니라고 주장합니다. 나는 이것이 실제로 일반적인 용어는 아니지만 이것이 "유비쿼터스 관심사"라고 생각한다.
Pace

4
@svidgen SOLID 원리는 모르는 사람들이 코드를 검토하고 왜 그렇게했는지 물어볼 때 유용합니다. 원칙을 지적하고 "그 이유"라고 말하는 것이
좋습니다.

1
로깅이 특별한 경우라고 생각하는 예가 있습니까? 일반적으로 사용중인 X 프레임 워크의 일부로 일부 데이터를 리디렉션하는 것은 매우 간단한 채널입니다.
ksiimson

답변:


42

아니.

SOLID는 불가피한 변경을 설명하기위한 지침으로 존재합니다. 당신이 있습니까 정말 ... 로깅 라이브러리, 또는 대상을 변경하려고하지 않거나 필터링 및 포맷, 또는 결코? 당신이 있습니까 정말 ... 당신의 캐싱 라이브러리, 또는 대상, 또는 전략, 또는 범위 지정 또는 변경하지 않을?

물론입니다. 상기 적어도 , 당신은 테스트를 위해 그 (것)들을 분리하기 위해 제정신 방식으로 이러한 것들을 조롱 할 것입니다. 테스트를 위해 격리하려는 경우 실제 이유로 격리하려는 비즈니스 이유가 발생할 수 있습니다.

그러면 로거 자체 가 변경을 처리 할 것이라는 주장을 얻게 됩니다. "아, 대상 / 필터링 / 포맷 / 전략이 바뀌면 설정 만 변경하면됩니다!" 그것은 쓰레기입니다. 이제 이러한 모든 것을 처리하는 God Object가있을뿐 아니라 정적 분석을 얻지 않고 컴파일 시간 오류가 발생하지 않는 XML (또는 이와 유사한)로 코드를 작성하고 있습니다. 실제로 효과적인 단위 테스트를받을 수 없습니다.

SOLID 지침을 위반하는 경우가 있습니까? 물론. 때로는 상황 이 바뀌지 않을 수도 있습니다 (완전히 다시 작성하지 않아도 됨). 때때로 LSP를 약간 위반하는 것이 가장 깨끗한 솔루션입니다. 때때로 고립 된 인터페이스를 만드는 것은 가치가 없습니다.

그러나 로깅 및 캐싱 (및 기타 유비쿼터스 간 절단 문제)은 그렇지 않습니다. 일반적으로 지침을 무시할 때 발생하는 커플 링 및 설계 문제의 훌륭한 예입니다.


22
그러면 어떤 대안이 있습니까? 당신이 쓰는 모든 수업에 ILogger를 주입합니까? 로거가 필요한 모든 수업에 데코레이터를 작성하십니까?
Robert Harvey

16
네. 어떤 것이 의존성이라면 그것을 의존성으로 만드십시오 . 그리고 그 수단 너무 많은 의존성, 또는 당신이 가서는 안 로거 곳을 통과하는 경우 - 좋은 , 지금 당신은 당신의 디자인을 수정할 수 있습니다.
Telastyn


20
내가 독단적 IoC와 관련하여 실제로 문제는 거의 모든 현대 코드 가 주입되거나 추상화되지 않은 것에 달려 있다는 것 입니다. 예를 들어 C #을 작성하면 종종 추상화 String하거나 모듈에서 벗어나지 Int32않을 List것입니다. 변화를 계획 하는 것이 합리적 이고 제정신 인 정도 입니다. 그리고 대부분 명백한 "핵심"유형을 넘어서서, 변화 할 가능성을 분별하는 것은 실제로 경험과 판단의 문제입니다.
svidgen

6
@ svidgen-교의 IoC를 옹호하는 것으로 내 대답을 읽지 않았기를 바랍니다. 그리고 우리가 이러한 핵심 유형 (및 신중한 다른 것들)을 추상화하지 않았다고해서 전역 List / String / Int / etc를 갖는 것이 괜찮다는 것을 의미하지는 않습니다.
Telastyn

38

이것이 "크로스 컷팅 문제"라는 용어의 요점입니다. 이는 SOLID 원칙에 맞지 않는 것을 의미합니다.

이상주의가 현실과 만나는 곳입니다.

SOLID를 처음 접하는 사람들과 교차 절단은 종종 이러한 정신적 도전에 부딪칩니다. 괜찮아, 놀라지 마 모든 것을 SOLID에 적용하려고 노력하지만 SOLID가 의미가없는 로깅 및 캐싱과 같은 몇 가지 장소가 있습니다. 크로스 컷팅은 SOLID의 형제입니다.


9
합리적이고 실용적이고 독단적이지 않은 답변.
user1936

11
교차 절단 문제로 5 가지 SOLID 원칙이 모두 어긋난 이유를 말씀해 주시겠습니까? 이해하는데 문제가 있습니다.
Doc Brown

4
네. 나는 각 원칙을 개별적으로 "파괴"할만한 충분한 이유를 생각할 수있다. 그러나 5 가지를 모두 깨뜨릴 단 하나의 이유는 아닙니다!
svidgen

1
단위 테스트를 위해 싱글 톤 로거 / 캐시를 조롱해야 할 때마다 벽에 머리를 부딪치지 않는 것이 이상적입니다. 웹 애플리케이션을 가지고 HttpContextBase있지 않은 상태에서 단위 테스트를하는 것이 어떤 것인지 상상해보십시오 . 나는이 수업이 없다면 나의 현실이 실제로 신맛이 나는 것을 확신한다.
devnull

2
@devnull은 아마도 그 자체가 교차 절단 문제가 아니라 문제 일 것입니다 ...
Boris the Spider

25

로깅을 위해 나는 생각합니다. 로깅은 광범위 하며 일반적으로 서비스 기능과 관련이 없습니다. 로깅 프레임 워크 싱글 톤 패턴을 사용하는 것이 일반적이며 잘 이해되고 있습니다. 당신이하지 않으면, 당신은 어디에서나 로거를 작성하고 주입 하고 당신은 그것을 원하지 않습니다.

위의 한 가지 문제는 누군가가 '그러나 로깅을 어떻게 테스트 할 수 있습니까?' 라고 말할 것입니다. . 내 생각은 실제로 로그 파일을 읽고 이해할 수 있다고 주장하는 것 외에도 일반적으로 로깅을 테스트하지 않는다는 것입니다. 로깅 테스트를 보았을 때 일반적으로 누군가 클래스가 실제로 무언가를 수행 했다고 주장해야하며 피드백을 얻기 위해 로그 메시지를 사용하고 있기 때문입니다. 나는 오히려 그 클래스에 리스너 / 옵저버를 등록하고 호출되는 테스트를 주장합니다. 그런 다음 해당 관찰자 내에 이벤트 로깅을 넣을 수 있습니다.

그러나 캐싱은 완전히 다른 시나리오라고 생각합니다.


3
지금까지 FP에서 약간의 혼란을 겪었으므로 핵심 비즈니스 로직에 로깅하지 않고 로깅, 오류 처리 등과 같은 항목을 사용 사례에 포함시키는 (모노 딕) 함수 구성에 대한 관심이 커졌습니다 ( fsharpforfunandprofit.com/rop 참조 )
sara

5
로깅 광범위 하지 않아야 합니다. 그렇다면 로그를 너무 많이 기록하고 실제로 해당 로그를 보러 갈 때 소음이 발생합니다. 로거 종속성을 주입하면 실제로 로그를 기록해야하는지 여부를 고려해야합니다.
RubberDuck

12
@RubberDuck-현장에서 버그 보고서를받을 때 "로깅이 널리 퍼져서는 안된다"고 말해 주어야 할 유일한 디버그 기능은 내가 확산되고 싶지 않은 로그 파일뿐입니다. 교훈은 벌목은 "보편적"이어야하고 매우 널리 퍼져 있어야한다는 것입니다.
덩크

15
@RubberDuck : 서버 소프트웨어에서 로깅은 생존 할 수있는 유일한 방법입니다. 12 시간 전에 자신의 랩톱 대신에 발생한 버그를 파악할 수있는 유일한 방법입니다. 소음에 대해 걱정하지 마십시오. 로그 관리 소프트웨어를 사용하여 로그를 쿼리 할 수 ​​있습니다 (이상적으로 오류 로그를 이메일로 보내는 알람을 설정해야 함)
slebetman

6
지원 담당자가 전화하여 "고객이 일부 페이지를 클릭하고 오류가 발생했습니다"라고 말합니다. 나는 그들에게 오류가 무엇을 말했는지 묻습니다. 고객이 무엇을 클릭했는지 구체적으로 묻습니다. 나는 그들이 재현 할 수 있는지 묻습니다. 필자는 로깅이 몇 가지 핵심 힌지 지점에 잘 배치 된 로거를 통해 대부분 달성 될 수 있지만 여기에 약간의 이상한 메시지도 있다는 점에 동의합니다. 로깅에 대한 두려움은 소프트웨어 품질을 저하시킵니다. 데이터가 너무 많으면 정리하십시오. 조기에 최적화하지 마십시오.
페이스

12

내 2 센트 ...

예, 아니오

당신이 채택한 원칙을 실제로 위반 해서는 안됩니다 . 그러나 원칙은 항상 더 높은 목표를 달성하기 위해 미묘한 차이를 가져야합니다. 그래서, 적절하게 조절 이해와 함께, 몇 가지 명백한 위반하지 않을 수 있습니다 실제 은 "정신"또는 위반 "전체 원칙의 몸."

특히 SOLID 원칙은 많은 뉘앙스를 요구할뿐만 아니라 "작업 가능하고 유지 관리 가능한 소프트웨어 제공"이라는 목표에 종속적입니다. 따라서 특정 SOLID 원칙을 준수하는 것은 SOLID의 목표와 상충 될 때 자멸적이고 모순적입니다. 그리고 여기서는 종종 유지 보수성을 능가 하는 것으로 나타났습니다 .

SOLIDD 는 어떻습니까? 재사용 가능한 모듈을 해당 컨텍스트에 상대적으로 무관하게 만들어 유지 보수성을 향상시키는 데 기여합니다. 그리고 "재사용 가능한 모듈"을 "다른 별개의 컨텍스트에서 사용하려는 코드 모음"으로 정의 할 수 있습니다. 그리고 이것은 단일 함수, 클래스, 클래스 세트 및 프로그램에 적용됩니다.

로거 구현을 변경하면 모듈이 "또 다른 고유 한 컨텍스트"가 될 수 있습니다.

그래서 두 가지 큰 경고를 드리겠습니다 .

첫째 , "재사용 가능한 모듈"을 구성하는 코드 블록 주위에 선을 그리는 것은 전문적인 판단의 문제입니다. 그리고 당신의 판단은 반드시 당신의 경험으로 제한됩니다.

당신이하지 않으면 현재 다른 맥락에서 모듈을 사용하여 계획, 그것은이다 아마 그것에 무력 의존하는 OK. 경고에 대한주의 사항 : 계획이 잘못되었을 수도 있지만 괜찮습니다. 모듈 후에 모듈을 더 오래 쓸수록 "언젠가 다시 필요할지"에 대한 감각이 더욱 직관적이고 정확 해집니다. 그러나, 당신은 아마도 회고 적으로 "나는 모든 것을 가능한 한 많이 모듈화하고 분리 했지만 과도하게하지는 않았다 "고 말하지 못할 것이다 .

판단의 잘못에 대해 죄책감을 느끼면 자백하고 계속하십시오 ...

둘째 : 반전 제어주입 의존성을 같지 않습니다 .

의존성 ad nauseam 주입 을 시작할 때 특히 그렇습니다 . 의존성 주입은 중요한 IoC 전략에 유용한 전술입니다. 그러나 DI는 인터페이스 및 어댑터 사용과 같은 다른 전술보다 모듈 내에서 컨텍스트에 대한 단일 노출 지점 보다 효과 가 적다고 주장합니다 .

그리고 잠시 이것에 초점을 맞추겠습니다. 왜냐하면 경우에도 당신이 분사 Logger 광고 싫증 , 당신은에 대한 코드를 작성에 필요한 Logger인터페이스를 제공합니다. Logger다른 순서로 매개 변수를 취하는 다른 공급 업체 의 새 제품 을 사용할 수 없었습니다 . 이러한 능력은 모듈 내에 존재하고 인터페이스 내에 단일 서브 모듈 (어댑터)을 갖는 인터페이스에 대한 코딩으로부터 비롯되어 종속성을 관리하는 데있다.

어댑터에 대해 코딩하는 경우 어댑터에 Logger삽입 되는지 어댑터에 의해 감지 되는지 는 일반적으로 전반적인 유지 관리 목표에 크게 영향을 미치지 않습니다. 그리고 더 중요한 것은 모듈 수준의 어댑터가 있다면 아무 것도 넣지 않는 것입니다. 모듈 용으로 작성 되었습니다 .

tl; dr-원칙을 사용하는 이유를 고려하지 않고 원칙에 대한 소란을 멈추십시오. 그리고, 더 실제적으로, 단지를 구축 Adapter각 모듈에 대해. "모듈"경계를 그릴 위치를 결정할 때 판단하십시오. 각 모듈 내에서 계속해서를 참조하십시오 Adapter. 그리고 물론, 주입 실제 로거으로 Adapter하지만 - 하지 를해야 할 수도 있습니다 모든 작은 일에 있습니다.


4
남자 ... 나는 더 짧은 대답을했지만 시간이 없었습니다.
svidgen

2
어댑터 사용시 +1 가능한 경우 타사 구성 요소를 교체 할 수 있도록 타사 구성 요소에 대한 종속성을 격리해야합니다. 로깅은이를위한 쉬운 대상입니다. 많은 로깅 구현이 존재하고 대부분 유사한 API를 가지고 있으므로 간단한 어댑터 구현을 통해이를 매우 쉽게 변경할 수 있습니다. 그리고 로깅 공급자를 절대로 변경하지 않을 것이라고 말하는 사람들에게 : 나는 이것을해야했습니다. 어댑터를 사용하지 않아서 진짜 고통을 겪었습니다.
Jules

"특히 많은 뉘앙스를 요구할뿐만 아니라 SOLID 원칙은 궁극적으로"작동 가능하고 유지 관리 가능한 소프트웨어 제공 "의 목표에 종속적입니다."-이것이 내가 본 최고의 진술 중 하나입니다. 약간의 OCD 코더로서, 나는 이상주의와 생산성과의 투쟁을 가졌습니다.
DVK

이전 답변에 대한 +1 또는 의견을 볼 때마다 다시 답변을 읽고 다시 엉뚱하고 불분명 한 작가라는 것을 발견했습니다. @DVK의 의견에 감사드립니다.
svidgen

어댑터는 생명의 은인이며 비용이 많이 들지 않으며 특히 SOLID를 적용하려고 할 때 인생을 훨씬 쉽게 만듭니다. 시험은 그들에게 산들 바람입니다.
Alan

8

로깅을 항상 싱글 톤으로 구현 해야한다는 생각 은 너무나 자주 견인되고있는 거짓말 중 하나입니다.

최신 운영 체제가 사용 되는 한 출력특성에 따라 여러 위치에 로그를 기록 할 수있는 것으로 인식되었습니다 .

시스템 설계자는 새로운 솔루션에 맹목적으로 포함하기 전에 과거 솔루션의 효능에 대해 끊임없이 의문을 제기해야합니다. 그들이 그러한 근면을 수행하지 않는다면, 그들은 일을하지 않는 것입니다.


2
그렇다면 제안 된 해결책은 무엇입니까? 작성하는 모든 수업에 ILogger를 주입합니까? 데코레이터 패턴을 사용하는 것은 어떻습니까?
Robert Harvey

4
실제로 내 질문에 대답하지 않습니까? 나는 단지 패턴을 단지 예로 들었다. 만약 당신이 더 나은 것을 염두에두고있을 필요는 없다.
Robert Harvey

8
구체적인 제안과 관련하여이 답변을 실제로 이해하지 못합니다.
Brian Agnew

3
@RobbieDee-그래서 당신은 우리가 여러 장소에 기록하고 싶을 수있는 "off-chance"에 의해 가장 복잡하고 불편한 방식으로 로깅을 구현해야한다고 말하는가? 이와 같은 변경이 발생한 경우에도 Logger를 원하는지 여부를 결정할 때 기존 Logger 인스턴스에 해당 기능을 추가하는 것이 클래스간에 인터페이스를 변경하고 인터페이스를 변경하는 모든 노력보다 더 많은 작업이 될 것이라고 생각하십니까? 여러 장소 로깅이 발생하지 않는 수십 개의 프로젝트?
덩크

2
Re : "출력의 특성에 따라 여러 곳에 로그를 기록하고 싶을 수도 있습니다": 물론 여러 개별 로깅 종속성을 주입하지 않고 로깅 프레임 워크에서 이를 처리하는 가장 좋은 방법 입니다. (공통 로깅 프레임 워크는 이미이를 지원합니다.)
ruakh

4

진정으로 로깅하는 것은 특별한 경우입니다.

@Telastyn의 글을 참고하세요 :

로깅 라이브러리 또는 대상을 변경하거나 필터링 또는 형식을 변경하지 않습니까?

로깅 라이브러리를 변경해야 할 것으로 예상되면 파사드를 사용해야합니다. Java 세계에있는 경우 SLF4J

나머지의 경우, 적절한 로깅 라이브러리는 로깅이 진행되는 위치, 필터링되는 이벤트, 로거 구성 파일을 사용하여 로그 이벤트의 형식을 지정하는 방법 및 사용자 정의 플러그인 클래스를 변경합니다. 다양한 상용 대안이 있습니다.

요컨대, 로깅에 대한 해결 된 문제이므로 문제를 해결하기 위해 Dependency Injection을 사용할 필요가 없습니다.

DI가 표준 로깅 방식보다 유리한 유일한 경우는 응용 프로그램의 로깅을 단위 테스트에 적용하려는 경우입니다. 그러나 대부분의 개발자는 로깅이 클래스 기능의 일부가 아니며 테스트 해야 할 것이 아니라고 말할 것입니다 .

@Telastyn의 글을 참고하세요 :

그러면 로거 자체가 변경을 처리 할 것이라는 주장을 얻게됩니다. "아, 대상 / 필터링 / 포맷 / 전략이 바뀌면 설정 만 변경하면됩니다!" 그것은 쓰레기입니다. 이제 이러한 모든 것을 처리하는 신 객체가있을뿐만 아니라 정적 분석을 얻지 않고 컴파일 시간 오류가 발생하지 않는 XML 또는 유사한 코드로 코드를 작성하고 있습니다. 실제로 효과적인 단위 테스트를받을 수 없습니다.

이것이 매우 이론적 인 소문입니다. 실제로 대부분의 개발자와 시스템 통합자는 구성 파일을 통해 로깅을 구성 할 수 있다는 사실을 좋아합니다. 그리고 그들은 모듈의 로깅을 단위 테스트하지 않을 것이라는 사실을 좋아합니다.

물론 로깅 구성을 채우면 문제가 발생할 수 있지만 시작하는 동안 응용 프로그램이 실패하거나 너무 많거나 너무 적은 로깅으로 나타납니다. 1) 구성 파일의 실수를 수정하여 이러한 문제를 쉽게 해결할 수 있습니다. 2) 대안은 로깅 레벨을 변경할 때마다 완전한 빌드 / 분석 / 테스트 / 배포주기입니다. 허용되지 않습니다.


3

, 아니오 !

예 : 다른 서브 시스템 (또는 시맨틱 레이어 또는 라이브러리 또는 모듈 식 번들링의 다른 개념) 이 동일한 공통 공유 싱글 톤을 사용하는 모든 서브 시스템보다는 초기화 중에 동일한 로거 또는 다른 로거를 수용하는 것이 합리적이라고 생각합니다 .

하나,

아니요 : 동시에 모든 작은 객체에서 로깅을 매개 변수화하는 것은 불합리합니다 (생성자 또는 인스턴스 방법으로). 불필요하고 무의미한 부풀림을 피하려면 소규모 엔티티는 엔 클로징 컨텍스트의 싱글 톤 로거를 사용해야합니다.


이것은 모듈화 수준을 생각해야하는 많은 이유 중 하나입니다. 메소드는 클래스로 묶이고 클래스는 서브 시스템 및 / 또는 의미 계층으로 묶습니다. 이 더 큰 번들은 귀중한 추상화 도구입니다. 모듈 형 경계 내에서 교차 할 때와 다른 고려 사항을 제공해야합니다.


3

먼저 강력한 싱글 톤 캐시로 시작합니다. 다음으로 볼 수있는 다음은 전역 상태, 설명이 class없는 es 및 테스트 할 수없는 코드의 API를 도입하는 데이터베이스 계층을위한 강력한 싱글 톤입니다 .

데이터베이스에 싱글 톤을 갖지 않기로 결정했다면, 아마도 캐시에 싱글 톤을 갖는 것은 좋은 생각이 아닐 수 있습니다. 결국 그것들은 다른 메커니즘을 사용하는 매우 유사한 개념 인 데이터 스토리지를 나타냅니다.

클래스에서 싱글 톤을 사용 하면 정적 메서드 뒤에 숨겨진 것이 무엇인지 알 수 없기 때문에 이론적 으로 무한한 수의 클래스에 특정 양의 종속성이있는 클래스가 됩니다.

지난 10 년 동안 나는 프로그래밍을 보냈지 만 로깅 논리를 변경하려는 노력을 보인 사례는 단 한 번 뿐이었다 (단일로 작성 됨). 따라서 의존성 주입을 좋아하지만 로깅은 실제로 큰 관심사가 아닙니다. 반면 캐시는 항상 의존성으로 만들 것입니다.


예, 로깅은 거의 변경되지 않으며 일반적으로 교체 가능한 모듈 일 필요는 없습니다. 그러나 로깅 로깅 클래스에 정적 종속성이있는 로깅 도우미 클래스를 단위 테스트하려고 시도했습니다. 테스트 할 수있는 가장 쉬운 메커니즘은 별도의 프로세스에서 테스트중인 클래스를 실행하고 STDOUT에 쓰도록 로거를 구성하고 테스트 케이스에서 출력을 구문 분석하는 것입니다. decided_ ಠ d 분명히 실시간 이외의 것을 원하지는 않습니까? 물론 시간대 / DST 엣지를 테스트 할 때를 제외하고…
amon

@amon : 시계는 DI와 동일한 목적, 즉 Joda-Time과 많은 포트를 제공하는 또 다른 메커니즘이 이미 있다는 점에서 로그인과 같습니다. (DI를 대신 사용하는 데 문제가있는 것은 아니지만 사용자 정의 주 사용 어댑터를 작성하는 것보다 Joda-Time을 사용하는 것이 더 간단하며, 아무도 후회하는 것을 본 적이 없습니다.)
ruakh

@amon "실제로는 실시간을 제외하고는 절대 원하지 않는 시계에 대해 비슷한 경험을했습니다. 물론 시간대 / DST 엣지를 테스트 할 때를 제외하고는…"또는 버그가 있다는 것을 알고 데이터베이스를 손상시키고 다시 가져 오는 유일한 희망은 이벤트 로그를 구문 분석하고 마지막 백업에서 시작하여 재생하는 것입니다 ... 그러나 갑자기 현재 로그 항목이 아닌 현재 로그 항목의 타임 스탬프를 기반으로 작동하려면 모든 코드가 필요합니다 시각.
Jules

3

예, 아니오, 그러나 대부분 아니오

나는 대부분의 대화가 정적 대 주입 인스턴스를 기반으로한다고 가정합니다. 아무도 로깅이 SRP를 깨뜨릴 것을 제안하지 않습니다. 우리는 주로 "종속성 역전 원리"에 대해 이야기하고 있습니다. Tbh 나는 대부분 Telastyn의 대답이 없다고 동의합니다.

스태틱을 사용하는 것이 언제 괜찮습니까? 분명히 때로는 괜찮습니다. 그렇습니다. 추상화의 혜택에 대한 답은 "아니오"라는 대답은 그들이 당신이 지불하는 것임을 지적합니다. 직업이 어려운 이유 중 하나는 모든 상황에 대해 적어두고 적용 할 수있는 답변이 없기 때문입니다.

갖다: Convert.ToInt32("1")

나는 이것을 선호한다 :

private readonly IConverter _converter;

public MyClass(IConverter converter)
{
   Guard.NotNull(converter)
   _converter = conveter
}

.... 
var foo = _converter.ToInt32("1");

왜? 전환 코드를 교체 할 수있는 유연성이 필요한 경우 코드를 리팩터링해야한다는 점에 동의합니다. 나는 이것을 조롱 할 수 없다는 것을 받아들이고 있습니다. 나는 단순성과 간결함이이 거래의 가치가 있다고 믿는다.

경우 스펙트럼의 다른 쪽 끝을 보면, IConverter를했다 SqlConnection, 나는 상당히 정적 호출로 그를보고 충격을 것입니다. 이유가 분명하지 않은 이유. 나는 SQLConnectionapplciation에서 상당히 "cross-cutting"할 수 있다고 지적 하므로 정확한 단어를 사용하지 않았을 것입니다.

더 같은 로깅 SQLConnection또는 Convert.ToInt32? 나는 'SQLConnection`과 더 비슷하다고 말하고 싶습니다.

로깅을 조롱해야합니다 . 외부 세계와 대화합니다. 를 사용하여 메소드를 작성할 때 Convert.ToIn32클래스의 별도로 테스트 가능한 출력을 계산하는 도구로 사용하고 있습니다. Convert"1"+ "2"== "3" 을 확인할 때 제대로 호출 할 필요가 없습니다 . 로깅은 다르며, 클래스의 전적으로 독립적 인 출력입니다. 나는 그것이 당신, 지원 팀 및 비즈니스에 가치가있는 출력이라고 가정합니다. 로깅이 정확하지 않으면 클래스가 작동하지 않으므로 단위 테스트를 통과해서는 안됩니다. 클래스 로그를 테스트해야합니다. 나는 이것이 살인자라고 생각한다. 나는 정말로 여기서 멈출 수있다.

또한 변경 될 가능성이 높다고 생각합니다. 좋은 로깅은 문자열을 인쇄하는 것이 아니라 응용 프로그램이 수행하는 작업을 보여줍니다 (이벤트 기반 로깅의 팬입니다). 기본 로깅이 매우 정교한보고 UI로 바뀌는 것을 보았습니다. 벌목 모양이 비슷 _logger.Log(new ApplicationStartingEvent())하거나 적 으면이 방향으로 향하는 것이 훨씬 쉽습니다 Logger.Log("Application has started"). 아마도 이것이 결코 일어날 수없는 미래를위한 재고를 창출하고 있다고 주장 할 수도 있습니다. 이것은 판단 요청이며 가치가 있다고 생각합니다.

실제로 내 개인 프로젝트 _logger에서 응용 프로그램이 수행하는 작업을 파악하기 위해 순수하게 로깅을 사용하지 않는 UI를 만들었습니다 . 이것은 애플리케이션이 무엇을하고 있는지 알아 내기 위해 코드를 작성할 필요가 없다는 것을 의미했으며, 결국 견고한 로깅으로 끝났습니다. 로깅에 대한 나의 태도가 단순하고 변하지 않았다고 생각한다면, 그 아이디어는 나에게 일어나지 않았을 것입니다.

로깅의 경우 Telastyn에 동의합니다.


내가 실수로 기록하는 방법 입니다. 기사 나 다른 것에 연결하고 싶지만 찾을 수 없습니다. .NET 세계에 있고 이벤트 로깅을 조회하는 경우을 찾을 수 Semantic Logging Application Block있습니다. MS "patterns and pratice"팀에 의해 생성 된 대부분의 코드처럼, 아이러니하게도 반 패턴입니다.
Nathan Cooper

3

첫 번째 교차 절단 문제는 주요 빌딩 블록이 아니며 시스템의 종속성으로 취급되어서는 안됩니다. 예를 들어 로거가 초기화되지 않았거나 캐시가 작동하지 않으면 시스템이 작동해야합니다. 어떻게 시스템을 덜 결합하고 응집력있게 만들 것입니까? OOID 시스템 설계에서 SOLID가 등장했습니다.

객체를 싱글 톤으로 유지하는 것은 SOLID와 관련이 없습니다. 그것은 객체가 메모리에 얼마나 오래 살기를 원하는지 당신의 객체 수명주기입니다.

초기화하기 위해 의존성이 필요한 클래스는 제공된 클래스 인스턴스가 싱글 톤인지 일시적인지 알 수 없습니다. 그러나 tldr; 모든 메소드 또는 클래스에서 Logger.Instance.Log ()를 작성하는 경우 문제가있는 코드 (코드 냄새 / 하드 커플 링)가 정말 지저분합니다. 사람들이 SOLID를 학대하기 시작하는 순간입니다. 그리고 OP와 같은 동료 개발자는 이와 같은 진정한 질문을하기 시작합니다.


2

상속과 특성의 조합 (일부 언어에서는 mixin이라고도 함)을 사용 하여이 문제를 해결했습니다. 특성은 이러한 종류의 교차 절단 문제를 해결하는 데 매우 편리합니다. 그것은 일반적으로 언어 기능이지만 실제 대답은 언어 기능에 의존한다는 것입니다.


흥미 롭군 나는 특성을 지원하는 언어를 사용하여 중요한 작업을 한 적이 없지만 향후 프로젝트에 그러한 언어를 사용하는 것을 고려 했으므로이를 확장하고 특성이 문제를 해결하는 방법을 보여 주면 도움이 될 것입니다.
Jules
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.