태그 보관물: code-smell

code-smell

#regions는 반 패턴 또는 코드 냄새입니까? 있습니다. 내가 할 때마다 다른 클래스

C #에서는 #region/ #endregion키워드를 사용하여 편집기에서 코드 영역을 축소 할 수 있습니다. 내가 할 때마다 다른 클래스 나 메소드로 리팩토링 될 수있는 큰 코드 덩어리를 숨기려고합니다. 예를 들어, 관리하기 쉽도록 3 개 또는 4 개의 영역이있는 500 줄의 코드가 포함 된 메서드를 보았습니다.

지역을 신중하게 사용하는 것이 문제의 징후입니까? 나에게 그런 것 같습니다.



답변

코드 냄새는 잠재적으로 버그의 수를 증가시키는 디자인에 문제가 있음을 나타내는 증상입니다. 이는 지역의 경우에는 해당되지 않지만 지역은 긴 방법처럼 코드 냄새를 유발할 수 있습니다.

이후:

반 패턴 (또는 반 패턴)은 일반적으로 사용될 수 있지만 실제로는 비 효과적이고 반 생산적인 사회 또는 비즈니스 운영 또는 소프트웨어 엔지니어링에 사용되는 패턴입니다.

영역 안티 패턴입니다. 코드의 품질이나 가독성을 높이 지 않는 더 많은 작업이 필요하므로 버그 수를 줄이지 않으며 코드를 리팩토링하기가 더 복잡해질 수 있습니다.

메소드 안에 영역을 사용하지 마십시오. 대신 리팩터링

방법은 짧아야 합니다. 메소드에 10 개의 행만있는 경우 다른 5 개에서 작업 할 때 영역을 사용하여 5 개를 숨기지 않을 수 있습니다.

또한 각 메소드는 하나만 수행해야합니다 . 반면에 지역은 다른 것을 분리 하기위한 입니다. 방법이 A, B를 수행하는 경우 두 영역을 만드는 것이 논리적이지만 잘못된 접근 방식입니다. 대신 메소드를 두 개의 개별 메소드로 리팩토링해야합니다.

이 경우 영역을 사용하면 리팩토링이 더 어려워 질 수 있습니다. 당신이 가지고 있다고 상상해보십시오 :

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    if (!verification)
    {
        throw new DataCorruptedException();
    }

    Do(data);
    DoSomethingElse(data);
    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine();
    auditEngine.Submit(data);
    #endregion
}

첫 번째 영역을 축소하여 두 번째 영역에 집중하는 것은 위험 할뿐만 아니라 흐름을 중지하는 예외를 잊어 버릴 수 있습니다 ( return대신 가드 조항이있을 수 있으므로 더 찾기가 어렵습니다) 코드를 이런 식으로 리팩토링해야하는 경우 :

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    var info = DoSomethingElse(data);

    if (verification)
    {
        Do(data);
    }

    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine(info);
    auditEngine.Submit(
        verification ? new AcceptedDataAudit(data) : new CorruptedDataAudit(data));
    #endregion
}

이제 영역은 의미가 없으며 첫 번째 영역의 코드를 보지 않고 두 번째 영역의 코드를 읽고 이해할 수 없습니다.

때때로 내가 본 또 다른 경우는 다음과 같습니다.

public void DoSomething(string a, int b)
{
    #region Validation of arguments
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }
    #endregion

    #region Do real work
    ...
    #endregion
}

인수 유효성 검사가 수십 개의 LOC에 걸쳐 시작될 때 영역을 사용하고 싶어하지만 .NET Framework 소스 코드에서 사용되는이 문제를 해결하는 더 좋은 방법이 있습니다.

public void DoSomething(string a, int b)
{
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }

    InternalDoSomething(a, b);
}

private void InternalDoSomething(string a, int b)
{
    ...
}

