C #에서 'using'지시문을 사용하지 않는 이유는 무엇입니까?


71

대규모 C # 프로젝트의 기존 코딩 표준에는 '사용'지시문의 고용을 금지하는 모든 유형 이름의 정규화 규칙이 포함되어 있습니다. 따라서 익숙한 것이 아니라

using System.Collections.Generic;

.... other stuff ....

List<string> myList = new List<string>();

( var금지 된 것도 놀라운 일이 아닙니다 .)

나는 결국 :

System.Collections.Generic.List<string> myList = new System.Collections.Generic.List<string>();

유용한 정보를 제공하지 않으면서도 입력이 134 % 증가합니다. 내 생각에, 증가의 100 %는 실제로 이해를 방해 하는 소음 (잡음)입니다 .

30 년 이상의 프로그래밍 과정에서 이러한 표준은 한두 번 제안되었지만 결코 구현되지는 않았습니다. 그 배후의 근거는 저를 피합니다. 표준을 강요하는 사람은 바보가 아니며, 그가 악의적이라고 생각하지 않습니다. 내가 뭔가를 놓치지 않으면 다른 대안으로 오도 된 것입니다.

그러한 표준이 부과되는 것을 들어 본 적이 있습니까? 그렇다면 그 이유는 무엇입니까? using이 사람이이 금지를 제거하도록 설득 할 수있는 "멍청하다"또는 "다른 사람이 사용하는 것"이외의 주장에 대해 생각할 수 있습니까 ?

추리

이 금지의 이유는 다음과 같습니다.

  1. 정규화 된 유형을 얻으려면 이름 위로 마우스를 가져가는 것이 번거 롭습니다. 항상 정규화 된 유형을 항상 표시하는 것이 좋습니다.
  2. 이메일로 전송 된 코드 스 니펫에는 완전한 이름이 없으므로 이해하기 어려울 수 있습니다.
  3. Visual Studio 외부에서 코드를 보거나 편집 할 때 (예 : 메모장 ++) 정규화 된 유형 이름을 얻는 것은 불가능합니다.

필자의 주장은 세 가지 경우가 모두 드물고, 드문 경우를 수용하기 위해 모든 사람들이 어수선하고 이해하기 어려운 코드의 가격을 지불하게하는 것은 잘못된 것입니다.

주요 관심사가 될 것으로 예상되는 잠재적 네임 스페이스 충돌 문제는 언급되지 않았습니다. 네임 스페이스가 있기 때문에 특히 놀랍습니다. 이는 MyCompany.MyProject.Core특히 나쁜 생각입니다. 난 아무것도 명명 것을 오래 전에 배운 System또는 CoreC #으로하는 광기에 대한 빠른 경로입니다.

다른 사람들이 지적했듯이 네임 스페이스 충돌은 리팩토링, 네임 스페이스 별칭 또는 부분적 자격으로 쉽게 처리 할 수 ​​있습니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
maple_shaft

1
: 그것은 (그러나 C ++ 세계에서) 좋은 생각이 될 수없는 이유의 실제 예제 에 대한 답변 "네임 스페이스를 사용하여 표준;"나쁜 사례로 간주 이유는? , " '사용'지시문과 선언 모두 금지되어 있습니다."
Peter Mortensen

추론 섹션을 읽기 전에 회사에 비슷한 규칙이 있기 때문에 실용적이지 않은 이유를 추측했습니다.
Gqqnbig 2016 년

답변:


69

더 넓은 질문 :

그러한 표준이 부과되는 것을 들어 본 적이 있습니까? 그렇다면 그 이유는 무엇입니까?

예, 들었습니다. 정규화 된 객체 이름을 사용하면 이름 충돌이 방지됩니다. 드물기는하지만, 일어날 때 예외적으로 가시적 일 수 있습니다.


예 : 해당 유형의 시나리오는 예를 통해 더 잘 설명 될 수 있습니다.

Lists<T>두 개의 별도 프로젝트에 속하는 두 가지가 있다고 가정 해 봅시다 .

