다른 함수 만 호출하는 함수 이것이 좋은 습관입니까?


13

현재 다양한 섹션 (모두 다른 형식이 필요함)이있는 보고서 세트를 작성 중이며 코드를 구성하는 가장 좋은 방법을 찾으려고합니다. 과거에 우리가했던 비슷한 보고서는 보고서의 모든 데이터 조작 및 서식을 수행하는 매우 큰 (200+ 라인) 기능을 가지므로 워크 플로는 다음과 같습니다.

DataTable reportTable = new DataTable();
void RunReport()
{
    reportTable = DataClass.getReportData();
    largeReportProcessingFunction();
    outputReportToUser();
}

이 큰 기능을 더 작은 덩어리로 나누고 싶지만 재사용 할 수없는 수십 개의 함수와 비슷한 역할을하는 "여기에 모든 것을 수행"하는 기능이 끝나는 것이 두렵습니다. 다음과 같이 작은 모든 함수를 호출하십시오.

void largeReportProcessingFunction()
{
    processSection1HeaderData();
    calculateSection1HeaderAverages();
    formatSection1HeaderDisplay();
    processSection1SummaryTableData();
    calculateSection1SummaryTableTotalRow();
    formatSection1SummaryTableDisplay();
    processSection1FooterData();
    getSection1FooterSummaryTotals();
    formatSection1FooterDisplay();

    processSection2HeaderData();
    calculateSection1HeaderAverages();
    formatSection1HeaderDisplay();
    calculateSection1HeaderAverages();
    ...
}

또는 한 단계 더 나아가면 :

void largeReportProcessingFunction()
{
    callAllSection1Functions();

    callAllSection2Functions();

    callAllSection3Functions();
    ...        
}

이것이 더 나은 해결책입니까? 조직적 관점에서 나는 그것이 (즉, 모든 것이 다른 것보다 훨씬 더 조직적이라고) 가정한다고 생각하지만, 코드 가독성에 대해서는 확실하지 않습니다 (잠재적으로는 다른 함수를 호출하는 큰 함수 체인).

생각?


하루가 끝나면 ... 가독성이 더 좋습니까? 예, 더 나은 솔루션입니다.
sylvanaar

답변:


18

이것은 일반적으로 기능적 분해 라고하며 일반적으로 올바르게 수행하면 좋습니다.

또한 함수의 구현은 단일 추상화 레벨 내에 있어야합니다. 를 수행하는 경우 largeReportProcessingFunction역할은 어떤 다른 처리 단계를 어떤 순서로 수행할지 정의하는 것입니다. 각 단계의 구현은 아래 추상화 계층 largeReportProcessingFunction에 있으며 직접 의존해서는 안됩니다.

그러나 이것은 네이밍의 잘못된 선택입니다.

void largeReportProcessingFunction() {
    callAllSection1Functions();
    callAllSection2Functions();
    callAllSection3Functions();
    ...        
}

당신은 볼 callAllSection1Functions실제로 말을하지 않기 때문에 실제로 추상화를 제공하지 않는 이름이 무엇 는 않습니다가 아니라 어떻게 그것을 않습니다. processSection1대신에 또는 문맥 상 실제로 의미있는 것을 호출해야합니다 .


6
"processSection1"이 의미있는 이름 인 방법을 볼 수 없다는 점을 제외하고는이 답변에 원칙적으로 동의합니다. 실제로는 "callAllSection1Functions"와 같습니다.
Eric King

2
@EricKing : callAllSection1Functions구현에 대한 세부 정보가 유출됩니다. 외부 관점에서 processSection1작업이 "모든 section1 기능"에 지연 되는지 또는 직접 수행하는지 또는 실제 작업을 수행하는 유니콘을 소환하기 위해 pixie-dust를 사용하는지 여부는 중요하지 않습니다. 를 호출 한 후 정말 문제입니다 그 모든 것을 processSection1, 섹션 1은 고려 될 수 처리 . 처리 는 일반적인 이름이지만 동의 가 높으면 (항상 노력해야 함) 문맥이 명확하게 명확 해집니다.
back2dos

2
"processXXX"라는 메소드는 거의 항상 끔찍하고 쓸모없는 이름입니다. 모든 방법은 'process'사물이므로 이름을 'processXXX'로 지정하는 것은 이름을 'doSomethingWithXXX'또는 'manipulateXXX'로 지정하는 것과 비슷합니다. 'processXXX'라는 메소드에는 거의 항상 더 나은 이름이 있습니다. 실제적인 관점에서 보면 'callAllSection1Functions'만큼 유용합니다.
Eric King

4

C #을 사용한다고 말 했으므로 객체 지향 언어를 사용한다는 사실을 활용하여 구조적 클래스 계층 구조를 작성할 수 있는지 궁금합니다. 예를 들어, 보고서를 섹션으로 나누는 것이 합리적이라면 Section클래스를 만들어 고객 별 요구 사항에 맞게 확장하십시오.

비 대화식 GUI를 만드는 것처럼 생각하는 것이 좋습니다. 다른 GUI 구성 요소 인 것처럼 작성할 수있는 오브젝트를 생각하십시오. 기본 보고서가 어떤 것인지 스스로에게 물어보십시오. 복잡한 것은 어떻습니까? 확장 점은 어디에 있어야합니까?


3

때에 따라 다르지. 작성하는 모든 함수가 실제로 단일 작업 단위 인 경우 호출 함수의 1-15, 16-30, 31-45 행에 해당하는 경우에는 문제가 없습니다. 하나의 작업을 수행하는 경우 긴 기능은 악의가 아닙니다. 보고서에 20 개의 필터가 모두 길어질 것입니다. 괜찮습니다. 필터 또는 필터 그룹으로 분류하면 더 큰 복잡성을 추가 할 수 있습니다.