메소드 외부의 영역을 사용하여 그룹화하지 마십시오

  • 어떤 사람들은 그것들을 사용하여 필드, 속성 등을 함께 그룹화합니다. 이 접근법은 잘못되었습니다. 코드가 StyleCop 호환 인 경우 필드, 속성, 개인 메서드, 생성자 등이 이미 그룹화되어 찾기 쉽습니다. 그렇지 않다면 코드베이스 전체에 균일 성을 보장하는 규칙 적용에 대해 생각할 시간입니다.

  • 다른 사람들은 영역을 사용 하여 유사한 엔티티를 많이 숨 깁니다 . 예를 들어, 수백 개의 필드가있는 클래스 (주석과 공백을 세면 최소 500 줄의 코드 작성)가있는 경우 해당 필드를 영역 안에 넣고 축소하여 잊어 버리려는 유혹을받을 수 있습니다. 다시 말하지만, 당신은 잘못하고 있습니다 : 클래스에 너무 많은 필드가 있으므로 상속을 사용하거나 객체를 여러 객체로 슬라이스하는 것에 대해 더 잘 생각해야합니다.

  • 마지막으로 일부 사람들은 영역을 사용 하여 관련 항목그룹화 하려는 유혹을받습니다 . 델리게이트와의 이벤트 또는 IO와 관련된 다른 방법과의 IO 관련 방법 등. 첫 번째 경우, 유지하기 어려운 혼란이됩니다. 읽고 이해하십시오. 두 번째 경우, 더 나은 디자인은 아마도 여러 클래스를 만드는 것입니다.

지역에 잘 사용됩니까?

아니요 . 레거시 사용이있었습니다 : 생성 된 코드. 그럼에도 불구하고 코드 생성 도구는 부분 클래스를 대신 사용해야합니다. C #에 지역 지원이있는 경우 대부분 레거시 사용으로 인해 발생하고 너무 많은 사람들이 코드에 지역을 사용했기 때문에 기존 코드베이스를 손상시키지 않으면 서 지역을 제거 할 수 없습니다.

에 대해 생각하십시오 goto. 언어 나 IDE가 기능을 지원한다고해서 매일 사용해야한다는 의미는 아닙니다. StyleCop SA1124 규칙은 명확합니다. 영역을 사용해서는 안됩니다. 못.

현재 동료의 코드를 코드 검토하고 있습니다. 코드베이스에는 많은 지역이 포함되어 있으며 실제로 지역을 사용하지 않는 방법과 지역이 나쁜 코드로 이어지는 이유의 완벽한 예입니다. 여기 몇 가지 예가 있어요.

4 000 LOC 몬스터 :

최근 Programmers.SE 어딘가에서 파일을 너무 많이 포함 할 때 using( “사용하지 않은 사용 제거”명령을 실행 한 후)이 파일 내부의 클래스가 너무 많이 수행되고 있음을 나타내는 좋은 신호입니다. 파일 자체의 크기에도 동일하게 적용됩니다.

코드를 검토하는 동안 4 000 LOC 파일을 발견했습니다. 이 코드의 작성자는 단순히 15 줄의 동일한 메소드를 수백 번 복사하여 붙여 넣은 것으로 나타 났으며 변수의 이름과 호출 된 메소드를 약간 변경했습니다. 간단한 정규 표현식을 사용하면 몇 가지 제네릭을 추가하여 파일을 4 000 LOC에서 500 LOC로 트리밍 할 수있었습니다. 좀 더 영리한 리팩토링을 사용하면이 클래스가 수십 줄로 줄어들 수 있습니다.

지역을 사용함으로써 저자는 코드를 유지 관리하는 것이 불가능하고 잘못 작성되었다는 사실을 무시하고 코드를 리팩토링하는 대신 코드를 크게 복제하도록 권장했습니다.

지역“Do A”, 지역“Do B”:

또 다른 훌륭한 예로는 단순히 작업 1, 작업 2, 작업 3 등을 수행 한 괴물 초기화 방법이 있습니다. 각각 독립적으로 5 ~ 6 개의 작업이있었습니다. 각 작업은 컨테이너 클래스에서 무언가를 초기화합니다. 이러한 모든 작업은 하나의 방법으로 그룹화되고 지역으로 그룹화되었습니다.