System.Collections.Generic.List<T>
MyCorp.CustomCollections.Optimized.List<T>

정규화 된 개체 이름을 사용할 때 어떤 개체 List<T>가 사용되고 있는지 분명 합니다. 그 선명도는 명백하게 자세한 정보를 요구합니다.

그리고 당신은 "잠깐만! 아무도 그런 목록을 사용하지 않을 것입니다!" 유지 보수 시나리오를 지적 할 곳입니다.

Foo회사에서 승인하고 최적화 한 회사를 사용하는 회 사용 모듈 을 작성했습니다 List<T>.

using MyCorp.CustomCollections.Optimized;

public class Foo {
    List<object> myList = ...;
}

나중에 새 개발자가 수행 한 작업을 확장하기로 결정합니다. 회사의 표준을 알지 못하고 using블록 을 업데이트합니다 .

using MyCorp.CustomCollections.Optimized;
using System.Collections.Generic;

그리고 서둘러 상황이 어떻게 나빠지는지 알 수 있습니다.

이름이 같지만 동일한 프로젝트 내에서 서로 다른 네임 스페이스에 두 개의 독점 클래스가있을 수 있다는 점은 간단합니다. 따라서 .NET 프레임 워크 제공 클래스와의 충돌에 대한 우려가 아닙니다.

MyCorp.WeightsAndLengths.Measurement();
MyCorp.TimeAndSpace.Measurement();

현실 :
자, 이것이 대부분의 프로젝트에서 일어날 가능성 이 있습니까? 아니 정말. 그러나 입력이 많은 대규모 프로젝트를 수행 할 때는 폭발 할 가능성을 최소화하기 위해 최선을 다합니다.

여러 기고 팀이있는 대규모 프로젝트는 응용 프로그램 세계에서 특별한 종류의 짐승입니다. 다른 프로젝트에 불합리하게 보이는 규칙은 프로젝트에 대한 입력 스트림과 기여하는 규칙이 프로젝트의 지침을 읽지 않았을 가능성으로 인해 더 적절 해집니다.

두 개의 큰 프로젝트가 병합 될 때도 발생할 수 있습니다. 두 프로젝트에 모두 비슷한 이름의 클래스가있는 경우 한 프로젝트에서 다른 프로젝트로 참조를 시작할 때 충돌이 발생합니다. 또한 프로젝트가 너무 커서 리팩토링하지 않거나 경영진이 리팩토링에 소요되는 시간을 지원하기위한 비용을 승인하지 않습니다.


대안 :
당신이 묻지 않았지만 이것이 문제에 대한 훌륭한 해결책아니라는 것을 지적 할 가치가 있습니다. 네임 스페이스 선언없이 충돌하는 클래스를 만드는 것은 좋지 않습니다.

List<T>특히 예약어로 취급해야하며 수업 이름으로 사용해서는 안됩니다.

마찬가지로, 프로젝트 내의 개별 네임 스페이스는 고유 한 클래스 이름을 갖도록 노력해야합니다. Foo()작업중 인 네임 스페이스를 다시 호출해야하는 것은 피해야 할 정신적 오버 헤드입니다. 갖는 또 다른 방법은 말했다 MyCorp.Bar.Foo()MyCorp.Baz.Foo()개발자 위로 피해야을 여행하는 것입니다.

다른 것이 없으면 모호성을 해결하기 위해 부분 네임 스페이스를 사용할 수 있습니다. 예를 들어 Foo()클래스 이름을 완전히 바꿀 수 없으면 부분 네임 스페이스를 사용할 수 있습니다.

Bar.Foo() 
Baz.Foo()

현재 프로젝트의 구체적인 이유 :

해당 표준에 따라 현재 프로젝트에 주어진 특정 이유로 질문을 업데이트했습니다. 그것들을보고 토끼의 흔적을 따라 내려가 보자.

정규화 된 유형을 얻으려면 이름 위로 마우스를 가져가는 것이 번거 롭습니다. 항상 정규화 된 유형을 항상 표시하는 것이 좋습니다.