개인 기능이 많으면 자동화 된 단위 테스트가 더 어려워 지므로 일부는 이러한 이유로 인해이를 피하려고 시도하지만 테스트를 수용하기 위해 더 복잡한 더 복잡한 디자인을 만드는 경향이 있기 때문에이 견해는 추론이 어렵습니다.


3
내 경험상 긴 기능 악하다.
Bernard

예제가 OO 언어 인 경우 기본 필터 클래스를 만들고 20 개의 필터 각각이 다른 파생 클래스에 있습니다. 올바른 필터를 얻으려면 스위치 문이 생성 호출로 대체됩니다. 각 기능은 하나의 작업을 수행하며 모두 작습니다.
DXM

3

C #을 사용하고 있으므로 객체를 더 많이 생각하십시오. 후속 함수가 의존하는 "전역"클래스 변수를 가짐으로써 여전히 절차 적으로 코딩하는 것처럼 보입니다.

개별 함수에서 논리를 분리하는 것이 단일 함수에서 모든 논리를 갖는 것보다 확실히 좋습니다. 나는 여러 객체에서 이것을 분해하여 함수가 작동하는 데이터를 분리하여 더 나아갈 수 있다고 확신합니다.

보고서 데이터를 전달할 수있는 ReportBuilder 클래스를 고려하십시오. ReportBuilder를 별도의 클래스로 나눌 수 있다면이 작업을 수행하십시오.


2
절차는 완벽하게 좋은 기능을합니다.
DeadMG

1

예.

여러 장소에서 자체 기능을 사용해야하는 코드 세그먼트가있는 경우 그렇지 않으면 기능을 변경해야하는 경우 여러 위치에서 변경해야합니다. 이것은 작업을 증가시킬뿐만 아니라 한 장소에서 코드가 변경 될 때 버그가 나타날 위험을 증가시킵니다.

또한 설명적인 메소드 이름이 사용되는 경우 메소드를 더 읽기 쉽게 만듭니다.


1

함수를 구별하기 위해 번호 매기기를 사용한다는 사실은 중복 또는 클래스가 너무 많은 기본 문제가 있음을 나타냅니다. 큰 함수를 여러 개의 작은 함수로 나누는 것은 복제를 리팩토링하는 데 유용한 단계 일 수 있지만 마지막 단계는 아닙니다. 예를 들어 두 가지 기능을 만듭니다.

processSection1HeaderData();
processSection2HeaderData();

섹션 헤더를 처리하는 데 사용되는 코드에 유사점이 없습니까? 차이점을 매개 변수화하여 두 가지에 대한 공통 함수를 추출 할 수 있습니까?


이것은 실제로 프로덕션 코드가 아니기 때문에 함수 이름은 예제 일뿐입니다 (프로덕션에서 함수 이름은 더 설명적임). 일반적으로 아니요, 서로 다른 섹션 간에는 유사성이 없습니다 (유사성이 있지만 가능한 한 코드를 재사용하려고합니다).
Eric C.

1

하위 기능을 재사용하지 않더라도 함수를 논리적 하위 기능으로 나누는 것이 도움이됩니다. 기능을 짧고 이해하기 쉬운 블록으로 나눕니다. 그러나 그것은 단지 n 줄의 줄뿐만 아니라 논리적 인 단위로 이루어져야합니다. 어떻게 구분해야 하는가는 코드에 따라 다르며 일반적인 주제는 동일한 객체에 대한 루프, 조건, 작업입니다. 기본적으로 개별 작업으로 설명 할 수있는 모든 것.

그렇습니다. 좋은 스타일입니다. 이상하게 들릴지 모르지만 재사용이 제한적이라고 생각하면 재사용 재사용에 대해 신중하게 생각하는 것이 좋습니다. 우연히 동일한 것이 아니라 사용법이 동일해야합니다. 동일한 블록에서 모든 사례를 처리하려고 시도하는 것은 종종 처음부터 큰 기능을 수행하는 방법입니다.


0

나는 이것이 주로 개인적인 취향이라고 생각합니다. 함수가 재사용 될 예정이라면 (그리고 더 일반적이고 재사용 할 수 없었습니까?) 나는 분명히 그것들을 분리한다고 말할 것입니다. 또한 함수 나 메소드에 2-3 화면 이상의 코드가 없어야한다는 것이 좋은 원칙이라고 들었습니다. 따라서 큰 기능이 계속 작동하면 코드를 더 읽기 쉽게 만들 수 있습니다.

이러한 보고서를 개발하기 위해 어떤 기술을 사용하고 있는지 언급하지 않았습니다. C #을 사용하고있는 것 같습니다. 그 맞습니까? 그렇다면 함수를 더 작은 것으로 나누지 않으려는 경우 #region 지시문 을 대안으로 고려할 수도 있습니다.


예, 저는 C #에서 일하고 있습니다. 일부 기능을 재사용 할 수는 있지만 이러한 보고서 중 많은 부분에 대해 서로 다른 섹션의 데이터 및 레이아웃이 크게 다릅니다 (고객 요구 사항).
Eric C.

1
지역 추천을 제외한 +1 지역을 사용하지 않습니다.
Bernard

@Bernard-특별한 이유가 있습니까? 나는 asker가 이미 함수 분할을 배제하지 않은 경우에만 #regions 사용을 고려한다고 가정합니다.
Joshua Carmody

2
지역은 코드를 숨기고 악용 될 수 있습니다 (예 : 중첩 지역). 코드 파일에서 모든 코드를 한 번에 보는 것이 좋습니다. 파일에서 코드를 시각적으로 분리 해야하는 경우 슬래시 줄을 사용합니다.
Bernard

2
지역은 일반적으로 코드 리팩토링이 필요한 신호입니다.
Coder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.