이것은 한 가지 장점이있었습니다.

  • 이 방법은 지역 이름을보고 이해하기가 매우 분명했습니다. 다시 말해 리팩토링 된 동일한 방법은 원래 방법과 동일합니다.

반면에 문제는 여러 가지였습니다.

  • 지역간에 종속성이 있는지는 확실하지 않았습니다. 바라건대, 변수 재사용은 없었습니다. 그렇지 않으면 유지 관리가 훨씬 악몽이 될 수 있습니다.

  • 이 방법은 테스트하기가 거의 불가능했습니다. 한 번에 20 가지를 수행하는 방법이 올바르게 수행되는지 어떻게 쉽게 알 수 있습니까?

필드 영역, 속성 영역, 생성자 영역 :

검토 된 코드에는 모든 필드, 모든 속성 등을 그룹화하는 많은 영역이 포함되어 있습니다. 이는 명백한 문제인 소스 코드 증가입니다.

파일을 열고 방대한 필드 목록을 보면 클래스를 먼저 리팩터링 한 다음 코드를 사용하는 경향이 있습니다. 지역에서는 물건을 무너 뜨리고 잊어 버리는 습관이 있습니다.

또 다른 문제는 모든 곳에서 수행하면 하나의 블록 영역을 만드는 것입니다. 이것은 실제로 내가 검토 한 코드에서 #region Constructor하나의 생성자 를 포함하는 많은 경우였습니다 .

마지막으로 필드, 속성, 생성자 등 은 이미 순서대로되어 있어야 합니다. 그것들이 관례 (대문자로 시작하는 상수 등)와 일치하면 요소의 유형이 멈추고 다른 시작 부분이 이미 분명하므로 명확하게 영역을 만들 필요가 없습니다.


답변

얼마나 많은 사람들 이 열정적으로 지역을 싫어하는지는 정말 놀랍습니다 !

나는 많은 반대 의견에 전적으로 동의합니다. 코드를 #region보이지 않게 숨기면 좋지 않습니다. 클래스를 #regions별도의 클래스로 리팩토링해야 할 때로 클래스를 나누는 것은 분명히 실수입니다. a #region를 사용하여 중복 된 의미 정보를 임베드 하는 것이 좋습니다.

그러나 그중 어느 것도 코드에서 영역을 사용하는 데 본질적으로 잘못된 것이 없다는 것을 의미하지 않습니다 ! 나는 대부분의 사람들의 반대 의견이 다른 사람들이 이와 같은 IDE 기능을 잘못 사용하려는 경향이있는 팀에서 일했다고 가정 할 수 있습니다. 본인은 일차적으로 일하는 것이 고급 스러우며 지역이 워크 플로를 구성하는 데 도움이 된 방식에 감사합니다. 어쩌면 그것은 강박 관념 장애 일지 모르지만 화면에서 얼마나 깔끔하고 우아하게 작성 되었든 한 번에 많은 코드를보고 싶지 않습니다. 논리적 지역으로 물건을 분리하면 제가 코드를 붕괴 할 수 없는 내가 코드에 작업에 대한 관심을 수행하십시오신경써 필자가 잘못 작성한 코드를 무시하지 않고있는 것보다 코드를 리팩터링하는 것이 이치에 맞지 않으며 추가 “메타”조직은 무의미한 것이 아니라 설명 적입니다.

이제 C ++에서 Windows API에 직접 프로그래밍하는 데 더 많은 시간을 보냈으므로 지역에 대한 지원이 C #만큼 좋기를 바랍니다. 대체 GUI 라이브러리를 사용하면 코드가 더 간단하거나 명확 해 지므로 화면에서 관련없는 코드 노이즈를 제거 할 필요가 없지만 다른 이유는 있습니다. 키보드와 IDE에 능숙하여 지역으로 세분화 된 코드를 확장 / 축소하는 데 1 초도 걸리지 않습니다. 내가 생각하고있는 코드만으로 의식의 초점을 제한하려고 노력하는 것은 두뇌의 힘을 아끼는 시간보다 가치가 있습니다. 그것은 모두 하나의 클래스 / 파일에 속하지만 동시에 내 화면에 속하지는 않습니다.