"수줍어?" 음 .. 아니야. 아마도 성가시다. 화면 포인터를 이동시키기 위해 몇 온스의 플라스틱을 움직이는 것은 번거롭지 않습니다 . 그러나 나는 산만하다.

이 추론은 다른 무엇보다 은폐처럼 보입니다. 필자는 응용 프로그램 내 클래스의 이름이 약하고 클래스 이름을 둘러싼 적절한 양의 의미 정보를 수집하기 위해 네임 스페이스에 의존해야한다고 생각합니다.

이것은 정규화 된 클래스 이름에 대한 정당화가 아니며, 부분적으로 정규화 된 클래스 이름을 사용하는 것에 대한 정당화 일 수 있습니다.

이메일로 전송 된 코드 스 니펫에는 완전한 이름이 없으므로 이해하기 어려울 수 있습니다.

이 (계속?) 추론은 클래스의 이름이 잘못되었다는 의심을 강화시킵니다. 다시 말해, 클래스 이름이 잘못되었다고해서 모든 것이 정규화 된 클래스 이름을 사용해야한다고 정당화되는 것은 아닙니다 . 클래스 이름을 이해하기 어려운 경우 정규화 된 클래스 이름으로 수정할 수있는 것보다 훨씬 잘못된 것이 있습니다.

Visual Studio 외부에서 코드를 보거나 편집 할 때 (예 : 메모장 ++) 정규화 된 유형 이름을 얻는 것은 불가능합니다.

모든 이유에서, 이것은 거의 내 음료를 뱉어 버렸습니다. 그러나 다시, 나는 떠난다.

팀이 Visual Studio 외부에서 코드를 자주 편집하거나 보는지 궁금합니다 . 그리고 지금 우리는 네임 스페이스가 무엇을 제공 할 것인지에 대해 직교하는 정당화를보고 있습니다. 이것은 툴링 된 논증이지만, 네임 스페이스는 코드에 조직 구조를 제공하기 위해 존재합니다.

툴링이 제공 할 수있는 기능을 활용하지 않는 개발자와 함께 명명 규칙이 열악한 프로젝트처럼 들립니다. 그리고 이러한 실제 문제를 해결하기보다는 증상 중 하나에 대해 반창고를 치기 위해 정규 클래스 이름이 필요합니다. 나는 이것을 오도 된 접근법으로 분류하는 것이 안전하다고 생각합니다.

이름이 잘못 지정된 클래스가 있고 리팩토링 할 수 없다고 가정하면 정답은 Visual Studio IDE를 최대한 활용하는 것입니다. VS PowerTools 패키지와 같은 플러그인을 추가하는 것이 좋습니다. 그런 다음 AtrociouslyNamedClass()클래스 이름을 클릭하고 F12 키를 누르고 클래스 정의로 직접 이동하여 수행하려는 작업을 더 잘 이해할 수 있습니다. 마찬가지로 Shift-F12를 클릭하여 현재 사용해야하는 코드의 모든 지점을 찾을 수 있습니다 AtrociouslyNamedClass().

외부 툴링 문제와 관련하여 가장 좋은 방법은 중지하는 것입니다. 스 니펫이 참조하는 내용을 즉시 명확하게 알 수없는 경우 스 니펫을 이메일로주고받지 마십시오. Visual Studio 외부의 다른 도구는 팀이 필요로하는 코드와 관련된 인텔리전스가 없으므로 다른 도구를 사용하지 마십시오. 메모장 ++는 훌륭한 도구이지만이 작업에는 적합하지 않습니다.

따라서 귀하가 제시 한 세 가지 정당성에 대한 귀하의 평가에 동의합니다. "내가 생각할 수없는이 프로젝트에 대한 근본적인 문제가 있는데 이것이 바로 우리가 그 문제를 '고정한 방법'입니다." 그리고 그것은 분명히 당신을 위해 붉은 깃발 역할을 할 수있는 팀 내에서 더 깊은 문제를 말합니다.