요점은 #regions코드를 분리하고 논리적으로 나누는 데 사용 하는 것이 모든 비용을 피하는 것이 나쁜 것은 아니라는 것입니다. Ed가 지적했듯이 “코드 냄새”가 아닙니다. 코드 냄새가 나면 해당 코드가 해당 지역에서 나오는 것이 아니라 해당 지역에 묻으려는 코드에서 온 것인지 확인할 수 있습니다. 기능이보다 체계적으로 구성되거나 더 나은 코드를 작성하는 데 도움이된다면 사용이라고합니다 . 방해가되거나 잘못 사용하는 경우 사용 을 중지 하십시오. 최악의 상황이 최악의 상황에서이를 사용하는 사람들과 팀을 이루어야하는 경우 키보드 단축키를 외우면 코드 외곽선이 꺼집니다. Ctrl+ M, Ctrl+P. 그리고 불평을 그만두십시오. 때때로 나는 이것이 “진정한”, “하드 코어”프로그래머로 보이기를 원하는 사람들이 스스로 시도하고 증명하는 것을 좋아하는 또 다른 방법이라는 느낌을받습니다. 구문 색상 표시를 피하는 것보다 영역을 피하는 것이 좋습니다. 그것은 당신을 더 사나운 개발자로 만들지 않습니다.

모든 방법 에서 , 메소드 내의 영역 은 단지 넌센스입니다. 당신이 그것을 원할 때마다, 당신은 별도의 방법으로 리팩토링해야합니다. 변명하지.


답변

우선, 더 이상 “코드 냄새”라는 용어를 참을 수 없습니다. 너무 자주 사용되며 좋은 코드를 물지 않으면 인식하지 못하는 사람들이 많이 사용합니다. 어쨌든 …

나는 개인적으로 많은 지역을 사용하는 것을 좋아하지 않습니다. 코드를 얻는 것이 더 어려워지고 코드가 관심이 있습니다. 매우 자주 만질 필요가없는 코드가 많을 때 지역을 좋아합니다. 그 외에도 그들은 내 방식대로 들어가는 것처럼 보이며 “비공개 방법”, “공용 방법”등과 같은 지역은 나를 미치게합니다. 그들은 다양한 의견에 유사합니다 i++ //increment i.

또한이 용어는 텍스트 편집기의 레이아웃이 아니라 프로그램 논리 / 디자인 패턴을 설명하는 데 일반적으로 사용되므로 영역 사용은 실제로 “반 패턴”이 될 수 없다고 덧붙입니다. 이것은 주관적입니다. 당신을 위해 일하는 것을 사용하십시오. 안티 패턴이 중요한 지역을 과도하게 사용하여 유지 보수 할 수없는 프로그램을 끝내지 않을 것입니다. 🙂


답변

그렇습니다 지역은 코드 냄새입니다!

컴파일러에서 영역이 모두 제거되어 기쁩니다. 모든 개발자는 다른 프로그래머에게 결코 가치가없는 자신의 무의미한 정리 체계를 고안합니다. 나는 아기를 꾸미고 아름답게 만들고자하는 프로그래머와 관련이 있으며 실제 가치와는 아무런 관련이 없습니다.

“게 이즈, 내 동료가 여기에서 일부 지역을 사용했으면 좋겠다”고 생각하는 한 가지 예가 있습니까?

모든 영역을 자동으로 확장하도록 IDE를 구성 할 수는 있지만 여전히 눈이 멀고 실제 코드를 읽는 데 어려움이 있습니다.

모든 공개 방법이 함께 묶여 있는지 여부는 정말로 덜 중요합니다. 축하합니다. 변수 선언과 초기화의 차이점을 알고 코드에 표시 할 필요가 없습니다.

무가치 손질!

또한 파일을 사용하고 영역을 사용하여 ‘정보 아키텍처’가 필요한 경우 핵심 문제와 싸우고 싶을 수 있습니다. 수업이 너무 큽니다! 작은 부분으로 나누는 것이 훨씬 유리하며 제대로 수행되면 진정한 의미 / 가독성이 추가됩니다.


답변

개인적으로 다양한 유형의 메소드 또는 코드 부분을 그룹화하는 방법으로 영역을 사용합니다.

따라서 코드 파일을 열 때 다음과 같이 보일 수 있습니다.

  • 공공 재산
  • 생성자
  • 저장 방법
  • 방법 편집
  • 개인 헬퍼 메소드

메소드 안에 영역을 넣지 않습니다. 코드 냄새의 징조 인 IMHO. 나는 한때 1200 줄이 넘는 방법을 발견했고 그 안에 5 개의 다른 지역이있었습니다. 무서운 광경이었다!

다른 개발자를 위해 더 빨리 찾을 수있는 방식으로 코드를 구성하는 방법으로 코드를 사용하는 경우 문제의 징후라고 생각하지 않습니다. 메소드 내부에서 코드 행을 숨기려면이 메소드를 다시 생각할 시간이라고 말하고 싶습니다.


답변

사용하여 #region매우 큰 클래스를 읽을 수 있도록 블록은 일반적으로 단일 책임의 원칙을 위반하는 기호입니다. 그들이 행동을 그룹화하는 데 사용된다면 , 수업이 너무 많은 일을하고 있을 가능성 이 있습니다 (다시 SRP를 위반).

“코드 냄새”줄을 고수하면서 #region블록 자체는 코드 냄새가 아니라 냄새를 숨기려고하는 “코드에 대한 열풍”입니다. 과거에는 톤을 많이 사용했지만 리팩토링을 시작하면 많이 숨기지 않기 때문에 더 적게 보이기 시작합니다.


답변

여기서 핵심 단어는 “유의 한”입니다. 메소드 안에 영역을 넣는 것이 합리적이라고 생각하기는 어렵습니다. 코드 숨김과 게으름이 너무 많습니다. 그러나 몇 가지 영역을 여기저기서 코드로 작성해야하는 이유가있을 수 있습니다.

많은 지역이 있다면 코드 냄새라고 생각합니다. 지역은 종종 향후 리팩토링을위한 가능한 장소의 힌트입니다. 많은 지역은 누군가가 실제로 힌트를 얻지 못한다는 것을 의미합니다.

신중하게 사용하면 많은 메소드를 가진 단일 클래스의 구조와 각각에 몇 개의 메소드를 가진 많은 클래스의 구조 사이에 좋은 중간 근거를 제공합니다. 클래스가 여러 클래스로 리팩토링되어야하는 시점에 가까워지기 시작했을 때 가장 유용하지만 아직은 그렇지 않습니다. 관련 메소드를 그룹화하여 나중에 계속 증가하는 관련 메소드 세트를 자체 클래스로 쉽게 추출 할 수 있습니다. 예를 들어, 500 줄의 코드에 접근하는 클래스가있는 경우 한 지역에서 함께 수집 된 총 200 줄의 코드를 사용하는 메소드 집합은 어떻게 든 리팩터링하기에 좋은 조각 일 것입니다. 방법도 좋은 대상이 될 수 있습니다.

영역을 사용하는 또 다른 방법은 큰 방법을 리팩토링하는 부정적인 영향 중 하나를 줄이는 것입니다. 독자가 주로 관련이없는 다른 방법을 찾기 위해 스크롤해야하는 작고 간결하며 쉽게 재사용되는 많은 방법. 지역은 독자를 위해 메소드와 헬퍼를 메타 캡슐화하는 좋은 방법이 될 수 있으므로 클래스의 다른 측면에서 작업하는 사람은 메소드를 축소하고 코드의 해당 부분을 빠르게 닫을 수 있습니다. 물론 이것은 지역이 실제로 체계적으로 구성되어 본질적으로 코드를 문서화하는 다른 방법으로 사용되는 경우에만 작동합니다.

일반적으로 지역은 내가 조직을 유지하고 코드를 “문서화”하는 데 도움이되며 지역을 사용하지 않는 경우보다 훨씬 빨리 리팩토링 할 수있는 장소를 찾도록 도와줍니다.