1
+1. 실제로 내부 네임 스페이스에서 약간의 충돌이 발생했습니다. 레거시 코드를 "2.0"프로젝트로 이식하는 것과 다른 네임 스페이스 컨텍스트에서 의미 적으로 유효한 몇 가지 클래스 이름 만 있습니다. 정말 까다로운 것은 동일한 이름을 가진 두 가지가 종종 비슷한 인터페이스를 가지므로 컴파일러가 불평하지 않는다는 것입니다 ... 런타임이됩니다!
svidgen

23
이 문제는 명시적인 네임 스페이스 사용으로 어수선한 코드를 요구하는 바보 같은 규칙을 부과하는 것이 아니라 네임 스페이스 별칭을 사용하여 해결됩니다.
David Arno

4
@DavidArno-동의하지 않습니다. 그러나 대규모 프로젝트에는 해당 옵션이 없을 수 있습니다. 나는 단지 큰 프로젝트가 그 규칙을 적용 할 수 있는지 지적하고 있습니다. 그래도 나는 규칙을 지지하지 않습니다 . 팀에 다른 옵션이 없기 때문에 때로는 필요할 수도 있습니다.

4
@ GlenH7 당신은 당신의 대답에 다른 가능한 솔루션을 지정하고 싶을 수도 있습니다. 나는 사람들이 이것에 걸려 넘어지는 것을보고 싶었다. "아, 좋은 생각이야!" 그래도 객관적이고 실용적으로 +1합니다.
RubberDuck

3
@JimMischel-규칙이 무언가에 대한 목발로 사용되고있는 것 같습니다 . 그 일이 무엇인지 결정하는 것이 불가능할 수도 있습니다. 높은 수준에서 그렇습니다. 때로는 허용 usings하지 않는 것에 대한 정당성이 있지만 프로젝트가 그러한 경우 중 하나 인 것처럼 들리는 것은 아닙니다.

16

한 회사에서 같은 이름을 가진 많은 수업을 받았지만 다른 수업 라이브러리에서 일했습니다.

예를 들어

  • 도메인. 고객
  • 레거시. 고객
  • 서비스 X. 고객
  • ViewModel. 고객
  • 데이터베이스. 고객

나쁜 디자인, 당신은 말할 수 있지만, 당신은 이러한 것들이 유기적으로 어떻게 발전하는지 알고 있으며 대안은 무엇입니까? 네임 스페이스를 포함하도록 모든 클래스의 이름을 바꾸겠습니까? 모든 주요 리팩토링?

어쨌든, 서로 다른 라이브러리를 모두 참조하는 프로젝트가 여러 버전의 클래스를 사용해야하는 곳이 여러 곳있었습니다.

으로 using직접 상단에,이, 엉덩이에 큰 고통이었다 ReSharper에서이 이상한 일들이 다시 작성, 시도하고 작동하도록 할 것입니다 using즉석에서 지시, 당신은 고객 그렇지 않으면 .. - 수 - 주조 된 직후을 얻을 것 고객 스타일 오류이며 어떤 유형이 올바른지 알 수 없습니다.

최소한 부분적인 네임 스페이스를 가지면

var cust = new Domain.Customer

또는

public void Purchase(ViewModel.Customer customer)

코드의 가독성을 크게 향상시키고 원하는 객체를 명시 적으로 만들었습니다.

코딩 표준이 아니며 전체 네임 스페이스가 아니 었으며 모든 클래스에 표준으로 적용되지 않았습니다.


13
"대안은 무엇입니까, 네임 스페이스를 포함하도록 모든 클래스의 이름을 바꾸겠습니까? 모든 것의 주요 리팩토링?" 예, (올바른) 대안입니다.
David Arno

2
단기적으로 만. 장기적으로 코드에서 명시 적 네임 스페이스를 사용하는 것보다 훨씬 저렴합니다.
David Arno

3
주식이 아닌 현금으로 나를 지불하는 한, 그 주장을 받아들이게되어 기쁘다.
Ewan

8
@David : 아니요. 올바른 대안이 아닙니다. 모든 식별자 또는 적어도 실제로 충돌하는 식별자를 완전히 규정하는 것이 올바른 방법이며 네임 스페이스가 처음 존재하는 이유는 동일한 이름이 다른 모듈에서 사용될 때 충돌을 일으키는 것입니다. 요점은 일부 모듈이 타사에서 제공 할 수 있으며 수정할 수없는 코드베이스입니다. 두 개의 다른 타사 라이브러리의 식별자가 충돌하여 두 라이브러리를 모두 사용해야하지만 둘 중 하나를 리팩터링 할 수없는 경우 어떻게해야합니까? 리팩토링이 항상 가능한 것은 아니기 때문에 네임 스페이스가 존재합니다.
Kaiserludi

4
@CarlSixsmith, 리팩토링에 대한 Martin Fowler의 견해를 구독하면 변경 사항이 사용자에게 영향을 미치면 리팩토링이 아닙니다. 또 다른 형태의 구조 조정입니다. 그러나 두 가지 점이 제기됩니다. 1. 모든 공용 메소드가 자동으로 API의 일부입니까? 2. 파울러 자신 은이 변화에 대한 패배와 싸우고 있음을 인정 하며, 대중의 변화를 포함하여 일반화 된 구조 조정을 의미하는 "리팩토링"이라는 용어를 사용하는 사람들이 점점 늘어나고 있습니다.
David Arno

7

너무 간결하거나 너무 짧으면 좋지 않습니다. 너무 많은 코드를 작성하지 않으면 서 미묘한 버그를 방지하기 위해 충분히 자세하게 설명하는 황금색 중간을 찾아야합니다.

C #에서 그 예는 인수의 이름입니다. 해결책을 찾는 데 몇 시간을 소비 하는 문제가 여러 번 발생 했지만 더 자세한 스타일의 글쓰기는 처음에는 버그를 방지 할 수 있습니다. 문제는 인수 순서의 오류로 구성됩니다. 예를 들어, 그것이 당신에게 잘 보이나요?

if (...) throw new ArgumentNullException("name", "The name should be specified.");
if (...) throw new ArgumentException("name", "The name contains forbidden characters.");

첫눈에 완벽하게 보이지만 버그가 있습니다. 예외 생성자의 서명은 다음과 같습니다.

public ArgumentException(string message, string paramName)
public ArgumentNullException(string paramName, string message)

논증의 순서에 주목 했습니까?

메소드가 동일한 유형의 둘 이상의 인수를 허용 할 때마다 인수 이름이 지정 되는보다 자세한 스타일을 채택함으로써 오류가 다시 발생하지 않도록합니다.

if (...) throw new ArgumentNullException(paramName: "name", message: "The name should be specified.");
if (...) throw new ArgumentException(paramName: "name", message: "The name contains forbidden characters.");

쓰기 시간이 더 길지만 디버깅 시간이 덜 걸립니다.

극단적으로 밀려 나면 매개 변수의 순서를 혼합 할 방법이없는 방법을 포함하여 모든 곳 에서 명명 된 인수를 강제로 사용할 수 있습니다doSomething(int, string) . 이것은 아마도 장기적으로 프로젝트에 해를 끼칠 것이므로 위에서 설명한 버그를 방지하지 않고도 훨씬 더 많은 코드를 얻을 수 있습니다.

귀하의 경우 "아니오 using"규칙 의 동기 는 MyCompany.Something.List<T>vs. 와 같은 잘못된 유형을 사용하기가 더 어렵다는 것 System.Collections.Generic.List<T>입니다.

IMHO, 코드를 읽기 어려운 비용이 잘못된 유형을 잘못 사용하는 위험이 약간 줄어드는 이점보다 훨씬 높지만 적어도이 규칙에 대한 정당한 이유가 있기 때문에 개인적으로 그러한 규칙을 피할 것입니다.


이와 같은 상황은 도구로 감지 할 수 있습니다. ReSharper paramNameInvokerParameterName속성을 표시하고 해당 매개 변수가 없으면 경고를 발행합니다.
Johnbot

2
@ Johnbot : 그들은 할 수 있지만 매우 제한된 수의 경우에 가능합니다. 내가 있다면 SomeBusiness.Something.DoStuff(string name, string description)? 이름과 설명이 무엇인지 이해할만큼 똑똑한 도구는 없습니다.
Arseni Mourzenko

이 경우 @ArseniMourzenko는 심지어 호출이 올바른지 아닌지를 알아내는 데 시간이 걸릴 필요가 있습니다.
Gqqnbig 2016 년

6

네임 스페이스는 코드에 계층 구조를 제공하여 짧은 이름을 허용합니다.

   MyCompany.Headquarters.Team.Leader
   MyCompany.Warehouse.Team.Leader

"using"키워드를 허용하면 일련의 이벤트가 있습니다.

  • 모두가 실제로 하나의 글로벌 네임 스페이스를 사용
    하고 있습니다 (원하는 네임 스페이스를 모두 포함하기 때문에)
  • 사람들이 이름 충돌을 일으키기 시작하거나
  • 이름 충돌에 대해 걱정하십시오 .

따라서 위험을 피하기 위해 모두 긴 이름을 사용하기 시작합니다.

   HeadquartersTeamLeader
   WarehouseTeamLeader

상황이 점점 커지고 있습니다.

  • 다른 사람이 이미 이름을 선택했을 수 있으므로 더 긴 이름을 사용하십시오.
  • 이름이 점점 길어집니다.
  • 길이는 최대 60 자 (영숫자 기준)를 초과 할 수 없습니다.

나는 이것이 일어나는 것을 보았으므로 "사용"을 금지하는 회사들에게 동정 할 수있다.


11
금지 using는 핵 옵션입니다. 네임 스페이스 별명 및 부분 한정이 바람직합니다.
Jim Mischel

1

문제 using는 명시 적 선언없이 네임 스페이스에 마술처럼 추가한다는 것입니다. 이것은 List<>도메인에 익숙하지 않고 어떤 것을 접하고 어떤 using절이 도입 되었는지 알지 못하는 유지 보수 프로그래머에게는 훨씬 더 큰 문제입니다 .

예를 들어 쓰기 import Java.util.*;보다는 Java에서 비슷한 문제가 발생합니다 import Java.util.List;. 후자의 선언 List<>은 소스에서 나중에 발생할 때 그 기원이 import선언 에서 알려 지도록 어떤 이름이 도입되었는지 문서화 합니다 .


6
도메인에 익숙하지 않은 사람이 어려움을 겪는 것이 사실이지만, 그가해야 할 일은 유형 이름 위로 마우스를 가져 가면 정규화 된 이름을 얻게됩니다. 또는 마우스 오른쪽 버튼을 클릭하고 유형 정의로 직접 이동할 수 있습니다. .NET Framework 유형의 경우 아마도 위치가 이미 알고있을 것입니다. 도메인 특정 유형의 경우 편한 사람이 되려면 일주일이 걸릴 것입니다. 그 시점에서 완전한 이름은 이해를 방해하는 소음 일뿐입니다.
Jim Mischel

Jim .. 정의 위에 마우스를 올려 놓아도 작동하지 않습니다. 전 세계의 일부 프로그래머가 Microsoft IDE를 사용하지 않을 가능성을 고려 했습니까? 어떤 경우에는, 당신의 카운터와 소스 것을, 내 지점을 무효화하지 않는 사용은 더 이상 그 자체로 문서입니다
마이클 Montenero

2
예, 최고의 도구를 사용하지 않고 C #에서 일하는 사람들이 있습니다. 그리고 완전한 자격이 "자체 문서화"라는 주장은 약간의 장점이 있지만, 그러한 코드는 가독성에 막대한 비용이 든다. 이 외의 코드는 노이즈를 발생시켜 실제로 코드의 일부를 가릴 수 있습니다.
Jim Mischel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.